diff --git a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp index 10863b43..befff9aa 100644 --- a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp +++ b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp @@ -7,272 +7,313 @@ #include #include -namespace amdgpu::bridge { -struct PadState { - std::uint64_t timestamp; - std::uint32_t unk; - std::uint32_t buttons; - std::uint8_t leftStickX; - std::uint8_t leftStickY; - std::uint8_t rightStickX; - std::uint8_t rightStickY; - std::uint8_t l2; - std::uint8_t r2; -}; - -enum { - kPadBtnL3 = 1 << 1, - kPadBtnR3 = 1 << 2, - kPadBtnOptions = 1 << 3, - kPadBtnUp = 1 << 4, - kPadBtnRight = 1 << 5, - kPadBtnDown = 1 << 6, - kPadBtnLeft = 1 << 7, - kPadBtnL2 = 1 << 8, - kPadBtnR2 = 1 << 9, - kPadBtnL1 = 1 << 10, - kPadBtnR1 = 1 << 11, - kPadBtnTriangle = 1 << 12, - kPadBtnCircle = 1 << 13, - kPadBtnCross = 1 << 14, - kPadBtnSquare = 1 << 15, - kPadBtnTouchPad = 1 << 20, - kPadBtnIntercepted = 1 << 31, -}; - -enum class CommandId : std::uint32_t { - Nop, - ProtectMemory, - CommandBuffer, - Flip -}; - -struct CmdMemoryProt { - std::uint64_t address; - std::uint64_t size; - std::uint32_t prot; -}; - -struct CmdCommandBuffer { - std::uint64_t queue; - std::uint64_t address; - std::uint64_t size; -}; - -struct CmdBuffer { - std::uint32_t width; - std::uint32_t height; - std::uint32_t pitch; - std::uint64_t address; - std::uint32_t pixelFormat; - std::uint32_t tilingMode; -}; - -struct CmdFlip { - std::uint32_t bufferIndex; - std::uint64_t arg; -}; - -enum { - kPageWriteWatch = 1 << 0, - kPageReadWriteLock = 1 << 1, - kPageInvalidated = 1 << 2, - kPageLazyLock = 1 << 3 -}; - -static constexpr auto kHostPageSize = 0x1000; - -struct BridgeHeader { - std::uint64_t size; - std::uint64_t info; - std::uint32_t pullerPid; - std::uint32_t pusherPid; - volatile std::uint64_t flags; - std::uint64_t vmAddress; - std::uint64_t vmSize; - char vmName[32]; - PadState kbPadState; - volatile std::uint32_t flipBuffer; - volatile std::uint64_t flipArg; - volatile std::uint64_t flipCount; - volatile std::uint64_t bufferInUseAddress; - std::uint32_t memoryAreaCount; - std::uint32_t commandBufferCount; - std::uint32_t bufferCount; - CmdMemoryProt memoryAreas[128]; - CmdCommandBuffer commandBuffers[32]; - CmdBuffer buffers[8]; - // orbis::shared_mutex cacheCommandMtx; - // orbis::shared_cv cacheCommandCv; - std::atomic cacheCommands[4]; - std::atomic gpuCacheCommand; - std::atomic cachePages[0x100'0000'0000 / kHostPageSize]; - - volatile std::uint64_t pull; - volatile std::uint64_t push; - std::uint64_t commands[]; -}; - -struct Command { - CommandId id; - - union { - CmdMemoryProt memoryProt; - CmdCommandBuffer commandBuffer; - CmdBuffer buffer; - CmdFlip flip; - }; -}; - -enum class BridgeFlags { - VmConfigured = 1 << 0, - PushLock = 1 << 1, - PullLock = 1 << 2, -}; - -struct BridgePusher { - BridgeHeader *header = nullptr; - - BridgePusher() = default; - BridgePusher(BridgeHeader *header) : header(header) {} - - void setVm(std::uint64_t address, std::uint64_t size, const char *name) { - header->vmAddress = address; - header->vmSize = size; - std::strncpy(header->vmName, name, sizeof(header->vmName)); - header->flags = - header->flags | static_cast(BridgeFlags::VmConfigured); - } - - void sendMemoryProtect(std::uint64_t address, std::uint64_t size, - std::uint32_t prot) { - sendCommand(CommandId::ProtectMemory, {address, size, prot}); - } - - void sendCommandBuffer(std::uint64_t queue, std::uint64_t address, - std::uint64_t size) { - sendCommand(CommandId::CommandBuffer, {queue, address, size}); - } - - void sendFlip(std::uint32_t bufferIndex, std::uint64_t arg) { - sendCommand(CommandId::Flip, {bufferIndex, arg}); - } - - void wait() { - while (header->pull != header->push) - ; - } - -private: - static std::uint64_t makeCommandHeader(CommandId id, std::size_t cmdSize) { - return static_cast(id) | - (static_cast(cmdSize - 1) << 32); - } - - void sendCommand(CommandId id, std::initializer_list args) { - std::size_t cmdSize = args.size() + 1; - std::uint64_t pos = getPushPosition(cmdSize); - - header->commands[pos++] = makeCommandHeader(id, cmdSize); - for (auto arg : args) { - header->commands[pos++] = arg; - } - header->push = pos; - } - - std::uint64_t getPushPosition(std::uint64_t cmdSize) { - std::uint64_t position = header->push; - - if (position + cmdSize > header->size) { - if (position < header->size) { - header->commands[position] = - static_cast(CommandId::Nop) | - ((header->size - position - 1) << 32); - } - - position = 0; - waitPuller(cmdSize); - } - - return position; - } - void waitPuller(std::uint64_t pullValue) { - while (header->pull < pullValue) { - ; - } - } -}; - -struct BridgePuller { - BridgeHeader *header = nullptr; - - BridgePuller() = default; - BridgePuller(BridgeHeader *header) : header(header) {} - - std::size_t pullCommands(Command *commands, std::size_t maxCount) { - std::size_t processed = 0; - - while (processed < maxCount) { - if (header->pull == header->push) { - break; - } - - auto pos = header->pull; - auto cmd = header->commands[pos]; - CommandId cmdId = static_cast(cmd); - std::uint32_t argsCount = cmd >> 32; - - if (cmdId != CommandId::Nop) { - commands[processed++] = - unpackCommand(cmdId, header->commands + pos + 1, argsCount); - } - - auto newPull = pos + argsCount + 1; - - if (newPull >= header->size) { - newPull = 0; - } - - header->pull = newPull; - } - - return processed; - } - -private: - Command unpackCommand(CommandId command, const std::uint64_t *args, - std::uint32_t argsCount) { - Command result; - result.id = command; - - switch (command) { - case CommandId::Nop: - return result; - - case CommandId::ProtectMemory: - result.memoryProt.address = args[0]; - result.memoryProt.size = args[1]; - result.memoryProt.prot = args[2]; - return result; - - case CommandId::CommandBuffer: - result.commandBuffer.queue = args[0]; - result.commandBuffer.address = args[1]; - result.commandBuffer.size = args[2]; - return result; - - case CommandId::Flip: - result.flip.bufferIndex = args[0]; - result.flip.arg = args[1]; - return result; - } - - __builtin_trap(); - } -}; - -BridgeHeader *createShmCommandBuffer(const char *name); -BridgeHeader *openShmCommandBuffer(const char *name); -void destroyShmCommandBuffer(BridgeHeader *buffer); -void unlinkShm(const char *name); +namespace amdgpu::bridge +{ + struct PadState + { + std::uint64_t timestamp; + std::uint32_t unk; + std::uint32_t buttons; + std::uint8_t leftStickX; + std::uint8_t leftStickY; + std::uint8_t rightStickX; + std::uint8_t rightStickY; + std::uint8_t l2; + std::uint8_t r2; + }; + + enum + { + kPadBtnL3 = 1 << 1, + kPadBtnR3 = 1 << 2, + kPadBtnOptions = 1 << 3, + kPadBtnUp = 1 << 4, + kPadBtnRight = 1 << 5, + kPadBtnDown = 1 << 6, + kPadBtnLeft = 1 << 7, + kPadBtnL2 = 1 << 8, + kPadBtnR2 = 1 << 9, + kPadBtnL1 = 1 << 10, + kPadBtnR1 = 1 << 11, + kPadBtnTriangle = 1 << 12, + kPadBtnCircle = 1 << 13, + kPadBtnCross = 1 << 14, + kPadBtnSquare = 1 << 15, + kPadBtnTouchPad = 1 << 20, + kPadBtnIntercepted = 1 << 31, + }; + + enum class CommandId : std::uint32_t + { + Nop, + ProtectMemory, + CommandBuffer, + Flip + }; + + struct CmdMemoryProt + { + std::uint64_t address; + std::uint64_t size; + std::uint32_t prot; + }; + + struct CmdCommandBuffer + { + std::uint64_t queue; + std::uint64_t address; + std::uint64_t size; + }; + + struct CmdBuffer + { + std::uint32_t width; + std::uint32_t height; + std::uint32_t pitch; + std::uint64_t address; + std::uint32_t pixelFormat; + std::uint32_t tilingMode; + }; + + struct CmdFlip + { + std::uint32_t bufferIndex; + std::uint64_t arg; + }; + + enum + { + kPageWriteWatch = 1 << 0, + kPageReadWriteLock = 1 << 1, + kPageInvalidated = 1 << 2, + kPageLazyLock = 1 << 3 + }; + + static constexpr auto kHostPageSize = 0x1000; + + struct BridgeHeader + { + std::uint64_t size; + std::uint64_t info; + std::uint32_t pullerPid; + std::uint32_t pusherPid; + volatile std::uint64_t flags; + std::uint64_t vmAddress; + std::uint64_t vmSize; + char vmName[32]; + PadState kbPadState; + volatile std::uint32_t flipBuffer; + volatile std::uint64_t flipArg; + volatile std::uint64_t flipCount; + volatile std::uint64_t bufferInUseAddress; + std::uint32_t memoryAreaCount; + std::uint32_t commandBufferCount; + std::uint32_t bufferCount; + CmdMemoryProt memoryAreas[128]; + CmdCommandBuffer commandBuffers[32]; + CmdBuffer buffers[8]; + // orbis::shared_mutex cacheCommandMtx; + // orbis::shared_cv cacheCommandCv; + std::atomic cacheCommands[4]; + std::atomic gpuCacheCommand; + std::atomic cachePages[0x100'0000'0000 / kHostPageSize]; + + volatile std::uint64_t pull; + volatile std::uint64_t push; + std::uint64_t commands[]; + }; + + struct Command + { + CommandId id; + + union + { + CmdMemoryProt memoryProt; + CmdCommandBuffer commandBuffer; + CmdBuffer buffer; + CmdFlip flip; + }; + }; + + enum class BridgeFlags + { + VmConfigured = 1 << 0, + PushLock = 1 << 1, + PullLock = 1 << 2, + }; + + struct BridgePusher + { + BridgeHeader* header = nullptr; + + BridgePusher() = default; + BridgePusher(BridgeHeader* header) + : header(header) + { + } + + void setVm(std::uint64_t address, std::uint64_t size, const char* name) + { + header->vmAddress = address; + header->vmSize = size; + std::strncpy(header->vmName, name, sizeof(header->vmName)); + header->flags = + header->flags | static_cast(BridgeFlags::VmConfigured); + } + + void sendMemoryProtect(std::uint64_t address, std::uint64_t size, + std::uint32_t prot) + { + sendCommand(CommandId::ProtectMemory, {address, size, prot}); + } + + void sendCommandBuffer(std::uint64_t queue, std::uint64_t address, + std::uint64_t size) + { + sendCommand(CommandId::CommandBuffer, {queue, address, size}); + } + + void sendFlip(std::uint32_t bufferIndex, std::uint64_t arg) + { + sendCommand(CommandId::Flip, {bufferIndex, arg}); + } + + void wait() + { + while (header->pull != header->push) + ; + } + + private: + static std::uint64_t makeCommandHeader(CommandId id, std::size_t cmdSize) + { + return static_cast(id) | + (static_cast(cmdSize - 1) << 32); + } + + void sendCommand(CommandId id, std::initializer_list args) + { + std::size_t cmdSize = args.size() + 1; + std::uint64_t pos = getPushPosition(cmdSize); + + header->commands[pos++] = makeCommandHeader(id, cmdSize); + for (auto arg : args) + { + header->commands[pos++] = arg; + } + header->push = pos; + } + + std::uint64_t getPushPosition(std::uint64_t cmdSize) + { + std::uint64_t position = header->push; + + if (position + cmdSize > header->size) + { + if (position < header->size) + { + header->commands[position] = + static_cast(CommandId::Nop) | + ((header->size - position - 1) << 32); + } + + position = 0; + waitPuller(cmdSize); + } + + return position; + } + void waitPuller(std::uint64_t pullValue) + { + while (header->pull < pullValue) + { + ; + } + } + }; + + struct BridgePuller + { + BridgeHeader* header = nullptr; + + BridgePuller() = default; + BridgePuller(BridgeHeader* header) + : header(header) + { + } + + std::size_t pullCommands(Command* commands, std::size_t maxCount) + { + std::size_t processed = 0; + + while (processed < maxCount) + { + if (header->pull == header->push) + { + break; + } + + auto pos = header->pull; + auto cmd = header->commands[pos]; + CommandId cmdId = static_cast(cmd); + std::uint32_t argsCount = cmd >> 32; + + if (cmdId != CommandId::Nop) + { + commands[processed++] = + unpackCommand(cmdId, header->commands + pos + 1, argsCount); + } + + auto newPull = pos + argsCount + 1; + + if (newPull >= header->size) + { + newPull = 0; + } + + header->pull = newPull; + } + + return processed; + } + + private: + Command unpackCommand(CommandId command, const std::uint64_t* args, + std::uint32_t argsCount) + { + Command result; + result.id = command; + + switch (command) + { + case CommandId::Nop: + return result; + + case CommandId::ProtectMemory: + result.memoryProt.address = args[0]; + result.memoryProt.size = args[1]; + result.memoryProt.prot = args[2]; + return result; + + case CommandId::CommandBuffer: + result.commandBuffer.queue = args[0]; + result.commandBuffer.address = args[1]; + result.commandBuffer.size = args[2]; + return result; + + case CommandId::Flip: + result.flip.bufferIndex = args[0]; + result.flip.arg = args[1]; + return result; + } + + __builtin_trap(); + } + }; + + BridgeHeader* createShmCommandBuffer(const char* name); + BridgeHeader* openShmCommandBuffer(const char* name); + void destroyShmCommandBuffer(BridgeHeader* buffer); + void unlinkShm(const char* name); } // namespace amdgpu::bridge diff --git a/hw/amdgpu/bridge/src/bridge.cpp b/hw/amdgpu/bridge/src/bridge.cpp index 63bb1fd1..3c1cf555 100644 --- a/hw/amdgpu/bridge/src/bridge.cpp +++ b/hw/amdgpu/bridge/src/bridge.cpp @@ -7,80 +7,92 @@ static int gShmFd = -1; static constexpr std::size_t kShmSize = sizeof(amdgpu::bridge::BridgeHeader) + - (sizeof(std::uint64_t) * (1024 * 1024)); -amdgpu::bridge::BridgeHeader * -amdgpu::bridge::createShmCommandBuffer(const char *name) { - if (gShmFd != -1) { - return nullptr; - } - - // unlinkShm(name); - - int fd = ::shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - - if (fd == -1) { - return nullptr; - } - - if (ftruncate(fd, kShmSize) < 0) { - ::close(fd); - return nullptr; - } - - void *memory = - ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (memory == MAP_FAILED) { - ::close(fd); - return nullptr; - } - - gShmFd = fd; - auto result = new (memory) amdgpu::bridge::BridgeHeader(); - result->size = - (kShmSize - sizeof(amdgpu::bridge::BridgeHeader)) / sizeof(std::uint64_t); - return result; + (sizeof(std::uint64_t) * (1024 * 1024)); +amdgpu::bridge::BridgeHeader* +amdgpu::bridge::createShmCommandBuffer(const char* name) +{ + if (gShmFd != -1) + { + return nullptr; + } + + // unlinkShm(name); + + int fd = ::shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + if (fd == -1) + { + return nullptr; + } + + if (ftruncate(fd, kShmSize) < 0) + { + ::close(fd); + return nullptr; + } + + void* memory = + ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (memory == MAP_FAILED) + { + ::close(fd); + return nullptr; + } + + gShmFd = fd; + auto result = new (memory) amdgpu::bridge::BridgeHeader(); + result->size = + (kShmSize - sizeof(amdgpu::bridge::BridgeHeader)) / sizeof(std::uint64_t); + return result; } -amdgpu::bridge::BridgeHeader * -amdgpu::bridge::openShmCommandBuffer(const char *name) { - if (gShmFd != -1) { - return nullptr; - } - - int fd = ::shm_open(name, O_RDWR, S_IRUSR | S_IWUSR); - - if (fd == -1) { - return nullptr; - } - - if (ftruncate(fd, kShmSize) < 0) { - ::close(fd); - return nullptr; - } - - void *memory = - ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (memory == MAP_FAILED) { - ::close(fd); - return nullptr; - } - - gShmFd = fd; - return new (memory) amdgpu::bridge::BridgeHeader; +amdgpu::bridge::BridgeHeader* +amdgpu::bridge::openShmCommandBuffer(const char* name) +{ + if (gShmFd != -1) + { + return nullptr; + } + + int fd = ::shm_open(name, O_RDWR, S_IRUSR | S_IWUSR); + + if (fd == -1) + { + return nullptr; + } + + if (ftruncate(fd, kShmSize) < 0) + { + ::close(fd); + return nullptr; + } + + void* memory = + ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (memory == MAP_FAILED) + { + ::close(fd); + return nullptr; + } + + gShmFd = fd; + return new (memory) amdgpu::bridge::BridgeHeader; } void amdgpu::bridge::destroyShmCommandBuffer( - amdgpu::bridge::BridgeHeader *buffer) { - if (gShmFd == -1) { - __builtin_trap(); - } - - buffer->~BridgeHeader(); - ::close(gShmFd); - gShmFd = -1; - ::munmap(buffer, kShmSize); + amdgpu::bridge::BridgeHeader* buffer) +{ + if (gShmFd == -1) + { + __builtin_trap(); + } + + buffer->~BridgeHeader(); + ::close(gShmFd); + gShmFd = -1; + ::munmap(buffer, kShmSize); } -void amdgpu::bridge::unlinkShm(const char *name) { ::shm_unlink(name); } +void amdgpu::bridge::unlinkShm(const char* name) { ::shm_unlink(name); } diff --git a/hw/amdgpu/device/include/amdgpu/device/device.hpp b/hw/amdgpu/device/include/amdgpu/device/device.hpp index d5d42695..088715ce 100644 --- a/hw/amdgpu/device/include/amdgpu/device/device.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/device.hpp @@ -9,1275 +9,1312 @@ #include #include -namespace amdgpu::device { -inline constexpr std::uint32_t getBits(std::uint32_t value, int end, - int begin) { - return (value >> begin) & ((1u << (end - begin + 1)) - 1); -} - -inline constexpr std::uint32_t getBit(std::uint32_t value, int bit) { - return (value >> bit) & 1; -} - -inline constexpr std::uint32_t genMask(std::uint32_t offset, - std::uint32_t bitCount) { - return ((1u << bitCount) - 1u) << offset; -} - -inline constexpr std::uint32_t getMaskEnd(std::uint32_t mask) { - return 32 - std::countl_zero(mask); -} - -inline constexpr std::uint32_t fetchMaskedValue(std::uint32_t hex, - std::uint32_t mask) { - return (hex & mask) >> std::countr_zero(mask); -} - -template >> -inline std::size_t calcStringLen(T value, unsigned base = 10) { - std::size_t n = 1; - std::size_t base2 = base * base; - std::size_t base3 = base2 * base; - std::size_t base4 = base3 * base; - - while (true) { - if (value < base) { - return n; - } - - if (value < base2) { - return n + 1; - } - - if (value < base3) { - return n + 2; - } - - if (value < base4) { - return n + 3; - } - - value /= base4; - n += 4; - } -} - -template >> -inline void toHexString(char *dst, std::size_t len, T value) { - while (len > 0) { - char digit = value % 16; - value /= 16; - - dst[--len] = digit < 10 ? '0' + digit : 'a' + digit - 10; - } -} - -inline std::string toHexString(unsigned value) { - auto len = calcStringLen(value, 16); - - std::string result(len, '\0'); - toHexString(result.data(), len, value); - return result; -} - -inline std::string toHexString(int value) { - bool isNeg = value < 0; - unsigned uval = isNeg ? static_cast(~value) + 1 : value; - auto len = calcStringLen(uval, 16); - - std::string result(len + (isNeg ? 1 : 0), '-'); - toHexString(result.data(), len, uval); - return result; -} - -enum Registers { - SPI_SHADER_PGM_LO_PS = 0x2c08, - SPI_SHADER_PGM_HI_PS = 0x2c09, - SPI_SHADER_PGM_RSRC1_PS = 0x2c0a, - SPI_SHADER_PGM_RSRC2_PS = 0x2c0b, - SPI_SHADER_USER_DATA_PS_0 = 0x2c0c, - SPI_SHADER_USER_DATA_PS_1, - SPI_SHADER_USER_DATA_PS_2, - SPI_SHADER_USER_DATA_PS_3, - SPI_SHADER_USER_DATA_PS_4, - SPI_SHADER_USER_DATA_PS_5, - SPI_SHADER_USER_DATA_PS_6, - SPI_SHADER_USER_DATA_PS_7, - SPI_SHADER_USER_DATA_PS_8, - SPI_SHADER_USER_DATA_PS_9, - SPI_SHADER_USER_DATA_PS_10, - SPI_SHADER_USER_DATA_PS_11, - SPI_SHADER_USER_DATA_PS_12, - SPI_SHADER_USER_DATA_PS_13, - SPI_SHADER_USER_DATA_PS_14, - SPI_SHADER_USER_DATA_PS_15, - - SPI_SHADER_PGM_LO_VS = 0x2c48, - SPI_SHADER_PGM_HI_VS = 0x2c49, - SPI_SHADER_PGM_RSRC1_VS = 0x2c4a, - SPI_SHADER_PGM_RSRC2_VS = 0x2c4b, - SPI_SHADER_USER_DATA_VS_0 = 0x2c4c, - SPI_SHADER_USER_DATA_VS_1 = 0x2c4d, - SPI_SHADER_USER_DATA_VS_2 = 0x2c4e, - SPI_SHADER_USER_DATA_VS_3 = 0x2c4f, - SPI_SHADER_USER_DATA_VS_4, - SPI_SHADER_USER_DATA_VS_5, - SPI_SHADER_USER_DATA_VS_6, - SPI_SHADER_USER_DATA_VS_7, - SPI_SHADER_USER_DATA_VS_8, - SPI_SHADER_USER_DATA_VS_9, - SPI_SHADER_USER_DATA_VS_10, - SPI_SHADER_USER_DATA_VS_11, - SPI_SHADER_USER_DATA_VS_12, - SPI_SHADER_USER_DATA_VS_13, - SPI_SHADER_USER_DATA_VS_14, - SPI_SHADER_USER_DATA_VS_15, - - COMPUTE_NUM_THREAD_X = 0x2e07, - COMPUTE_NUM_THREAD_Y, - COMPUTE_NUM_THREAD_Z, - COMPUTE_PGM_LO = 0x2e0c, - COMPUTE_PGM_HI, - COMPUTE_PGM_RSRC1 = 0x2e12, - COMPUTE_PGM_RSRC2, - COMPUTE_USER_DATA_0 = 0x2e40, - COMPUTE_USER_DATA_1, - COMPUTE_USER_DATA_2, - COMPUTE_USER_DATA_3, - COMPUTE_USER_DATA_4, - COMPUTE_USER_DATA_5, - COMPUTE_USER_DATA_6, - COMPUTE_USER_DATA_7, - COMPUTE_USER_DATA_8, - COMPUTE_USER_DATA_9, - COMPUTE_USER_DATA_10, - COMPUTE_USER_DATA_11, - COMPUTE_USER_DATA_12, - COMPUTE_USER_DATA_13, - COMPUTE_USER_DATA_14, - COMPUTE_USER_DATA_15, - - DB_RENDER_CONTROL = 0xa000, - DB_DEPTH_VIEW = 0xA002, - DB_HTILE_DATA_BASE = 0xA005, - DB_DEPTH_CLEAR = 0xA00B, - PA_SC_SCREEN_SCISSOR_TL = 0xa00c, - PA_SC_SCREEN_SCISSOR_BR = 0xa00d, - DB_DEPTH_INFO = 0xA00F, - DB_Z_INFO = 0xA010, - DB_STENCIL_INFO = 0xA011, - DB_Z_READ_BASE = 0xA012, - DB_STENCIL_READ_BASE = 0xA013, - DB_Z_WRITE_BASE = 0xA014, - DB_STENCIL_WRITE_BASE = 0xA015, - DB_DEPTH_SIZE = 0xA016, - DB_DEPTH_SLICE = 0xA017, - PA_SU_HARDWARE_SCREEN_OFFSET = 0xa08d, - CB_TARGET_MASK = 0xA08e, - CB_SHADER_MASK = 0xa08f, - PA_SC_VPORT_ZMIN_0 = 0xA0b4, - PA_SC_VPORT_ZMAX_0 = 0xA0b5, - PA_CL_VPORT_XSCALE = 0xa10f, - PA_CL_VPORT_XOFFSET, - PA_CL_VPORT_YSCALE, - PA_CL_VPORT_YOFFSET, - PA_CL_VPORT_ZSCALE, - PA_CL_VPORT_ZOFFSET, - SPI_PS_INPUT_CNTL_0 = 0xa191, - SPI_VS_OUT_CONFIG = 0xa1b1, - SPI_PS_INPUT_ENA = 0xa1b3, - SPI_PS_INPUT_ADDR = 0xa1b4, - SPI_PS_IN_CONTROL = 0xa1b6, - SPI_BARYC_CNTL = 0xa1b8, - SPI_SHADER_POS_FORMAT = 0xa1c3, - SPI_SHADER_Z_FORMAT = 0xa1c4, - SPI_SHADER_COL_FORMAT = 0xa1c5, - DB_DEPTH_CONTROL = 0xa200, - CB_COLOR_CONTROL = 0xa202, - DB_SHADER_CONTROL = 0xa203, - PA_CL_CLIP_CNTL = 0xa204, - PA_SU_SC_MODE_CNTL = 0xa205, - PA_CL_VTE_CNTL = 0xa206, - PA_CL_VS_OUT_CNTL = 0xa207, - DB_HTILE_SURFACE = 0xA2AF, - VGT_SHADER_STAGES_EN = 0xa2d5, - PA_CL_GB_VERT_CLIP_ADJ = 0xa2fa, - PA_CL_GB_VERT_DISC_ADJ, - PA_CL_GB_HORZ_CLIP_ADJ, - PA_CL_GB_HORZ_DISC_ADJ, - - CB_COLOR0_BASE = 0xA318, - CB_COLOR0_PITCH, - CB_COLOR0_SLICE, - CB_COLOR0_VIEW, - CB_COLOR0_INFO, - CB_COLOR0_ATTRIB, - CB_COLOR0_DCC_CONTROL, - CB_COLOR0_CMASK, - CB_COLOR0_CMASK_SLICE, - CB_COLOR0_FMASK, - CB_COLOR0_FMASK_SLICE, - CB_COLOR0_CLEAR_WORD0, - CB_COLOR0_CLEAR_WORD1, - CB_COLOR0_DCC_BASE, - CB_COLOR0_UNK0, - - CB_COLOR1_BASE, - CB_COLOR1_PITCH, - CB_COLOR1_SLICE, - CB_COLOR1_VIEW, - CB_COLOR1_INFO, - CB_COLOR1_ATTRIB, - CB_COLOR1_DCC_CONTROL, - CB_COLOR1_CMASK, - CB_COLOR1_CMASK_SLICE, - CB_COLOR1_FMASK, - CB_COLOR1_FMASK_SLICE, - CB_COLOR1_CLEAR_WORD0, - CB_COLOR1_CLEAR_WORD1, - CB_COLOR1_DCC_BASE, - CB_COLOR1_UNK0, - - CB_COLOR2_BASE, - CB_COLOR2_PITCH, - CB_COLOR2_SLICE, - CB_COLOR2_VIEW, - CB_COLOR2_INFO, - CB_COLOR2_ATTRIB, - CB_COLOR2_DCC_CONTROL, - CB_COLOR2_CMASK, - CB_COLOR2_CMASK_SLICE, - CB_COLOR2_FMASK, - CB_COLOR2_FMASK_SLICE, - CB_COLOR2_CLEAR_WORD0, - CB_COLOR2_CLEAR_WORD1, - CB_COLOR2_DCC_BASE, - CB_COLOR2_UNK0, - - CB_COLOR3_BASE, - CB_COLOR3_PITCH, - CB_COLOR3_SLICE, - CB_COLOR3_VIEW, - CB_COLOR3_INFO, - CB_COLOR3_ATTRIB, - CB_COLOR3_DCC_CONTROL, - CB_COLOR3_CMASK, - CB_COLOR3_CMASK_SLICE, - CB_COLOR3_FMASK, - CB_COLOR3_FMASK_SLICE, - CB_COLOR3_CLEAR_WORD0, - CB_COLOR3_CLEAR_WORD1, - CB_COLOR3_DCC_BASE, - CB_COLOR3_UNK0, - - CB_COLOR4_BASE, - CB_COLOR4_PITCH, - CB_COLOR4_SLICE, - CB_COLOR4_VIEW, - CB_COLOR4_INFO, - CB_COLOR4_ATTRIB, - CB_COLOR4_DCC_CONTROL, - CB_COLOR4_CMASK, - CB_COLOR4_CMASK_SLICE, - CB_COLOR4_FMASK, - CB_COLOR4_FMASK_SLICE, - CB_COLOR4_CLEAR_WORD0, - CB_COLOR4_CLEAR_WORD1, - CB_COLOR4_DCC_BASE, - CB_COLOR4_UNK0, - - CB_COLOR5_BASE, - CB_COLOR5_PITCH, - CB_COLOR5_SLICE, - CB_COLOR5_VIEW, - CB_COLOR5_INFO, - CB_COLOR5_ATTRIB, - CB_COLOR5_DCC_CONTROL, - CB_COLOR5_CMASK, - CB_COLOR5_CMASK_SLICE, - CB_COLOR5_FMASK, - CB_COLOR5_FMASK_SLICE, - CB_COLOR5_CLEAR_WORD0, - CB_COLOR5_CLEAR_WORD1, - CB_COLOR5_DCC_BASE, - CB_COLOR5_UNK0, - - CB_COLOR6_BASE, - CB_COLOR6_PITCH, - CB_COLOR6_SLICE, - CB_COLOR6_VIEW, - CB_COLOR6_INFO, - CB_COLOR6_ATTRIB, - CB_COLOR6_DCC_CONTROL, - CB_COLOR6_CMASK, - CB_COLOR6_CMASK_SLICE, - CB_COLOR6_FMASK, - CB_COLOR6_FMASK_SLICE, - CB_COLOR6_CLEAR_WORD0, - CB_COLOR6_CLEAR_WORD1, - CB_COLOR6_DCC_BASE, - CB_COLOR6_UNK0, - - CB_BLEND0_CONTROL = 0xa1e0, - - VGT_PRIMITIVE_TYPE = 0xc242, -}; - -inline std::string registerToString(int reg) { - switch (reg) { - case SPI_SHADER_PGM_LO_PS: - return "SPI_SHADER_PGM_LO_PS"; - case SPI_SHADER_PGM_HI_PS: - return "SPI_SHADER_PGM_HI_PS"; - case SPI_SHADER_PGM_RSRC1_PS: - return "SPI_SHADER_PGM_RSRC1_PS"; - case SPI_SHADER_PGM_RSRC2_PS: - return "SPI_SHADER_PGM_RSRC2_PS"; - case SPI_SHADER_USER_DATA_PS_0: - return "SPI_SHADER_USER_DATA_PS_0"; - case SPI_SHADER_USER_DATA_PS_1: - return "SPI_SHADER_USER_DATA_PS_1"; - case SPI_SHADER_USER_DATA_PS_2: - return "SPI_SHADER_USER_DATA_PS_2"; - case SPI_SHADER_USER_DATA_PS_3: - return "SPI_SHADER_USER_DATA_PS_3"; - case SPI_SHADER_USER_DATA_PS_4: - return "SPI_SHADER_USER_DATA_PS_4"; - case SPI_SHADER_USER_DATA_PS_5: - return "SPI_SHADER_USER_DATA_PS_5"; - case SPI_SHADER_USER_DATA_PS_6: - return "SPI_SHADER_USER_DATA_PS_6"; - case SPI_SHADER_USER_DATA_PS_7: - return "SPI_SHADER_USER_DATA_PS_7"; - case SPI_SHADER_USER_DATA_PS_8: - return "SPI_SHADER_USER_DATA_PS_8"; - case SPI_SHADER_USER_DATA_PS_9: - return "SPI_SHADER_USER_DATA_PS_9"; - case SPI_SHADER_USER_DATA_PS_10: - return "SPI_SHADER_USER_DATA_PS_10"; - case SPI_SHADER_USER_DATA_PS_11: - return "SPI_SHADER_USER_DATA_PS_11"; - case SPI_SHADER_USER_DATA_PS_12: - return "SPI_SHADER_USER_DATA_PS_12"; - case SPI_SHADER_USER_DATA_PS_13: - return "SPI_SHADER_USER_DATA_PS_13"; - case SPI_SHADER_USER_DATA_PS_14: - return "SPI_SHADER_USER_DATA_PS_14"; - case SPI_SHADER_USER_DATA_PS_15: - return "SPI_SHADER_USER_DATA_PS_15"; - case SPI_SHADER_PGM_LO_VS: - return "SPI_SHADER_PGM_LO_VS"; - case SPI_SHADER_PGM_HI_VS: - return "SPI_SHADER_PGM_HI_VS"; - case SPI_SHADER_PGM_RSRC1_VS: - return "SPI_SHADER_PGM_RSRC1_VS"; - case SPI_SHADER_PGM_RSRC2_VS: - return "SPI_SHADER_PGM_RSRC2_VS"; - case SPI_SHADER_USER_DATA_VS_0: - return "SPI_SHADER_USER_DATA_VS_0"; - case SPI_SHADER_USER_DATA_VS_1: - return "SPI_SHADER_USER_DATA_VS_1"; - case SPI_SHADER_USER_DATA_VS_2: - return "SPI_SHADER_USER_DATA_VS_2"; - case SPI_SHADER_USER_DATA_VS_3: - return "SPI_SHADER_USER_DATA_VS_3"; - case SPI_SHADER_USER_DATA_VS_4: - return "SPI_SHADER_USER_DATA_VS_4"; - case SPI_SHADER_USER_DATA_VS_5: - return "SPI_SHADER_USER_DATA_VS_5"; - case SPI_SHADER_USER_DATA_VS_6: - return "SPI_SHADER_USER_DATA_VS_6"; - case SPI_SHADER_USER_DATA_VS_7: - return "SPI_SHADER_USER_DATA_VS_7"; - case SPI_SHADER_USER_DATA_VS_8: - return "SPI_SHADER_USER_DATA_VS_8"; - case SPI_SHADER_USER_DATA_VS_9: - return "SPI_SHADER_USER_DATA_VS_9"; - case SPI_SHADER_USER_DATA_VS_10: - return "SPI_SHADER_USER_DATA_VS_10"; - case SPI_SHADER_USER_DATA_VS_11: - return "SPI_SHADER_USER_DATA_VS_11"; - case SPI_SHADER_USER_DATA_VS_12: - return "SPI_SHADER_USER_DATA_VS_12"; - case SPI_SHADER_USER_DATA_VS_13: - return "SPI_SHADER_USER_DATA_VS_13"; - case SPI_SHADER_USER_DATA_VS_14: - return "SPI_SHADER_USER_DATA_VS_14"; - case SPI_SHADER_USER_DATA_VS_15: - return "SPI_SHADER_USER_DATA_VS_15"; - case COMPUTE_NUM_THREAD_X: - return "COMPUTE_NUM_THREAD_X"; - case COMPUTE_NUM_THREAD_Y: - return "COMPUTE_NUM_THREAD_Y"; - case COMPUTE_NUM_THREAD_Z: - return "COMPUTE_NUM_THREAD_Z"; - case COMPUTE_PGM_LO: - return "COMPUTE_PGM_LO"; - case COMPUTE_PGM_HI: - return "COMPUTE_PGM_HI"; - case COMPUTE_PGM_RSRC1: - return "COMPUTE_PGM_RSRC1"; - case COMPUTE_PGM_RSRC2: - return "COMPUTE_PGM_RSRC2"; - case COMPUTE_USER_DATA_0: - return "COMPUTE_USER_DATA_0"; - case COMPUTE_USER_DATA_1: - return "COMPUTE_USER_DATA_1"; - case COMPUTE_USER_DATA_2: - return "COMPUTE_USER_DATA_2"; - case COMPUTE_USER_DATA_3: - return "COMPUTE_USER_DATA_3"; - case COMPUTE_USER_DATA_4: - return "COMPUTE_USER_DATA_4"; - case COMPUTE_USER_DATA_5: - return "COMPUTE_USER_DATA_5"; - case COMPUTE_USER_DATA_6: - return "COMPUTE_USER_DATA_6"; - case COMPUTE_USER_DATA_7: - return "COMPUTE_USER_DATA_7"; - case COMPUTE_USER_DATA_8: - return "COMPUTE_USER_DATA_8"; - case COMPUTE_USER_DATA_9: - return "COMPUTE_USER_DATA_9"; - case COMPUTE_USER_DATA_10: - return "COMPUTE_USER_DATA_10"; - case COMPUTE_USER_DATA_11: - return "COMPUTE_USER_DATA_11"; - case COMPUTE_USER_DATA_12: - return "COMPUTE_USER_DATA_12"; - case COMPUTE_USER_DATA_13: - return "COMPUTE_USER_DATA_13"; - case COMPUTE_USER_DATA_14: - return "COMPUTE_USER_DATA_14"; - case COMPUTE_USER_DATA_15: - return "COMPUTE_USER_DATA_15"; - case DB_DEPTH_CLEAR: - return "DB_DEPTH_CLEAR"; - case DB_RENDER_CONTROL: - return "DB_RENDER_CONTROL"; - case DB_DEPTH_VIEW: - return "DB_DEPTH_VIEW"; - case DB_HTILE_DATA_BASE: - return "DB_HTILE_DATA_BASE"; - case PA_SC_SCREEN_SCISSOR_TL: - return "PA_SC_SCREEN_SCISSOR_TL"; - case PA_SC_SCREEN_SCISSOR_BR: - return "PA_SC_SCREEN_SCISSOR_BR"; - case DB_DEPTH_INFO: - return "DB_DEPTH_INFO"; - case DB_Z_INFO: - return "DB_Z_INFO"; - case DB_STENCIL_INFO: - return "DB_STENCIL_INFO"; - case DB_Z_READ_BASE: - return "DB_Z_READ_BASE"; - case DB_STENCIL_READ_BASE: - return "DB_STENCIL_READ_BASE"; - case DB_Z_WRITE_BASE: - return "DB_Z_WRITE_BASE"; - case DB_STENCIL_WRITE_BASE: - return "DB_STENCIL_WRITE_BASE"; - case DB_DEPTH_SIZE: - return "DB_DEPTH_SIZE"; - case DB_DEPTH_SLICE: - return "DB_DEPTH_SLICE"; - case PA_SU_HARDWARE_SCREEN_OFFSET: - return "PA_SU_HARDWARE_SCREEN_OFFSET"; - case CB_TARGET_MASK: - return "CB_TARGET_MASK"; - case CB_SHADER_MASK: - return "CB_SHADER_MASK"; - case PA_SC_VPORT_ZMIN_0: - return "PA_SC_VPORT_ZMIN_0"; - case PA_SC_VPORT_ZMAX_0: - return "PA_SC_VPORT_ZMAX_0"; - case PA_CL_VPORT_XSCALE: - return "PA_CL_VPORT_XSCALE"; - case PA_CL_VPORT_XOFFSET: - return "PA_CL_VPORT_XOFFSET"; - case PA_CL_VPORT_YSCALE: - return "PA_CL_VPORT_YSCALE"; - case PA_CL_VPORT_YOFFSET: - return "PA_CL_VPORT_YOFFSET"; - case PA_CL_VPORT_ZSCALE: - return "PA_CL_VPORT_ZSCALE"; - case PA_CL_VPORT_ZOFFSET: - return "PA_CL_VPORT_ZOFFSET"; - case SPI_PS_INPUT_CNTL_0: - return "SPI_PS_INPUT_CNTL_0"; - case SPI_VS_OUT_CONFIG: - return "SPI_VS_OUT_CONFIG"; - case SPI_PS_INPUT_ENA: - return "SPI_PS_INPUT_ENA"; - case SPI_PS_INPUT_ADDR: - return "SPI_PS_INPUT_ADDR"; - case SPI_PS_IN_CONTROL: - return "SPI_PS_IN_CONTROL"; - case SPI_BARYC_CNTL: - return "SPI_BARYC_CNTL"; - case SPI_SHADER_POS_FORMAT: - return "SPI_SHADER_POS_FORMAT"; - case SPI_SHADER_Z_FORMAT: - return "SPI_SHADER_Z_FORMAT"; - case SPI_SHADER_COL_FORMAT: - return "SPI_SHADER_COL_FORMAT"; - case DB_DEPTH_CONTROL: - return "DB_DEPTH_CONTROL"; - case CB_COLOR_CONTROL: - return "DB_COLOR_CONTROL"; - case DB_SHADER_CONTROL: - return "DB_SHADER_CONTROL"; - case PA_CL_CLIP_CNTL: - return "PA_CL_CLIP_CNTL"; - case PA_SU_SC_MODE_CNTL: - return "PA_SU_SC_MODE_CNTL"; - case PA_CL_VTE_CNTL: - return "PA_CL_VTE_CNTL"; - case PA_CL_VS_OUT_CNTL: - return "PA_CL_VS_OUT_CNTL"; - case DB_HTILE_SURFACE: - return "DB_HTILE_SURFACE"; - case VGT_SHADER_STAGES_EN: - return "VGT_SHADER_STAGES_EN"; - case PA_CL_GB_VERT_CLIP_ADJ: - return "PA_CL_GB_VERT_CLIP_ADJ"; - case PA_CL_GB_VERT_DISC_ADJ: - return "PA_CL_GB_VERT_DISC_ADJ"; - case PA_CL_GB_HORZ_CLIP_ADJ: - return "PA_CL_GB_HORZ_CLIP_ADJ"; - case PA_CL_GB_HORZ_DISC_ADJ: - return "PA_CL_GB_HORZ_DISC_ADJ"; - case CB_COLOR0_BASE: - return "CB_COLOR0_BASE"; - case CB_COLOR0_PITCH: - return "CB_COLOR0_PITCH"; - case CB_COLOR0_SLICE: - return "CB_COLOR0_SLICE"; - case CB_COLOR0_VIEW: - return "CB_COLOR0_VIEW"; - case CB_COLOR0_INFO: - return "CB_COLOR0_INFO"; - case CB_COLOR0_ATTRIB: - return "CB_COLOR0_ATTRIB"; - case CB_COLOR0_DCC_CONTROL: - return "CB_COLOR0_DCC_CONTROL"; - case CB_COLOR0_CMASK: - return "CB_COLOR0_CMASK"; - case CB_COLOR0_CMASK_SLICE: - return "CB_COLOR0_CMASK_SLICE"; - case CB_COLOR0_FMASK: - return "CB_COLOR0_FMASK"; - case CB_COLOR0_FMASK_SLICE: - return "CB_COLOR0_FMASK_SLICE"; - case CB_COLOR0_CLEAR_WORD0: - return "CB_COLOR0_CLEAR_WORD0"; - case CB_COLOR0_CLEAR_WORD1: - return "CB_COLOR0_CLEAR_WORD1"; - case CB_COLOR0_DCC_BASE: - return "CB_COLOR0_DCC_BASE"; - case CB_COLOR1_BASE: - return "CB_COLOR1_BASE"; - case CB_COLOR1_PITCH: - return "CB_COLOR1_PITCH"; - case CB_COLOR1_SLICE: - return "CB_COLOR1_SLICE"; - case CB_COLOR1_VIEW: - return "CB_COLOR1_VIEW"; - case CB_COLOR1_INFO: - return "CB_COLOR1_INFO"; - case CB_COLOR1_ATTRIB: - return "CB_COLOR1_ATTRIB"; - case CB_COLOR1_DCC_CONTROL: - return "CB_COLOR1_DCC_CONTROL"; - case CB_COLOR1_CMASK: - return "CB_COLOR1_CMASK"; - case CB_COLOR1_CMASK_SLICE: - return "CB_COLOR1_CMASK_SLICE"; - case CB_COLOR1_FMASK: - return "CB_COLOR1_FMASK"; - case CB_COLOR1_FMASK_SLICE: - return "CB_COLOR1_FMASK_SLICE"; - case CB_COLOR1_CLEAR_WORD0: - return "CB_COLOR1_CLEAR_WORD0"; - case CB_COLOR1_CLEAR_WORD1: - return "CB_COLOR1_CLEAR_WORD1"; - case CB_COLOR1_DCC_BASE: - return "CB_COLOR1_DCC_BASE"; - case CB_COLOR2_BASE: - return "CB_COLOR2_BASE"; - case CB_COLOR2_PITCH: - return "CB_COLOR2_PITCH"; - case CB_COLOR2_SLICE: - return "CB_COLOR2_SLICE"; - case CB_COLOR2_VIEW: - return "CB_COLOR2_VIEW"; - case CB_COLOR2_INFO: - return "CB_COLOR2_INFO"; - case CB_COLOR2_ATTRIB: - return "CB_COLOR2_ATTRIB"; - case CB_COLOR2_DCC_CONTROL: - return "CB_COLOR2_DCC_CONTROL"; - case CB_COLOR2_CMASK: - return "CB_COLOR2_CMASK"; - case CB_COLOR2_CMASK_SLICE: - return "CB_COLOR2_CMASK_SLICE"; - case CB_COLOR2_FMASK: - return "CB_COLOR2_FMASK"; - case CB_COLOR2_FMASK_SLICE: - return "CB_COLOR2_FMASK_SLICE"; - case CB_COLOR2_CLEAR_WORD0: - return "CB_COLOR2_CLEAR_WORD0"; - case CB_COLOR2_CLEAR_WORD1: - return "CB_COLOR2_CLEAR_WORD1"; - case CB_COLOR2_DCC_BASE: - return "CB_COLOR2_DCC_BASE"; - case CB_COLOR3_BASE: - return "CB_COLOR3_BASE"; - case CB_COLOR3_PITCH: - return "CB_COLOR3_PITCH"; - case CB_COLOR3_SLICE: - return "CB_COLOR3_SLICE"; - case CB_COLOR3_VIEW: - return "CB_COLOR3_VIEW"; - case CB_COLOR3_INFO: - return "CB_COLOR3_INFO"; - case CB_COLOR3_ATTRIB: - return "CB_COLOR3_ATTRIB"; - case CB_COLOR3_DCC_CONTROL: - return "CB_COLOR3_DCC_CONTROL"; - case CB_COLOR3_CMASK: - return "CB_COLOR3_CMASK"; - case CB_COLOR3_CMASK_SLICE: - return "CB_COLOR3_CMASK_SLICE"; - case CB_COLOR3_FMASK: - return "CB_COLOR3_FMASK"; - case CB_COLOR3_FMASK_SLICE: - return "CB_COLOR3_FMASK_SLICE"; - case CB_COLOR3_CLEAR_WORD0: - return "CB_COLOR3_CLEAR_WORD0"; - case CB_COLOR3_CLEAR_WORD1: - return "CB_COLOR3_CLEAR_WORD1"; - case CB_COLOR3_DCC_BASE: - return "CB_COLOR3_DCC_BASE"; - case CB_COLOR4_BASE: - return "CB_COLOR4_BASE"; - case CB_COLOR4_PITCH: - return "CB_COLOR4_PITCH"; - case CB_COLOR4_SLICE: - return "CB_COLOR4_SLICE"; - case CB_COLOR4_VIEW: - return "CB_COLOR4_VIEW"; - case CB_COLOR4_INFO: - return "CB_COLOR4_INFO"; - case CB_COLOR4_ATTRIB: - return "CB_COLOR4_ATTRIB"; - case CB_COLOR4_DCC_CONTROL: - return "CB_COLOR4_DCC_CONTROL"; - case CB_COLOR4_CMASK: - return "CB_COLOR4_CMASK"; - case CB_COLOR4_CMASK_SLICE: - return "CB_COLOR4_CMASK_SLICE"; - case CB_COLOR4_FMASK: - return "CB_COLOR4_FMASK"; - case CB_COLOR4_FMASK_SLICE: - return "CB_COLOR4_FMASK_SLICE"; - case CB_COLOR4_CLEAR_WORD0: - return "CB_COLOR4_CLEAR_WORD0"; - case CB_COLOR4_CLEAR_WORD1: - return "CB_COLOR4_CLEAR_WORD1"; - case CB_COLOR4_DCC_BASE: - return "CB_COLOR4_DCC_BASE"; - case CB_COLOR5_BASE: - return "CB_COLOR5_BASE"; - case CB_COLOR5_PITCH: - return "CB_COLOR5_PITCH"; - case CB_COLOR5_SLICE: - return "CB_COLOR5_SLICE"; - case CB_COLOR5_VIEW: - return "CB_COLOR5_VIEW"; - case CB_COLOR5_INFO: - return "CB_COLOR5_INFO"; - case CB_COLOR5_ATTRIB: - return "CB_COLOR5_ATTRIB"; - case CB_COLOR5_DCC_CONTROL: - return "CB_COLOR5_DCC_CONTROL"; - case CB_COLOR5_CMASK: - return "CB_COLOR5_CMASK"; - case CB_COLOR5_CMASK_SLICE: - return "CB_COLOR5_CMASK_SLICE"; - case CB_COLOR5_FMASK: - return "CB_COLOR5_FMASK"; - case CB_COLOR5_FMASK_SLICE: - return "CB_COLOR5_FMASK_SLICE"; - case CB_COLOR5_CLEAR_WORD0: - return "CB_COLOR5_CLEAR_WORD0"; - case CB_COLOR5_CLEAR_WORD1: - return "CB_COLOR5_CLEAR_WORD1"; - case CB_COLOR5_DCC_BASE: - return "CB_COLOR5_DCC_BASE"; - case CB_COLOR6_BASE: - return "CB_COLOR6_BASE"; - case CB_COLOR6_PITCH: - return "CB_COLOR6_PITCH"; - case CB_COLOR6_SLICE: - return "CB_COLOR6_SLICE"; - case CB_COLOR6_VIEW: - return "CB_COLOR6_VIEW"; - case CB_COLOR6_INFO: - return "CB_COLOR6_INFO"; - case CB_COLOR6_ATTRIB: - return "CB_COLOR6_ATTRIB"; - case CB_COLOR6_DCC_CONTROL: - return "CB_COLOR6_DCC_CONTROL"; - case CB_COLOR6_CMASK: - return "CB_COLOR6_CMASK"; - case CB_COLOR6_CMASK_SLICE: - return "CB_COLOR6_CMASK_SLICE"; - case CB_COLOR6_FMASK: - return "CB_COLOR6_FMASK"; - case CB_COLOR6_FMASK_SLICE: - return "CB_COLOR6_FMASK_SLICE"; - case CB_COLOR6_CLEAR_WORD0: - return "CB_COLOR6_CLEAR_WORD0"; - case CB_COLOR6_CLEAR_WORD1: - return "CB_COLOR6_CLEAR_WORD1"; - case CB_COLOR6_DCC_BASE: - return "CB_COLOR6_DCC_BASE"; - case CB_BLEND0_CONTROL: - return "CB_BLEND0_CONTROL"; - - case VGT_PRIMITIVE_TYPE: - return "VGT_PRIMITIVE_TYPE"; - } - - return ""; -} - -enum Opcodes { - kOpcodeNOP = 0x10, - kOpcodeSET_BASE = 0x11, - kOpcodeCLEAR_STATE = 0x12, - kOpcodeINDEX_BUFFER_SIZE = 0x13, - kOpcodeDISPATCH_DIRECT = 0x15, - kOpcodeDISPATCH_INDIRECT = 0x16, - kOpcodeINDIRECT_BUFFER_END = 0x17, - kOpcodeMODE_CONTROL = 0x18, - kOpcodeATOMIC_GDS = 0x1D, - kOpcodeATOMIC_MEM = 0x1E, - kOpcodeOCCLUSION_QUERY = 0x1F, - kOpcodeSET_PREDICATION = 0x20, - kOpcodeREG_RMW = 0x21, - kOpcodeCOND_EXEC = 0x22, - kOpcodePRED_EXEC = 0x23, - kOpcodeDRAW_INDIRECT = 0x24, - kOpcodeDRAW_INDEX_INDIRECT = 0x25, - kOpcodeINDEX_BASE = 0x26, - kOpcodeDRAW_INDEX_2 = 0x27, - kOpcodeCONTEXT_CONTROL = 0x28, - kOpcodeDRAW_INDEX_OFFSET = 0x29, - kOpcodeINDEX_TYPE = 0x2A, - kOpcodeDRAW_INDEX = 0x2B, - kOpcodeDRAW_INDIRECT_MULTI = 0x2C, - kOpcodeDRAW_INDEX_AUTO = 0x2D, - kOpcodeDRAW_INDEX_IMMD = 0x2E, - kOpcodeNUM_INSTANCES = 0x2F, - kOpcodeDRAW_INDEX_MULTI_AUTO = 0x30, - kOpcodeINDIRECT_BUFFER_32 = 0x32, - kOpcodeINDIRECT_BUFFER_CONST = 0x33, - kOpcodeSTRMOUT_BUFFER_UPDATE = 0x34, - kOpcodeDRAW_INDEX_OFFSET_2 = 0x35, - kOpcodeDRAW_PREAMBLE = 0x36, - kOpcodeWRITE_DATA = 0x37, - kOpcodeDRAW_INDEX_INDIRECT_MULTI = 0x38, - kOpcodeMEM_SEMAPHORE = 0x39, - kOpcodeMPEG_INDEX = 0x3A, - kOpcodeCOPY_DW = 0x3B, - kOpcodeWAIT_REG_MEM = 0x3C, - kOpcodeMEM_WRITE = 0x3D, - kOpcodeINDIRECT_BUFFER_3F = 0x3F, - kOpcodeCOPY_DATA = 0x40, - kOpcodeCP_DMA = 0x41, - kOpcodePFP_SYNC_ME = 0x42, - kOpcodeSURFACE_SYNC = 0x43, - kOpcodeME_INITIALIZE = 0x44, - kOpcodeCOND_WRITE = 0x45, - kOpcodeEVENT_WRITE = 0x46, - kOpcodeEVENT_WRITE_EOP = 0x47, - kOpcodeEVENT_WRITE_EOS = 0x48, - kOpcodeRELEASE_MEM = 0x49, - kOpcodePREAMBLE_CNTL = 0x4A, - kOpcodeRB_OFFSET = 0x4B, - kOpcodeALU_PS_CONST_BUFFER_COPY = 0x4C, - kOpcodeALU_VS_CONST_BUFFER_COPY = 0x4D, - kOpcodeALU_PS_CONST_UPDATE = 0x4E, - kOpcodeALU_VS_CONST_UPDATE = 0x4F, - kOpcodeDMA_DATA = 0x50, - kOpcodeONE_REG_WRITE = 0x57, - kOpcodeAQUIRE_MEM = 0x58, - kOpcodeREWIND = 0x59, - kOpcodeLOAD_UCONFIG_REG = 0x5E, - kOpcodeLOAD_SH_REG = 0x5F, - kOpcodeLOAD_CONFIG_REG = 0x60, - kOpcodeLOAD_CONTEXT_REG = 0x61, - kOpcodeSET_CONFIG_REG = 0x68, - kOpcodeSET_CONTEXT_REG = 0x69, - kOpcodeSET_ALU_CONST = 0x6A, - kOpcodeSET_BOOL_CONST = 0x6B, - kOpcodeSET_LOOP_CONST = 0x6C, - kOpcodeSET_RESOURCE = 0x6D, - kOpcodeSET_SAMPLER = 0x6E, - kOpcodeSET_CTL_CONST = 0x6F, - kOpcodeSET_RESOURCE_OFFSET = 0x70, - kOpcodeSET_ALU_CONST_VS = 0x71, - kOpcodeSET_ALU_CONST_DI = 0x72, - kOpcodeSET_CONTEXT_REG_INDIRECT = 0x73, - kOpcodeSET_RESOURCE_INDIRECT = 0x74, - kOpcodeSET_APPEND_CNT = 0x75, - kOpcodeSET_SH_REG = 0x76, - kOpcodeSET_SH_REG_OFFSET = 0x77, - kOpcodeSET_QUEUE_REG = 0x78, - kOpcodeSET_UCONFIG_REG = 0x79, - kOpcodeSCRATCH_RAM_WRITE = 0x7D, - kOpcodeSCRATCH_RAM_READ = 0x7E, - kOpcodeLOAD_CONST_RAM = 0x80, - kOpcodeWRITE_CONST_RAM = 0x81, - kOpcodeDUMP_CONST_RAM = 0x83, - kOpcodeINCREMENT_CE_COUNTER = 0x84, - kOpcodeINCREMENT_DE_COUNTER = 0x85, - kOpcodeWAIT_ON_CE_COUNTER = 0x86, - kOpcodeWAIT_ON_DE_COUNTER_DIFF = 0x88, - kOpcodeSWITCH_BUFFER = 0x8B, -}; - -inline const std::string opcodeToString(int op) { - switch (op) { - case kOpcodeNOP: - return "IT_NOP"; - case kOpcodeSET_BASE: - return "IT_SET_BASE"; - case kOpcodeCLEAR_STATE: - return "IT_CLEAR_STATE"; - case kOpcodeINDEX_BUFFER_SIZE: - return "IT_INDEX_BUFFER_SIZE"; - case kOpcodeDISPATCH_DIRECT: - return "IT_DISPATCH_DIRECT"; - case kOpcodeDISPATCH_INDIRECT: - return "IT_DISPATCH_INDIRECT"; - case kOpcodeINDIRECT_BUFFER_END: - return "IT_INDIRECT_BUFFER_END"; - case kOpcodeATOMIC_GDS: - return "IT_ATOMIC_GDS"; - case kOpcodeATOMIC_MEM: - return "IT_ATOMIC_MEM"; - case kOpcodeOCCLUSION_QUERY: - return "IT_OCCLUSION_QUERY"; - case kOpcodeSET_PREDICATION: - return "IT_SET_PREDICATION"; - case kOpcodeREG_RMW: - return "IT_REG_RMW"; - case kOpcodeCOND_EXEC: - return "IT_COND_EXEC"; - case kOpcodePRED_EXEC: - return "IT_PRED_EXEC"; - case kOpcodeDRAW_INDIRECT: - return "IT_DRAW_INDIRECT"; - case kOpcodeDRAW_INDEX_INDIRECT: - return "IT_DRAW_INDEX_INDIRECT"; - case kOpcodeINDEX_BASE: - return "IT_INDEX_BASE"; - case kOpcodeDRAW_INDEX_2: - return "IT_DRAW_INDEX_2"; - case kOpcodeCONTEXT_CONTROL: - return "IT_CONTEXT_CONTROL"; - case kOpcodeINDEX_TYPE: - return "IT_INDEX_TYPE"; - case kOpcodeDRAW_INDEX: - return "IT_DRAW_INDEX"; - case kOpcodeDRAW_INDIRECT_MULTI: - return "IT_DRAW_INDIRECT_MULTI"; - case kOpcodeDRAW_INDEX_AUTO: - return "IT_DRAW_INDEX_AUTO"; - case kOpcodeDRAW_INDEX_IMMD: - return "IT_DRAW_INDEX_IMMD"; - case kOpcodeNUM_INSTANCES: - return "IT_NUM_INSTANCES"; - case kOpcodeDRAW_INDEX_MULTI_AUTO: - return "IT_DRAW_INDEX_MULTI_AUTO"; - case kOpcodeINDIRECT_BUFFER_32: - return "IT_INDIRECT_BUFFER_32"; - case kOpcodeINDIRECT_BUFFER_CONST: - return "IT_INDIRECT_BUFFER_CONST"; - case kOpcodeSTRMOUT_BUFFER_UPDATE: - return "IT_STRMOUT_BUFFER_UPDATE"; - case kOpcodeDRAW_INDEX_OFFSET_2: - return "IT_DRAW_INDEX_OFFSET_2"; - case kOpcodeDRAW_PREAMBLE: - return "IT_DRAW_PREAMBLE"; - case kOpcodeWRITE_DATA: - return "IT_WRITE_DATA"; - case kOpcodeDRAW_INDEX_INDIRECT_MULTI: - return "IT_DRAW_INDEX_INDIRECT_MULTI"; - case kOpcodeMEM_SEMAPHORE: - return "IT_MEM_SEMAPHORE"; - case kOpcodeMPEG_INDEX: - return "IT_MPEG_INDEX"; - case kOpcodeCOPY_DW: - return "IT_COPY_DW"; - case kOpcodeWAIT_REG_MEM: - return "IT_WAIT_REG_MEM"; - case kOpcodeMEM_WRITE: - return "IT_MEM_WRITE"; - case kOpcodeINDIRECT_BUFFER_3F: - return "IT_INDIRECT_BUFFER_3F"; - case kOpcodeCOPY_DATA: - return "IT_COPY_DATA"; - case kOpcodeCP_DMA: - return "IT_CP_DMA"; - case kOpcodePFP_SYNC_ME: - return "IT_PFP_SYNC_ME"; - case kOpcodeSURFACE_SYNC: - return "IT_SURFACE_SYNC"; - case kOpcodeME_INITIALIZE: - return "IT_ME_INITIALIZE"; - case kOpcodeCOND_WRITE: - return "IT_COND_WRITE"; - case kOpcodeEVENT_WRITE: - return "IT_EVENT_WRITE"; - case kOpcodeEVENT_WRITE_EOP: - return "IT_EVENT_WRITE_EOP"; - case kOpcodeEVENT_WRITE_EOS: - return "IT_EVENT_WRITE_EOS"; - case kOpcodeRELEASE_MEM: - return "IT_RELEASE_MEM"; - case kOpcodePREAMBLE_CNTL: - return "IT_PREAMBLE_CNTL"; - case kOpcodeDMA_DATA: - return "IT_DMA_DATA"; - case kOpcodeONE_REG_WRITE: - return "IT_ONE_REG_WRITE"; - case kOpcodeAQUIRE_MEM: - return "IT_AQUIRE_MEM"; - case kOpcodeREWIND: - return "IT_REWIND"; - case kOpcodeLOAD_UCONFIG_REG: - return "IT_LOAD_UCONFIG_REG"; - case kOpcodeLOAD_SH_REG: - return "IT_LOAD_SH_REG"; - case kOpcodeLOAD_CONFIG_REG: - return "IT_LOAD_CONFIG_REG"; - case kOpcodeLOAD_CONTEXT_REG: - return "IT_LOAD_CONTEXT_REG"; - case kOpcodeSET_CONFIG_REG: - return "IT_SET_CONFIG_REG"; - case kOpcodeSET_CONTEXT_REG: - return "IT_SET_CONTEXT_REG"; - case kOpcodeSET_ALU_CONST: - return "IT_SET_ALU_CONST"; - case kOpcodeSET_BOOL_CONST: - return "IT_SET_BOOL_CONST"; - case kOpcodeSET_LOOP_CONST: - return "IT_SET_LOOP_CONST"; - case kOpcodeSET_RESOURCE: - return "IT_SET_RESOURCE"; - case kOpcodeSET_SAMPLER: - return "IT_SET_SAMPLER"; - case kOpcodeSET_CTL_CONST: - return "IT_SET_CTL_CONST"; - case kOpcodeSET_CONTEXT_REG_INDIRECT: - return "IT_SET_CONTEXT_REG_INDIRECT"; - case kOpcodeSET_SH_REG: - return "IT_SET_SH_REG"; - case kOpcodeSET_SH_REG_OFFSET: - return "IT_SET_SH_REG_OFFSET"; - case kOpcodeSET_QUEUE_REG: - return "IT_SET_QUEUE_REG"; - case kOpcodeSET_UCONFIG_REG: - return "IT_SET_UCONFIG_REG"; - case kOpcodeSCRATCH_RAM_WRITE: - return "IT_SCRATCH_RAM_WRITE"; - case kOpcodeSCRATCH_RAM_READ: - return "IT_SCRATCH_RAM_READ"; - case kOpcodeLOAD_CONST_RAM: - return "IT_LOAD_CONST_RAM"; - case kOpcodeWRITE_CONST_RAM: - return "IT_WRITE_CONST_RAM"; - case kOpcodeDUMP_CONST_RAM: - return "IT_DUMP_CONST_RAM"; - case kOpcodeINCREMENT_CE_COUNTER: - return "IT_INCREMENT_CE_COUNTER"; - case kOpcodeINCREMENT_DE_COUNTER: - return "IT_INCREMENT_DE_COUNTER"; - case kOpcodeWAIT_ON_CE_COUNTER: - return "IT_WAIT_ON_CE_COUNTER"; - case kOpcodeWAIT_ON_DE_COUNTER_DIFF: - return "IT_WAIT_ON_DE_COUNTER_DIFF"; - case kOpcodeSWITCH_BUFFER: - return "IT_SWITCH_BUFFER"; - } - - return ""; -} - -inline void dumpShader(const std::uint32_t *data) { - flockfile(stdout); - while (true) { - auto instHex = *data; - bool isEnd = instHex == 0xBF810000 || instHex == 0xBE802000; - - shader::Instruction inst(data); - - for (int i = 0; i < inst.size(); ++i) { - std::printf("%08X ", data[i]); - } - - inst.dump(); - printf("\n"); - data += inst.size(); - - if (isEnd) { - break; - } - } - funlockfile(stdout); -} - -enum BlendMultiplier { - kBlendMultiplierZero = 0x00000000, - kBlendMultiplierOne = 0x00000001, - kBlendMultiplierSrcColor = 0x00000002, - kBlendMultiplierOneMinusSrcColor = 0x00000003, - kBlendMultiplierSrcAlpha = 0x00000004, - kBlendMultiplierOneMinusSrcAlpha = 0x00000005, - kBlendMultiplierDestAlpha = 0x00000006, - kBlendMultiplierOneMinusDestAlpha = 0x00000007, - kBlendMultiplierDestColor = 0x00000008, - kBlendMultiplierOneMinusDestColor = 0x00000009, - kBlendMultiplierSrcAlphaSaturate = 0x0000000a, - kBlendMultiplierConstantColor = 0x0000000d, - kBlendMultiplierOneMinusConstantColor = 0x0000000e, - kBlendMultiplierSrc1Color = 0x0000000f, - kBlendMultiplierInverseSrc1Color = 0x00000010, - kBlendMultiplierSrc1Alpha = 0x00000011, - kBlendMultiplierInverseSrc1Alpha = 0x00000012, - kBlendMultiplierConstantAlpha = 0x00000013, - kBlendMultiplierOneMinusConstantAlpha = 0x00000014, -}; - -enum BlendFunc { - kBlendFuncAdd = 0x00000000, - kBlendFuncSubtract = 0x00000001, - kBlendFuncMin = 0x00000002, - kBlendFuncMax = 0x00000003, - kBlendFuncReverseSubtract = 0x00000004, -}; - -enum PrimitiveType : unsigned { - kPrimitiveTypeNone = 0x00000000, - kPrimitiveTypePointList = 0x00000001, - kPrimitiveTypeLineList = 0x00000002, - kPrimitiveTypeLineStrip = 0x00000003, - kPrimitiveTypeTriList = 0x00000004, - kPrimitiveTypeTriFan = 0x00000005, - kPrimitiveTypeTriStrip = 0x00000006, - kPrimitiveTypePatch = 0x00000009, - kPrimitiveTypeLineListAdjacency = 0x0000000a, - kPrimitiveTypeLineStripAdjacency = 0x0000000b, - kPrimitiveTypeTriListAdjacency = 0x0000000c, - kPrimitiveTypeTriStripAdjacency = 0x0000000d, - kPrimitiveTypeRectList = 0x00000011, - kPrimitiveTypeLineLoop = 0x00000012, - kPrimitiveTypeQuadList = 0x00000013, - kPrimitiveTypeQuadStrip = 0x00000014, - kPrimitiveTypePolygon = 0x00000015 -}; - -enum SurfaceFormat : unsigned { - kSurfaceFormatInvalid = 0x00000000, - kSurfaceFormat8 = 0x00000001, - kSurfaceFormat16 = 0x00000002, - kSurfaceFormat8_8 = 0x00000003, - kSurfaceFormat32 = 0x00000004, - kSurfaceFormat16_16 = 0x00000005, - kSurfaceFormat10_11_11 = 0x00000006, - kSurfaceFormat11_11_10 = 0x00000007, - kSurfaceFormat10_10_10_2 = 0x00000008, - kSurfaceFormat2_10_10_10 = 0x00000009, - kSurfaceFormat8_8_8_8 = 0x0000000a, - kSurfaceFormat32_32 = 0x0000000b, - kSurfaceFormat16_16_16_16 = 0x0000000c, - kSurfaceFormat32_32_32 = 0x0000000d, - kSurfaceFormat32_32_32_32 = 0x0000000e, - kSurfaceFormat5_6_5 = 0x00000010, - kSurfaceFormat1_5_5_5 = 0x00000011, - kSurfaceFormat5_5_5_1 = 0x00000012, - kSurfaceFormat4_4_4_4 = 0x00000013, - kSurfaceFormat8_24 = 0x00000014, - kSurfaceFormat24_8 = 0x00000015, - kSurfaceFormatX24_8_32 = 0x00000016, - kSurfaceFormatGB_GR = 0x00000020, - kSurfaceFormatBG_RG = 0x00000021, - kSurfaceFormat5_9_9_9 = 0x00000022, - kSurfaceFormatBc1 = 0x00000023, - kSurfaceFormatBc2 = 0x00000024, - kSurfaceFormatBc3 = 0x00000025, - kSurfaceFormatBc4 = 0x00000026, - kSurfaceFormatBc5 = 0x00000027, - kSurfaceFormatBc6 = 0x00000028, - kSurfaceFormatBc7 = 0x00000029, - kSurfaceFormatFmask8_S2_F1 = 0x0000002C, - kSurfaceFormatFmask8_S4_F1 = 0x0000002D, - kSurfaceFormatFmask8_S8_F1 = 0x0000002E, - kSurfaceFormatFmask8_S2_F2 = 0x0000002F, - kSurfaceFormatFmask8_S4_F2 = 0x00000030, - kSurfaceFormatFmask8_S4_F4 = 0x00000031, - kSurfaceFormatFmask16_S16_F1 = 0x00000032, - kSurfaceFormatFmask16_S8_F2 = 0x00000033, - kSurfaceFormatFmask32_S16_F2 = 0x00000034, - kSurfaceFormatFmask32_S8_F4 = 0x00000035, - kSurfaceFormatFmask32_S8_F8 = 0x00000036, - kSurfaceFormatFmask64_S16_F4 = 0x00000037, - kSurfaceFormatFmask64_S16_F8 = 0x00000038, - kSurfaceFormat4_4 = 0x00000039, - kSurfaceFormat6_5_5 = 0x0000003A, - kSurfaceFormat1 = 0x0000003B, - kSurfaceFormat1Reversed = 0x0000003C, -}; - -enum TextureChannelType : unsigned { - kTextureChannelTypeUNorm = 0x00000000, - kTextureChannelTypeSNorm = 0x00000001, - kTextureChannelTypeUScaled = 0x00000002, - kTextureChannelTypeSScaled = 0x00000003, - kTextureChannelTypeUInt = 0x00000004, - kTextureChannelTypeSInt = 0x00000005, - kTextureChannelTypeSNormNoZero = 0x00000006, - kTextureChannelTypeFloat = 0x00000007, - kTextureChannelTypeSrgb = 0x00000009, - kTextureChannelTypeUBNorm = 0x0000000A, - kTextureChannelTypeUBNormNoZero = 0x0000000B, - kTextureChannelTypeUBInt = 0x0000000C, - kTextureChannelTypeUBScaled = 0x0000000D, -}; - -struct GnmVBuffer { - uint64_t base : 44; - uint64_t mtype_L1s : 2; - uint64_t mtype_L2 : 2; - uint64_t stride : 14; - uint64_t cache_swizzle : 1; - uint64_t swizzle_en : 1; - - uint32_t num_records; - - uint32_t dst_sel_x : 3; - uint32_t dst_sel_y : 3; - uint32_t dst_sel_z : 3; - uint32_t dst_sel_w : 3; - - uint32_t nfmt : 3; - uint32_t dfmt : 4; - uint32_t element_size : 2; - uint32_t index_stride : 2; - uint32_t addtid_en : 1; - uint32_t reserved0 : 1; - uint32_t hash_en : 1; - uint32_t reserved1 : 1; - uint32_t mtype : 3; - uint32_t type : 2; - - std::uint64_t getAddress() const { return base; } - - uint32_t getStride() const { return stride; } - - uint32_t getSize() const { - uint32_t stride = getStride(); - uint32_t numElements = getNumRecords(); - return stride ? numElements * stride : numElements; - } - - uint32_t getNumRecords() const { return num_records; } - uint32_t getElementSize() const { return element_size; } - uint32_t getIndexStrideSize() const { return index_stride; } - SurfaceFormat getSurfaceFormat() const { return (SurfaceFormat)dfmt; } - TextureChannelType getChannelType() const { return (TextureChannelType)nfmt; } -}; - -static_assert(sizeof(GnmVBuffer) == sizeof(std::uint64_t) * 2); - -enum class TextureType : uint64_t { - Dim1D = 8, - Dim2D, - Dim3D, - Cube, - Array1D, - Array2D, - Msaa2D, - MsaaArray2D, -}; - -struct GnmTBuffer { - uint64_t baseaddr256 : 38; - uint64_t mtype_L2 : 2; - uint64_t min_lod : 12; - SurfaceFormat dfmt : 6; - TextureChannelType nfmt : 4; - uint64_t mtype01 : 2; - - uint64_t width : 14; - uint64_t height : 14; - uint64_t perfMod : 3; - uint64_t interlaced : 1; - uint64_t dst_sel_x : 3; - uint64_t dst_sel_y : 3; - uint64_t dst_sel_z : 3; - uint64_t dst_sel_w : 3; - uint64_t base_level : 4; - uint64_t last_level : 4; - uint64_t tiling_idx : 5; - uint64_t pow2pad : 1; - uint64_t mtype2 : 1; - uint64_t : 1; // reserved - TextureType type : 4; - - uint64_t depth : 13; - uint64_t pitch : 14; - uint64_t : 5; // reserved - uint64_t base_array : 13; - uint64_t last_array : 13; - uint64_t : 6; // reserved - - uint64_t min_lod_warn : 12; // fixed point 4.8 - uint64_t counter_bank_id : 8; - uint64_t LOD_hdw_cnt_en : 1; - uint64_t : 42; // reserved - - std::uint64_t getAddress() const { - return static_cast(static_cast(baseaddr256)) - << 8; - } -}; - -static_assert(sizeof(GnmTBuffer) == sizeof(std::uint64_t) * 4); - -constexpr auto kPageSize = 0x4000; - -void setVkDevice(VkDevice device, - VkPhysicalDeviceMemoryProperties memProperties, - VkPhysicalDeviceProperties devProperties); - -struct AmdgpuDevice { - void handleProtectMemory(std::uint64_t address, std::uint64_t size, - std::uint32_t prot); - void handleCommandBuffer(std::uint64_t queueId, std::uint64_t address, - std::uint64_t size); - bool handleFlip(VkQueue queue, VkCommandBuffer cmdBuffer, - TaskChain &initTaskChain, std::uint32_t bufferIndex, - std::uint64_t arg, VkImage targetImage, - VkExtent2D targetExtent, VkSemaphore waitSemaphore, - VkSemaphore signalSemaphore, VkFence fence); - - AmdgpuDevice(amdgpu::bridge::BridgeHeader *bridge); - - ~AmdgpuDevice(); -}; +namespace amdgpu::device +{ + inline constexpr std::uint32_t getBits(std::uint32_t value, int end, + int begin) + { + return (value >> begin) & ((1u << (end - begin + 1)) - 1); + } + + inline constexpr std::uint32_t getBit(std::uint32_t value, int bit) + { + return (value >> bit) & 1; + } + + inline constexpr std::uint32_t genMask(std::uint32_t offset, + std::uint32_t bitCount) + { + return ((1u << bitCount) - 1u) << offset; + } + + inline constexpr std::uint32_t getMaskEnd(std::uint32_t mask) + { + return 32 - std::countl_zero(mask); + } + + inline constexpr std::uint32_t fetchMaskedValue(std::uint32_t hex, + std::uint32_t mask) + { + return (hex & mask) >> std::countr_zero(mask); + } + + template >> + inline std::size_t calcStringLen(T value, unsigned base = 10) + { + std::size_t n = 1; + std::size_t base2 = base * base; + std::size_t base3 = base2 * base; + std::size_t base4 = base3 * base; + + while (true) + { + if (value < base) + { + return n; + } + + if (value < base2) + { + return n + 1; + } + + if (value < base3) + { + return n + 2; + } + + if (value < base4) + { + return n + 3; + } + + value /= base4; + n += 4; + } + } + + template >> + inline void toHexString(char* dst, std::size_t len, T value) + { + while (len > 0) + { + char digit = value % 16; + value /= 16; + + dst[--len] = digit < 10 ? '0' + digit : 'a' + digit - 10; + } + } + + inline std::string toHexString(unsigned value) + { + auto len = calcStringLen(value, 16); + + std::string result(len, '\0'); + toHexString(result.data(), len, value); + return result; + } + + inline std::string toHexString(int value) + { + bool isNeg = value < 0; + unsigned uval = isNeg ? static_cast(~value) + 1 : value; + auto len = calcStringLen(uval, 16); + + std::string result(len + (isNeg ? 1 : 0), '-'); + toHexString(result.data(), len, uval); + return result; + } + + enum Registers + { + SPI_SHADER_PGM_LO_PS = 0x2c08, + SPI_SHADER_PGM_HI_PS = 0x2c09, + SPI_SHADER_PGM_RSRC1_PS = 0x2c0a, + SPI_SHADER_PGM_RSRC2_PS = 0x2c0b, + SPI_SHADER_USER_DATA_PS_0 = 0x2c0c, + SPI_SHADER_USER_DATA_PS_1, + SPI_SHADER_USER_DATA_PS_2, + SPI_SHADER_USER_DATA_PS_3, + SPI_SHADER_USER_DATA_PS_4, + SPI_SHADER_USER_DATA_PS_5, + SPI_SHADER_USER_DATA_PS_6, + SPI_SHADER_USER_DATA_PS_7, + SPI_SHADER_USER_DATA_PS_8, + SPI_SHADER_USER_DATA_PS_9, + SPI_SHADER_USER_DATA_PS_10, + SPI_SHADER_USER_DATA_PS_11, + SPI_SHADER_USER_DATA_PS_12, + SPI_SHADER_USER_DATA_PS_13, + SPI_SHADER_USER_DATA_PS_14, + SPI_SHADER_USER_DATA_PS_15, + + SPI_SHADER_PGM_LO_VS = 0x2c48, + SPI_SHADER_PGM_HI_VS = 0x2c49, + SPI_SHADER_PGM_RSRC1_VS = 0x2c4a, + SPI_SHADER_PGM_RSRC2_VS = 0x2c4b, + SPI_SHADER_USER_DATA_VS_0 = 0x2c4c, + SPI_SHADER_USER_DATA_VS_1 = 0x2c4d, + SPI_SHADER_USER_DATA_VS_2 = 0x2c4e, + SPI_SHADER_USER_DATA_VS_3 = 0x2c4f, + SPI_SHADER_USER_DATA_VS_4, + SPI_SHADER_USER_DATA_VS_5, + SPI_SHADER_USER_DATA_VS_6, + SPI_SHADER_USER_DATA_VS_7, + SPI_SHADER_USER_DATA_VS_8, + SPI_SHADER_USER_DATA_VS_9, + SPI_SHADER_USER_DATA_VS_10, + SPI_SHADER_USER_DATA_VS_11, + SPI_SHADER_USER_DATA_VS_12, + SPI_SHADER_USER_DATA_VS_13, + SPI_SHADER_USER_DATA_VS_14, + SPI_SHADER_USER_DATA_VS_15, + + COMPUTE_NUM_THREAD_X = 0x2e07, + COMPUTE_NUM_THREAD_Y, + COMPUTE_NUM_THREAD_Z, + COMPUTE_PGM_LO = 0x2e0c, + COMPUTE_PGM_HI, + COMPUTE_PGM_RSRC1 = 0x2e12, + COMPUTE_PGM_RSRC2, + COMPUTE_USER_DATA_0 = 0x2e40, + COMPUTE_USER_DATA_1, + COMPUTE_USER_DATA_2, + COMPUTE_USER_DATA_3, + COMPUTE_USER_DATA_4, + COMPUTE_USER_DATA_5, + COMPUTE_USER_DATA_6, + COMPUTE_USER_DATA_7, + COMPUTE_USER_DATA_8, + COMPUTE_USER_DATA_9, + COMPUTE_USER_DATA_10, + COMPUTE_USER_DATA_11, + COMPUTE_USER_DATA_12, + COMPUTE_USER_DATA_13, + COMPUTE_USER_DATA_14, + COMPUTE_USER_DATA_15, + + DB_RENDER_CONTROL = 0xa000, + DB_DEPTH_VIEW = 0xA002, + DB_HTILE_DATA_BASE = 0xA005, + DB_DEPTH_CLEAR = 0xA00B, + PA_SC_SCREEN_SCISSOR_TL = 0xa00c, + PA_SC_SCREEN_SCISSOR_BR = 0xa00d, + DB_DEPTH_INFO = 0xA00F, + DB_Z_INFO = 0xA010, + DB_STENCIL_INFO = 0xA011, + DB_Z_READ_BASE = 0xA012, + DB_STENCIL_READ_BASE = 0xA013, + DB_Z_WRITE_BASE = 0xA014, + DB_STENCIL_WRITE_BASE = 0xA015, + DB_DEPTH_SIZE = 0xA016, + DB_DEPTH_SLICE = 0xA017, + PA_SU_HARDWARE_SCREEN_OFFSET = 0xa08d, + CB_TARGET_MASK = 0xA08e, + CB_SHADER_MASK = 0xa08f, + PA_SC_VPORT_ZMIN_0 = 0xA0b4, + PA_SC_VPORT_ZMAX_0 = 0xA0b5, + PA_CL_VPORT_XSCALE = 0xa10f, + PA_CL_VPORT_XOFFSET, + PA_CL_VPORT_YSCALE, + PA_CL_VPORT_YOFFSET, + PA_CL_VPORT_ZSCALE, + PA_CL_VPORT_ZOFFSET, + SPI_PS_INPUT_CNTL_0 = 0xa191, + SPI_VS_OUT_CONFIG = 0xa1b1, + SPI_PS_INPUT_ENA = 0xa1b3, + SPI_PS_INPUT_ADDR = 0xa1b4, + SPI_PS_IN_CONTROL = 0xa1b6, + SPI_BARYC_CNTL = 0xa1b8, + SPI_SHADER_POS_FORMAT = 0xa1c3, + SPI_SHADER_Z_FORMAT = 0xa1c4, + SPI_SHADER_COL_FORMAT = 0xa1c5, + DB_DEPTH_CONTROL = 0xa200, + CB_COLOR_CONTROL = 0xa202, + DB_SHADER_CONTROL = 0xa203, + PA_CL_CLIP_CNTL = 0xa204, + PA_SU_SC_MODE_CNTL = 0xa205, + PA_CL_VTE_CNTL = 0xa206, + PA_CL_VS_OUT_CNTL = 0xa207, + DB_HTILE_SURFACE = 0xA2AF, + VGT_SHADER_STAGES_EN = 0xa2d5, + PA_CL_GB_VERT_CLIP_ADJ = 0xa2fa, + PA_CL_GB_VERT_DISC_ADJ, + PA_CL_GB_HORZ_CLIP_ADJ, + PA_CL_GB_HORZ_DISC_ADJ, + + CB_COLOR0_BASE = 0xA318, + CB_COLOR0_PITCH, + CB_COLOR0_SLICE, + CB_COLOR0_VIEW, + CB_COLOR0_INFO, + CB_COLOR0_ATTRIB, + CB_COLOR0_DCC_CONTROL, + CB_COLOR0_CMASK, + CB_COLOR0_CMASK_SLICE, + CB_COLOR0_FMASK, + CB_COLOR0_FMASK_SLICE, + CB_COLOR0_CLEAR_WORD0, + CB_COLOR0_CLEAR_WORD1, + CB_COLOR0_DCC_BASE, + CB_COLOR0_UNK0, + + CB_COLOR1_BASE, + CB_COLOR1_PITCH, + CB_COLOR1_SLICE, + CB_COLOR1_VIEW, + CB_COLOR1_INFO, + CB_COLOR1_ATTRIB, + CB_COLOR1_DCC_CONTROL, + CB_COLOR1_CMASK, + CB_COLOR1_CMASK_SLICE, + CB_COLOR1_FMASK, + CB_COLOR1_FMASK_SLICE, + CB_COLOR1_CLEAR_WORD0, + CB_COLOR1_CLEAR_WORD1, + CB_COLOR1_DCC_BASE, + CB_COLOR1_UNK0, + + CB_COLOR2_BASE, + CB_COLOR2_PITCH, + CB_COLOR2_SLICE, + CB_COLOR2_VIEW, + CB_COLOR2_INFO, + CB_COLOR2_ATTRIB, + CB_COLOR2_DCC_CONTROL, + CB_COLOR2_CMASK, + CB_COLOR2_CMASK_SLICE, + CB_COLOR2_FMASK, + CB_COLOR2_FMASK_SLICE, + CB_COLOR2_CLEAR_WORD0, + CB_COLOR2_CLEAR_WORD1, + CB_COLOR2_DCC_BASE, + CB_COLOR2_UNK0, + + CB_COLOR3_BASE, + CB_COLOR3_PITCH, + CB_COLOR3_SLICE, + CB_COLOR3_VIEW, + CB_COLOR3_INFO, + CB_COLOR3_ATTRIB, + CB_COLOR3_DCC_CONTROL, + CB_COLOR3_CMASK, + CB_COLOR3_CMASK_SLICE, + CB_COLOR3_FMASK, + CB_COLOR3_FMASK_SLICE, + CB_COLOR3_CLEAR_WORD0, + CB_COLOR3_CLEAR_WORD1, + CB_COLOR3_DCC_BASE, + CB_COLOR3_UNK0, + + CB_COLOR4_BASE, + CB_COLOR4_PITCH, + CB_COLOR4_SLICE, + CB_COLOR4_VIEW, + CB_COLOR4_INFO, + CB_COLOR4_ATTRIB, + CB_COLOR4_DCC_CONTROL, + CB_COLOR4_CMASK, + CB_COLOR4_CMASK_SLICE, + CB_COLOR4_FMASK, + CB_COLOR4_FMASK_SLICE, + CB_COLOR4_CLEAR_WORD0, + CB_COLOR4_CLEAR_WORD1, + CB_COLOR4_DCC_BASE, + CB_COLOR4_UNK0, + + CB_COLOR5_BASE, + CB_COLOR5_PITCH, + CB_COLOR5_SLICE, + CB_COLOR5_VIEW, + CB_COLOR5_INFO, + CB_COLOR5_ATTRIB, + CB_COLOR5_DCC_CONTROL, + CB_COLOR5_CMASK, + CB_COLOR5_CMASK_SLICE, + CB_COLOR5_FMASK, + CB_COLOR5_FMASK_SLICE, + CB_COLOR5_CLEAR_WORD0, + CB_COLOR5_CLEAR_WORD1, + CB_COLOR5_DCC_BASE, + CB_COLOR5_UNK0, + + CB_COLOR6_BASE, + CB_COLOR6_PITCH, + CB_COLOR6_SLICE, + CB_COLOR6_VIEW, + CB_COLOR6_INFO, + CB_COLOR6_ATTRIB, + CB_COLOR6_DCC_CONTROL, + CB_COLOR6_CMASK, + CB_COLOR6_CMASK_SLICE, + CB_COLOR6_FMASK, + CB_COLOR6_FMASK_SLICE, + CB_COLOR6_CLEAR_WORD0, + CB_COLOR6_CLEAR_WORD1, + CB_COLOR6_DCC_BASE, + CB_COLOR6_UNK0, + + CB_BLEND0_CONTROL = 0xa1e0, + + VGT_PRIMITIVE_TYPE = 0xc242, + }; + + inline std::string registerToString(int reg) + { + switch (reg) + { + case SPI_SHADER_PGM_LO_PS: + return "SPI_SHADER_PGM_LO_PS"; + case SPI_SHADER_PGM_HI_PS: + return "SPI_SHADER_PGM_HI_PS"; + case SPI_SHADER_PGM_RSRC1_PS: + return "SPI_SHADER_PGM_RSRC1_PS"; + case SPI_SHADER_PGM_RSRC2_PS: + return "SPI_SHADER_PGM_RSRC2_PS"; + case SPI_SHADER_USER_DATA_PS_0: + return "SPI_SHADER_USER_DATA_PS_0"; + case SPI_SHADER_USER_DATA_PS_1: + return "SPI_SHADER_USER_DATA_PS_1"; + case SPI_SHADER_USER_DATA_PS_2: + return "SPI_SHADER_USER_DATA_PS_2"; + case SPI_SHADER_USER_DATA_PS_3: + return "SPI_SHADER_USER_DATA_PS_3"; + case SPI_SHADER_USER_DATA_PS_4: + return "SPI_SHADER_USER_DATA_PS_4"; + case SPI_SHADER_USER_DATA_PS_5: + return "SPI_SHADER_USER_DATA_PS_5"; + case SPI_SHADER_USER_DATA_PS_6: + return "SPI_SHADER_USER_DATA_PS_6"; + case SPI_SHADER_USER_DATA_PS_7: + return "SPI_SHADER_USER_DATA_PS_7"; + case SPI_SHADER_USER_DATA_PS_8: + return "SPI_SHADER_USER_DATA_PS_8"; + case SPI_SHADER_USER_DATA_PS_9: + return "SPI_SHADER_USER_DATA_PS_9"; + case SPI_SHADER_USER_DATA_PS_10: + return "SPI_SHADER_USER_DATA_PS_10"; + case SPI_SHADER_USER_DATA_PS_11: + return "SPI_SHADER_USER_DATA_PS_11"; + case SPI_SHADER_USER_DATA_PS_12: + return "SPI_SHADER_USER_DATA_PS_12"; + case SPI_SHADER_USER_DATA_PS_13: + return "SPI_SHADER_USER_DATA_PS_13"; + case SPI_SHADER_USER_DATA_PS_14: + return "SPI_SHADER_USER_DATA_PS_14"; + case SPI_SHADER_USER_DATA_PS_15: + return "SPI_SHADER_USER_DATA_PS_15"; + case SPI_SHADER_PGM_LO_VS: + return "SPI_SHADER_PGM_LO_VS"; + case SPI_SHADER_PGM_HI_VS: + return "SPI_SHADER_PGM_HI_VS"; + case SPI_SHADER_PGM_RSRC1_VS: + return "SPI_SHADER_PGM_RSRC1_VS"; + case SPI_SHADER_PGM_RSRC2_VS: + return "SPI_SHADER_PGM_RSRC2_VS"; + case SPI_SHADER_USER_DATA_VS_0: + return "SPI_SHADER_USER_DATA_VS_0"; + case SPI_SHADER_USER_DATA_VS_1: + return "SPI_SHADER_USER_DATA_VS_1"; + case SPI_SHADER_USER_DATA_VS_2: + return "SPI_SHADER_USER_DATA_VS_2"; + case SPI_SHADER_USER_DATA_VS_3: + return "SPI_SHADER_USER_DATA_VS_3"; + case SPI_SHADER_USER_DATA_VS_4: + return "SPI_SHADER_USER_DATA_VS_4"; + case SPI_SHADER_USER_DATA_VS_5: + return "SPI_SHADER_USER_DATA_VS_5"; + case SPI_SHADER_USER_DATA_VS_6: + return "SPI_SHADER_USER_DATA_VS_6"; + case SPI_SHADER_USER_DATA_VS_7: + return "SPI_SHADER_USER_DATA_VS_7"; + case SPI_SHADER_USER_DATA_VS_8: + return "SPI_SHADER_USER_DATA_VS_8"; + case SPI_SHADER_USER_DATA_VS_9: + return "SPI_SHADER_USER_DATA_VS_9"; + case SPI_SHADER_USER_DATA_VS_10: + return "SPI_SHADER_USER_DATA_VS_10"; + case SPI_SHADER_USER_DATA_VS_11: + return "SPI_SHADER_USER_DATA_VS_11"; + case SPI_SHADER_USER_DATA_VS_12: + return "SPI_SHADER_USER_DATA_VS_12"; + case SPI_SHADER_USER_DATA_VS_13: + return "SPI_SHADER_USER_DATA_VS_13"; + case SPI_SHADER_USER_DATA_VS_14: + return "SPI_SHADER_USER_DATA_VS_14"; + case SPI_SHADER_USER_DATA_VS_15: + return "SPI_SHADER_USER_DATA_VS_15"; + case COMPUTE_NUM_THREAD_X: + return "COMPUTE_NUM_THREAD_X"; + case COMPUTE_NUM_THREAD_Y: + return "COMPUTE_NUM_THREAD_Y"; + case COMPUTE_NUM_THREAD_Z: + return "COMPUTE_NUM_THREAD_Z"; + case COMPUTE_PGM_LO: + return "COMPUTE_PGM_LO"; + case COMPUTE_PGM_HI: + return "COMPUTE_PGM_HI"; + case COMPUTE_PGM_RSRC1: + return "COMPUTE_PGM_RSRC1"; + case COMPUTE_PGM_RSRC2: + return "COMPUTE_PGM_RSRC2"; + case COMPUTE_USER_DATA_0: + return "COMPUTE_USER_DATA_0"; + case COMPUTE_USER_DATA_1: + return "COMPUTE_USER_DATA_1"; + case COMPUTE_USER_DATA_2: + return "COMPUTE_USER_DATA_2"; + case COMPUTE_USER_DATA_3: + return "COMPUTE_USER_DATA_3"; + case COMPUTE_USER_DATA_4: + return "COMPUTE_USER_DATA_4"; + case COMPUTE_USER_DATA_5: + return "COMPUTE_USER_DATA_5"; + case COMPUTE_USER_DATA_6: + return "COMPUTE_USER_DATA_6"; + case COMPUTE_USER_DATA_7: + return "COMPUTE_USER_DATA_7"; + case COMPUTE_USER_DATA_8: + return "COMPUTE_USER_DATA_8"; + case COMPUTE_USER_DATA_9: + return "COMPUTE_USER_DATA_9"; + case COMPUTE_USER_DATA_10: + return "COMPUTE_USER_DATA_10"; + case COMPUTE_USER_DATA_11: + return "COMPUTE_USER_DATA_11"; + case COMPUTE_USER_DATA_12: + return "COMPUTE_USER_DATA_12"; + case COMPUTE_USER_DATA_13: + return "COMPUTE_USER_DATA_13"; + case COMPUTE_USER_DATA_14: + return "COMPUTE_USER_DATA_14"; + case COMPUTE_USER_DATA_15: + return "COMPUTE_USER_DATA_15"; + case DB_DEPTH_CLEAR: + return "DB_DEPTH_CLEAR"; + case DB_RENDER_CONTROL: + return "DB_RENDER_CONTROL"; + case DB_DEPTH_VIEW: + return "DB_DEPTH_VIEW"; + case DB_HTILE_DATA_BASE: + return "DB_HTILE_DATA_BASE"; + case PA_SC_SCREEN_SCISSOR_TL: + return "PA_SC_SCREEN_SCISSOR_TL"; + case PA_SC_SCREEN_SCISSOR_BR: + return "PA_SC_SCREEN_SCISSOR_BR"; + case DB_DEPTH_INFO: + return "DB_DEPTH_INFO"; + case DB_Z_INFO: + return "DB_Z_INFO"; + case DB_STENCIL_INFO: + return "DB_STENCIL_INFO"; + case DB_Z_READ_BASE: + return "DB_Z_READ_BASE"; + case DB_STENCIL_READ_BASE: + return "DB_STENCIL_READ_BASE"; + case DB_Z_WRITE_BASE: + return "DB_Z_WRITE_BASE"; + case DB_STENCIL_WRITE_BASE: + return "DB_STENCIL_WRITE_BASE"; + case DB_DEPTH_SIZE: + return "DB_DEPTH_SIZE"; + case DB_DEPTH_SLICE: + return "DB_DEPTH_SLICE"; + case PA_SU_HARDWARE_SCREEN_OFFSET: + return "PA_SU_HARDWARE_SCREEN_OFFSET"; + case CB_TARGET_MASK: + return "CB_TARGET_MASK"; + case CB_SHADER_MASK: + return "CB_SHADER_MASK"; + case PA_SC_VPORT_ZMIN_0: + return "PA_SC_VPORT_ZMIN_0"; + case PA_SC_VPORT_ZMAX_0: + return "PA_SC_VPORT_ZMAX_0"; + case PA_CL_VPORT_XSCALE: + return "PA_CL_VPORT_XSCALE"; + case PA_CL_VPORT_XOFFSET: + return "PA_CL_VPORT_XOFFSET"; + case PA_CL_VPORT_YSCALE: + return "PA_CL_VPORT_YSCALE"; + case PA_CL_VPORT_YOFFSET: + return "PA_CL_VPORT_YOFFSET"; + case PA_CL_VPORT_ZSCALE: + return "PA_CL_VPORT_ZSCALE"; + case PA_CL_VPORT_ZOFFSET: + return "PA_CL_VPORT_ZOFFSET"; + case SPI_PS_INPUT_CNTL_0: + return "SPI_PS_INPUT_CNTL_0"; + case SPI_VS_OUT_CONFIG: + return "SPI_VS_OUT_CONFIG"; + case SPI_PS_INPUT_ENA: + return "SPI_PS_INPUT_ENA"; + case SPI_PS_INPUT_ADDR: + return "SPI_PS_INPUT_ADDR"; + case SPI_PS_IN_CONTROL: + return "SPI_PS_IN_CONTROL"; + case SPI_BARYC_CNTL: + return "SPI_BARYC_CNTL"; + case SPI_SHADER_POS_FORMAT: + return "SPI_SHADER_POS_FORMAT"; + case SPI_SHADER_Z_FORMAT: + return "SPI_SHADER_Z_FORMAT"; + case SPI_SHADER_COL_FORMAT: + return "SPI_SHADER_COL_FORMAT"; + case DB_DEPTH_CONTROL: + return "DB_DEPTH_CONTROL"; + case CB_COLOR_CONTROL: + return "DB_COLOR_CONTROL"; + case DB_SHADER_CONTROL: + return "DB_SHADER_CONTROL"; + case PA_CL_CLIP_CNTL: + return "PA_CL_CLIP_CNTL"; + case PA_SU_SC_MODE_CNTL: + return "PA_SU_SC_MODE_CNTL"; + case PA_CL_VTE_CNTL: + return "PA_CL_VTE_CNTL"; + case PA_CL_VS_OUT_CNTL: + return "PA_CL_VS_OUT_CNTL"; + case DB_HTILE_SURFACE: + return "DB_HTILE_SURFACE"; + case VGT_SHADER_STAGES_EN: + return "VGT_SHADER_STAGES_EN"; + case PA_CL_GB_VERT_CLIP_ADJ: + return "PA_CL_GB_VERT_CLIP_ADJ"; + case PA_CL_GB_VERT_DISC_ADJ: + return "PA_CL_GB_VERT_DISC_ADJ"; + case PA_CL_GB_HORZ_CLIP_ADJ: + return "PA_CL_GB_HORZ_CLIP_ADJ"; + case PA_CL_GB_HORZ_DISC_ADJ: + return "PA_CL_GB_HORZ_DISC_ADJ"; + case CB_COLOR0_BASE: + return "CB_COLOR0_BASE"; + case CB_COLOR0_PITCH: + return "CB_COLOR0_PITCH"; + case CB_COLOR0_SLICE: + return "CB_COLOR0_SLICE"; + case CB_COLOR0_VIEW: + return "CB_COLOR0_VIEW"; + case CB_COLOR0_INFO: + return "CB_COLOR0_INFO"; + case CB_COLOR0_ATTRIB: + return "CB_COLOR0_ATTRIB"; + case CB_COLOR0_DCC_CONTROL: + return "CB_COLOR0_DCC_CONTROL"; + case CB_COLOR0_CMASK: + return "CB_COLOR0_CMASK"; + case CB_COLOR0_CMASK_SLICE: + return "CB_COLOR0_CMASK_SLICE"; + case CB_COLOR0_FMASK: + return "CB_COLOR0_FMASK"; + case CB_COLOR0_FMASK_SLICE: + return "CB_COLOR0_FMASK_SLICE"; + case CB_COLOR0_CLEAR_WORD0: + return "CB_COLOR0_CLEAR_WORD0"; + case CB_COLOR0_CLEAR_WORD1: + return "CB_COLOR0_CLEAR_WORD1"; + case CB_COLOR0_DCC_BASE: + return "CB_COLOR0_DCC_BASE"; + case CB_COLOR1_BASE: + return "CB_COLOR1_BASE"; + case CB_COLOR1_PITCH: + return "CB_COLOR1_PITCH"; + case CB_COLOR1_SLICE: + return "CB_COLOR1_SLICE"; + case CB_COLOR1_VIEW: + return "CB_COLOR1_VIEW"; + case CB_COLOR1_INFO: + return "CB_COLOR1_INFO"; + case CB_COLOR1_ATTRIB: + return "CB_COLOR1_ATTRIB"; + case CB_COLOR1_DCC_CONTROL: + return "CB_COLOR1_DCC_CONTROL"; + case CB_COLOR1_CMASK: + return "CB_COLOR1_CMASK"; + case CB_COLOR1_CMASK_SLICE: + return "CB_COLOR1_CMASK_SLICE"; + case CB_COLOR1_FMASK: + return "CB_COLOR1_FMASK"; + case CB_COLOR1_FMASK_SLICE: + return "CB_COLOR1_FMASK_SLICE"; + case CB_COLOR1_CLEAR_WORD0: + return "CB_COLOR1_CLEAR_WORD0"; + case CB_COLOR1_CLEAR_WORD1: + return "CB_COLOR1_CLEAR_WORD1"; + case CB_COLOR1_DCC_BASE: + return "CB_COLOR1_DCC_BASE"; + case CB_COLOR2_BASE: + return "CB_COLOR2_BASE"; + case CB_COLOR2_PITCH: + return "CB_COLOR2_PITCH"; + case CB_COLOR2_SLICE: + return "CB_COLOR2_SLICE"; + case CB_COLOR2_VIEW: + return "CB_COLOR2_VIEW"; + case CB_COLOR2_INFO: + return "CB_COLOR2_INFO"; + case CB_COLOR2_ATTRIB: + return "CB_COLOR2_ATTRIB"; + case CB_COLOR2_DCC_CONTROL: + return "CB_COLOR2_DCC_CONTROL"; + case CB_COLOR2_CMASK: + return "CB_COLOR2_CMASK"; + case CB_COLOR2_CMASK_SLICE: + return "CB_COLOR2_CMASK_SLICE"; + case CB_COLOR2_FMASK: + return "CB_COLOR2_FMASK"; + case CB_COLOR2_FMASK_SLICE: + return "CB_COLOR2_FMASK_SLICE"; + case CB_COLOR2_CLEAR_WORD0: + return "CB_COLOR2_CLEAR_WORD0"; + case CB_COLOR2_CLEAR_WORD1: + return "CB_COLOR2_CLEAR_WORD1"; + case CB_COLOR2_DCC_BASE: + return "CB_COLOR2_DCC_BASE"; + case CB_COLOR3_BASE: + return "CB_COLOR3_BASE"; + case CB_COLOR3_PITCH: + return "CB_COLOR3_PITCH"; + case CB_COLOR3_SLICE: + return "CB_COLOR3_SLICE"; + case CB_COLOR3_VIEW: + return "CB_COLOR3_VIEW"; + case CB_COLOR3_INFO: + return "CB_COLOR3_INFO"; + case CB_COLOR3_ATTRIB: + return "CB_COLOR3_ATTRIB"; + case CB_COLOR3_DCC_CONTROL: + return "CB_COLOR3_DCC_CONTROL"; + case CB_COLOR3_CMASK: + return "CB_COLOR3_CMASK"; + case CB_COLOR3_CMASK_SLICE: + return "CB_COLOR3_CMASK_SLICE"; + case CB_COLOR3_FMASK: + return "CB_COLOR3_FMASK"; + case CB_COLOR3_FMASK_SLICE: + return "CB_COLOR3_FMASK_SLICE"; + case CB_COLOR3_CLEAR_WORD0: + return "CB_COLOR3_CLEAR_WORD0"; + case CB_COLOR3_CLEAR_WORD1: + return "CB_COLOR3_CLEAR_WORD1"; + case CB_COLOR3_DCC_BASE: + return "CB_COLOR3_DCC_BASE"; + case CB_COLOR4_BASE: + return "CB_COLOR4_BASE"; + case CB_COLOR4_PITCH: + return "CB_COLOR4_PITCH"; + case CB_COLOR4_SLICE: + return "CB_COLOR4_SLICE"; + case CB_COLOR4_VIEW: + return "CB_COLOR4_VIEW"; + case CB_COLOR4_INFO: + return "CB_COLOR4_INFO"; + case CB_COLOR4_ATTRIB: + return "CB_COLOR4_ATTRIB"; + case CB_COLOR4_DCC_CONTROL: + return "CB_COLOR4_DCC_CONTROL"; + case CB_COLOR4_CMASK: + return "CB_COLOR4_CMASK"; + case CB_COLOR4_CMASK_SLICE: + return "CB_COLOR4_CMASK_SLICE"; + case CB_COLOR4_FMASK: + return "CB_COLOR4_FMASK"; + case CB_COLOR4_FMASK_SLICE: + return "CB_COLOR4_FMASK_SLICE"; + case CB_COLOR4_CLEAR_WORD0: + return "CB_COLOR4_CLEAR_WORD0"; + case CB_COLOR4_CLEAR_WORD1: + return "CB_COLOR4_CLEAR_WORD1"; + case CB_COLOR4_DCC_BASE: + return "CB_COLOR4_DCC_BASE"; + case CB_COLOR5_BASE: + return "CB_COLOR5_BASE"; + case CB_COLOR5_PITCH: + return "CB_COLOR5_PITCH"; + case CB_COLOR5_SLICE: + return "CB_COLOR5_SLICE"; + case CB_COLOR5_VIEW: + return "CB_COLOR5_VIEW"; + case CB_COLOR5_INFO: + return "CB_COLOR5_INFO"; + case CB_COLOR5_ATTRIB: + return "CB_COLOR5_ATTRIB"; + case CB_COLOR5_DCC_CONTROL: + return "CB_COLOR5_DCC_CONTROL"; + case CB_COLOR5_CMASK: + return "CB_COLOR5_CMASK"; + case CB_COLOR5_CMASK_SLICE: + return "CB_COLOR5_CMASK_SLICE"; + case CB_COLOR5_FMASK: + return "CB_COLOR5_FMASK"; + case CB_COLOR5_FMASK_SLICE: + return "CB_COLOR5_FMASK_SLICE"; + case CB_COLOR5_CLEAR_WORD0: + return "CB_COLOR5_CLEAR_WORD0"; + case CB_COLOR5_CLEAR_WORD1: + return "CB_COLOR5_CLEAR_WORD1"; + case CB_COLOR5_DCC_BASE: + return "CB_COLOR5_DCC_BASE"; + case CB_COLOR6_BASE: + return "CB_COLOR6_BASE"; + case CB_COLOR6_PITCH: + return "CB_COLOR6_PITCH"; + case CB_COLOR6_SLICE: + return "CB_COLOR6_SLICE"; + case CB_COLOR6_VIEW: + return "CB_COLOR6_VIEW"; + case CB_COLOR6_INFO: + return "CB_COLOR6_INFO"; + case CB_COLOR6_ATTRIB: + return "CB_COLOR6_ATTRIB"; + case CB_COLOR6_DCC_CONTROL: + return "CB_COLOR6_DCC_CONTROL"; + case CB_COLOR6_CMASK: + return "CB_COLOR6_CMASK"; + case CB_COLOR6_CMASK_SLICE: + return "CB_COLOR6_CMASK_SLICE"; + case CB_COLOR6_FMASK: + return "CB_COLOR6_FMASK"; + case CB_COLOR6_FMASK_SLICE: + return "CB_COLOR6_FMASK_SLICE"; + case CB_COLOR6_CLEAR_WORD0: + return "CB_COLOR6_CLEAR_WORD0"; + case CB_COLOR6_CLEAR_WORD1: + return "CB_COLOR6_CLEAR_WORD1"; + case CB_COLOR6_DCC_BASE: + return "CB_COLOR6_DCC_BASE"; + case CB_BLEND0_CONTROL: + return "CB_BLEND0_CONTROL"; + + case VGT_PRIMITIVE_TYPE: + return "VGT_PRIMITIVE_TYPE"; + } + + return ""; + } + + enum Opcodes + { + kOpcodeNOP = 0x10, + kOpcodeSET_BASE = 0x11, + kOpcodeCLEAR_STATE = 0x12, + kOpcodeINDEX_BUFFER_SIZE = 0x13, + kOpcodeDISPATCH_DIRECT = 0x15, + kOpcodeDISPATCH_INDIRECT = 0x16, + kOpcodeINDIRECT_BUFFER_END = 0x17, + kOpcodeMODE_CONTROL = 0x18, + kOpcodeATOMIC_GDS = 0x1D, + kOpcodeATOMIC_MEM = 0x1E, + kOpcodeOCCLUSION_QUERY = 0x1F, + kOpcodeSET_PREDICATION = 0x20, + kOpcodeREG_RMW = 0x21, + kOpcodeCOND_EXEC = 0x22, + kOpcodePRED_EXEC = 0x23, + kOpcodeDRAW_INDIRECT = 0x24, + kOpcodeDRAW_INDEX_INDIRECT = 0x25, + kOpcodeINDEX_BASE = 0x26, + kOpcodeDRAW_INDEX_2 = 0x27, + kOpcodeCONTEXT_CONTROL = 0x28, + kOpcodeDRAW_INDEX_OFFSET = 0x29, + kOpcodeINDEX_TYPE = 0x2A, + kOpcodeDRAW_INDEX = 0x2B, + kOpcodeDRAW_INDIRECT_MULTI = 0x2C, + kOpcodeDRAW_INDEX_AUTO = 0x2D, + kOpcodeDRAW_INDEX_IMMD = 0x2E, + kOpcodeNUM_INSTANCES = 0x2F, + kOpcodeDRAW_INDEX_MULTI_AUTO = 0x30, + kOpcodeINDIRECT_BUFFER_32 = 0x32, + kOpcodeINDIRECT_BUFFER_CONST = 0x33, + kOpcodeSTRMOUT_BUFFER_UPDATE = 0x34, + kOpcodeDRAW_INDEX_OFFSET_2 = 0x35, + kOpcodeDRAW_PREAMBLE = 0x36, + kOpcodeWRITE_DATA = 0x37, + kOpcodeDRAW_INDEX_INDIRECT_MULTI = 0x38, + kOpcodeMEM_SEMAPHORE = 0x39, + kOpcodeMPEG_INDEX = 0x3A, + kOpcodeCOPY_DW = 0x3B, + kOpcodeWAIT_REG_MEM = 0x3C, + kOpcodeMEM_WRITE = 0x3D, + kOpcodeINDIRECT_BUFFER_3F = 0x3F, + kOpcodeCOPY_DATA = 0x40, + kOpcodeCP_DMA = 0x41, + kOpcodePFP_SYNC_ME = 0x42, + kOpcodeSURFACE_SYNC = 0x43, + kOpcodeME_INITIALIZE = 0x44, + kOpcodeCOND_WRITE = 0x45, + kOpcodeEVENT_WRITE = 0x46, + kOpcodeEVENT_WRITE_EOP = 0x47, + kOpcodeEVENT_WRITE_EOS = 0x48, + kOpcodeRELEASE_MEM = 0x49, + kOpcodePREAMBLE_CNTL = 0x4A, + kOpcodeRB_OFFSET = 0x4B, + kOpcodeALU_PS_CONST_BUFFER_COPY = 0x4C, + kOpcodeALU_VS_CONST_BUFFER_COPY = 0x4D, + kOpcodeALU_PS_CONST_UPDATE = 0x4E, + kOpcodeALU_VS_CONST_UPDATE = 0x4F, + kOpcodeDMA_DATA = 0x50, + kOpcodeONE_REG_WRITE = 0x57, + kOpcodeAQUIRE_MEM = 0x58, + kOpcodeREWIND = 0x59, + kOpcodeLOAD_UCONFIG_REG = 0x5E, + kOpcodeLOAD_SH_REG = 0x5F, + kOpcodeLOAD_CONFIG_REG = 0x60, + kOpcodeLOAD_CONTEXT_REG = 0x61, + kOpcodeSET_CONFIG_REG = 0x68, + kOpcodeSET_CONTEXT_REG = 0x69, + kOpcodeSET_ALU_CONST = 0x6A, + kOpcodeSET_BOOL_CONST = 0x6B, + kOpcodeSET_LOOP_CONST = 0x6C, + kOpcodeSET_RESOURCE = 0x6D, + kOpcodeSET_SAMPLER = 0x6E, + kOpcodeSET_CTL_CONST = 0x6F, + kOpcodeSET_RESOURCE_OFFSET = 0x70, + kOpcodeSET_ALU_CONST_VS = 0x71, + kOpcodeSET_ALU_CONST_DI = 0x72, + kOpcodeSET_CONTEXT_REG_INDIRECT = 0x73, + kOpcodeSET_RESOURCE_INDIRECT = 0x74, + kOpcodeSET_APPEND_CNT = 0x75, + kOpcodeSET_SH_REG = 0x76, + kOpcodeSET_SH_REG_OFFSET = 0x77, + kOpcodeSET_QUEUE_REG = 0x78, + kOpcodeSET_UCONFIG_REG = 0x79, + kOpcodeSCRATCH_RAM_WRITE = 0x7D, + kOpcodeSCRATCH_RAM_READ = 0x7E, + kOpcodeLOAD_CONST_RAM = 0x80, + kOpcodeWRITE_CONST_RAM = 0x81, + kOpcodeDUMP_CONST_RAM = 0x83, + kOpcodeINCREMENT_CE_COUNTER = 0x84, + kOpcodeINCREMENT_DE_COUNTER = 0x85, + kOpcodeWAIT_ON_CE_COUNTER = 0x86, + kOpcodeWAIT_ON_DE_COUNTER_DIFF = 0x88, + kOpcodeSWITCH_BUFFER = 0x8B, + }; + + inline const std::string opcodeToString(int op) + { + switch (op) + { + case kOpcodeNOP: + return "IT_NOP"; + case kOpcodeSET_BASE: + return "IT_SET_BASE"; + case kOpcodeCLEAR_STATE: + return "IT_CLEAR_STATE"; + case kOpcodeINDEX_BUFFER_SIZE: + return "IT_INDEX_BUFFER_SIZE"; + case kOpcodeDISPATCH_DIRECT: + return "IT_DISPATCH_DIRECT"; + case kOpcodeDISPATCH_INDIRECT: + return "IT_DISPATCH_INDIRECT"; + case kOpcodeINDIRECT_BUFFER_END: + return "IT_INDIRECT_BUFFER_END"; + case kOpcodeATOMIC_GDS: + return "IT_ATOMIC_GDS"; + case kOpcodeATOMIC_MEM: + return "IT_ATOMIC_MEM"; + case kOpcodeOCCLUSION_QUERY: + return "IT_OCCLUSION_QUERY"; + case kOpcodeSET_PREDICATION: + return "IT_SET_PREDICATION"; + case kOpcodeREG_RMW: + return "IT_REG_RMW"; + case kOpcodeCOND_EXEC: + return "IT_COND_EXEC"; + case kOpcodePRED_EXEC: + return "IT_PRED_EXEC"; + case kOpcodeDRAW_INDIRECT: + return "IT_DRAW_INDIRECT"; + case kOpcodeDRAW_INDEX_INDIRECT: + return "IT_DRAW_INDEX_INDIRECT"; + case kOpcodeINDEX_BASE: + return "IT_INDEX_BASE"; + case kOpcodeDRAW_INDEX_2: + return "IT_DRAW_INDEX_2"; + case kOpcodeCONTEXT_CONTROL: + return "IT_CONTEXT_CONTROL"; + case kOpcodeINDEX_TYPE: + return "IT_INDEX_TYPE"; + case kOpcodeDRAW_INDEX: + return "IT_DRAW_INDEX"; + case kOpcodeDRAW_INDIRECT_MULTI: + return "IT_DRAW_INDIRECT_MULTI"; + case kOpcodeDRAW_INDEX_AUTO: + return "IT_DRAW_INDEX_AUTO"; + case kOpcodeDRAW_INDEX_IMMD: + return "IT_DRAW_INDEX_IMMD"; + case kOpcodeNUM_INSTANCES: + return "IT_NUM_INSTANCES"; + case kOpcodeDRAW_INDEX_MULTI_AUTO: + return "IT_DRAW_INDEX_MULTI_AUTO"; + case kOpcodeINDIRECT_BUFFER_32: + return "IT_INDIRECT_BUFFER_32"; + case kOpcodeINDIRECT_BUFFER_CONST: + return "IT_INDIRECT_BUFFER_CONST"; + case kOpcodeSTRMOUT_BUFFER_UPDATE: + return "IT_STRMOUT_BUFFER_UPDATE"; + case kOpcodeDRAW_INDEX_OFFSET_2: + return "IT_DRAW_INDEX_OFFSET_2"; + case kOpcodeDRAW_PREAMBLE: + return "IT_DRAW_PREAMBLE"; + case kOpcodeWRITE_DATA: + return "IT_WRITE_DATA"; + case kOpcodeDRAW_INDEX_INDIRECT_MULTI: + return "IT_DRAW_INDEX_INDIRECT_MULTI"; + case kOpcodeMEM_SEMAPHORE: + return "IT_MEM_SEMAPHORE"; + case kOpcodeMPEG_INDEX: + return "IT_MPEG_INDEX"; + case kOpcodeCOPY_DW: + return "IT_COPY_DW"; + case kOpcodeWAIT_REG_MEM: + return "IT_WAIT_REG_MEM"; + case kOpcodeMEM_WRITE: + return "IT_MEM_WRITE"; + case kOpcodeINDIRECT_BUFFER_3F: + return "IT_INDIRECT_BUFFER_3F"; + case kOpcodeCOPY_DATA: + return "IT_COPY_DATA"; + case kOpcodeCP_DMA: + return "IT_CP_DMA"; + case kOpcodePFP_SYNC_ME: + return "IT_PFP_SYNC_ME"; + case kOpcodeSURFACE_SYNC: + return "IT_SURFACE_SYNC"; + case kOpcodeME_INITIALIZE: + return "IT_ME_INITIALIZE"; + case kOpcodeCOND_WRITE: + return "IT_COND_WRITE"; + case kOpcodeEVENT_WRITE: + return "IT_EVENT_WRITE"; + case kOpcodeEVENT_WRITE_EOP: + return "IT_EVENT_WRITE_EOP"; + case kOpcodeEVENT_WRITE_EOS: + return "IT_EVENT_WRITE_EOS"; + case kOpcodeRELEASE_MEM: + return "IT_RELEASE_MEM"; + case kOpcodePREAMBLE_CNTL: + return "IT_PREAMBLE_CNTL"; + case kOpcodeDMA_DATA: + return "IT_DMA_DATA"; + case kOpcodeONE_REG_WRITE: + return "IT_ONE_REG_WRITE"; + case kOpcodeAQUIRE_MEM: + return "IT_AQUIRE_MEM"; + case kOpcodeREWIND: + return "IT_REWIND"; + case kOpcodeLOAD_UCONFIG_REG: + return "IT_LOAD_UCONFIG_REG"; + case kOpcodeLOAD_SH_REG: + return "IT_LOAD_SH_REG"; + case kOpcodeLOAD_CONFIG_REG: + return "IT_LOAD_CONFIG_REG"; + case kOpcodeLOAD_CONTEXT_REG: + return "IT_LOAD_CONTEXT_REG"; + case kOpcodeSET_CONFIG_REG: + return "IT_SET_CONFIG_REG"; + case kOpcodeSET_CONTEXT_REG: + return "IT_SET_CONTEXT_REG"; + case kOpcodeSET_ALU_CONST: + return "IT_SET_ALU_CONST"; + case kOpcodeSET_BOOL_CONST: + return "IT_SET_BOOL_CONST"; + case kOpcodeSET_LOOP_CONST: + return "IT_SET_LOOP_CONST"; + case kOpcodeSET_RESOURCE: + return "IT_SET_RESOURCE"; + case kOpcodeSET_SAMPLER: + return "IT_SET_SAMPLER"; + case kOpcodeSET_CTL_CONST: + return "IT_SET_CTL_CONST"; + case kOpcodeSET_CONTEXT_REG_INDIRECT: + return "IT_SET_CONTEXT_REG_INDIRECT"; + case kOpcodeSET_SH_REG: + return "IT_SET_SH_REG"; + case kOpcodeSET_SH_REG_OFFSET: + return "IT_SET_SH_REG_OFFSET"; + case kOpcodeSET_QUEUE_REG: + return "IT_SET_QUEUE_REG"; + case kOpcodeSET_UCONFIG_REG: + return "IT_SET_UCONFIG_REG"; + case kOpcodeSCRATCH_RAM_WRITE: + return "IT_SCRATCH_RAM_WRITE"; + case kOpcodeSCRATCH_RAM_READ: + return "IT_SCRATCH_RAM_READ"; + case kOpcodeLOAD_CONST_RAM: + return "IT_LOAD_CONST_RAM"; + case kOpcodeWRITE_CONST_RAM: + return "IT_WRITE_CONST_RAM"; + case kOpcodeDUMP_CONST_RAM: + return "IT_DUMP_CONST_RAM"; + case kOpcodeINCREMENT_CE_COUNTER: + return "IT_INCREMENT_CE_COUNTER"; + case kOpcodeINCREMENT_DE_COUNTER: + return "IT_INCREMENT_DE_COUNTER"; + case kOpcodeWAIT_ON_CE_COUNTER: + return "IT_WAIT_ON_CE_COUNTER"; + case kOpcodeWAIT_ON_DE_COUNTER_DIFF: + return "IT_WAIT_ON_DE_COUNTER_DIFF"; + case kOpcodeSWITCH_BUFFER: + return "IT_SWITCH_BUFFER"; + } + + return ""; + } + + inline void dumpShader(const std::uint32_t* data) + { + flockfile(stdout); + while (true) + { + auto instHex = *data; + bool isEnd = instHex == 0xBF810000 || instHex == 0xBE802000; + + shader::Instruction inst(data); + + for (int i = 0; i < inst.size(); ++i) + { + std::printf("%08X ", data[i]); + } + + inst.dump(); + printf("\n"); + data += inst.size(); + + if (isEnd) + { + break; + } + } + funlockfile(stdout); + } + + enum BlendMultiplier + { + kBlendMultiplierZero = 0x00000000, + kBlendMultiplierOne = 0x00000001, + kBlendMultiplierSrcColor = 0x00000002, + kBlendMultiplierOneMinusSrcColor = 0x00000003, + kBlendMultiplierSrcAlpha = 0x00000004, + kBlendMultiplierOneMinusSrcAlpha = 0x00000005, + kBlendMultiplierDestAlpha = 0x00000006, + kBlendMultiplierOneMinusDestAlpha = 0x00000007, + kBlendMultiplierDestColor = 0x00000008, + kBlendMultiplierOneMinusDestColor = 0x00000009, + kBlendMultiplierSrcAlphaSaturate = 0x0000000a, + kBlendMultiplierConstantColor = 0x0000000d, + kBlendMultiplierOneMinusConstantColor = 0x0000000e, + kBlendMultiplierSrc1Color = 0x0000000f, + kBlendMultiplierInverseSrc1Color = 0x00000010, + kBlendMultiplierSrc1Alpha = 0x00000011, + kBlendMultiplierInverseSrc1Alpha = 0x00000012, + kBlendMultiplierConstantAlpha = 0x00000013, + kBlendMultiplierOneMinusConstantAlpha = 0x00000014, + }; + + enum BlendFunc + { + kBlendFuncAdd = 0x00000000, + kBlendFuncSubtract = 0x00000001, + kBlendFuncMin = 0x00000002, + kBlendFuncMax = 0x00000003, + kBlendFuncReverseSubtract = 0x00000004, + }; + + enum PrimitiveType : unsigned + { + kPrimitiveTypeNone = 0x00000000, + kPrimitiveTypePointList = 0x00000001, + kPrimitiveTypeLineList = 0x00000002, + kPrimitiveTypeLineStrip = 0x00000003, + kPrimitiveTypeTriList = 0x00000004, + kPrimitiveTypeTriFan = 0x00000005, + kPrimitiveTypeTriStrip = 0x00000006, + kPrimitiveTypePatch = 0x00000009, + kPrimitiveTypeLineListAdjacency = 0x0000000a, + kPrimitiveTypeLineStripAdjacency = 0x0000000b, + kPrimitiveTypeTriListAdjacency = 0x0000000c, + kPrimitiveTypeTriStripAdjacency = 0x0000000d, + kPrimitiveTypeRectList = 0x00000011, + kPrimitiveTypeLineLoop = 0x00000012, + kPrimitiveTypeQuadList = 0x00000013, + kPrimitiveTypeQuadStrip = 0x00000014, + kPrimitiveTypePolygon = 0x00000015 + }; + + enum SurfaceFormat : unsigned + { + kSurfaceFormatInvalid = 0x00000000, + kSurfaceFormat8 = 0x00000001, + kSurfaceFormat16 = 0x00000002, + kSurfaceFormat8_8 = 0x00000003, + kSurfaceFormat32 = 0x00000004, + kSurfaceFormat16_16 = 0x00000005, + kSurfaceFormat10_11_11 = 0x00000006, + kSurfaceFormat11_11_10 = 0x00000007, + kSurfaceFormat10_10_10_2 = 0x00000008, + kSurfaceFormat2_10_10_10 = 0x00000009, + kSurfaceFormat8_8_8_8 = 0x0000000a, + kSurfaceFormat32_32 = 0x0000000b, + kSurfaceFormat16_16_16_16 = 0x0000000c, + kSurfaceFormat32_32_32 = 0x0000000d, + kSurfaceFormat32_32_32_32 = 0x0000000e, + kSurfaceFormat5_6_5 = 0x00000010, + kSurfaceFormat1_5_5_5 = 0x00000011, + kSurfaceFormat5_5_5_1 = 0x00000012, + kSurfaceFormat4_4_4_4 = 0x00000013, + kSurfaceFormat8_24 = 0x00000014, + kSurfaceFormat24_8 = 0x00000015, + kSurfaceFormatX24_8_32 = 0x00000016, + kSurfaceFormatGB_GR = 0x00000020, + kSurfaceFormatBG_RG = 0x00000021, + kSurfaceFormat5_9_9_9 = 0x00000022, + kSurfaceFormatBc1 = 0x00000023, + kSurfaceFormatBc2 = 0x00000024, + kSurfaceFormatBc3 = 0x00000025, + kSurfaceFormatBc4 = 0x00000026, + kSurfaceFormatBc5 = 0x00000027, + kSurfaceFormatBc6 = 0x00000028, + kSurfaceFormatBc7 = 0x00000029, + kSurfaceFormatFmask8_S2_F1 = 0x0000002C, + kSurfaceFormatFmask8_S4_F1 = 0x0000002D, + kSurfaceFormatFmask8_S8_F1 = 0x0000002E, + kSurfaceFormatFmask8_S2_F2 = 0x0000002F, + kSurfaceFormatFmask8_S4_F2 = 0x00000030, + kSurfaceFormatFmask8_S4_F4 = 0x00000031, + kSurfaceFormatFmask16_S16_F1 = 0x00000032, + kSurfaceFormatFmask16_S8_F2 = 0x00000033, + kSurfaceFormatFmask32_S16_F2 = 0x00000034, + kSurfaceFormatFmask32_S8_F4 = 0x00000035, + kSurfaceFormatFmask32_S8_F8 = 0x00000036, + kSurfaceFormatFmask64_S16_F4 = 0x00000037, + kSurfaceFormatFmask64_S16_F8 = 0x00000038, + kSurfaceFormat4_4 = 0x00000039, + kSurfaceFormat6_5_5 = 0x0000003A, + kSurfaceFormat1 = 0x0000003B, + kSurfaceFormat1Reversed = 0x0000003C, + }; + + enum TextureChannelType : unsigned + { + kTextureChannelTypeUNorm = 0x00000000, + kTextureChannelTypeSNorm = 0x00000001, + kTextureChannelTypeUScaled = 0x00000002, + kTextureChannelTypeSScaled = 0x00000003, + kTextureChannelTypeUInt = 0x00000004, + kTextureChannelTypeSInt = 0x00000005, + kTextureChannelTypeSNormNoZero = 0x00000006, + kTextureChannelTypeFloat = 0x00000007, + kTextureChannelTypeSrgb = 0x00000009, + kTextureChannelTypeUBNorm = 0x0000000A, + kTextureChannelTypeUBNormNoZero = 0x0000000B, + kTextureChannelTypeUBInt = 0x0000000C, + kTextureChannelTypeUBScaled = 0x0000000D, + }; + + struct GnmVBuffer + { + uint64_t base : 44; + uint64_t mtype_L1s : 2; + uint64_t mtype_L2 : 2; + uint64_t stride : 14; + uint64_t cache_swizzle : 1; + uint64_t swizzle_en : 1; + + uint32_t num_records; + + uint32_t dst_sel_x : 3; + uint32_t dst_sel_y : 3; + uint32_t dst_sel_z : 3; + uint32_t dst_sel_w : 3; + + uint32_t nfmt : 3; + uint32_t dfmt : 4; + uint32_t element_size : 2; + uint32_t index_stride : 2; + uint32_t addtid_en : 1; + uint32_t reserved0 : 1; + uint32_t hash_en : 1; + uint32_t reserved1 : 1; + uint32_t mtype : 3; + uint32_t type : 2; + + std::uint64_t getAddress() const { return base; } + + uint32_t getStride() const { return stride; } + + uint32_t getSize() const + { + uint32_t stride = getStride(); + uint32_t numElements = getNumRecords(); + return stride ? numElements * stride : numElements; + } + + uint32_t getNumRecords() const { return num_records; } + uint32_t getElementSize() const { return element_size; } + uint32_t getIndexStrideSize() const { return index_stride; } + SurfaceFormat getSurfaceFormat() const { return (SurfaceFormat)dfmt; } + TextureChannelType getChannelType() const { return (TextureChannelType)nfmt; } + }; + + static_assert(sizeof(GnmVBuffer) == sizeof(std::uint64_t) * 2); + + enum class TextureType : uint64_t + { + Dim1D = 8, + Dim2D, + Dim3D, + Cube, + Array1D, + Array2D, + Msaa2D, + MsaaArray2D, + }; + + struct GnmTBuffer + { + uint64_t baseaddr256 : 38; + uint64_t mtype_L2 : 2; + uint64_t min_lod : 12; + SurfaceFormat dfmt : 6; + TextureChannelType nfmt : 4; + uint64_t mtype01 : 2; + + uint64_t width : 14; + uint64_t height : 14; + uint64_t perfMod : 3; + uint64_t interlaced : 1; + uint64_t dst_sel_x : 3; + uint64_t dst_sel_y : 3; + uint64_t dst_sel_z : 3; + uint64_t dst_sel_w : 3; + uint64_t base_level : 4; + uint64_t last_level : 4; + uint64_t tiling_idx : 5; + uint64_t pow2pad : 1; + uint64_t mtype2 : 1; + uint64_t : 1; // reserved + TextureType type : 4; + + uint64_t depth : 13; + uint64_t pitch : 14; + uint64_t : 5; // reserved + uint64_t base_array : 13; + uint64_t last_array : 13; + uint64_t : 6; // reserved + + uint64_t min_lod_warn : 12; // fixed point 4.8 + uint64_t counter_bank_id : 8; + uint64_t LOD_hdw_cnt_en : 1; + uint64_t : 42; // reserved + + std::uint64_t getAddress() const + { + return static_cast(static_cast(baseaddr256)) + << 8; + } + }; + + static_assert(sizeof(GnmTBuffer) == sizeof(std::uint64_t) * 4); + + constexpr auto kPageSize = 0x4000; + + void setVkDevice(VkDevice device, + VkPhysicalDeviceMemoryProperties memProperties, + VkPhysicalDeviceProperties devProperties); + + struct AmdgpuDevice + { + void handleProtectMemory(std::uint64_t address, std::uint64_t size, + std::uint32_t prot); + void handleCommandBuffer(std::uint64_t queueId, std::uint64_t address, + std::uint64_t size); + bool handleFlip(VkQueue queue, VkCommandBuffer cmdBuffer, + TaskChain& initTaskChain, std::uint32_t bufferIndex, + std::uint64_t arg, VkImage targetImage, + VkExtent2D targetExtent, VkSemaphore waitSemaphore, + VkSemaphore signalSemaphore, VkFence fence); + + AmdgpuDevice(amdgpu::bridge::BridgeHeader* bridge); + + ~AmdgpuDevice(); + }; } // namespace amdgpu::device diff --git a/hw/amdgpu/device/include/amdgpu/device/gpu-scheduler.hpp b/hw/amdgpu/device/include/amdgpu/device/gpu-scheduler.hpp index a080369e..eb873c77 100644 --- a/hw/amdgpu/device/include/amdgpu/device/gpu-scheduler.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/gpu-scheduler.hpp @@ -11,375 +11,436 @@ #include #include -namespace amdgpu::device { -enum class ProcessQueue { - Graphics = 1 << 1, - Compute = 1 << 2, - Transfer = 1 << 3, - Any = Graphics | Compute | Transfer -}; - -inline ProcessQueue operator|(ProcessQueue lhs, ProcessQueue rhs) { - return static_cast(std::to_underlying(lhs) | - std::to_underlying(rhs)); -} - -inline ProcessQueue operator&(ProcessQueue lhs, ProcessQueue rhs) { - return static_cast(std::to_underlying(lhs) & - std::to_underlying(rhs)); -} - -struct TaskChain; -class GpuScheduler; - -Scheduler &getCpuScheduler(); -GpuScheduler &getGpuScheduler(ProcessQueue queue); - -struct GpuTaskLayout { - static constexpr auto kInvalidId = 0; //~static_cast(0); - - Ref chain; - std::uint64_t id; - std::uint64_t waitId = kInvalidId; - VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - - std::function invoke; - std::function submit; -}; - -struct TaskChain { - vk::Semaphore semaphore; - std::uint64_t nextTaskId = 1; - std::atomic refs{0}; - std::vector taskLocations; - - void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } - void decRef() { - if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) { - delete this; - } - } - - static Ref Create() { - auto result = new TaskChain(); - result->semaphore = vk::Semaphore::Create(); - return result; - } - - std::uint64_t add(ProcessQueue queue, std::uint64_t waitId, - std::function invoke); - - std::uint64_t add(ProcessQueue queue, - std::function invoke) { - return add(queue, GpuTaskLayout::kInvalidId, std::move(invoke)); - } - - template - requires requires(T &&t) { - { t() } -> std::same_as; - } - std::uint64_t add(std::uint64_t waitId, T &&task) { - auto prevTaskId = getLastTaskId(); - auto id = nextTaskId++; - enum class State { - WaitTask, - PrevTask, - }; - auto cpuTask = createCpuTask([=, task = std::forward(task), - self = Ref(this), state = State::WaitTask]( - const AsyncTaskCtl &) mutable { - if (state == State::WaitTask) { - if (waitId != GpuTaskLayout::kInvalidId) { - if (self->semaphore.getCounterValue() < waitId) { - return TaskResult::Reschedule; - } - } - - auto result = task(); - - if (result != TaskResult::Complete) { - return result; - } - state = State::PrevTask; - } - - if (state == State::PrevTask) { - if (prevTaskId != GpuTaskLayout::kInvalidId && waitId != prevTaskId) { - if (self->semaphore.getCounterValue() < prevTaskId) { - return TaskResult::Reschedule; - } - } - - self->semaphore.signal(id); - } - - return TaskResult::Complete; - }); - getCpuScheduler().enqueue(std::move(cpuTask)); - return id; - } - - template - requires requires(T &&t) { - { t() } -> std::same_as; - } - std::uint64_t add(std::uint64_t waitId, T &&task) { - auto prevTaskId = getLastTaskId(); - auto id = nextTaskId++; - enum class State { - WaitTask, - PrevTask, - }; - auto cpuTask = createCpuTask([=, task = std::forward(task), - self = Ref(this), state = State::WaitTask]( - const AsyncTaskCtl &) mutable { - if (state == State::WaitTask) { - if (waitId != GpuTaskLayout::kInvalidId) { - if (self->semaphore.getCounterValue() < waitId) { - return TaskResult::Reschedule; - } - } - - task(); - state = State::PrevTask; - } - - if (state == State::PrevTask) { - if (prevTaskId != GpuTaskLayout::kInvalidId && waitId != prevTaskId) { - if (self->semaphore.getCounterValue() < prevTaskId) { - return TaskResult::Reschedule; - } - } - - self->semaphore.signal(id); - } - return TaskResult::Complete; - }); - getCpuScheduler().enqueue(std::move(cpuTask)); - return id; - } - - template - requires requires(T &&t) { - { t() } -> std::same_as; - } - std::uint64_t add(T &&task) { - return add(GpuTaskLayout::kInvalidId, std::forward(task)); - } - - template - requires requires(T &&t) { - { t() } -> std::same_as; - } - std::uint64_t add(T &&task) { - return add(GpuTaskLayout::kInvalidId, std::forward(task)); - } - - std::uint64_t getLastTaskId() const { return nextTaskId - 1; } - - std::uint64_t createExternalTask() { return nextTaskId++; } - void notifyExternalTaskComplete(std::uint64_t id) { semaphore.signal(id); } - - bool isComplete() const { return isComplete(getLastTaskId()); } - - bool isComplete(std::uint64_t task) const { - return semaphore.getCounterValue() >= task; - } - - bool empty() const { return getLastTaskId() == GpuTaskLayout::kInvalidId; } - - void wait(std::uint64_t task = GpuTaskLayout::kInvalidId) const { - if (empty()) { - return; - } - - if (task == GpuTaskLayout::kInvalidId) { - task = getLastTaskId(); - } - - Verify() << semaphore.wait(task, UINT64_MAX); - } -}; - -class GpuScheduler { - std::list workThreads; - std::vector tasks; - std::vector delayedTasks; - std::mutex taskMtx; - std::condition_variable taskCv; - std::atomic exit{false}; - std::string debugName; - -public: - explicit GpuScheduler(std::span> queues, - std::string debugName) - : debugName(debugName) { - for (std::size_t index = 0; auto [queue, queueFamilyIndex] : queues) { - workThreads.push_back(std::thread{[=, this] { - setThreadName( - ("GPU " + std::to_string(index) + " " + debugName).c_str()); - entry(queue, queueFamilyIndex); - }}); - - ++index; - } - } - - ~GpuScheduler() { - exit = true; - taskCv.notify_all(); - - for (auto &thread : workThreads) { - thread.join(); - } - } - - void enqueue(GpuTaskLayout &&task) { - std::lock_guard lock(taskMtx); - tasks.push_back(std::move(task)); - taskCv.notify_one(); - } - -private: - void submitTask(VkCommandPool pool, VkQueue queue, GpuTaskLayout &task) { - VkCommandBuffer cmdBuffer; - { - VkCommandBufferAllocateInfo allocateInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - Verify() << vkAllocateCommandBuffers(vk::g_vkDevice, &allocateInfo, - &cmdBuffer); - - VkCommandBufferBeginInfo beginInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, - }; - - vkBeginCommandBuffer(cmdBuffer, &beginInfo); - } - - task.invoke(cmdBuffer); - - vkEndCommandBuffer(cmdBuffer); - - if (task.submit) { - task.submit(queue, cmdBuffer); - return; - } - - VkSemaphoreSubmitInfo signalSemSubmitInfo = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = task.chain->semaphore.getHandle(), - .value = task.id, - .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, - }; - - VkSemaphoreSubmitInfo waitSemSubmitInfo = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = task.chain->semaphore.getHandle(), - .value = task.waitId, - .stageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, - }; - - VkCommandBufferSubmitInfo cmdBufferSubmitInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = cmdBuffer, - }; - - VkSubmitInfo2 submitInfo{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .waitSemaphoreInfoCount = - static_cast(task.waitId ? 1 : 0), - .pWaitSemaphoreInfos = &waitSemSubmitInfo, - .commandBufferInfoCount = 1, - .pCommandBufferInfos = &cmdBufferSubmitInfo, - .signalSemaphoreInfoCount = 1, - .pSignalSemaphoreInfos = &signalSemSubmitInfo, - }; - - Verify() << vkQueueSubmit2(queue, 1, &submitInfo, VK_NULL_HANDLE); - - // if (task.signalChain->semaphore.wait( - // task.id, std::chrono::duration_cast( - // std::chrono::seconds(10)) - // .count())) { - // util::unreachable("gpu operation takes too long time. wait id = %lu\n", - // task.waitId); - // } - } - - void entry(VkQueue queue, std::uint32_t queueFamilyIndex) { - VkCommandPool pool; - { - VkCommandPoolCreateInfo poolCreateInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .queueFamilyIndex = queueFamilyIndex}; - - Verify() << vkCreateCommandPool(vk::g_vkDevice, &poolCreateInfo, - vk::g_vkAllocator, &pool); - } - - while (!exit.load(std::memory_order::relaxed)) { - GpuTaskLayout task; - - { - std::unique_lock lock(taskMtx); - - while (tasks.empty()) { - if (tasks.empty() && delayedTasks.empty()) { - taskCv.wait(lock); - } - - if (tasks.empty()) { - std::swap(delayedTasks, tasks); - } - } - - task = std::move(tasks.back()); - tasks.pop_back(); - } - - if (task.waitId != GpuTaskLayout::kInvalidId && - !task.chain->isComplete(task.waitId)) { - std::unique_lock lock(taskMtx); - delayedTasks.push_back(std::move(task)); - taskCv.notify_one(); - continue; - } - - submitTask(pool, queue, task); - } - - vkDestroyCommandPool(vk::g_vkDevice, pool, vk::g_vkAllocator); - } -}; - -inline std::uint64_t -TaskChain::add(ProcessQueue queue, std::uint64_t waitId, - std::function invoke) { - VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - if (waitId == GpuTaskLayout::kInvalidId) { - waitId = getLastTaskId(); - waitStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - auto id = nextTaskId++; - - getGpuScheduler(queue).enqueue({ - .chain = Ref(this), - .id = id, - .waitId = waitId, - .waitStage = waitStage, - .invoke = std::move(invoke), - }); - - return id; -} - -GpuScheduler &getTransferQueueScheduler(); -GpuScheduler &getComputeQueueScheduler(); -GpuScheduler &getGraphicsQueueScheduler(); +namespace amdgpu::device +{ + enum class ProcessQueue + { + Graphics = 1 << 1, + Compute = 1 << 2, + Transfer = 1 << 3, + Any = Graphics | Compute | Transfer + }; + + inline ProcessQueue operator|(ProcessQueue lhs, ProcessQueue rhs) + { + return static_cast(std::to_underlying(lhs) | + std::to_underlying(rhs)); + } + + inline ProcessQueue operator&(ProcessQueue lhs, ProcessQueue rhs) + { + return static_cast(std::to_underlying(lhs) & + std::to_underlying(rhs)); + } + + struct TaskChain; + class GpuScheduler; + + Scheduler& getCpuScheduler(); + GpuScheduler& getGpuScheduler(ProcessQueue queue); + + struct GpuTaskLayout + { + static constexpr auto kInvalidId = 0; //~static_cast(0); + + Ref chain; + std::uint64_t id; + std::uint64_t waitId = kInvalidId; + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + std::function invoke; + std::function submit; + }; + + struct TaskChain + { + vk::Semaphore semaphore; + std::uint64_t nextTaskId = 1; + std::atomic refs{0}; + std::vector taskLocations; + + void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } + void decRef() + { + if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) + { + delete this; + } + } + + static Ref Create() + { + auto result = new TaskChain(); + result->semaphore = vk::Semaphore::Create(); + return result; + } + + std::uint64_t add(ProcessQueue queue, std::uint64_t waitId, + std::function invoke); + + std::uint64_t add(ProcessQueue queue, + std::function invoke) + { + return add(queue, GpuTaskLayout::kInvalidId, std::move(invoke)); + } + + template + requires requires(T&& t) + { + { + t() + } -> std::same_as; + } + std::uint64_t add(std::uint64_t waitId, T&& task) + { + auto prevTaskId = getLastTaskId(); + auto id = nextTaskId++; + enum class State + { + WaitTask, + PrevTask, + }; + auto cpuTask = createCpuTask([=, task = std::forward(task), + self = Ref(this), state = State::WaitTask]( + const AsyncTaskCtl&) mutable { + if (state == State::WaitTask) + { + if (waitId != GpuTaskLayout::kInvalidId) + { + if (self->semaphore.getCounterValue() < waitId) + { + return TaskResult::Reschedule; + } + } + + auto result = task(); + + if (result != TaskResult::Complete) + { + return result; + } + state = State::PrevTask; + } + + if (state == State::PrevTask) + { + if (prevTaskId != GpuTaskLayout::kInvalidId && waitId != prevTaskId) + { + if (self->semaphore.getCounterValue() < prevTaskId) + { + return TaskResult::Reschedule; + } + } + + self->semaphore.signal(id); + } + + return TaskResult::Complete; + }); + getCpuScheduler().enqueue(std::move(cpuTask)); + return id; + } + + template + requires requires(T&& t) + { + { + t() + } -> std::same_as; + } + std::uint64_t add(std::uint64_t waitId, T&& task) + { + auto prevTaskId = getLastTaskId(); + auto id = nextTaskId++; + enum class State + { + WaitTask, + PrevTask, + }; + auto cpuTask = createCpuTask([=, task = std::forward(task), + self = Ref(this), state = State::WaitTask]( + const AsyncTaskCtl&) mutable { + if (state == State::WaitTask) + { + if (waitId != GpuTaskLayout::kInvalidId) + { + if (self->semaphore.getCounterValue() < waitId) + { + return TaskResult::Reschedule; + } + } + + task(); + state = State::PrevTask; + } + + if (state == State::PrevTask) + { + if (prevTaskId != GpuTaskLayout::kInvalidId && waitId != prevTaskId) + { + if (self->semaphore.getCounterValue() < prevTaskId) + { + return TaskResult::Reschedule; + } + } + + self->semaphore.signal(id); + } + return TaskResult::Complete; + }); + getCpuScheduler().enqueue(std::move(cpuTask)); + return id; + } + + template + requires requires(T&& t) + { + { + t() + } -> std::same_as; + } + std::uint64_t add(T&& task) + { + return add(GpuTaskLayout::kInvalidId, std::forward(task)); + } + + template + requires requires(T&& t) + { + { + t() + } -> std::same_as; + } + std::uint64_t add(T&& task) + { + return add(GpuTaskLayout::kInvalidId, std::forward(task)); + } + + std::uint64_t getLastTaskId() const { return nextTaskId - 1; } + + std::uint64_t createExternalTask() { return nextTaskId++; } + void notifyExternalTaskComplete(std::uint64_t id) { semaphore.signal(id); } + + bool isComplete() const { return isComplete(getLastTaskId()); } + + bool isComplete(std::uint64_t task) const + { + return semaphore.getCounterValue() >= task; + } + + bool empty() const { return getLastTaskId() == GpuTaskLayout::kInvalidId; } + + void wait(std::uint64_t task = GpuTaskLayout::kInvalidId) const + { + if (empty()) + { + return; + } + + if (task == GpuTaskLayout::kInvalidId) + { + task = getLastTaskId(); + } + + Verify() << semaphore.wait(task, UINT64_MAX); + } + }; + + class GpuScheduler + { + std::list workThreads; + std::vector tasks; + std::vector delayedTasks; + std::mutex taskMtx; + std::condition_variable taskCv; + std::atomic exit{false}; + std::string debugName; + + public: + explicit GpuScheduler(std::span> queues, + std::string debugName) + : debugName(debugName) + { + for (std::size_t index = 0; auto [queue, queueFamilyIndex] : queues) + { + workThreads.push_back(std::thread{[=, this] { + setThreadName( + ("GPU " + std::to_string(index) + " " + debugName).c_str()); + entry(queue, queueFamilyIndex); + }}); + + ++index; + } + } + + ~GpuScheduler() + { + exit = true; + taskCv.notify_all(); + + for (auto& thread : workThreads) + { + thread.join(); + } + } + + void enqueue(GpuTaskLayout&& task) + { + std::lock_guard lock(taskMtx); + tasks.push_back(std::move(task)); + taskCv.notify_one(); + } + + private: + void submitTask(VkCommandPool pool, VkQueue queue, GpuTaskLayout& task) + { + VkCommandBuffer cmdBuffer; + { + VkCommandBufferAllocateInfo allocateInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + Verify() << vkAllocateCommandBuffers(vk::g_vkDevice, &allocateInfo, + &cmdBuffer); + + VkCommandBufferBeginInfo beginInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + + vkBeginCommandBuffer(cmdBuffer, &beginInfo); + } + + task.invoke(cmdBuffer); + + vkEndCommandBuffer(cmdBuffer); + + if (task.submit) + { + task.submit(queue, cmdBuffer); + return; + } + + VkSemaphoreSubmitInfo signalSemSubmitInfo = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = task.chain->semaphore.getHandle(), + .value = task.id, + .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, + }; + + VkSemaphoreSubmitInfo waitSemSubmitInfo = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = task.chain->semaphore.getHandle(), + .value = task.waitId, + .stageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, + }; + + VkCommandBufferSubmitInfo cmdBufferSubmitInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .commandBuffer = cmdBuffer, + }; + + VkSubmitInfo2 submitInfo{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .waitSemaphoreInfoCount = + static_cast(task.waitId ? 1 : 0), + .pWaitSemaphoreInfos = &waitSemSubmitInfo, + .commandBufferInfoCount = 1, + .pCommandBufferInfos = &cmdBufferSubmitInfo, + .signalSemaphoreInfoCount = 1, + .pSignalSemaphoreInfos = &signalSemSubmitInfo, + }; + + Verify() << vkQueueSubmit2(queue, 1, &submitInfo, VK_NULL_HANDLE); + + // if (task.signalChain->semaphore.wait( + // task.id, std::chrono::duration_cast( + // std::chrono::seconds(10)) + // .count())) { + // util::unreachable("gpu operation takes too long time. wait id = %lu\n", + // task.waitId); + // } + } + + void entry(VkQueue queue, std::uint32_t queueFamilyIndex) + { + VkCommandPool pool; + { + VkCommandPoolCreateInfo poolCreateInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .queueFamilyIndex = queueFamilyIndex}; + + Verify() << vkCreateCommandPool(vk::g_vkDevice, &poolCreateInfo, + vk::g_vkAllocator, &pool); + } + + while (!exit.load(std::memory_order::relaxed)) + { + GpuTaskLayout task; + + { + std::unique_lock lock(taskMtx); + + while (tasks.empty()) + { + if (tasks.empty() && delayedTasks.empty()) + { + taskCv.wait(lock); + } + + if (tasks.empty()) + { + std::swap(delayedTasks, tasks); + } + } + + task = std::move(tasks.back()); + tasks.pop_back(); + } + + if (task.waitId != GpuTaskLayout::kInvalidId && + !task.chain->isComplete(task.waitId)) + { + std::unique_lock lock(taskMtx); + delayedTasks.push_back(std::move(task)); + taskCv.notify_one(); + continue; + } + + submitTask(pool, queue, task); + } + + vkDestroyCommandPool(vk::g_vkDevice, pool, vk::g_vkAllocator); + } + }; + + inline std::uint64_t + TaskChain::add(ProcessQueue queue, std::uint64_t waitId, + std::function invoke) + { + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + if (waitId == GpuTaskLayout::kInvalidId) + { + waitId = getLastTaskId(); + waitStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + auto id = nextTaskId++; + + getGpuScheduler(queue).enqueue({ + .chain = Ref(this), + .id = id, + .waitId = waitId, + .waitStage = waitStage, + .invoke = std::move(invoke), + }); + + return id; + } + + GpuScheduler& getTransferQueueScheduler(); + GpuScheduler& getComputeQueueScheduler(); + GpuScheduler& getGraphicsQueueScheduler(); } // namespace amdgpu::device diff --git a/hw/amdgpu/device/include/amdgpu/device/pm4.hpp b/hw/amdgpu/device/include/amdgpu/device/pm4.hpp index 6d9cf259..79ed8c78 100644 --- a/hw/amdgpu/device/include/amdgpu/device/pm4.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/pm4.hpp @@ -1,101 +1,103 @@ #pragma once -namespace amdgpu { -enum PM4Opcodes { - NOP = 0x10, - SET_BASE = 0x11, - CLEAR_STATE = 0x12, - INDEX_BUFFER_SIZE = 0x13, - DISPATCH_DIRECT = 0x15, - DISPATCH_INDIRECT = 0x16, - INDIRECT_BUFFER_END = 0x17, - MODE_CONTROL = 0x18, - ATOMIC_GDS = 0x1D, - ATOMIC_MEM = 0x1E, - OCCLUSION_QUERY = 0x1F, - SET_PREDICATION = 0x20, - REG_RMW = 0x21, - COND_EXEC = 0x22, - PRED_EXEC = 0x23, - DRAW_INDIRECT = 0x24, - DRAW_INDEX_INDIRECT = 0x25, - INDEX_BASE = 0x26, - DRAW_INDEX_2 = 0x27, - CONTEXT_CONTROL = 0x28, - DRAW_INDEX_OFFSET = 0x29, - INDEX_TYPE = 0x2A, - DRAW_INDEX = 0x2B, - DRAW_INDIRECT_MULTI = 0x2C, - DRAW_INDEX_AUTO = 0x2D, - DRAW_INDEX_IMMD = 0x2E, - NUM_INSTANCES = 0x2F, - DRAW_INDEX_MULTI_AUTO = 0x30, - INDIRECT_BUFFER_32 = 0x32, - INDIRECT_BUFFER_CONST = 0x33, - STRMOUT_BUFFER_UPDATE = 0x34, - DRAW_INDEX_OFFSET_2 = 0x35, - DRAW_PREAMBLE = 0x36, - WRITE_DATA = 0x37, - DRAW_INDEX_INDIRECT_MULTI = 0x38, - MEM_SEMAPHORE = 0x39, - MPEG_INDEX = 0x3A, - COPY_DW = 0x3B, - WAIT_REG_MEM = 0x3C, - MEM_WRITE = 0x3D, - INDIRECT_BUFFER_3F = 0x3F, - COPY_DATA = 0x40, - CP_DMA = 0x41, - PFP_SYNC_ME = 0x42, - SURFACE_SYNC = 0x43, - ME_INITIALIZE = 0x44, - COND_WRITE = 0x45, - EVENT_WRITE = 0x46, - EVENT_WRITE_EOP = 0x47, - EVENT_WRITE_EOS = 0x48, - RELEASE_MEM = 0x49, - PREAMBLE_CNTL = 0x4A, - RB_OFFSET = 0x4B, - ALU_PS_CONST_BUFFER_COPY = 0x4C, - ALU_VS_CONST_BUFFER_COPY = 0x4D, - ALU_PS_CONST_UPDATE = 0x4E, - ALU_VS_CONST_UPDATE = 0x4F, - DMA_DATA = 0x50, - ONE_REG_WRITE = 0x57, - AQUIRE_MEM = 0x58, - REWIND = 0x59, - LOAD_UCONFIG_REG = 0x5E, - LOAD_SH_REG = 0x5F, - LOAD_CONFIG_REG = 0x60, - LOAD_CONTEXT_REG = 0x61, - SET_CONFIG_REG = 0x68, - SET_CONTEXT_REG = 0x69, - SET_ALU_CONST = 0x6A, - SET_BOOL_CONST = 0x6B, - SET_LOOP_CONST = 0x6C, - SET_RESOURCE = 0x6D, - SET_SAMPLER = 0x6E, - SET_CTL_CONST = 0x6F, - SET_RESOURCE_OFFSET = 0x70, - SET_ALU_CONST_VS = 0x71, - SET_ALU_CONST_DI = 0x72, - SET_CONTEXT_REG_INDIRECT = 0x73, - SET_RESOURCE_INDIRECT = 0x74, - SET_APPEND_CNT = 0x75, - SET_SH_REG = 0x76, - SET_SH_REG_OFFSET = 0x77, - SET_QUEUE_REG = 0x78, - SET_UCONFIG_REG = 0x79, - SCRATCH_RAM_WRITE = 0x7D, - SCRATCH_RAM_READ = 0x7E, - LOAD_CONST_RAM = 0x80, - WRITE_CONST_RAM = 0x81, - DUMP_CONST_RAM = 0x83, - INCREMENT_CE_COUNTER = 0x84, - INCREMENT_DE_COUNTER = 0x85, - WAIT_ON_CE_COUNTER = 0x86, - WAIT_ON_DE_COUNTER_DIFF = 0x88, - SWITCH_BUFFER = 0x8B, -}; +namespace amdgpu +{ + enum PM4Opcodes + { + NOP = 0x10, + SET_BASE = 0x11, + CLEAR_STATE = 0x12, + INDEX_BUFFER_SIZE = 0x13, + DISPATCH_DIRECT = 0x15, + DISPATCH_INDIRECT = 0x16, + INDIRECT_BUFFER_END = 0x17, + MODE_CONTROL = 0x18, + ATOMIC_GDS = 0x1D, + ATOMIC_MEM = 0x1E, + OCCLUSION_QUERY = 0x1F, + SET_PREDICATION = 0x20, + REG_RMW = 0x21, + COND_EXEC = 0x22, + PRED_EXEC = 0x23, + DRAW_INDIRECT = 0x24, + DRAW_INDEX_INDIRECT = 0x25, + INDEX_BASE = 0x26, + DRAW_INDEX_2 = 0x27, + CONTEXT_CONTROL = 0x28, + DRAW_INDEX_OFFSET = 0x29, + INDEX_TYPE = 0x2A, + DRAW_INDEX = 0x2B, + DRAW_INDIRECT_MULTI = 0x2C, + DRAW_INDEX_AUTO = 0x2D, + DRAW_INDEX_IMMD = 0x2E, + NUM_INSTANCES = 0x2F, + DRAW_INDEX_MULTI_AUTO = 0x30, + INDIRECT_BUFFER_32 = 0x32, + INDIRECT_BUFFER_CONST = 0x33, + STRMOUT_BUFFER_UPDATE = 0x34, + DRAW_INDEX_OFFSET_2 = 0x35, + DRAW_PREAMBLE = 0x36, + WRITE_DATA = 0x37, + DRAW_INDEX_INDIRECT_MULTI = 0x38, + MEM_SEMAPHORE = 0x39, + MPEG_INDEX = 0x3A, + COPY_DW = 0x3B, + WAIT_REG_MEM = 0x3C, + MEM_WRITE = 0x3D, + INDIRECT_BUFFER_3F = 0x3F, + COPY_DATA = 0x40, + CP_DMA = 0x41, + PFP_SYNC_ME = 0x42, + SURFACE_SYNC = 0x43, + ME_INITIALIZE = 0x44, + COND_WRITE = 0x45, + EVENT_WRITE = 0x46, + EVENT_WRITE_EOP = 0x47, + EVENT_WRITE_EOS = 0x48, + RELEASE_MEM = 0x49, + PREAMBLE_CNTL = 0x4A, + RB_OFFSET = 0x4B, + ALU_PS_CONST_BUFFER_COPY = 0x4C, + ALU_VS_CONST_BUFFER_COPY = 0x4D, + ALU_PS_CONST_UPDATE = 0x4E, + ALU_VS_CONST_UPDATE = 0x4F, + DMA_DATA = 0x50, + ONE_REG_WRITE = 0x57, + AQUIRE_MEM = 0x58, + REWIND = 0x59, + LOAD_UCONFIG_REG = 0x5E, + LOAD_SH_REG = 0x5F, + LOAD_CONFIG_REG = 0x60, + LOAD_CONTEXT_REG = 0x61, + SET_CONFIG_REG = 0x68, + SET_CONTEXT_REG = 0x69, + SET_ALU_CONST = 0x6A, + SET_BOOL_CONST = 0x6B, + SET_LOOP_CONST = 0x6C, + SET_RESOURCE = 0x6D, + SET_SAMPLER = 0x6E, + SET_CTL_CONST = 0x6F, + SET_RESOURCE_OFFSET = 0x70, + SET_ALU_CONST_VS = 0x71, + SET_ALU_CONST_DI = 0x72, + SET_CONTEXT_REG_INDIRECT = 0x73, + SET_RESOURCE_INDIRECT = 0x74, + SET_APPEND_CNT = 0x75, + SET_SH_REG = 0x76, + SET_SH_REG_OFFSET = 0x77, + SET_QUEUE_REG = 0x78, + SET_UCONFIG_REG = 0x79, + SCRATCH_RAM_WRITE = 0x7D, + SCRATCH_RAM_READ = 0x7E, + LOAD_CONST_RAM = 0x80, + WRITE_CONST_RAM = 0x81, + DUMP_CONST_RAM = 0x83, + INCREMENT_CE_COUNTER = 0x84, + INCREMENT_DE_COUNTER = 0x85, + WAIT_ON_CE_COUNTER = 0x86, + WAIT_ON_DE_COUNTER_DIFF = 0x88, + SWITCH_BUFFER = 0x8B, + }; -const char *pm4OpcodeToString(int opcode); + const char* pm4OpcodeToString(int opcode); } // namespace amdgpu diff --git a/hw/amdgpu/device/include/amdgpu/device/scheduler.hpp b/hw/amdgpu/device/include/amdgpu/device/scheduler.hpp index 37fc97f7..d025eaed 100644 --- a/hw/amdgpu/device/include/amdgpu/device/scheduler.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/scheduler.hpp @@ -13,442 +13,568 @@ #include #include -namespace amdgpu::device { -inline void setThreadName(const char *name) { - pthread_setname_np(pthread_self(), name); -} - -template class Ref { - T *m_ref = nullptr; - -public: - Ref() = default; - Ref(std::nullptr_t) {} - - template - requires(std::is_base_of_v) - Ref(OT *ref) : m_ref(ref) { - if (m_ref != nullptr) { - ref->incRef(); - } - } - - template - requires(std::is_base_of_v) - Ref(const Ref &other) : m_ref(other.get()) { - if (m_ref != nullptr) { - m_ref->incRef(); - } - } - - template - requires(std::is_base_of_v) - Ref(Ref &&other) : m_ref(other.release()) {} - - Ref(const Ref &other) : m_ref(other.get()) { - if (m_ref != nullptr) { - m_ref->incRef(); - } - } - Ref(Ref &&other) : m_ref(other.release()) {} - - template - requires(std::is_base_of_v) - Ref &operator=(Ref &&other) { - other.swap(*this); - return *this; - } - - template - requires(std::is_base_of_v) - Ref &operator=(OT *other) { - *this = Ref(other); - return *this; - } - - template - requires(std::is_base_of_v) - Ref &operator=(const Ref &other) { - *this = Ref(other); - return *this; - } - - Ref &operator=(const Ref &other) { - *this = Ref(other); - return *this; - } - - Ref &operator=(Ref &&other) { - other.swap(*this); - return *this; - } - - ~Ref() { - if (m_ref != nullptr) { - m_ref->decRef(); - } - } - - void swap(Ref &other) { std::swap(m_ref, other.m_ref); } - T *get() const { return m_ref; } - T *release() { return std::exchange(m_ref, nullptr); } - T *operator->() const { return m_ref; } - explicit operator bool() const { return m_ref != nullptr; } - bool operator==(std::nullptr_t) const { return m_ref == nullptr; } - bool operator==(const Ref &other) const = default; - bool operator==(const T *other) const { return m_ref == other; } - auto operator<=>(const T *other) const { return m_ref <=> other; } - auto operator<=>(const Ref &other) const = default; -}; - -template Ref(T *) -> Ref; -template Ref(Ref) -> Ref; - -enum class TaskState { Created, InProgress, Complete, Canceled }; -enum class TaskResult { Complete, Canceled, Reschedule }; - -struct AsyncTaskCtl { - std::atomic refs{0}; - std::atomic stateStorage{TaskState::Created}; - std::atomic cancelRequested{false}; - - virtual ~AsyncTaskCtl() = default; - - void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } - void decRef() { - if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) { - delete this; - } - } - - bool isCancelRequested() const { - return cancelRequested.load(std::memory_order::relaxed) == true; - } - bool isCanceled() const { return getState() == TaskState::Canceled; } - bool isComplete() const { return getState() == TaskState::Complete; } - bool isInProgress() const { return getState() == TaskState::InProgress; } - - TaskState getState() const { - return stateStorage.load(std::memory_order::relaxed); - } - - void cancel() { cancelRequested.store(true, std::memory_order::relaxed); } - - void wait() { - if (stateStorage.load(std::memory_order::relaxed) == TaskState::Created) { - util::unreachable("attempt to wait task that wasn't scheduled\n"); - } - stateStorage.wait(TaskState::InProgress, std::memory_order::relaxed); - } -}; - -struct CpuTaskCtl : AsyncTaskCtl { - virtual TaskResult invoke() = 0; -}; - -namespace detail { -template -concept LambdaWithoutClosure = requires(T t) { +t; }; -} - -template struct AsyncCpuTask; - -template - requires requires(T t, const AsyncTaskCtl &ctl) { - { t(ctl) } -> std::same_as; - requires detail::LambdaWithoutClosure; - } -struct AsyncCpuTask : CpuTaskCtl { - static constexpr TaskResult (*fn)(const AsyncTaskCtl &) = +std::declval(); - - AsyncCpuTask() = default; - AsyncCpuTask(T &&) {} - - TaskResult invoke() override { - auto &base = *static_cast(this); - - return fn(base); - } -}; - -template - requires requires(T t, const AsyncTaskCtl &ctl) { - { t(ctl) } -> std::same_as; - requires !detail::LambdaWithoutClosure; - } -struct AsyncCpuTask : CpuTaskCtl { - alignas(T) std::byte taskStorage[sizeof(T)]; - - AsyncCpuTask(T &&t) { new (taskStorage) T(std::forward(t)); } - ~AsyncCpuTask() { std::bit_cast(&taskStorage)->~T(); } - - TaskResult invoke() override { - auto &lambda = *std::bit_cast(&taskStorage); - auto &base = *static_cast(this); - return lambda(base); - } -}; - -template - requires requires(T t, const AsyncTaskCtl &ctl) { - { t(ctl) } -> std::same_as; - } -Ref createCpuTask(T &&task) { - return Ref(new AsyncCpuTask(std::forward(task))); -} - -template - requires requires(T t) { - { t() } -> std::same_as; - } -Ref createCpuTask(T &&task) { - return createCpuTask( - [task = std::forward(task)]( - const AsyncTaskCtl &) mutable -> TaskResult { return task(); }); -} - -template - requires requires(T t) { - { t() } -> std::same_as; - } -Ref createCpuTask(T &&task) { - return createCpuTask([task = std::forward(task)]( - const AsyncTaskCtl &ctl) mutable -> TaskResult { - if (ctl.isCancelRequested()) { - return TaskResult::Canceled; - } - - task(); - return TaskResult::Complete; - }); -} - -template - requires requires(T t, const AsyncTaskCtl &ctl) { - { t(ctl) } -> std::same_as; - } -Ref createCpuTask(T &&task) { - return createCpuTask([task = std::forward(task)](const AsyncTaskCtl &ctl) { - if (ctl.isCancelRequested()) { - return TaskResult::Canceled; - } - - task(ctl); - return TaskResult::Complete; - }); -} - -class Scheduler; - -class CpuTaskSet { - std::vector> tasks; - -public: - void append(Ref task) { tasks.push_back(std::move(task)); } - - void wait() { - for (auto task : tasks) { - task->wait(); - } - - tasks.clear(); - } - - void enqueue(Scheduler &scheduler); -}; - -class TaskSet { - struct TaskEntry { - Ref ctl; - std::function schedule; - }; - - std::vector tasks; - -public: - template - requires requires(Scheduler &sched, Ref task) { - sched.enqueue(std::move(task)); - task->wait(); - static_cast>(task); - } - void append(Scheduler &sched, Ref task) { - Ref rawTask = task; - auto schedFn = [sched = &sched, task = std::move(task)] { - sched->enqueue(std::move(task)); - }; - - tasks.push_back({ - .ctl = std::move(rawTask), - .schedule = std::move(schedFn), - }); - } - - void schedule() { - for (auto &task : tasks) { - if (auto schedule = std::exchange(task.schedule, nullptr)) { - schedule(); - } - } - } - - bool isCanceled() const { - for (auto &task : tasks) { - if (task.ctl->isCanceled()) { - return true; - } - } - - return false; - } - - bool isComplete() const { - for (auto &task : tasks) { - if (!task.ctl->isComplete()) { - return false; - } - } - - return true; - } - - bool isInProgress() const { - for (auto &task : tasks) { - if (task.ctl->isInProgress()) { - return true; - } - } - - return false; - } - - void clear() { tasks.clear(); } - - void wait() const { - for (auto &task : tasks) { - assert(task.schedule == nullptr); - task.ctl->wait(); - } - } - - void cancel() { - for (auto &task : tasks) { - task.ctl->cancel(); - } - } -}; - -class Scheduler { - std::vector workThreads; - std::vector> tasks; - std::vector> rescheduleTasks; - std::mutex taskMtx; - std::condition_variable taskCv; - std::atomic exit{false}; - -public: - explicit Scheduler(std::size_t threadCount) { - for (std::size_t i = 0; i < threadCount; ++i) { - workThreads.push_back(std::thread{[this, i] { - setThreadName(("CPU " + std::to_string(i)).c_str()); - entry(); - }}); - } - } - - ~Scheduler() { - exit = true; - taskCv.notify_all(); - - for (auto &thread : workThreads) { - thread.join(); - } - } - - void enqueue(Ref task) { - std::lock_guard lock(taskMtx); - TaskState prevState = TaskState::Created; - if (!task->stateStorage.compare_exchange_strong( - prevState, TaskState::InProgress, std::memory_order::relaxed)) { - util::unreachable("attempt to schedule cpu task in wrong state %u", - (unsigned)prevState); - } - tasks.push_back(std::move(task)); - taskCv.notify_one(); - } - - template - requires requires(T &&task) { createCpuTask(std::forward(task)); } - Ref enqueue(T &&task) { - auto taskHandle = createCpuTask(std::forward(task)); - enqueue(taskHandle); - return taskHandle; - } - - template - requires requires(T &&task) { createCpuTask(std::forward(task)); } - void enqueue(CpuTaskSet &set, T &&task) { - auto taskCtl = enqueue(std::forward(task)); - set.append(taskCtl); - } - -private: - Ref fetchTask() { - std::unique_lock lock(taskMtx); - - while (tasks.empty()) { - if (rescheduleTasks.empty() && tasks.empty()) { - taskCv.wait(lock); - } - - if (tasks.empty()) { - std::swap(rescheduleTasks, tasks); - } - } - - auto result = std::move(tasks.back()); - tasks.pop_back(); - return result; - } - - Ref invokeTask(Ref task) { - switch (task->invoke()) { - case TaskResult::Complete: - task->stateStorage.store(TaskState::Complete, std::memory_order::relaxed); - task->stateStorage.notify_all(); - return {}; - - case TaskResult::Canceled: - task->stateStorage.store(TaskState::Canceled, std::memory_order::relaxed); - task->stateStorage.notify_all(); - return {}; - - case TaskResult::Reschedule: - return task; - } - - std::abort(); - } - - void entry() { - while (!exit.load(std::memory_order::relaxed)) { - Ref task = fetchTask(); - - auto rescheduleTask = invokeTask(std::move(task)); - if (rescheduleTask == nullptr) { - continue; - } - - std::unique_lock lock(taskMtx); - rescheduleTasks.push_back(std::move(rescheduleTask)); - taskCv.notify_one(); - } - } -}; - -inline void CpuTaskSet::enqueue(Scheduler &scheduler) { - for (auto task : tasks) { - scheduler.enqueue(std::move(task)); - } -} +namespace amdgpu::device +{ + inline void setThreadName(const char* name) + { + pthread_setname_np(pthread_self(), name); + } + + template + class Ref + { + T* m_ref = nullptr; + + public: + Ref() = default; + Ref(std::nullptr_t) {} + + template + requires(std::is_base_of_v) + Ref(OT* ref) + : m_ref(ref) + { + if (m_ref != nullptr) + { + ref->incRef(); + } + } + + template + requires(std::is_base_of_v) + Ref(const Ref& other) + : m_ref(other.get()) + { + if (m_ref != nullptr) + { + m_ref->incRef(); + } + } + + template + requires(std::is_base_of_v) + Ref(Ref&& other) + : m_ref(other.release()) + { + } + + Ref(const Ref& other) + : m_ref(other.get()) + { + if (m_ref != nullptr) + { + m_ref->incRef(); + } + } + Ref(Ref&& other) + : m_ref(other.release()) + { + } + + template + requires(std::is_base_of_v) + Ref& + operator=(Ref&& other) + { + other.swap(*this); + return *this; + } + + template + requires(std::is_base_of_v) + Ref& + operator=(OT* other) + { + *this = Ref(other); + return *this; + } + + template + requires(std::is_base_of_v) + Ref& + operator=(const Ref& other) + { + *this = Ref(other); + return *this; + } + + Ref& operator=(const Ref& other) + { + *this = Ref(other); + return *this; + } + + Ref& operator=(Ref&& other) + { + other.swap(*this); + return *this; + } + + ~Ref() + { + if (m_ref != nullptr) + { + m_ref->decRef(); + } + } + + void swap(Ref& other) { std::swap(m_ref, other.m_ref); } + T* get() const { return m_ref; } + T* release() { return std::exchange(m_ref, nullptr); } + T* operator->() const { return m_ref; } + explicit operator bool() const { return m_ref != nullptr; } + bool operator==(std::nullptr_t) const { return m_ref == nullptr; } + bool operator==(const Ref& other) const = default; + bool operator==(const T* other) const { return m_ref == other; } + auto operator<=>(const T* other) const { return m_ref <=> other; } + auto operator<=>(const Ref& other) const = default; + }; + + template + Ref(T*) -> Ref; + template + Ref(Ref) -> Ref; + + enum class TaskState + { + Created, + InProgress, + Complete, + Canceled + }; + enum class TaskResult + { + Complete, + Canceled, + Reschedule + }; + + struct AsyncTaskCtl + { + std::atomic refs{0}; + std::atomic stateStorage{TaskState::Created}; + std::atomic cancelRequested{false}; + + virtual ~AsyncTaskCtl() = default; + + void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } + void decRef() + { + if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) + { + delete this; + } + } + + bool isCancelRequested() const + { + return cancelRequested.load(std::memory_order::relaxed) == true; + } + bool isCanceled() const { return getState() == TaskState::Canceled; } + bool isComplete() const { return getState() == TaskState::Complete; } + bool isInProgress() const { return getState() == TaskState::InProgress; } + + TaskState getState() const + { + return stateStorage.load(std::memory_order::relaxed); + } + + void cancel() { cancelRequested.store(true, std::memory_order::relaxed); } + + void wait() + { + if (stateStorage.load(std::memory_order::relaxed) == TaskState::Created) + { + util::unreachable("attempt to wait task that wasn't scheduled\n"); + } + stateStorage.wait(TaskState::InProgress, std::memory_order::relaxed); + } + }; + + struct CpuTaskCtl : AsyncTaskCtl + { + virtual TaskResult invoke() = 0; + }; + + namespace detail + { + template + concept LambdaWithoutClosure = requires(T t) + { + +t; + }; + } // namespace detail + + template + struct AsyncCpuTask; + + template + requires requires(T t, const AsyncTaskCtl& ctl) + { + { + t(ctl) + } -> std::same_as; + requires detail::LambdaWithoutClosure; + } + struct AsyncCpuTask : CpuTaskCtl + { + static constexpr TaskResult (*fn)(const AsyncTaskCtl&) = +std::declval(); + + AsyncCpuTask() = default; + AsyncCpuTask(T&&) {} + + TaskResult invoke() override + { + auto& base = *static_cast(this); + + return fn(base); + } + }; + + template + requires requires(T t, const AsyncTaskCtl& ctl) + { + { + t(ctl) + } -> std::same_as; + requires !detail::LambdaWithoutClosure; + } + struct AsyncCpuTask : CpuTaskCtl + { + alignas(T) std::byte taskStorage[sizeof(T)]; + + AsyncCpuTask(T&& t) { new (taskStorage) T(std::forward(t)); } + ~AsyncCpuTask() { std::bit_cast(&taskStorage)->~T(); } + + TaskResult invoke() override + { + auto& lambda = *std::bit_cast(&taskStorage); + auto& base = *static_cast(this); + return lambda(base); + } + }; + + template + requires requires(T t, const AsyncTaskCtl& ctl) + { + { + t(ctl) + } -> std::same_as; + } + Ref createCpuTask(T&& task) + { + return Ref(new AsyncCpuTask(std::forward(task))); + } + + template + requires requires(T t) + { + { + t() + } -> std::same_as; + } + Ref createCpuTask(T&& task) + { + return createCpuTask( + [task = std::forward(task)]( + const AsyncTaskCtl&) mutable -> TaskResult { return task(); }); + } + + template + requires requires(T t) + { + { + t() + } -> std::same_as; + } + Ref createCpuTask(T&& task) + { + return createCpuTask([task = std::forward(task)]( + const AsyncTaskCtl& ctl) mutable -> TaskResult { + if (ctl.isCancelRequested()) + { + return TaskResult::Canceled; + } + + task(); + return TaskResult::Complete; + }); + } + + template + requires requires(T t, const AsyncTaskCtl& ctl) + { + { + t(ctl) + } -> std::same_as; + } + Ref createCpuTask(T&& task) + { + return createCpuTask([task = std::forward(task)](const AsyncTaskCtl& ctl) { + if (ctl.isCancelRequested()) + { + return TaskResult::Canceled; + } + + task(ctl); + return TaskResult::Complete; + }); + } + + class Scheduler; + + class CpuTaskSet + { + std::vector> tasks; + + public: + void append(Ref task) { tasks.push_back(std::move(task)); } + + void wait() + { + for (auto task : tasks) + { + task->wait(); + } + + tasks.clear(); + } + + void enqueue(Scheduler& scheduler); + }; + + class TaskSet + { + struct TaskEntry + { + Ref ctl; + std::function schedule; + }; + + std::vector tasks; + + public: + template + requires requires(Scheduler& sched, Ref task) + { + sched.enqueue(std::move(task)); + task->wait(); + static_cast>(task); + } + void append(Scheduler& sched, Ref task) + { + Ref rawTask = task; + auto schedFn = [sched = &sched, task = std::move(task)] { + sched->enqueue(std::move(task)); + }; + + tasks.push_back({ + .ctl = std::move(rawTask), + .schedule = std::move(schedFn), + }); + } + + void schedule() + { + for (auto& task : tasks) + { + if (auto schedule = std::exchange(task.schedule, nullptr)) + { + schedule(); + } + } + } + + bool isCanceled() const + { + for (auto& task : tasks) + { + if (task.ctl->isCanceled()) + { + return true; + } + } + + return false; + } + + bool isComplete() const + { + for (auto& task : tasks) + { + if (!task.ctl->isComplete()) + { + return false; + } + } + + return true; + } + + bool isInProgress() const + { + for (auto& task : tasks) + { + if (task.ctl->isInProgress()) + { + return true; + } + } + + return false; + } + + void clear() { tasks.clear(); } + + void wait() const + { + for (auto& task : tasks) + { + assert(task.schedule == nullptr); + task.ctl->wait(); + } + } + + void cancel() + { + for (auto& task : tasks) + { + task.ctl->cancel(); + } + } + }; + + class Scheduler + { + std::vector workThreads; + std::vector> tasks; + std::vector> rescheduleTasks; + std::mutex taskMtx; + std::condition_variable taskCv; + std::atomic exit{false}; + + public: + explicit Scheduler(std::size_t threadCount) + { + for (std::size_t i = 0; i < threadCount; ++i) + { + workThreads.push_back(std::thread{[this, i] { + setThreadName(("CPU " + std::to_string(i)).c_str()); + entry(); + }}); + } + } + + ~Scheduler() + { + exit = true; + taskCv.notify_all(); + + for (auto& thread : workThreads) + { + thread.join(); + } + } + + void enqueue(Ref task) + { + std::lock_guard lock(taskMtx); + TaskState prevState = TaskState::Created; + if (!task->stateStorage.compare_exchange_strong( + prevState, TaskState::InProgress, std::memory_order::relaxed)) + { + util::unreachable("attempt to schedule cpu task in wrong state %u", + (unsigned)prevState); + } + tasks.push_back(std::move(task)); + taskCv.notify_one(); + } + + template + requires requires(T&& task) { createCpuTask(std::forward(task)); } + Ref enqueue(T&& task) + { + auto taskHandle = createCpuTask(std::forward(task)); + enqueue(taskHandle); + return taskHandle; + } + + template + requires requires(T&& task) { createCpuTask(std::forward(task)); } + void enqueue(CpuTaskSet& set, T&& task) + { + auto taskCtl = enqueue(std::forward(task)); + set.append(taskCtl); + } + + private: + Ref fetchTask() + { + std::unique_lock lock(taskMtx); + + while (tasks.empty()) + { + if (rescheduleTasks.empty() && tasks.empty()) + { + taskCv.wait(lock); + } + + if (tasks.empty()) + { + std::swap(rescheduleTasks, tasks); + } + } + + auto result = std::move(tasks.back()); + tasks.pop_back(); + return result; + } + + Ref invokeTask(Ref task) + { + switch (task->invoke()) + { + case TaskResult::Complete: + task->stateStorage.store(TaskState::Complete, std::memory_order::relaxed); + task->stateStorage.notify_all(); + return {}; + + case TaskResult::Canceled: + task->stateStorage.store(TaskState::Canceled, std::memory_order::relaxed); + task->stateStorage.notify_all(); + return {}; + + case TaskResult::Reschedule: + return task; + } + + std::abort(); + } + + void entry() + { + while (!exit.load(std::memory_order::relaxed)) + { + Ref task = fetchTask(); + + auto rescheduleTask = invokeTask(std::move(task)); + if (rescheduleTask == nullptr) + { + continue; + } + + std::unique_lock lock(taskMtx); + rescheduleTasks.push_back(std::move(rescheduleTask)); + taskCv.notify_one(); + } + } + }; + + inline void CpuTaskSet::enqueue(Scheduler& scheduler) + { + for (auto task : tasks) + { + scheduler.enqueue(std::move(task)); + } + } } // namespace amdgpu::device diff --git a/hw/amdgpu/device/include/amdgpu/device/tiler.hpp b/hw/amdgpu/device/include/amdgpu/device/tiler.hpp index 5afcdd88..4cdbe814 100644 --- a/hw/amdgpu/device/include/amdgpu/device/tiler.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/tiler.hpp @@ -5,568 +5,591 @@ #include #include -namespace amdgpu::device { -enum TileMode { - kTileModeDepth_2dThin_64, - kTileModeDepth_2dThin_128, - kTileModeDepth_2dThin_256, - kTileModeDepth_2dThin_512, - kTileModeDepth_2dThin_1K, - kTileModeDepth_1dThin, - kTileModeDepth_2dThinPrt_256, - kTileModeDepth_2dThinPrt_1K, - - kTileModeDisplay_LinearAligned, - kTileModeDisplay_1dThin, - kTileModeDisplay_2dThin, - kTileModeDisplay_ThinPrt, - kTileModeDisplay_2dThinPrt, - - kTileModeThin_1dThin, - kTileModeThin_2dThin, - kTileModeThin_3dThin, - kTileModeThin_ThinPrt, - kTileModeThin_2dThinPrt, - kTileModeThin_3dThinPrt, - - kTileModeThick_1dThick, - kTileModeThick_2dThick, - kTileModeThick_3dThick, - kTileModeThick_ThickPrt, - kTileModeThick_2dThickPrt, - kTileModeThick_3dThickPrt, - kTileModeThick_2dXThick, - kTileModeThick_3dXThick, -}; - -enum MacroTileMode { - kMacroTileMode_1x4_16, - kMacroTileMode_1x2_16, - kMacroTileMode_1x1_16, - kMacroTileMode_1x1_16_dup, - kMacroTileMode_1x1_8, - kMacroTileMode_1x1_4, - kMacroTileMode_1x1_2, - kMacroTileMode_1x1_2_dup, - kMacroTileMode_1x8_16, - kMacroTileMode_1x4_16_dup, - kMacroTileMode_1x2_16_dup, - kMacroTileMode_1x1_16_dup2, - kMacroTileMode_1x1_8_dup, - kMacroTileMode_1x1_4_dup, - kMacroTileMode_1x1_2_dup2, - kMacroTileMode_1x1_2_dup3, -}; - -inline constexpr auto kMicroTileWidth = 8; -inline constexpr auto kMicroTileHeight = 8; - -inline uint64_t computeLinearElementByteOffset( - uint32_t x, uint32_t y, uint32_t z, uint32_t fragmentIndex, uint32_t pitch, - uint32_t slicePitchElems, uint32_t bitsPerElement, - uint32_t numFragmentsPerPixel) { - uint64_t absoluteElementIndex = z * slicePitchElems + y * pitch + x; - return (absoluteElementIndex * bitsPerElement * numFragmentsPerPixel) + - (bitsPerElement * fragmentIndex); -} - -inline uint32_t get1dThickElementIndex(uint32_t x, uint32_t y, uint32_t z, - uint32_t bpp) { - uint32_t elem = 0; - - switch (bpp) { - case 8: - case 16: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((y >> 0) & 0x1) << 1; - elem |= ((x >> 1) & 0x1) << 2; - elem |= ((y >> 1) & 0x1) << 3; - elem |= ((z >> 0) & 0x1) << 4; - elem |= ((z >> 1) & 0x1) << 5; - elem |= ((x >> 2) & 0x1) << 6; - elem |= ((y >> 2) & 0x1) << 7; - break; - case 32: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((y >> 0) & 0x1) << 1; - elem |= ((x >> 1) & 0x1) << 2; - elem |= ((z >> 0) & 0x1) << 3; - elem |= ((y >> 1) & 0x1) << 4; - elem |= ((z >> 1) & 0x1) << 5; - elem |= ((x >> 2) & 0x1) << 6; - elem |= ((y >> 2) & 0x1) << 7; - break; - - case 64: - case 128: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((y >> 0) & 0x1) << 1; - elem |= ((z >> 0) & 0x1) << 2; - elem |= ((x >> 1) & 0x1) << 3; - elem |= ((y >> 1) & 0x1) << 4; - elem |= ((z >> 1) & 0x1) << 5; - elem |= ((x >> 2) & 0x1) << 6; - elem |= ((y >> 2) & 0x1) << 7; - break; - - default: - util::unreachable(); - } - - return elem; -} - -inline uint32_t getThinElementIndex(uint32_t x, uint32_t y) { - uint32_t elem = 0; - - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((y >> 0) & 0x1) << 1; - elem |= ((x >> 1) & 0x1) << 2; - elem |= ((y >> 1) & 0x1) << 3; - elem |= ((x >> 2) & 0x1) << 4; - elem |= ((y >> 2) & 0x1) << 5; - - return elem; -} - -inline uint32_t getDisplayElementIndex(uint32_t x, uint32_t y, uint32_t bpp) { - uint32_t elem = 0; - switch (bpp) { - case 8: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((x >> 1) & 0x1) << 1; - elem |= ((x >> 2) & 0x1) << 2; - elem |= ((y >> 1) & 0x1) << 3; - elem |= ((y >> 0) & 0x1) << 4; - elem |= ((y >> 2) & 0x1) << 5; - break; - case 16: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((x >> 1) & 0x1) << 1; - elem |= ((x >> 2) & 0x1) << 2; - elem |= ((y >> 0) & 0x1) << 3; - elem |= ((y >> 1) & 0x1) << 4; - elem |= ((y >> 2) & 0x1) << 5; - break; - case 32: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((x >> 1) & 0x1) << 1; - elem |= ((y >> 0) & 0x1) << 2; - elem |= ((x >> 2) & 0x1) << 3; - elem |= ((y >> 1) & 0x1) << 4; - elem |= ((y >> 2) & 0x1) << 5; - break; - case 64: - elem |= ((x >> 0) & 0x1) << 0; - elem |= ((y >> 0) & 0x1) << 1; - elem |= ((x >> 1) & 0x1) << 2; - elem |= ((x >> 2) & 0x1) << 3; - elem |= ((y >> 1) & 0x1) << 4; - elem |= ((y >> 2) & 0x1) << 5; - break; - default: - std::abort(); - } - - return elem; -} -inline uint64_t computeThin1dThinTileElementOffset(std::uint32_t bpp, - uint32_t x, uint32_t y, - uint32_t z, - std::uint64_t height, - std::uint64_t pitch) { - uint64_t elementIndex = getThinElementIndex(x, y); - - auto tileBytes = kMicroTileWidth * kMicroTileHeight * bpp; - - auto paddedWidth = pitch; - - auto tilesPerRow = paddedWidth / kMicroTileWidth; - auto tilesPerSlice = std::max(tilesPerRow * (height / kMicroTileHeight), 1UL); - - uint64_t sliceOffset = z * tilesPerSlice * tileBytes; - - uint64_t tileRowIndex = y / kMicroTileHeight; - uint64_t tileColumnIndex = x / kMicroTileWidth; - uint64_t tileOffset = - (tileRowIndex * tilesPerRow + tileColumnIndex) * tileBytes; - - return (sliceOffset + tileOffset) + elementIndex * bpp; -} -inline uint64_t computeThick1dThickTileElementOffset(std::uint32_t bpp, - uint32_t x, uint32_t y, - uint32_t z, - std::uint64_t height, - std::uint64_t pitch) { - uint64_t elementIndex = get1dThickElementIndex(x, y, z, bpp * 8); - - auto tileBytes = (kMicroTileWidth * kMicroTileHeight * bpp * 8 * 4 + 7) / 8; - - auto paddedWidth = pitch; - - auto tilesPerRow = paddedWidth / kMicroTileWidth; - auto tilesPerSlice = std::max(tilesPerRow * (height / kMicroTileHeight), 1UL); - - uint64_t sliceOffset = (z / 4) * tilesPerSlice * tileBytes; - - uint64_t tileRowIndex = y / kMicroTileHeight; - uint64_t tileColumnIndex = x / kMicroTileWidth; - uint64_t tileOffset = - (tileRowIndex * tilesPerRow + tileColumnIndex) * tileBytes; - - return (sliceOffset + tileOffset) + elementIndex * bpp; -} - -static constexpr auto kPipeInterleaveBytes = 256; - -inline void getMacroTileData(MacroTileMode macroTileMode, uint32_t &bankWidth, - uint32_t &bankHeight, uint32_t ¯oTileAspect, - uint32_t &numBanks) { - switch (macroTileMode) { - case kMacroTileMode_1x4_16: - bankWidth = 1; - bankHeight = 4; - macroTileAspect = 4; - numBanks = 16; - break; - case kMacroTileMode_1x2_16: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 2; - numBanks = 16; - break; - case kMacroTileMode_1x1_16: - bankWidth = 1; - bankHeight = 2; - macroTileAspect = 2; - numBanks = 16; - break; - case kMacroTileMode_1x1_16_dup: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 2; - numBanks = 16; - break; - case kMacroTileMode_1x1_8: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 8; - break; - case kMacroTileMode_1x1_4: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 4; - break; - case kMacroTileMode_1x1_2: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 2; - break; - case kMacroTileMode_1x1_2_dup: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 2; - break; - case kMacroTileMode_1x8_16: - bankWidth = 1; - bankHeight = 8; - macroTileAspect = 4; - numBanks = 16; - break; - case kMacroTileMode_1x4_16_dup: - bankWidth = 1; - bankHeight = 4; - macroTileAspect = 4; - numBanks = 16; - break; - case kMacroTileMode_1x2_16_dup: - bankWidth = 1; - bankHeight = 2; - macroTileAspect = 2; - numBanks = 16; - break; - case kMacroTileMode_1x1_16_dup2: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 2; - numBanks = 16; - break; - case kMacroTileMode_1x1_8_dup: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 8; - break; - case kMacroTileMode_1x1_4_dup: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 4; - break; - case kMacroTileMode_1x1_2_dup2: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 2; - break; - case kMacroTileMode_1x1_2_dup3: - bankWidth = 1; - bankHeight = 1; - macroTileAspect = 1; - numBanks = 2; - break; - default: - util::unreachable(); - } -} - -static constexpr uint32_t log2(uint32_t i) { return 31 - __builtin_clz(i | 1); } - -inline constexpr uint32_t kDramRowSize = 0x400; - -inline constexpr uint32_t getPipeP8_32x32_8x16Index(uint32_t x, uint32_t y) { - std::uint32_t pipe = 0; - pipe |= (((x >> 4) ^ (y >> 3) ^ (x >> 5)) & 0x1) << 0; - pipe |= (((x >> 3) ^ (y >> 4)) & 0x1) << 1; - pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; - return pipe; -} - -inline constexpr uint32_t getPipeP8_32x32_16x16Index(uint32_t x, uint32_t y) { - std::uint32_t pipe = 0; - pipe |= (((x >> 3) ^ (y >> 3) ^ (x >> 4)) & 0x1) << 0; - pipe |= (((x >> 4) ^ (y >> 4)) & 0x1) << 1; - pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; - return pipe; -} - -inline constexpr uint32_t getPipeP16Index(uint32_t x, uint32_t y) { - std::uint32_t pipe = 0; - pipe |= (((x >> 3) ^ (y >> 3) ^ (x >> 4)) & 0x1) << 0; - pipe |= (((x >> 4) ^ (y >> 4)) & 0x1) << 1; - pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; - pipe |= (((x >> 6) ^ (y >> 5)) & 0x1) << 3; - return pipe; -} - -inline constexpr uint32_t getBankIndex(uint32_t x, uint32_t y, - uint32_t bankWidth, uint32_t bankHeight, - uint32_t numBanks, uint32_t numPipes) { - const uint32_t xShiftOffset = log2(bankWidth * numPipes); - const uint32_t yShiftOffset = log2(bankHeight); - const uint32_t xs = x >> xShiftOffset; - const uint32_t ys = y >> yShiftOffset; - - uint32_t bank = 0; - switch (numBanks) { - case 2: - bank |= (((xs >> 3) ^ (ys >> 3)) & 0x1) << 0; - break; - case 4: - bank |= (((xs >> 3) ^ (ys >> 4)) & 0x1) << 0; - bank |= (((xs >> 4) ^ (ys >> 3)) & 0x1) << 1; - break; - case 8: - bank |= (((xs >> 3) ^ (ys >> 5)) & 0x1) << 0; - bank |= (((xs >> 4) ^ (ys >> 4) ^ (ys >> 5)) & 0x1) << 1; - bank |= (((xs >> 5) ^ (ys >> 3)) & 0x1) << 2; - break; - case 16: - bank |= (((xs >> 3) ^ (ys >> 6)) & 0x1) << 0; - bank |= (((xs >> 4) ^ (ys >> 5) ^ (ys >> 6)) & 0x1) << 1; - bank |= (((xs >> 5) ^ (ys >> 4)) & 0x1) << 2; - bank |= (((xs >> 6) ^ (ys >> 3)) & 0x1) << 3; - break; - default: - util::unreachable(); - } - - return bank; -} - -inline uint64_t compute2dThinTileElementOffset( - std::uint32_t bpp, MacroTileMode macroTileMode, uint64_t elementIndex, - std::uint8_t tileSwizzleMask, std::uint32_t fragmentIndex, - std::uint32_t arraySlice, uint32_t x, uint32_t y, uint32_t z, - std::uint64_t height, std::uint64_t pitch) { - // P8_32x32_8x16 - constexpr auto numPipes = 8; - constexpr auto pipeInterleaveBytes = 256; - - std::uint32_t bankWidth; - std::uint32_t bankHeight; - std::uint32_t macroTileAspect; - std::uint32_t numBanks; - - getMacroTileData(macroTileMode, bankWidth, bankHeight, macroTileAspect, - numBanks); - - uint32_t tileBytes1x = (bpp * kMicroTileWidth * kMicroTileHeight + 7) / 8; - constexpr auto sampleSplit = 1 << 2; - auto tileSplitC = std::max(256, tileBytes1x * sampleSplit); - auto tileSplitBytes = std::min(kDramRowSize, tileSplitC); - std::uint32_t numFragmentsPerPixel = 1; // TODO - - constexpr auto pipeInterleaveBits = log2(pipeInterleaveBytes); - constexpr auto pipeInterleaveMask = (1 << (pipeInterleaveBits)) - 1; - constexpr auto pipeBits = log2(numPipes); - auto bankBits = log2(numBanks); - auto bankSwizzleMask = tileSwizzleMask; - constexpr auto pipeSwizzleMask = 0; - auto macroTileWidth = - (kMicroTileWidth * bankWidth * numPipes) * macroTileAspect; - auto macroTileHeight = - (kMicroTileHeight * bankHeight * numBanks) / macroTileAspect; - - uint64_t pipe = getPipeP8_32x32_8x16Index(x, y); - uint64_t bank = getBankIndex(x, y, bankWidth, bankHeight, numBanks, numPipes); - - uint32_t tileBytes = - (kMicroTileWidth * kMicroTileHeight * bpp * numFragmentsPerPixel + 7) / 8; - - uint64_t fragmentOffset = - fragmentIndex * (tileBytes / numFragmentsPerPixel) * 8; - uint64_t elementOffset = fragmentOffset + (elementIndex * bpp); - - uint64_t slicesPerTile = 1; - uint64_t tileSplitSlice = 0; - if (tileBytes > tileSplitBytes) { - slicesPerTile = tileBytes / tileSplitBytes; - tileSplitSlice = elementOffset / (tileSplitBytes * 8); - elementOffset %= (tileSplitBytes * 8); - tileBytes = tileSplitBytes; - } - - uint64_t macroTileBytes = (macroTileWidth / kMicroTileWidth) * - (macroTileHeight / kMicroTileHeight) * tileBytes / - (numPipes * numBanks); - uint64_t macroTilesPerRow = pitch / macroTileWidth; - uint64_t macroTileRowIndex = y / macroTileHeight; - uint64_t macroTileColumnIndex = x / macroTileWidth; - uint64_t macroTileIndex = - (macroTileRowIndex * macroTilesPerRow) + macroTileColumnIndex; - uint64_t macroTileOffset = macroTileIndex * macroTileBytes; - uint64_t macroTilesPerSlice = macroTilesPerRow * (height / macroTileHeight); - uint64_t sliceBytes = macroTilesPerSlice * macroTileBytes; - uint32_t slice = z; - uint64_t sliceOffset = (tileSplitSlice + slicesPerTile * slice) * sliceBytes; - if (arraySlice != 0) { - slice = arraySlice; - } - - uint64_t tileRowIndex = (y / kMicroTileHeight) % bankHeight; - uint64_t tileColumnIndex = ((x / kMicroTileWidth) / numPipes) % bankWidth; - uint64_t tileIndex = (tileRowIndex * bankWidth) + tileColumnIndex; - uint64_t tileOffset = tileIndex * tileBytes; - - uint64_t bankSwizzle = bankSwizzleMask; - uint64_t pipeSwizzle = pipeSwizzleMask; - - uint64_t pipe_slice_rotation = 0; - pipeSwizzle += pipe_slice_rotation; - pipeSwizzle &= (numPipes - 1); - pipe = pipe ^ pipeSwizzle; - - uint32_t sliceRotation = ((numBanks / 2) - 1) * slice; - uint64_t tileSplitSliceRotation = ((numBanks / 2) + 1) * tileSplitSlice; - - bank ^= bankSwizzle + sliceRotation; - bank ^= tileSplitSliceRotation; - bank &= (numBanks - 1); - - uint64_t totalOffset = - (sliceOffset + macroTileOffset + tileOffset) * 8 + elementOffset; - uint64_t bitOffset = totalOffset & 0x7; - totalOffset /= 8; - - uint64_t pipeInterleaveOffset = totalOffset & pipeInterleaveMask; - uint64_t offset = totalOffset >> pipeInterleaveBits; - - uint64_t byteOffset = pipeInterleaveOffset | (pipe << (pipeInterleaveBits)) | - (bank << (pipeInterleaveBits + pipeBits)) | - (offset << (pipeInterleaveBits + pipeBits + bankBits)); - - return (byteOffset << 3) | bitOffset; -} - -inline uint64_t computeTiledElementByteOffset( - TileMode tileMode, std::uint32_t bpp, uint32_t x, uint32_t y, uint32_t z, - MacroTileMode macroTileMode, std::uint8_t tileSwizzleMask, - std::uint32_t fragmentIndex, std::uint32_t mipLevel, - std::uint32_t arraySlice, uint64_t width, std::uint64_t height, - std::uint64_t depth, std::uint64_t pitch, std::uint64_t depthPitch) { - switch (tileMode) { - case kTileModeDepth_2dThin_64: - util::unreachable(); - case kTileModeDepth_2dThin_128: - util::unreachable(); - case kTileModeDepth_2dThin_256: - util::unreachable(); - case kTileModeDepth_2dThin_512: - util::unreachable(); - case kTileModeDepth_2dThin_1K: - util::unreachable(); - case kTileModeDepth_1dThin: - util::unreachable(); - case kTileModeDepth_2dThinPrt_256: - util::unreachable(); - case kTileModeDepth_2dThinPrt_1K: - util::unreachable(); - - case kTileModeDisplay_LinearAligned: - return x * y * z * ((bpp + 7) / 8); - - case kTileModeDisplay_1dThin: - util::unreachable(); - case kTileModeDisplay_2dThin: - return compute2dThinTileElementOffset(bpp, macroTileMode, - getDisplayElementIndex(x, y, bpp), - tileSwizzleMask, fragmentIndex, - arraySlice, x, y, z, height, pitch) / - 8; - case kTileModeDisplay_ThinPrt: - util::unreachable(); - case kTileModeDisplay_2dThinPrt: - util::unreachable(); - case kTileModeThin_1dThin: - return computeThin1dThinTileElementOffset(((bpp + 7) / 8), x, y, z, height, - pitch); - case kTileModeThin_2dThin: - return compute2dThinTileElementOffset( - bpp, macroTileMode, getThinElementIndex(x, y), tileSwizzleMask, - fragmentIndex, arraySlice, x, y, z, height, pitch) / - 8; - case kTileModeThin_3dThin: - util::unreachable(); - case kTileModeThin_ThinPrt: - util::unreachable(); - case kTileModeThin_2dThinPrt: - util::unreachable(); - case kTileModeThin_3dThinPrt: - util::unreachable(); - case kTileModeThick_1dThick: - return computeThick1dThickTileElementOffset(((bpp + 7) / 8), x, y, z, - height, pitch); - case kTileModeThick_2dThick: - util::unreachable(); - case kTileModeThick_3dThick: - util::unreachable(); - case kTileModeThick_ThickPrt: - util::unreachable(); - case kTileModeThick_2dThickPrt: - util::unreachable(); - case kTileModeThick_3dThickPrt: - util::unreachable(); - case kTileModeThick_2dXThick: - util::unreachable(); - case kTileModeThick_3dXThick: - util::unreachable(); - } - - util::unreachable(); -} +namespace amdgpu::device +{ + enum TileMode + { + kTileModeDepth_2dThin_64, + kTileModeDepth_2dThin_128, + kTileModeDepth_2dThin_256, + kTileModeDepth_2dThin_512, + kTileModeDepth_2dThin_1K, + kTileModeDepth_1dThin, + kTileModeDepth_2dThinPrt_256, + kTileModeDepth_2dThinPrt_1K, + + kTileModeDisplay_LinearAligned, + kTileModeDisplay_1dThin, + kTileModeDisplay_2dThin, + kTileModeDisplay_ThinPrt, + kTileModeDisplay_2dThinPrt, + + kTileModeThin_1dThin, + kTileModeThin_2dThin, + kTileModeThin_3dThin, + kTileModeThin_ThinPrt, + kTileModeThin_2dThinPrt, + kTileModeThin_3dThinPrt, + + kTileModeThick_1dThick, + kTileModeThick_2dThick, + kTileModeThick_3dThick, + kTileModeThick_ThickPrt, + kTileModeThick_2dThickPrt, + kTileModeThick_3dThickPrt, + kTileModeThick_2dXThick, + kTileModeThick_3dXThick, + }; + + enum MacroTileMode + { + kMacroTileMode_1x4_16, + kMacroTileMode_1x2_16, + kMacroTileMode_1x1_16, + kMacroTileMode_1x1_16_dup, + kMacroTileMode_1x1_8, + kMacroTileMode_1x1_4, + kMacroTileMode_1x1_2, + kMacroTileMode_1x1_2_dup, + kMacroTileMode_1x8_16, + kMacroTileMode_1x4_16_dup, + kMacroTileMode_1x2_16_dup, + kMacroTileMode_1x1_16_dup2, + kMacroTileMode_1x1_8_dup, + kMacroTileMode_1x1_4_dup, + kMacroTileMode_1x1_2_dup2, + kMacroTileMode_1x1_2_dup3, + }; + + inline constexpr auto kMicroTileWidth = 8; + inline constexpr auto kMicroTileHeight = 8; + + inline uint64_t computeLinearElementByteOffset( + uint32_t x, uint32_t y, uint32_t z, uint32_t fragmentIndex, uint32_t pitch, + uint32_t slicePitchElems, uint32_t bitsPerElement, + uint32_t numFragmentsPerPixel) + { + uint64_t absoluteElementIndex = z * slicePitchElems + y * pitch + x; + return (absoluteElementIndex * bitsPerElement * numFragmentsPerPixel) + + (bitsPerElement * fragmentIndex); + } + + inline uint32_t get1dThickElementIndex(uint32_t x, uint32_t y, uint32_t z, + uint32_t bpp) + { + uint32_t elem = 0; + + switch (bpp) + { + case 8: + case 16: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((y >> 0) & 0x1) << 1; + elem |= ((x >> 1) & 0x1) << 2; + elem |= ((y >> 1) & 0x1) << 3; + elem |= ((z >> 0) & 0x1) << 4; + elem |= ((z >> 1) & 0x1) << 5; + elem |= ((x >> 2) & 0x1) << 6; + elem |= ((y >> 2) & 0x1) << 7; + break; + case 32: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((y >> 0) & 0x1) << 1; + elem |= ((x >> 1) & 0x1) << 2; + elem |= ((z >> 0) & 0x1) << 3; + elem |= ((y >> 1) & 0x1) << 4; + elem |= ((z >> 1) & 0x1) << 5; + elem |= ((x >> 2) & 0x1) << 6; + elem |= ((y >> 2) & 0x1) << 7; + break; + + case 64: + case 128: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((y >> 0) & 0x1) << 1; + elem |= ((z >> 0) & 0x1) << 2; + elem |= ((x >> 1) & 0x1) << 3; + elem |= ((y >> 1) & 0x1) << 4; + elem |= ((z >> 1) & 0x1) << 5; + elem |= ((x >> 2) & 0x1) << 6; + elem |= ((y >> 2) & 0x1) << 7; + break; + + default: + util::unreachable(); + } + + return elem; + } + + inline uint32_t getThinElementIndex(uint32_t x, uint32_t y) + { + uint32_t elem = 0; + + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((y >> 0) & 0x1) << 1; + elem |= ((x >> 1) & 0x1) << 2; + elem |= ((y >> 1) & 0x1) << 3; + elem |= ((x >> 2) & 0x1) << 4; + elem |= ((y >> 2) & 0x1) << 5; + + return elem; + } + + inline uint32_t getDisplayElementIndex(uint32_t x, uint32_t y, uint32_t bpp) + { + uint32_t elem = 0; + switch (bpp) + { + case 8: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((x >> 1) & 0x1) << 1; + elem |= ((x >> 2) & 0x1) << 2; + elem |= ((y >> 1) & 0x1) << 3; + elem |= ((y >> 0) & 0x1) << 4; + elem |= ((y >> 2) & 0x1) << 5; + break; + case 16: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((x >> 1) & 0x1) << 1; + elem |= ((x >> 2) & 0x1) << 2; + elem |= ((y >> 0) & 0x1) << 3; + elem |= ((y >> 1) & 0x1) << 4; + elem |= ((y >> 2) & 0x1) << 5; + break; + case 32: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((x >> 1) & 0x1) << 1; + elem |= ((y >> 0) & 0x1) << 2; + elem |= ((x >> 2) & 0x1) << 3; + elem |= ((y >> 1) & 0x1) << 4; + elem |= ((y >> 2) & 0x1) << 5; + break; + case 64: + elem |= ((x >> 0) & 0x1) << 0; + elem |= ((y >> 0) & 0x1) << 1; + elem |= ((x >> 1) & 0x1) << 2; + elem |= ((x >> 2) & 0x1) << 3; + elem |= ((y >> 1) & 0x1) << 4; + elem |= ((y >> 2) & 0x1) << 5; + break; + default: + std::abort(); + } + + return elem; + } + inline uint64_t computeThin1dThinTileElementOffset(std::uint32_t bpp, + uint32_t x, uint32_t y, + uint32_t z, + std::uint64_t height, + std::uint64_t pitch) + { + uint64_t elementIndex = getThinElementIndex(x, y); + + auto tileBytes = kMicroTileWidth * kMicroTileHeight * bpp; + + auto paddedWidth = pitch; + + auto tilesPerRow = paddedWidth / kMicroTileWidth; + auto tilesPerSlice = std::max(tilesPerRow * (height / kMicroTileHeight), 1UL); + + uint64_t sliceOffset = z * tilesPerSlice * tileBytes; + + uint64_t tileRowIndex = y / kMicroTileHeight; + uint64_t tileColumnIndex = x / kMicroTileWidth; + uint64_t tileOffset = + (tileRowIndex * tilesPerRow + tileColumnIndex) * tileBytes; + + return (sliceOffset + tileOffset) + elementIndex * bpp; + } + inline uint64_t computeThick1dThickTileElementOffset(std::uint32_t bpp, + uint32_t x, uint32_t y, + uint32_t z, + std::uint64_t height, + std::uint64_t pitch) + { + uint64_t elementIndex = get1dThickElementIndex(x, y, z, bpp * 8); + + auto tileBytes = (kMicroTileWidth * kMicroTileHeight * bpp * 8 * 4 + 7) / 8; + + auto paddedWidth = pitch; + + auto tilesPerRow = paddedWidth / kMicroTileWidth; + auto tilesPerSlice = std::max(tilesPerRow * (height / kMicroTileHeight), 1UL); + + uint64_t sliceOffset = (z / 4) * tilesPerSlice * tileBytes; + + uint64_t tileRowIndex = y / kMicroTileHeight; + uint64_t tileColumnIndex = x / kMicroTileWidth; + uint64_t tileOffset = + (tileRowIndex * tilesPerRow + tileColumnIndex) * tileBytes; + + return (sliceOffset + tileOffset) + elementIndex * bpp; + } + + static constexpr auto kPipeInterleaveBytes = 256; + + inline void getMacroTileData(MacroTileMode macroTileMode, uint32_t& bankWidth, + uint32_t& bankHeight, uint32_t& macroTileAspect, + uint32_t& numBanks) + { + switch (macroTileMode) + { + case kMacroTileMode_1x4_16: + bankWidth = 1; + bankHeight = 4; + macroTileAspect = 4; + numBanks = 16; + break; + case kMacroTileMode_1x2_16: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 2; + numBanks = 16; + break; + case kMacroTileMode_1x1_16: + bankWidth = 1; + bankHeight = 2; + macroTileAspect = 2; + numBanks = 16; + break; + case kMacroTileMode_1x1_16_dup: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 2; + numBanks = 16; + break; + case kMacroTileMode_1x1_8: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 8; + break; + case kMacroTileMode_1x1_4: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 4; + break; + case kMacroTileMode_1x1_2: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 2; + break; + case kMacroTileMode_1x1_2_dup: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 2; + break; + case kMacroTileMode_1x8_16: + bankWidth = 1; + bankHeight = 8; + macroTileAspect = 4; + numBanks = 16; + break; + case kMacroTileMode_1x4_16_dup: + bankWidth = 1; + bankHeight = 4; + macroTileAspect = 4; + numBanks = 16; + break; + case kMacroTileMode_1x2_16_dup: + bankWidth = 1; + bankHeight = 2; + macroTileAspect = 2; + numBanks = 16; + break; + case kMacroTileMode_1x1_16_dup2: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 2; + numBanks = 16; + break; + case kMacroTileMode_1x1_8_dup: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 8; + break; + case kMacroTileMode_1x1_4_dup: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 4; + break; + case kMacroTileMode_1x1_2_dup2: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 2; + break; + case kMacroTileMode_1x1_2_dup3: + bankWidth = 1; + bankHeight = 1; + macroTileAspect = 1; + numBanks = 2; + break; + default: + util::unreachable(); + } + } + + static constexpr uint32_t log2(uint32_t i) { return 31 - __builtin_clz(i | 1); } + + inline constexpr uint32_t kDramRowSize = 0x400; + + inline constexpr uint32_t getPipeP8_32x32_8x16Index(uint32_t x, uint32_t y) + { + std::uint32_t pipe = 0; + pipe |= (((x >> 4) ^ (y >> 3) ^ (x >> 5)) & 0x1) << 0; + pipe |= (((x >> 3) ^ (y >> 4)) & 0x1) << 1; + pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; + return pipe; + } + + inline constexpr uint32_t getPipeP8_32x32_16x16Index(uint32_t x, uint32_t y) + { + std::uint32_t pipe = 0; + pipe |= (((x >> 3) ^ (y >> 3) ^ (x >> 4)) & 0x1) << 0; + pipe |= (((x >> 4) ^ (y >> 4)) & 0x1) << 1; + pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; + return pipe; + } + + inline constexpr uint32_t getPipeP16Index(uint32_t x, uint32_t y) + { + std::uint32_t pipe = 0; + pipe |= (((x >> 3) ^ (y >> 3) ^ (x >> 4)) & 0x1) << 0; + pipe |= (((x >> 4) ^ (y >> 4)) & 0x1) << 1; + pipe |= (((x >> 5) ^ (y >> 5)) & 0x1) << 2; + pipe |= (((x >> 6) ^ (y >> 5)) & 0x1) << 3; + return pipe; + } + + inline constexpr uint32_t getBankIndex(uint32_t x, uint32_t y, + uint32_t bankWidth, uint32_t bankHeight, + uint32_t numBanks, uint32_t numPipes) + { + const uint32_t xShiftOffset = log2(bankWidth * numPipes); + const uint32_t yShiftOffset = log2(bankHeight); + const uint32_t xs = x >> xShiftOffset; + const uint32_t ys = y >> yShiftOffset; + + uint32_t bank = 0; + switch (numBanks) + { + case 2: + bank |= (((xs >> 3) ^ (ys >> 3)) & 0x1) << 0; + break; + case 4: + bank |= (((xs >> 3) ^ (ys >> 4)) & 0x1) << 0; + bank |= (((xs >> 4) ^ (ys >> 3)) & 0x1) << 1; + break; + case 8: + bank |= (((xs >> 3) ^ (ys >> 5)) & 0x1) << 0; + bank |= (((xs >> 4) ^ (ys >> 4) ^ (ys >> 5)) & 0x1) << 1; + bank |= (((xs >> 5) ^ (ys >> 3)) & 0x1) << 2; + break; + case 16: + bank |= (((xs >> 3) ^ (ys >> 6)) & 0x1) << 0; + bank |= (((xs >> 4) ^ (ys >> 5) ^ (ys >> 6)) & 0x1) << 1; + bank |= (((xs >> 5) ^ (ys >> 4)) & 0x1) << 2; + bank |= (((xs >> 6) ^ (ys >> 3)) & 0x1) << 3; + break; + default: + util::unreachable(); + } + + return bank; + } + + inline uint64_t compute2dThinTileElementOffset( + std::uint32_t bpp, MacroTileMode macroTileMode, uint64_t elementIndex, + std::uint8_t tileSwizzleMask, std::uint32_t fragmentIndex, + std::uint32_t arraySlice, uint32_t x, uint32_t y, uint32_t z, + std::uint64_t height, std::uint64_t pitch) + { + // P8_32x32_8x16 + constexpr auto numPipes = 8; + constexpr auto pipeInterleaveBytes = 256; + + std::uint32_t bankWidth; + std::uint32_t bankHeight; + std::uint32_t macroTileAspect; + std::uint32_t numBanks; + + getMacroTileData(macroTileMode, bankWidth, bankHeight, macroTileAspect, + numBanks); + + uint32_t tileBytes1x = (bpp * kMicroTileWidth * kMicroTileHeight + 7) / 8; + constexpr auto sampleSplit = 1 << 2; + auto tileSplitC = std::max(256, tileBytes1x * sampleSplit); + auto tileSplitBytes = std::min(kDramRowSize, tileSplitC); + std::uint32_t numFragmentsPerPixel = 1; // TODO + + constexpr auto pipeInterleaveBits = log2(pipeInterleaveBytes); + constexpr auto pipeInterleaveMask = (1 << (pipeInterleaveBits)) - 1; + constexpr auto pipeBits = log2(numPipes); + auto bankBits = log2(numBanks); + auto bankSwizzleMask = tileSwizzleMask; + constexpr auto pipeSwizzleMask = 0; + auto macroTileWidth = + (kMicroTileWidth * bankWidth * numPipes) * macroTileAspect; + auto macroTileHeight = + (kMicroTileHeight * bankHeight * numBanks) / macroTileAspect; + + uint64_t pipe = getPipeP8_32x32_8x16Index(x, y); + uint64_t bank = getBankIndex(x, y, bankWidth, bankHeight, numBanks, numPipes); + + uint32_t tileBytes = + (kMicroTileWidth * kMicroTileHeight * bpp * numFragmentsPerPixel + 7) / 8; + + uint64_t fragmentOffset = + fragmentIndex * (tileBytes / numFragmentsPerPixel) * 8; + uint64_t elementOffset = fragmentOffset + (elementIndex * bpp); + + uint64_t slicesPerTile = 1; + uint64_t tileSplitSlice = 0; + if (tileBytes > tileSplitBytes) + { + slicesPerTile = tileBytes / tileSplitBytes; + tileSplitSlice = elementOffset / (tileSplitBytes * 8); + elementOffset %= (tileSplitBytes * 8); + tileBytes = tileSplitBytes; + } + + uint64_t macroTileBytes = (macroTileWidth / kMicroTileWidth) * + (macroTileHeight / kMicroTileHeight) * tileBytes / + (numPipes * numBanks); + uint64_t macroTilesPerRow = pitch / macroTileWidth; + uint64_t macroTileRowIndex = y / macroTileHeight; + uint64_t macroTileColumnIndex = x / macroTileWidth; + uint64_t macroTileIndex = + (macroTileRowIndex * macroTilesPerRow) + macroTileColumnIndex; + uint64_t macroTileOffset = macroTileIndex * macroTileBytes; + uint64_t macroTilesPerSlice = macroTilesPerRow * (height / macroTileHeight); + uint64_t sliceBytes = macroTilesPerSlice * macroTileBytes; + uint32_t slice = z; + uint64_t sliceOffset = (tileSplitSlice + slicesPerTile * slice) * sliceBytes; + if (arraySlice != 0) + { + slice = arraySlice; + } + + uint64_t tileRowIndex = (y / kMicroTileHeight) % bankHeight; + uint64_t tileColumnIndex = ((x / kMicroTileWidth) / numPipes) % bankWidth; + uint64_t tileIndex = (tileRowIndex * bankWidth) + tileColumnIndex; + uint64_t tileOffset = tileIndex * tileBytes; + + uint64_t bankSwizzle = bankSwizzleMask; + uint64_t pipeSwizzle = pipeSwizzleMask; + + uint64_t pipe_slice_rotation = 0; + pipeSwizzle += pipe_slice_rotation; + pipeSwizzle &= (numPipes - 1); + pipe = pipe ^ pipeSwizzle; + + uint32_t sliceRotation = ((numBanks / 2) - 1) * slice; + uint64_t tileSplitSliceRotation = ((numBanks / 2) + 1) * tileSplitSlice; + + bank ^= bankSwizzle + sliceRotation; + bank ^= tileSplitSliceRotation; + bank &= (numBanks - 1); + + uint64_t totalOffset = + (sliceOffset + macroTileOffset + tileOffset) * 8 + elementOffset; + uint64_t bitOffset = totalOffset & 0x7; + totalOffset /= 8; + + uint64_t pipeInterleaveOffset = totalOffset & pipeInterleaveMask; + uint64_t offset = totalOffset >> pipeInterleaveBits; + + uint64_t byteOffset = pipeInterleaveOffset | (pipe << (pipeInterleaveBits)) | + (bank << (pipeInterleaveBits + pipeBits)) | + (offset << (pipeInterleaveBits + pipeBits + bankBits)); + + return (byteOffset << 3) | bitOffset; + } + + inline uint64_t computeTiledElementByteOffset( + TileMode tileMode, std::uint32_t bpp, uint32_t x, uint32_t y, uint32_t z, + MacroTileMode macroTileMode, std::uint8_t tileSwizzleMask, + std::uint32_t fragmentIndex, std::uint32_t mipLevel, + std::uint32_t arraySlice, uint64_t width, std::uint64_t height, + std::uint64_t depth, std::uint64_t pitch, std::uint64_t depthPitch) + { + switch (tileMode) + { + case kTileModeDepth_2dThin_64: + util::unreachable(); + case kTileModeDepth_2dThin_128: + util::unreachable(); + case kTileModeDepth_2dThin_256: + util::unreachable(); + case kTileModeDepth_2dThin_512: + util::unreachable(); + case kTileModeDepth_2dThin_1K: + util::unreachable(); + case kTileModeDepth_1dThin: + util::unreachable(); + case kTileModeDepth_2dThinPrt_256: + util::unreachable(); + case kTileModeDepth_2dThinPrt_1K: + util::unreachable(); + + case kTileModeDisplay_LinearAligned: + return x * y * z * ((bpp + 7) / 8); + + case kTileModeDisplay_1dThin: + util::unreachable(); + case kTileModeDisplay_2dThin: + return compute2dThinTileElementOffset(bpp, macroTileMode, + getDisplayElementIndex(x, y, bpp), + tileSwizzleMask, fragmentIndex, + arraySlice, x, y, z, height, pitch) / + 8; + case kTileModeDisplay_ThinPrt: + util::unreachable(); + case kTileModeDisplay_2dThinPrt: + util::unreachable(); + case kTileModeThin_1dThin: + return computeThin1dThinTileElementOffset(((bpp + 7) / 8), x, y, z, height, + pitch); + case kTileModeThin_2dThin: + return compute2dThinTileElementOffset( + bpp, macroTileMode, getThinElementIndex(x, y), tileSwizzleMask, + fragmentIndex, arraySlice, x, y, z, height, pitch) / + 8; + case kTileModeThin_3dThin: + util::unreachable(); + case kTileModeThin_ThinPrt: + util::unreachable(); + case kTileModeThin_2dThinPrt: + util::unreachable(); + case kTileModeThin_3dThinPrt: + util::unreachable(); + case kTileModeThick_1dThick: + return computeThick1dThickTileElementOffset(((bpp + 7) / 8), x, y, z, + height, pitch); + case kTileModeThick_2dThick: + util::unreachable(); + case kTileModeThick_3dThick: + util::unreachable(); + case kTileModeThick_ThickPrt: + util::unreachable(); + case kTileModeThick_2dThickPrt: + util::unreachable(); + case kTileModeThick_3dThickPrt: + util::unreachable(); + case kTileModeThick_2dXThick: + util::unreachable(); + case kTileModeThick_3dXThick: + util::unreachable(); + } + + util::unreachable(); + } } // namespace amdgpu::device diff --git a/hw/amdgpu/device/include/amdgpu/device/vk.hpp b/hw/amdgpu/device/include/amdgpu/device/vk.hpp index 0de04cf1..7d608d54 100644 --- a/hw/amdgpu/device/include/amdgpu/device/vk.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/vk.hpp @@ -14,972 +14,1078 @@ #include #include -namespace amdgpu::device::vk { -extern VkDevice g_vkDevice; -extern VkAllocationCallbacks *g_vkAllocator; -extern std::vector> g_computeQueues; -extern std::vector> g_graphicsQueues; - -std::uint32_t findPhysicalMemoryTypeIndex(std::uint32_t typeBits, - VkMemoryPropertyFlags properties); - -class DeviceMemory { - VkDeviceMemory mDeviceMemory = VK_NULL_HANDLE; - VkDeviceSize mSize = 0; - unsigned mMemoryTypeIndex = 0; - -public: - DeviceMemory(DeviceMemory &) = delete; - DeviceMemory(DeviceMemory &&other) { *this = std::move(other); } - DeviceMemory() = default; - - ~DeviceMemory() { - if (mDeviceMemory != nullptr) { - vkFreeMemory(g_vkDevice, mDeviceMemory, g_vkAllocator); - } - } - - DeviceMemory &operator=(DeviceMemory &&other) { - std::swap(mDeviceMemory, other.mDeviceMemory); - std::swap(mSize, other.mSize); - std::swap(mMemoryTypeIndex, other.mMemoryTypeIndex); - return *this; - } - - VkDeviceMemory getHandle() const { return mDeviceMemory; } - VkDeviceSize getSize() const { return mSize; } - unsigned getMemoryTypeIndex() const { return mMemoryTypeIndex; } - - static DeviceMemory AllocateFromType(std::size_t size, - unsigned memoryTypeIndex) { - VkMemoryAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = size; - allocInfo.memoryTypeIndex = memoryTypeIndex; - - DeviceMemory result; - Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, - &result.mDeviceMemory); - result.mSize = size; - result.mMemoryTypeIndex = memoryTypeIndex; - return result; - } - - static DeviceMemory Allocate(std::size_t size, unsigned memoryTypeBits, - VkMemoryPropertyFlags properties) { - return AllocateFromType( - size, findPhysicalMemoryTypeIndex(memoryTypeBits, properties)); - } - - static DeviceMemory Allocate(VkMemoryRequirements requirements, - VkMemoryPropertyFlags properties) { - return AllocateFromType( - requirements.size, - findPhysicalMemoryTypeIndex(requirements.memoryTypeBits, properties)); - } - - static DeviceMemory CreateExternalFd(int fd, std::size_t size, - unsigned memoryTypeIndex) { - VkImportMemoryFdInfoKHR importMemoryInfo{ - VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, - nullptr, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, - fd, - }; - - VkMemoryAllocateInfo allocInfo{ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &importMemoryInfo, - .allocationSize = size, - .memoryTypeIndex = memoryTypeIndex, - }; - - DeviceMemory result; - Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, - &result.mDeviceMemory); - result.mSize = size; - result.mMemoryTypeIndex = memoryTypeIndex; - return result; - } - static DeviceMemory - CreateExternalHostMemory(void *hostPointer, std::size_t size, - VkMemoryPropertyFlags properties) { - VkMemoryHostPointerPropertiesEXT hostPointerProperties = { - .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT}; - - auto vkGetMemoryHostPointerPropertiesEXT = - (PFN_vkGetMemoryHostPointerPropertiesEXT)vkGetDeviceProcAddr( - g_vkDevice, "vkGetMemoryHostPointerPropertiesEXT"); - - Verify() << vkGetMemoryHostPointerPropertiesEXT( - g_vkDevice, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, - hostPointer, &hostPointerProperties); - - auto memoryTypeBits = hostPointerProperties.memoryTypeBits; - - VkImportMemoryHostPointerInfoEXT importMemoryInfo = { - VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT, - nullptr, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, - hostPointer, - }; - - auto memoryTypeIndex = - findPhysicalMemoryTypeIndex(memoryTypeBits, properties); - - VkMemoryAllocateInfo allocInfo{ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &importMemoryInfo, - .allocationSize = size, - .memoryTypeIndex = memoryTypeIndex, - }; - - DeviceMemory result; - Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, - &result.mDeviceMemory); - result.mSize = size; - result.mMemoryTypeIndex = memoryTypeIndex; - return result; - } - - void *map(VkDeviceSize offset, VkDeviceSize size) { - void *result = 0; - Verify() << vkMapMemory(g_vkDevice, mDeviceMemory, offset, size, 0, - &result); - - return result; - } - - void unmap() { vkUnmapMemory(g_vkDevice, mDeviceMemory); } -}; - -struct DeviceMemoryRef { - VkDeviceMemory deviceMemory = VK_NULL_HANDLE; - VkDeviceSize offset = 0; - VkDeviceSize size = 0; - void *data = nullptr; - void *allocator = nullptr; - - void (*release)(DeviceMemoryRef &memoryRef) = nullptr; -}; - -class MemoryResource { - DeviceMemory mMemory; - char *mData = nullptr; - util::MemoryAreaTable<> table; - const char *debugName = ""; - - std::mutex mMtx; - -public: - MemoryResource() = default; - ~MemoryResource() { - if (mMemory.getHandle() != nullptr && mData != nullptr) { - vkUnmapMemory(g_vkDevice, mMemory.getHandle()); - } - } - - void initFromHost(void *data, std::size_t size) { - assert(mMemory.getHandle() == nullptr); - auto properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - mMemory = DeviceMemory::CreateExternalHostMemory(data, size, properties); - table.map(0, size); - debugName = "direct"; - } - - void initHostVisible(std::size_t size) { - assert(mMemory.getHandle() == nullptr); - auto properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - auto memory = DeviceMemory::Allocate(size, ~0, properties); - - void *data = nullptr; - Verify() << vkMapMemory(g_vkDevice, memory.getHandle(), 0, size, 0, &data); - - mMemory = std::move(memory); - table.map(0, size); - mData = reinterpret_cast(data); - debugName = "host"; - } - - void initDeviceLocal(std::size_t size) { - assert(mMemory.getHandle() == nullptr); - auto properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - mMemory = DeviceMemory::Allocate(size, ~0, properties); - table.map(0, size); - debugName = "local"; - } - - DeviceMemoryRef allocate(VkMemoryRequirements requirements) { - if ((requirements.memoryTypeBits & (1 << mMemory.getMemoryTypeIndex())) == - 0) { - util::unreachable(); - } - - std::lock_guard lock(mMtx); - - for (auto elem : table) { - auto offset = (elem.beginAddress + requirements.alignment - 1) & - ~(requirements.alignment - 1); - - if (offset >= elem.endAddress) { - continue; - } - - auto blockSize = elem.endAddress - offset; - - if (blockSize < requirements.size) { - continue; - } - - if (debugName == std::string_view{"local"}) { - std::printf("memory: allocation %s memory %lx-%lx\n", debugName, offset, - offset + requirements.size); - } - - table.unmap(offset, offset + requirements.size); - return {mMemory.getHandle(), - offset, - requirements.size, - mData, - this, - [](DeviceMemoryRef &memoryRef) { - auto self = - reinterpret_cast(memoryRef.allocator); - self->deallocate(memoryRef); - }}; - } - - util::unreachable("out of memory resource"); - } - - void deallocate(DeviceMemoryRef memory) { - std::lock_guard lock(mMtx); - table.map(memory.offset, memory.offset + memory.size); - std::printf("memory: free %s memory %lx-%lx\n", debugName, memory.offset, - memory.offset + memory.size); - } - - void dump() { - std::lock_guard lock(mMtx); - - for (auto elem : table) { - std::fprintf(stderr, "%zu - %zu\n", elem.beginAddress, elem.endAddress); - } - } - - DeviceMemoryRef getFromOffset(std::uint64_t offset, std::size_t size) { - return {mMemory.getHandle(), offset, size, nullptr, nullptr, nullptr}; - } - - explicit operator bool() const { return mMemory.getHandle() != nullptr; } -}; - -struct Semaphore { - VkSemaphore mSemaphore = VK_NULL_HANDLE; - -public: - Semaphore(const Semaphore &) = delete; - - Semaphore() = default; - Semaphore(Semaphore &&other) { *this = std::move(other); } - - Semaphore &operator=(Semaphore &&other) { - std::swap(mSemaphore, other.mSemaphore); - return *this; - } - - ~Semaphore() { - if (mSemaphore != VK_NULL_HANDLE) { - vkDestroySemaphore(g_vkDevice, mSemaphore, nullptr); - } - } - - static Semaphore Create(std::uint64_t initialValue = 0) { - VkSemaphoreTypeCreateInfo typeCreateInfo = { - VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, nullptr, - VK_SEMAPHORE_TYPE_TIMELINE, initialValue}; - - VkSemaphoreCreateInfo createInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - &typeCreateInfo, 0}; - - Semaphore result; - Verify() << vkCreateSemaphore(g_vkDevice, &createInfo, nullptr, - &result.mSemaphore); - return result; - } - - VkResult wait(std::uint64_t value, uint64_t timeout) const { - VkSemaphoreWaitInfo waitInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, - nullptr, - VK_SEMAPHORE_WAIT_ANY_BIT, - 1, - &mSemaphore, - &value}; - - return vkWaitSemaphores(g_vkDevice, &waitInfo, timeout); - } - - void signal(std::uint64_t value) { - VkSemaphoreSignalInfo signalInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, - nullptr, mSemaphore, value}; - - Verify() << vkSignalSemaphore(g_vkDevice, &signalInfo); - } - - std::uint64_t getCounterValue() const { - std::uint64_t result = 0; - Verify() << vkGetSemaphoreCounterValue(g_vkDevice, mSemaphore, &result); - return result; - } - - VkSemaphore getHandle() const { return mSemaphore; } - - bool operator==(std::nullptr_t) const { return mSemaphore == nullptr; } - bool operator!=(std::nullptr_t) const { return mSemaphore != nullptr; } -}; - -struct BinSemaphore { - VkSemaphore mSemaphore = VK_NULL_HANDLE; - -public: - BinSemaphore(const BinSemaphore &) = delete; - - BinSemaphore() = default; - BinSemaphore(BinSemaphore &&other) { *this = std::move(other); } - - BinSemaphore &operator=(BinSemaphore &&other) { - std::swap(mSemaphore, other.mSemaphore); - return *this; - } - - ~BinSemaphore() { - if (mSemaphore != VK_NULL_HANDLE) { - vkDestroySemaphore(g_vkDevice, mSemaphore, nullptr); - } - } - - static BinSemaphore Create() { - VkSemaphoreTypeCreateInfo typeCreateInfo = { - VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, nullptr, - VK_SEMAPHORE_TYPE_BINARY, 0}; - - VkSemaphoreCreateInfo createInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - &typeCreateInfo, 0}; - - BinSemaphore result; - Verify() << vkCreateSemaphore(g_vkDevice, &createInfo, nullptr, - &result.mSemaphore); - return result; - } - - VkSemaphore getHandle() const { return mSemaphore; } - - bool operator==(std::nullptr_t) const { return mSemaphore == nullptr; } -}; - -struct Fence { - VkFence mFence = VK_NULL_HANDLE; - -public: - Fence(const Fence &) = delete; - - Fence() = default; - Fence(Fence &&other) { *this = std::move(other); } - - Fence &operator=(Fence &&other) { - std::swap(mFence, other.mFence); - return *this; - } - - ~Fence() { - if (mFence != VK_NULL_HANDLE) { - vkDestroyFence(g_vkDevice, mFence, nullptr); - } - } - - static Fence Create() { - VkFenceCreateInfo fenceCreateInfo = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - nullptr, 0}; - Fence result; - Verify() << vkCreateFence(g_vkDevice, &fenceCreateInfo, nullptr, - &result.mFence); - return result; - } - - void wait() const { - Verify() << vkWaitForFences(g_vkDevice, 1, &mFence, 1, UINT64_MAX); - } - - bool isComplete() const { - return vkGetFenceStatus(g_vkDevice, mFence) == VK_SUCCESS; - } - - void reset() { vkResetFences(g_vkDevice, 1, &mFence); } - - VkFence getHandle() const { return mFence; } - - bool operator==(std::nullptr_t) const { return mFence == nullptr; } -}; - -struct CommandBuffer { - VkCommandBuffer mCmdBuffer = VK_NULL_HANDLE; - -public: - CommandBuffer(const CommandBuffer &) = delete; - - CommandBuffer() = default; - CommandBuffer(CommandBuffer &&other) { *this = std::move(other); } - - CommandBuffer &operator=(CommandBuffer &&other) { - std::swap(mCmdBuffer, other.mCmdBuffer); - return *this; - } - - CommandBuffer(VkCommandPool commandPool, - VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - VkCommandBufferUsageFlagBits flags = {}) { - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = level; - allocInfo.commandPool = commandPool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - vkAllocateCommandBuffers(g_vkDevice, &allocInfo, &commandBuffer); - - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = flags; - - vkBeginCommandBuffer(commandBuffer, &beginInfo); - } - - void end() { vkEndCommandBuffer(mCmdBuffer); } - - bool operator==(std::nullptr_t) const { return mCmdBuffer == nullptr; } - bool operator!=(std::nullptr_t) const { return mCmdBuffer != nullptr; } -}; - -class Buffer { - VkBuffer mBuffer = VK_NULL_HANDLE; - DeviceMemoryRef mMemory; - -public: - Buffer(const Buffer &) = delete; - - Buffer() = default; - Buffer(Buffer &&other) { *this = std::move(other); } - ~Buffer() { - if (mBuffer != nullptr) { - vkDestroyBuffer(g_vkDevice, mBuffer, g_vkAllocator); - - if (mMemory.release != nullptr) { - mMemory.release(mMemory); - } - } - } - - Buffer &operator=(Buffer &&other) { - std::swap(mBuffer, other.mBuffer); - std::swap(mMemory, other.mMemory); - return *this; - } - - Buffer(std::size_t size, VkBufferUsageFlags usage, - VkBufferCreateFlags flags = 0, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - std::span queueFamilyIndices = {}) { - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.flags = flags; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = sharingMode; - bufferInfo.queueFamilyIndexCount = queueFamilyIndices.size(); - bufferInfo.pQueueFamilyIndices = queueFamilyIndices.data(); - - Verify() << vkCreateBuffer(g_vkDevice, &bufferInfo, g_vkAllocator, - &mBuffer); - } - - void *getData() const { - return reinterpret_cast(mMemory.data) + mMemory.offset; - } - - static Buffer - CreateExternal(std::size_t size, VkBufferUsageFlags usage, - VkBufferCreateFlags flags = 0, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - std::span queueFamilyIndices = {}) { - VkExternalMemoryBufferCreateInfo info{ - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, nullptr, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT}; - - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.pNext = &info; - bufferInfo.flags = flags; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = sharingMode; - bufferInfo.queueFamilyIndexCount = queueFamilyIndices.size(); - bufferInfo.pQueueFamilyIndices = queueFamilyIndices.data(); - - Buffer result; - - Verify() << vkCreateBuffer(g_vkDevice, &bufferInfo, g_vkAllocator, - &result.mBuffer); - - return result; - } - - static Buffer - Allocate(MemoryResource &pool, std::size_t size, VkBufferUsageFlags usage, - VkBufferCreateFlags flags = 0, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - std::span queueFamilyIndices = {}) { - Buffer result(size, usage, flags, sharingMode, queueFamilyIndices); - result.allocateAndBind(pool); - - return result; - } - - VkBuffer getHandle() const { return mBuffer; } - [[nodiscard]] VkBuffer release() { return std::exchange(mBuffer, nullptr); } - - VkMemoryRequirements getMemoryRequirements() const { - VkMemoryRequirements requirements{}; - vkGetBufferMemoryRequirements(g_vkDevice, mBuffer, &requirements); - return requirements; - } - - void allocateAndBind(MemoryResource &pool) { - auto memory = pool.allocate(getMemoryRequirements()); - bindMemory(memory); - } - - void bindMemory(DeviceMemoryRef memory) { - Verify() << vkBindBufferMemory(g_vkDevice, mBuffer, memory.deviceMemory, - memory.offset); - mMemory = memory; - } - - void copyTo(VkCommandBuffer cmdBuffer, VkBuffer dstBuffer, - std::span regions) { - vkCmdCopyBuffer(cmdBuffer, mBuffer, dstBuffer, regions.size(), - regions.data()); - - VkDependencyInfo depInfo = {.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; - vkCmdPipelineBarrier2(cmdBuffer, &depInfo); - } - - void readFromImage(const void *address, std::uint32_t pixelSize, - TileMode tileMode, uint32_t width, uint32_t height, - uint32_t depth, uint32_t pitch) { - if (address == nullptr || tileMode == 0 || getData() == nullptr) { - return; - } - - if (tileMode == kTileModeDisplay_LinearAligned) { - // std::fprintf(stderr, "Unsupported tile mode %x\n", tileMode); - if (pitch == width) { - auto imageSize = width * height * depth * pixelSize; - std::memcpy(getData(), address, imageSize); - return; - } - - auto src = reinterpret_cast(address); - auto dst = reinterpret_cast(getData()); - - for (std::uint32_t y = 0; y < height; ++y) { - std::memcpy(dst + y * width * pixelSize, src + y * pitch * pixelSize, - width * pixelSize); - } - - return; - } - - auto src = reinterpret_cast(address); - auto dst = reinterpret_cast(getData()); - - for (uint32_t y = 0; y < height; ++y) { - auto linearOffset = - computeLinearElementByteOffset(0, y, 0, 0, pitch, 1, pixelSize, 1); - - for (std::uint32_t x = 0; x + 1 < width; x += 2) { - auto tiledOffset = computeTiledElementByteOffset( - tileMode, pixelSize * 8, x, y, 0, kMacroTileMode_1x2_16, 0, 0, 0, 0, - width, height, 1, pitch, 1); - - std::memcpy(dst + linearOffset, src + tiledOffset, pixelSize * 2); - linearOffset += pixelSize * 2; - } - } - } - - void writeAsImageTo(void *address, std::uint32_t pixelSize, TileMode tileMode, - uint32_t width, uint32_t height, uint32_t depth, - uint32_t pitch) { - if (address == nullptr || tileMode == 0) { - return; - } - - if (tileMode == kTileModeDisplay_LinearAligned) { - // std::fprintf(stderr, "Unsupported tile mode %x\n", tileMode); - if (pitch == width) { - auto bufferSize = width * height * depth * pixelSize; - std::memcpy(address, getData(), bufferSize); - return; - } - - auto src = reinterpret_cast(getData()); - auto dst = reinterpret_cast(address); - - for (std::uint32_t y = 0; y < height; ++y) { - std::memcpy(dst + y * pitch * pixelSize, src + y * width * pixelSize, - width * pixelSize); - } - return; - } - - auto src = reinterpret_cast(getData()); - auto dst = reinterpret_cast(address); - - for (uint32_t y = 0; y < height; ++y) { - for (uint32_t x = 0; x < width; ++x) { - auto tiledOffset = computeTiledElementByteOffset( - tileMode, pixelSize * 8, x, y, 0, kMacroTileMode_1x2_16, 0, 0, 0, 0, - width, height, 1, pitch, 1); - - auto linearOffset = - computeLinearElementByteOffset(x, y, 0, 0, pitch, 1, pixelSize, 1); - - std::memcpy(dst + tiledOffset, src + linearOffset, pixelSize); - } - } - } - - // const DeviceMemoryRef &getMemory() const { return mMemory; } - bool operator==(std::nullptr_t) const { return mBuffer == nullptr; } - bool operator!=(std::nullptr_t) const { return mBuffer != nullptr; } -}; - -class Image2D; - -class ImageRef { - VkImage mImage = VK_NULL_HANDLE; - VkFormat mFormat = {}; - VkImageAspectFlags mAspects = {}; - VkImageLayout *mLayout = {}; - unsigned mWidth = 0; - unsigned mHeight = 0; - unsigned mDepth = 0; - -public: - ImageRef() = default; - ImageRef(Image2D &); - - static ImageRef Create(VkImage image, VkFormat format, - VkImageAspectFlags aspects, VkImageLayout *layout, - unsigned width, unsigned height, unsigned depth) { - ImageRef result; - result.mImage = image; - result.mFormat = format; - result.mAspects = aspects; - result.mLayout = layout; - result.mWidth = width; - result.mHeight = height; - result.mDepth = depth; - return result; - } - - unsigned getWidth() const { return mWidth; } - unsigned getHeight() const { return mHeight; } - unsigned getDepth() const { return mDepth; } - VkImage getHandle() const { return mImage; } - - VkMemoryRequirements getMemoryRequirements() const { - VkMemoryRequirements requirements{}; - vkGetImageMemoryRequirements(g_vkDevice, mImage, &requirements); - return requirements; - } - - VkSubresourceLayout getSubresourceLayout(VkImageAspectFlags aspectMask, - uint32_t mipLevel = 0, - uint32_t arrayLayer = 0) const { - VkImageSubresource subResource{.aspectMask = aspectMask, - .mipLevel = mipLevel, - .arrayLayer = arrayLayer}; - VkSubresourceLayout subResourceLayout; - vkGetImageSubresourceLayout(g_vkDevice, mImage, &subResource, - &subResourceLayout); - - return subResourceLayout; - } - - void readFromBuffer(VkCommandBuffer cmdBuffer, VkBuffer buffer, - VkImageAspectFlags destAspect, - VkDeviceSize bufferOffset = 0) { - transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_GENERAL); - - VkBufferImageCopy region{}; - region.bufferOffset = bufferOffset; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = destAspect; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {mWidth, mHeight, 1}; - - vkCmdCopyBufferToImage(cmdBuffer, buffer, mImage, VK_IMAGE_LAYOUT_GENERAL, - 1, ®ion); - } - - void writeToBuffer(VkCommandBuffer cmdBuffer, VkBuffer buffer, - VkImageAspectFlags sourceAspect) { - transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_GENERAL); - - VkBufferImageCopy region{}; - region.bufferOffset = 0; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = sourceAspect; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {mWidth, mHeight, 1}; - - vkCmdCopyImageToBuffer(cmdBuffer, mImage, VK_IMAGE_LAYOUT_GENERAL, buffer, - 1, ®ion); - } - - [[nodiscard]] Buffer writeToBuffer(VkCommandBuffer cmdBuffer, - MemoryResource &pool, - VkImageAspectFlags sourceAspect) { - auto transferBuffer = Buffer::Allocate( - pool, getMemoryRequirements().size, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - writeToBuffer(cmdBuffer, transferBuffer.getHandle(), sourceAspect); - return transferBuffer; - } - - [[nodiscard]] Buffer read(VkCommandBuffer cmdBuffer, MemoryResource &pool, - const void *address, TileMode tileMode, - VkImageAspectFlags destAspect, std::uint32_t bpp, - std::size_t width = 0, std::size_t height = 0, - std::size_t pitch = 0) { - if (width == 0) { - width = mWidth; - } - if (height == 0) { - height = mHeight; - } - if (pitch == 0) { - pitch = width; - } - auto memSize = getMemoryRequirements().size; - auto transferBuffer = Buffer::Allocate( - pool, memSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - transferBuffer.readFromImage(address, bpp, tileMode, width, height, 1, - pitch); - - readFromBuffer(cmdBuffer, transferBuffer.getHandle(), destAspect); - - return transferBuffer; - } - - void transitionLayout(VkCommandBuffer cmdBuffer, VkImageLayout newLayout) { - if (*mLayout == newLayout) { - return; - } - - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = *mLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = mImage; - barrier.subresourceRange.aspectMask = mAspects; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - auto layoutToStageAccess = [](VkImageLayout layout) - -> std::pair { - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_GENERAL: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_SHADER_READ_BIT}; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; - - default: - util::unreachable("unsupported layout transition! %d", layout); - } - }; - - auto [sourceStage, sourceAccess] = layoutToStageAccess(*mLayout); - auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); - - barrier.srcAccessMask = sourceAccess; - barrier.dstAccessMask = destinationAccess; - - vkCmdPipelineBarrier(cmdBuffer, sourceStage, destinationStage, 0, 0, - nullptr, 0, nullptr, 1, &barrier); - - *mLayout = newLayout; - } -}; - -class Image2D { - VkImage mImage = VK_NULL_HANDLE; - VkFormat mFormat = {}; - VkImageAspectFlags mAspects = {}; - VkImageLayout mLayout = {}; - unsigned mWidth = 0; - unsigned mHeight = 0; - DeviceMemoryRef mMemory; - -public: - Image2D(const Image2D &) = delete; - - Image2D() = default; - Image2D(Image2D &&other) { *this = std::move(other); } - - ~Image2D() { - if (mImage != nullptr) { - vkDestroyImage(g_vkDevice, mImage, g_vkAllocator); - - if (mMemory.release != nullptr) { - mMemory.release(mMemory); - } - } - } - - Image2D &operator=(Image2D &&other) { - std::swap(mImage, other.mImage); - std::swap(mFormat, other.mFormat); - std::swap(mAspects, other.mAspects); - std::swap(mLayout, other.mLayout); - std::swap(mWidth, other.mWidth); - std::swap(mHeight, other.mHeight); - return *this; - } - - Image2D(uint32_t width, uint32_t height, VkFormat format, - VkImageUsageFlags usage, - VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, - VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - uint32_t mipLevels = 1, uint32_t arrayLevels = 1, - VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = mipLevels; - imageInfo.arrayLayers = arrayLevels; - imageInfo.format = format; - imageInfo.tiling = tiling; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usage; - imageInfo.samples = samples; - imageInfo.sharingMode = sharingMode; - - mFormat = format; - - if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - mAspects |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } else { - mAspects |= VK_IMAGE_ASPECT_COLOR_BIT; - } - - mLayout = initialLayout; - mWidth = width; - mHeight = height; - - Verify() << vkCreateImage(g_vkDevice, &imageInfo, nullptr, &mImage); - } - - static Image2D - Allocate(MemoryResource &pool, uint32_t width, uint32_t height, - VkFormat format, VkImageUsageFlags usage, - VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, - VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - uint32_t mipLevels = 1, uint32_t arrayLevels = 1, - VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { - - Image2D result(width, height, format, usage, tiling, samples, sharingMode, - mipLevels, arrayLevels, initialLayout); - - result.allocateAndBind(pool); - return result; - } - - VkImage getHandle() const { return mImage; } - [[nodiscard]] VkImage release() { return std::exchange(mImage, nullptr); } - - VkMemoryRequirements getMemoryRequirements() const { - VkMemoryRequirements requirements{}; - vkGetImageMemoryRequirements(g_vkDevice, mImage, &requirements); - return requirements; - } - - void allocateAndBind(MemoryResource &pool) { - auto memory = pool.allocate(getMemoryRequirements()); - bindMemory(memory); - } - - void bindMemory(DeviceMemoryRef memory) { - Verify() << vkBindImageMemory(g_vkDevice, mImage, memory.deviceMemory, - memory.offset); - mMemory = memory; - } - - const DeviceMemoryRef &getMemory() const { return mMemory; } - friend ImageRef; -}; - -inline ImageRef::ImageRef(Image2D &image) { - mImage = image.mImage; - mFormat = image.mFormat; - mAspects = image.mAspects; - mLayout = &image.mLayout; - mWidth = image.mWidth; - mHeight = image.mHeight; - mDepth = 1; -} +namespace amdgpu::device::vk +{ + extern VkDevice g_vkDevice; + extern VkAllocationCallbacks* g_vkAllocator; + extern std::vector> g_computeQueues; + extern std::vector> g_graphicsQueues; + + std::uint32_t findPhysicalMemoryTypeIndex(std::uint32_t typeBits, + VkMemoryPropertyFlags properties); + + class DeviceMemory + { + VkDeviceMemory mDeviceMemory = VK_NULL_HANDLE; + VkDeviceSize mSize = 0; + unsigned mMemoryTypeIndex = 0; + + public: + DeviceMemory(DeviceMemory&) = delete; + DeviceMemory(DeviceMemory&& other) { *this = std::move(other); } + DeviceMemory() = default; + + ~DeviceMemory() + { + if (mDeviceMemory != nullptr) + { + vkFreeMemory(g_vkDevice, mDeviceMemory, g_vkAllocator); + } + } + + DeviceMemory& operator=(DeviceMemory&& other) + { + std::swap(mDeviceMemory, other.mDeviceMemory); + std::swap(mSize, other.mSize); + std::swap(mMemoryTypeIndex, other.mMemoryTypeIndex); + return *this; + } + + VkDeviceMemory getHandle() const { return mDeviceMemory; } + VkDeviceSize getSize() const { return mSize; } + unsigned getMemoryTypeIndex() const { return mMemoryTypeIndex; } + + static DeviceMemory AllocateFromType(std::size_t size, + unsigned memoryTypeIndex) + { + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = size; + allocInfo.memoryTypeIndex = memoryTypeIndex; + + DeviceMemory result; + Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, + &result.mDeviceMemory); + result.mSize = size; + result.mMemoryTypeIndex = memoryTypeIndex; + return result; + } + + static DeviceMemory Allocate(std::size_t size, unsigned memoryTypeBits, + VkMemoryPropertyFlags properties) + { + return AllocateFromType( + size, findPhysicalMemoryTypeIndex(memoryTypeBits, properties)); + } + + static DeviceMemory Allocate(VkMemoryRequirements requirements, + VkMemoryPropertyFlags properties) + { + return AllocateFromType( + requirements.size, + findPhysicalMemoryTypeIndex(requirements.memoryTypeBits, properties)); + } + + static DeviceMemory CreateExternalFd(int fd, std::size_t size, + unsigned memoryTypeIndex) + { + VkImportMemoryFdInfoKHR importMemoryInfo{ + VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, + nullptr, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + fd, + }; + + VkMemoryAllocateInfo allocInfo{ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &importMemoryInfo, + .allocationSize = size, + .memoryTypeIndex = memoryTypeIndex, + }; + + DeviceMemory result; + Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, + &result.mDeviceMemory); + result.mSize = size; + result.mMemoryTypeIndex = memoryTypeIndex; + return result; + } + static DeviceMemory + CreateExternalHostMemory(void* hostPointer, std::size_t size, + VkMemoryPropertyFlags properties) + { + VkMemoryHostPointerPropertiesEXT hostPointerProperties = { + .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT}; + + auto vkGetMemoryHostPointerPropertiesEXT = + (PFN_vkGetMemoryHostPointerPropertiesEXT)vkGetDeviceProcAddr( + g_vkDevice, "vkGetMemoryHostPointerPropertiesEXT"); + + Verify() << vkGetMemoryHostPointerPropertiesEXT( + g_vkDevice, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, + hostPointer, &hostPointerProperties); + + auto memoryTypeBits = hostPointerProperties.memoryTypeBits; + + VkImportMemoryHostPointerInfoEXT importMemoryInfo = { + VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT, + nullptr, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, + hostPointer, + }; + + auto memoryTypeIndex = + findPhysicalMemoryTypeIndex(memoryTypeBits, properties); + + VkMemoryAllocateInfo allocInfo{ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &importMemoryInfo, + .allocationSize = size, + .memoryTypeIndex = memoryTypeIndex, + }; + + DeviceMemory result; + Verify() << vkAllocateMemory(g_vkDevice, &allocInfo, g_vkAllocator, + &result.mDeviceMemory); + result.mSize = size; + result.mMemoryTypeIndex = memoryTypeIndex; + return result; + } + + void* map(VkDeviceSize offset, VkDeviceSize size) + { + void* result = 0; + Verify() << vkMapMemory(g_vkDevice, mDeviceMemory, offset, size, 0, + &result); + + return result; + } + + void unmap() { vkUnmapMemory(g_vkDevice, mDeviceMemory); } + }; + + struct DeviceMemoryRef + { + VkDeviceMemory deviceMemory = VK_NULL_HANDLE; + VkDeviceSize offset = 0; + VkDeviceSize size = 0; + void* data = nullptr; + void* allocator = nullptr; + + void (*release)(DeviceMemoryRef& memoryRef) = nullptr; + }; + + class MemoryResource + { + DeviceMemory mMemory; + char* mData = nullptr; + util::MemoryAreaTable<> table; + const char* debugName = ""; + + std::mutex mMtx; + + public: + MemoryResource() = default; + ~MemoryResource() + { + if (mMemory.getHandle() != nullptr && mData != nullptr) + { + vkUnmapMemory(g_vkDevice, mMemory.getHandle()); + } + } + + void initFromHost(void* data, std::size_t size) + { + assert(mMemory.getHandle() == nullptr); + auto properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + mMemory = DeviceMemory::CreateExternalHostMemory(data, size, properties); + table.map(0, size); + debugName = "direct"; + } + + void initHostVisible(std::size_t size) + { + assert(mMemory.getHandle() == nullptr); + auto properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + auto memory = DeviceMemory::Allocate(size, ~0, properties); + + void* data = nullptr; + Verify() << vkMapMemory(g_vkDevice, memory.getHandle(), 0, size, 0, &data); + + mMemory = std::move(memory); + table.map(0, size); + mData = reinterpret_cast(data); + debugName = "host"; + } + + void initDeviceLocal(std::size_t size) + { + assert(mMemory.getHandle() == nullptr); + auto properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + mMemory = DeviceMemory::Allocate(size, ~0, properties); + table.map(0, size); + debugName = "local"; + } + + DeviceMemoryRef allocate(VkMemoryRequirements requirements) + { + if ((requirements.memoryTypeBits & (1 << mMemory.getMemoryTypeIndex())) == + 0) + { + util::unreachable(); + } + + std::lock_guard lock(mMtx); + + for (auto elem : table) + { + auto offset = (elem.beginAddress + requirements.alignment - 1) & + ~(requirements.alignment - 1); + + if (offset >= elem.endAddress) + { + continue; + } + + auto blockSize = elem.endAddress - offset; + + if (blockSize < requirements.size) + { + continue; + } + + if (debugName == std::string_view{"local"}) + { + std::printf("memory: allocation %s memory %lx-%lx\n", debugName, offset, + offset + requirements.size); + } + + table.unmap(offset, offset + requirements.size); + return {mMemory.getHandle(), + offset, + requirements.size, + mData, + this, + [](DeviceMemoryRef& memoryRef) { + auto self = + reinterpret_cast(memoryRef.allocator); + self->deallocate(memoryRef); + }}; + } + + util::unreachable("out of memory resource"); + } + + void deallocate(DeviceMemoryRef memory) + { + std::lock_guard lock(mMtx); + table.map(memory.offset, memory.offset + memory.size); + std::printf("memory: free %s memory %lx-%lx\n", debugName, memory.offset, + memory.offset + memory.size); + } + + void dump() + { + std::lock_guard lock(mMtx); + + for (auto elem : table) + { + std::fprintf(stderr, "%zu - %zu\n", elem.beginAddress, elem.endAddress); + } + } + + DeviceMemoryRef getFromOffset(std::uint64_t offset, std::size_t size) + { + return {mMemory.getHandle(), offset, size, nullptr, nullptr, nullptr}; + } + + explicit operator bool() const { return mMemory.getHandle() != nullptr; } + }; + + struct Semaphore + { + VkSemaphore mSemaphore = VK_NULL_HANDLE; + + public: + Semaphore(const Semaphore&) = delete; + + Semaphore() = default; + Semaphore(Semaphore&& other) { *this = std::move(other); } + + Semaphore& operator=(Semaphore&& other) + { + std::swap(mSemaphore, other.mSemaphore); + return *this; + } + + ~Semaphore() + { + if (mSemaphore != VK_NULL_HANDLE) + { + vkDestroySemaphore(g_vkDevice, mSemaphore, nullptr); + } + } + + static Semaphore Create(std::uint64_t initialValue = 0) + { + VkSemaphoreTypeCreateInfo typeCreateInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, nullptr, + VK_SEMAPHORE_TYPE_TIMELINE, initialValue}; + + VkSemaphoreCreateInfo createInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + &typeCreateInfo, 0}; + + Semaphore result; + Verify() << vkCreateSemaphore(g_vkDevice, &createInfo, nullptr, + &result.mSemaphore); + return result; + } + + VkResult wait(std::uint64_t value, uint64_t timeout) const + { + VkSemaphoreWaitInfo waitInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + nullptr, + VK_SEMAPHORE_WAIT_ANY_BIT, + 1, + &mSemaphore, + &value}; + + return vkWaitSemaphores(g_vkDevice, &waitInfo, timeout); + } + + void signal(std::uint64_t value) + { + VkSemaphoreSignalInfo signalInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + nullptr, mSemaphore, value}; + + Verify() << vkSignalSemaphore(g_vkDevice, &signalInfo); + } + + std::uint64_t getCounterValue() const + { + std::uint64_t result = 0; + Verify() << vkGetSemaphoreCounterValue(g_vkDevice, mSemaphore, &result); + return result; + } + + VkSemaphore getHandle() const { return mSemaphore; } + + bool operator==(std::nullptr_t) const { return mSemaphore == nullptr; } + bool operator!=(std::nullptr_t) const { return mSemaphore != nullptr; } + }; + + struct BinSemaphore + { + VkSemaphore mSemaphore = VK_NULL_HANDLE; + + public: + BinSemaphore(const BinSemaphore&) = delete; + + BinSemaphore() = default; + BinSemaphore(BinSemaphore&& other) { *this = std::move(other); } + + BinSemaphore& operator=(BinSemaphore&& other) + { + std::swap(mSemaphore, other.mSemaphore); + return *this; + } + + ~BinSemaphore() + { + if (mSemaphore != VK_NULL_HANDLE) + { + vkDestroySemaphore(g_vkDevice, mSemaphore, nullptr); + } + } + + static BinSemaphore Create() + { + VkSemaphoreTypeCreateInfo typeCreateInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, nullptr, + VK_SEMAPHORE_TYPE_BINARY, 0}; + + VkSemaphoreCreateInfo createInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + &typeCreateInfo, 0}; + + BinSemaphore result; + Verify() << vkCreateSemaphore(g_vkDevice, &createInfo, nullptr, + &result.mSemaphore); + return result; + } + + VkSemaphore getHandle() const { return mSemaphore; } + + bool operator==(std::nullptr_t) const { return mSemaphore == nullptr; } + }; + + struct Fence + { + VkFence mFence = VK_NULL_HANDLE; + + public: + Fence(const Fence&) = delete; + + Fence() = default; + Fence(Fence&& other) { *this = std::move(other); } + + Fence& operator=(Fence&& other) + { + std::swap(mFence, other.mFence); + return *this; + } + + ~Fence() + { + if (mFence != VK_NULL_HANDLE) + { + vkDestroyFence(g_vkDevice, mFence, nullptr); + } + } + + static Fence Create() + { + VkFenceCreateInfo fenceCreateInfo = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + nullptr, 0}; + Fence result; + Verify() << vkCreateFence(g_vkDevice, &fenceCreateInfo, nullptr, + &result.mFence); + return result; + } + + void wait() const + { + Verify() << vkWaitForFences(g_vkDevice, 1, &mFence, 1, UINT64_MAX); + } + + bool isComplete() const + { + return vkGetFenceStatus(g_vkDevice, mFence) == VK_SUCCESS; + } + + void reset() { vkResetFences(g_vkDevice, 1, &mFence); } + + VkFence getHandle() const { return mFence; } + + bool operator==(std::nullptr_t) const { return mFence == nullptr; } + }; + + struct CommandBuffer + { + VkCommandBuffer mCmdBuffer = VK_NULL_HANDLE; + + public: + CommandBuffer(const CommandBuffer&) = delete; + + CommandBuffer() = default; + CommandBuffer(CommandBuffer&& other) { *this = std::move(other); } + + CommandBuffer& operator=(CommandBuffer&& other) + { + std::swap(mCmdBuffer, other.mCmdBuffer); + return *this; + } + + CommandBuffer(VkCommandPool commandPool, + VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + VkCommandBufferUsageFlagBits flags = {}) + { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = level; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(g_vkDevice, &allocInfo, &commandBuffer); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = flags; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + } + + void end() { vkEndCommandBuffer(mCmdBuffer); } + + bool operator==(std::nullptr_t) const { return mCmdBuffer == nullptr; } + bool operator!=(std::nullptr_t) const { return mCmdBuffer != nullptr; } + }; + + class Buffer + { + VkBuffer mBuffer = VK_NULL_HANDLE; + DeviceMemoryRef mMemory; + + public: + Buffer(const Buffer&) = delete; + + Buffer() = default; + Buffer(Buffer&& other) { *this = std::move(other); } + ~Buffer() + { + if (mBuffer != nullptr) + { + vkDestroyBuffer(g_vkDevice, mBuffer, g_vkAllocator); + + if (mMemory.release != nullptr) + { + mMemory.release(mMemory); + } + } + } + + Buffer& operator=(Buffer&& other) + { + std::swap(mBuffer, other.mBuffer); + std::swap(mMemory, other.mMemory); + return *this; + } + + Buffer(std::size_t size, VkBufferUsageFlags usage, + VkBufferCreateFlags flags = 0, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + std::span queueFamilyIndices = {}) + { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.flags = flags; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = sharingMode; + bufferInfo.queueFamilyIndexCount = queueFamilyIndices.size(); + bufferInfo.pQueueFamilyIndices = queueFamilyIndices.data(); + + Verify() << vkCreateBuffer(g_vkDevice, &bufferInfo, g_vkAllocator, + &mBuffer); + } + + void* getData() const + { + return reinterpret_cast(mMemory.data) + mMemory.offset; + } + + static Buffer + CreateExternal(std::size_t size, VkBufferUsageFlags usage, + VkBufferCreateFlags flags = 0, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + std::span queueFamilyIndices = {}) + { + VkExternalMemoryBufferCreateInfo info{ + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, nullptr, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT}; + + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.pNext = &info; + bufferInfo.flags = flags; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = sharingMode; + bufferInfo.queueFamilyIndexCount = queueFamilyIndices.size(); + bufferInfo.pQueueFamilyIndices = queueFamilyIndices.data(); + + Buffer result; + + Verify() << vkCreateBuffer(g_vkDevice, &bufferInfo, g_vkAllocator, + &result.mBuffer); + + return result; + } + + static Buffer + Allocate(MemoryResource& pool, std::size_t size, VkBufferUsageFlags usage, + VkBufferCreateFlags flags = 0, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + std::span queueFamilyIndices = {}) + { + Buffer result(size, usage, flags, sharingMode, queueFamilyIndices); + result.allocateAndBind(pool); + + return result; + } + + VkBuffer getHandle() const { return mBuffer; } + [[nodiscard]] VkBuffer release() { return std::exchange(mBuffer, nullptr); } + + VkMemoryRequirements getMemoryRequirements() const + { + VkMemoryRequirements requirements{}; + vkGetBufferMemoryRequirements(g_vkDevice, mBuffer, &requirements); + return requirements; + } + + void allocateAndBind(MemoryResource& pool) + { + auto memory = pool.allocate(getMemoryRequirements()); + bindMemory(memory); + } + + void bindMemory(DeviceMemoryRef memory) + { + Verify() << vkBindBufferMemory(g_vkDevice, mBuffer, memory.deviceMemory, + memory.offset); + mMemory = memory; + } + + void copyTo(VkCommandBuffer cmdBuffer, VkBuffer dstBuffer, + std::span regions) + { + vkCmdCopyBuffer(cmdBuffer, mBuffer, dstBuffer, regions.size(), + regions.data()); + + VkDependencyInfo depInfo = {.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + vkCmdPipelineBarrier2(cmdBuffer, &depInfo); + } + + void readFromImage(const void* address, std::uint32_t pixelSize, + TileMode tileMode, uint32_t width, uint32_t height, + uint32_t depth, uint32_t pitch) + { + if (address == nullptr || tileMode == 0 || getData() == nullptr) + { + return; + } + + if (tileMode == kTileModeDisplay_LinearAligned) + { + // std::fprintf(stderr, "Unsupported tile mode %x\n", tileMode); + if (pitch == width) + { + auto imageSize = width * height * depth * pixelSize; + std::memcpy(getData(), address, imageSize); + return; + } + + auto src = reinterpret_cast(address); + auto dst = reinterpret_cast(getData()); + + for (std::uint32_t y = 0; y < height; ++y) + { + std::memcpy(dst + y * width * pixelSize, src + y * pitch * pixelSize, + width * pixelSize); + } + + return; + } + + auto src = reinterpret_cast(address); + auto dst = reinterpret_cast(getData()); + + for (uint32_t y = 0; y < height; ++y) + { + auto linearOffset = + computeLinearElementByteOffset(0, y, 0, 0, pitch, 1, pixelSize, 1); + + for (std::uint32_t x = 0; x + 1 < width; x += 2) + { + auto tiledOffset = computeTiledElementByteOffset( + tileMode, pixelSize * 8, x, y, 0, kMacroTileMode_1x2_16, 0, 0, 0, 0, + width, height, 1, pitch, 1); + + std::memcpy(dst + linearOffset, src + tiledOffset, pixelSize * 2); + linearOffset += pixelSize * 2; + } + } + } + + void writeAsImageTo(void* address, std::uint32_t pixelSize, TileMode tileMode, + uint32_t width, uint32_t height, uint32_t depth, + uint32_t pitch) + { + if (address == nullptr || tileMode == 0) + { + return; + } + + if (tileMode == kTileModeDisplay_LinearAligned) + { + // std::fprintf(stderr, "Unsupported tile mode %x\n", tileMode); + if (pitch == width) + { + auto bufferSize = width * height * depth * pixelSize; + std::memcpy(address, getData(), bufferSize); + return; + } + + auto src = reinterpret_cast(getData()); + auto dst = reinterpret_cast(address); + + for (std::uint32_t y = 0; y < height; ++y) + { + std::memcpy(dst + y * pitch * pixelSize, src + y * width * pixelSize, + width * pixelSize); + } + return; + } + + auto src = reinterpret_cast(getData()); + auto dst = reinterpret_cast(address); + + for (uint32_t y = 0; y < height; ++y) + { + for (uint32_t x = 0; x < width; ++x) + { + auto tiledOffset = computeTiledElementByteOffset( + tileMode, pixelSize * 8, x, y, 0, kMacroTileMode_1x2_16, 0, 0, 0, 0, + width, height, 1, pitch, 1); + + auto linearOffset = + computeLinearElementByteOffset(x, y, 0, 0, pitch, 1, pixelSize, 1); + + std::memcpy(dst + tiledOffset, src + linearOffset, pixelSize); + } + } + } + + // const DeviceMemoryRef &getMemory() const { return mMemory; } + bool operator==(std::nullptr_t) const { return mBuffer == nullptr; } + bool operator!=(std::nullptr_t) const { return mBuffer != nullptr; } + }; + + class Image2D; + + class ImageRef + { + VkImage mImage = VK_NULL_HANDLE; + VkFormat mFormat = {}; + VkImageAspectFlags mAspects = {}; + VkImageLayout* mLayout = {}; + unsigned mWidth = 0; + unsigned mHeight = 0; + unsigned mDepth = 0; + + public: + ImageRef() = default; + ImageRef(Image2D&); + + static ImageRef Create(VkImage image, VkFormat format, + VkImageAspectFlags aspects, VkImageLayout* layout, + unsigned width, unsigned height, unsigned depth) + { + ImageRef result; + result.mImage = image; + result.mFormat = format; + result.mAspects = aspects; + result.mLayout = layout; + result.mWidth = width; + result.mHeight = height; + result.mDepth = depth; + return result; + } + + unsigned getWidth() const { return mWidth; } + unsigned getHeight() const { return mHeight; } + unsigned getDepth() const { return mDepth; } + VkImage getHandle() const { return mImage; } + + VkMemoryRequirements getMemoryRequirements() const + { + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(g_vkDevice, mImage, &requirements); + return requirements; + } + + VkSubresourceLayout getSubresourceLayout(VkImageAspectFlags aspectMask, + uint32_t mipLevel = 0, + uint32_t arrayLayer = 0) const + { + VkImageSubresource subResource{.aspectMask = aspectMask, + .mipLevel = mipLevel, + .arrayLayer = arrayLayer}; + VkSubresourceLayout subResourceLayout; + vkGetImageSubresourceLayout(g_vkDevice, mImage, &subResource, + &subResourceLayout); + + return subResourceLayout; + } + + void readFromBuffer(VkCommandBuffer cmdBuffer, VkBuffer buffer, + VkImageAspectFlags destAspect, + VkDeviceSize bufferOffset = 0) + { + transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_GENERAL); + + VkBufferImageCopy region{}; + region.bufferOffset = bufferOffset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = destAspect; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {mWidth, mHeight, 1}; + + vkCmdCopyBufferToImage(cmdBuffer, buffer, mImage, VK_IMAGE_LAYOUT_GENERAL, + 1, ®ion); + } + + void writeToBuffer(VkCommandBuffer cmdBuffer, VkBuffer buffer, + VkImageAspectFlags sourceAspect) + { + transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_GENERAL); + + VkBufferImageCopy region{}; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = sourceAspect; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {mWidth, mHeight, 1}; + + vkCmdCopyImageToBuffer(cmdBuffer, mImage, VK_IMAGE_LAYOUT_GENERAL, buffer, + 1, ®ion); + } + + [[nodiscard]] Buffer writeToBuffer(VkCommandBuffer cmdBuffer, + MemoryResource& pool, + VkImageAspectFlags sourceAspect) + { + auto transferBuffer = Buffer::Allocate( + pool, getMemoryRequirements().size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + + writeToBuffer(cmdBuffer, transferBuffer.getHandle(), sourceAspect); + return transferBuffer; + } + + [[nodiscard]] Buffer read(VkCommandBuffer cmdBuffer, MemoryResource& pool, + const void* address, TileMode tileMode, + VkImageAspectFlags destAspect, std::uint32_t bpp, + std::size_t width = 0, std::size_t height = 0, + std::size_t pitch = 0) + { + if (width == 0) + { + width = mWidth; + } + if (height == 0) + { + height = mHeight; + } + if (pitch == 0) + { + pitch = width; + } + auto memSize = getMemoryRequirements().size; + auto transferBuffer = Buffer::Allocate( + pool, memSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + + transferBuffer.readFromImage(address, bpp, tileMode, width, height, 1, + pitch); + + readFromBuffer(cmdBuffer, transferBuffer.getHandle(), destAspect); + + return transferBuffer; + } + + void transitionLayout(VkCommandBuffer cmdBuffer, VkImageLayout newLayout) + { + if (*mLayout == newLayout) + { + return; + } + + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = *mLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = mImage; + barrier.subresourceRange.aspectMask = mAspects; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + auto layoutToStageAccess = [](VkImageLayout layout) + -> std::pair { + switch (layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_GENERAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT}; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; + + default: + util::unreachable("unsupported layout transition! %d", layout); + } + }; + + auto [sourceStage, sourceAccess] = layoutToStageAccess(*mLayout); + auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); + + barrier.srcAccessMask = sourceAccess; + barrier.dstAccessMask = destinationAccess; + + vkCmdPipelineBarrier(cmdBuffer, sourceStage, destinationStage, 0, 0, + nullptr, 0, nullptr, 1, &barrier); + + *mLayout = newLayout; + } + }; + + class Image2D + { + VkImage mImage = VK_NULL_HANDLE; + VkFormat mFormat = {}; + VkImageAspectFlags mAspects = {}; + VkImageLayout mLayout = {}; + unsigned mWidth = 0; + unsigned mHeight = 0; + DeviceMemoryRef mMemory; + + public: + Image2D(const Image2D&) = delete; + + Image2D() = default; + Image2D(Image2D&& other) { *this = std::move(other); } + + ~Image2D() + { + if (mImage != nullptr) + { + vkDestroyImage(g_vkDevice, mImage, g_vkAllocator); + + if (mMemory.release != nullptr) + { + mMemory.release(mMemory); + } + } + } + + Image2D& operator=(Image2D&& other) + { + std::swap(mImage, other.mImage); + std::swap(mFormat, other.mFormat); + std::swap(mAspects, other.mAspects); + std::swap(mLayout, other.mLayout); + std::swap(mWidth, other.mWidth); + std::swap(mHeight, other.mHeight); + return *this; + } + + Image2D(uint32_t width, uint32_t height, VkFormat format, + VkImageUsageFlags usage, + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + uint32_t mipLevels = 1, uint32_t arrayLevels = 1, + VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) + { + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = mipLevels; + imageInfo.arrayLayers = arrayLevels; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = samples; + imageInfo.sharingMode = sharingMode; + + mFormat = format; + + if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) + { + mAspects |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + else + { + mAspects |= VK_IMAGE_ASPECT_COLOR_BIT; + } + + mLayout = initialLayout; + mWidth = width; + mHeight = height; + + Verify() << vkCreateImage(g_vkDevice, &imageInfo, nullptr, &mImage); + } + + static Image2D + Allocate(MemoryResource& pool, uint32_t width, uint32_t height, + VkFormat format, VkImageUsageFlags usage, + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + uint32_t mipLevels = 1, uint32_t arrayLevels = 1, + VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) + { + + Image2D result(width, height, format, usage, tiling, samples, sharingMode, + mipLevels, arrayLevels, initialLayout); + + result.allocateAndBind(pool); + return result; + } + + VkImage getHandle() const { return mImage; } + [[nodiscard]] VkImage release() { return std::exchange(mImage, nullptr); } + + VkMemoryRequirements getMemoryRequirements() const + { + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(g_vkDevice, mImage, &requirements); + return requirements; + } + + void allocateAndBind(MemoryResource& pool) + { + auto memory = pool.allocate(getMemoryRequirements()); + bindMemory(memory); + } + + void bindMemory(DeviceMemoryRef memory) + { + Verify() << vkBindImageMemory(g_vkDevice, mImage, memory.deviceMemory, + memory.offset); + mMemory = memory; + } + + const DeviceMemoryRef& getMemory() const { return mMemory; } + friend ImageRef; + }; + + inline ImageRef::ImageRef(Image2D& image) + { + mImage = image.mImage; + mFormat = image.mFormat; + mAspects = image.mAspects; + mLayout = &image.mLayout; + mWidth = image.mWidth; + mHeight = image.mHeight; + mDepth = 1; + } } // namespace amdgpu::device::vk diff --git a/hw/amdgpu/device/src/device.cpp b/hw/amdgpu/device/src/device.cpp index 3bb16416..1fd442b9 100644 --- a/hw/amdgpu/device/src/device.cpp +++ b/hw/amdgpu/device/src/device.cpp @@ -41,324 +41,368 @@ using namespace amdgpu; using namespace amdgpu::device; static const bool kUseDirectMemory = false; -static amdgpu::bridge::BridgeHeader *g_bridge; +static amdgpu::bridge::BridgeHeader* g_bridge; -void *g_rwMemory; +void* g_rwMemory; std::size_t g_memorySize; std::uint64_t g_memoryBase; RemoteMemory g_hostMemory; -namespace amdgpu::device::vk { -VkDevice g_vkDevice = VK_NULL_HANDLE; -VkAllocationCallbacks *g_vkAllocator = nullptr; -std::vector> g_computeQueues; -std::vector> g_graphicsQueues; - -static VkPhysicalDeviceMemoryProperties g_physicalMemoryProperties; -static VkPhysicalDeviceProperties g_physicalDeviceProperties; -std::uint32_t findPhysicalMemoryTypeIndex(std::uint32_t typeBits, - VkMemoryPropertyFlags properties) { - typeBits &= (1 << g_physicalMemoryProperties.memoryTypeCount) - 1; - - while (typeBits != 0) { - auto typeIndex = std::countr_zero(typeBits); - - if ((g_physicalMemoryProperties.memoryTypes[typeIndex].propertyFlags & - properties) == properties) { - return typeIndex; - } - - typeBits &= ~(1 << typeIndex); - } - - util::unreachable("Failed to find memory type with properties %x", - properties); -} +namespace amdgpu::device::vk +{ + VkDevice g_vkDevice = VK_NULL_HANDLE; + VkAllocationCallbacks* g_vkAllocator = nullptr; + std::vector> g_computeQueues; + std::vector> g_graphicsQueues; + + static VkPhysicalDeviceMemoryProperties g_physicalMemoryProperties; + static VkPhysicalDeviceProperties g_physicalDeviceProperties; + std::uint32_t findPhysicalMemoryTypeIndex(std::uint32_t typeBits, + VkMemoryPropertyFlags properties) + { + typeBits &= (1 << g_physicalMemoryProperties.memoryTypeCount) - 1; + + while (typeBits != 0) + { + auto typeIndex = std::countr_zero(typeBits); + + if ((g_physicalMemoryProperties.memoryTypes[typeIndex].propertyFlags & + properties) == properties) + { + return typeIndex; + } + + typeBits &= ~(1 << typeIndex); + } + + util::unreachable("Failed to find memory type with properties %x", + properties); + } } // namespace amdgpu::device::vk -namespace amdgpu::device { -GpuScheduler &getComputeQueueScheduler() { - static GpuScheduler result{vk::g_computeQueues, "compute"}; - return result; -} -GpuScheduler &getGraphicsQueueScheduler() { - static GpuScheduler result{vk::g_graphicsQueues, "graphics"}; - return result; -} - -Scheduler &getCpuScheduler() { - static Scheduler result{4}; - return result; -} - -GpuScheduler &getGpuScheduler(ProcessQueue queue) { - // TODO: compute scheduler load factor - if ((queue & ProcessQueue::Transfer) == ProcessQueue::Transfer) { - return getComputeQueueScheduler(); - } - - if ((queue & ProcessQueue::Compute) == ProcessQueue::Compute) { - return getComputeQueueScheduler(); - } - - if ((queue & ProcessQueue::Graphics) == ProcessQueue::Graphics) { - return getGraphicsQueueScheduler(); - } - - std::abort(); -} +namespace amdgpu::device +{ + GpuScheduler& getComputeQueueScheduler() + { + static GpuScheduler result{vk::g_computeQueues, "compute"}; + return result; + } + GpuScheduler& getGraphicsQueueScheduler() + { + static GpuScheduler result{vk::g_graphicsQueues, "graphics"}; + return result; + } + + Scheduler& getCpuScheduler() + { + static Scheduler result{4}; + return result; + } + + GpuScheduler& getGpuScheduler(ProcessQueue queue) + { + // TODO: compute scheduler load factor + if ((queue & ProcessQueue::Transfer) == ProcessQueue::Transfer) + { + return getComputeQueueScheduler(); + } + + if ((queue & ProcessQueue::Compute) == ProcessQueue::Compute) + { + return getComputeQueueScheduler(); + } + + if ((queue & ProcessQueue::Graphics) == ProcessQueue::Graphics) + { + return getGraphicsQueueScheduler(); + } + + std::abort(); + } } // namespace amdgpu::device static VkResult _vkCreateShadersEXT(VkDevice device, uint32_t createInfoCount, - const VkShaderCreateInfoEXT *pCreateInfos, - const VkAllocationCallbacks *pAllocator, - VkShaderEXT *pShaders) { - static auto fn = (PFN_vkCreateShadersEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCreateShadersEXT"); - return fn(device, createInfoCount, pCreateInfos, pAllocator, pShaders); + const VkShaderCreateInfoEXT* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkShaderEXT* pShaders) +{ + static auto fn = (PFN_vkCreateShadersEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCreateShadersEXT"); + return fn(device, createInfoCount, pCreateInfos, pAllocator, pShaders); } static void _vkDestroyShaderEXT(VkDevice device, VkShaderEXT shader, - const VkAllocationCallbacks *pAllocator) { - static auto fn = (PFN_vkDestroyShaderEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkDestroyShaderEXT"); + const VkAllocationCallbacks* pAllocator) +{ + static auto fn = (PFN_vkDestroyShaderEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkDestroyShaderEXT"); - fn(device, shader, pAllocator); + fn(device, shader, pAllocator); } static void _vkCmdBindShadersEXT(VkCommandBuffer commandBuffer, - uint32_t stageCount, - const VkShaderStageFlagBits *pStages, - const VkShaderEXT *pShaders) { - static PFN_vkCmdBindShadersEXT fn = - (PFN_vkCmdBindShadersEXT)vkGetDeviceProcAddr(vk::g_vkDevice, - "vkCmdBindShadersEXT"); - - return fn(commandBuffer, stageCount, pStages, pShaders); + uint32_t stageCount, + const VkShaderStageFlagBits* pStages, + const VkShaderEXT* pShaders) +{ + static PFN_vkCmdBindShadersEXT fn = + (PFN_vkCmdBindShadersEXT)vkGetDeviceProcAddr(vk::g_vkDevice, + "vkCmdBindShadersEXT"); + + return fn(commandBuffer, stageCount, pStages, pShaders); } static void _vkCmdSetColorBlendEnableEXT(VkCommandBuffer commandBuffer, - uint32_t firstAttachment, - uint32_t attachmentCount, - const VkBool32 *pColorBlendEnables) { - static PFN_vkCmdSetColorBlendEnableEXT fn; - - if (fn == nullptr) { - fn = (PFN_vkCmdSetColorBlendEnableEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetColorBlendEnableEXT"); - } - - return fn(commandBuffer, firstAttachment, attachmentCount, - pColorBlendEnables); + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkBool32* pColorBlendEnables) +{ + static PFN_vkCmdSetColorBlendEnableEXT fn; + + if (fn == nullptr) + { + fn = (PFN_vkCmdSetColorBlendEnableEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetColorBlendEnableEXT"); + } + + return fn(commandBuffer, firstAttachment, attachmentCount, + pColorBlendEnables); } static void _vkCmdSetColorBlendEquationEXT( - VkCommandBuffer commandBuffer, uint32_t firstAttachment, - uint32_t attachmentCount, - const VkColorBlendEquationEXT *pColorBlendEquations) { - static PFN_vkCmdSetColorBlendEquationEXT fn; - - if (fn == nullptr) { - fn = (PFN_vkCmdSetColorBlendEquationEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetColorBlendEquationEXT"); - } - - return fn(commandBuffer, firstAttachment, attachmentCount, - pColorBlendEquations); + VkCommandBuffer commandBuffer, uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendEquationEXT* pColorBlendEquations) +{ + static PFN_vkCmdSetColorBlendEquationEXT fn; + + if (fn == nullptr) + { + fn = (PFN_vkCmdSetColorBlendEquationEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetColorBlendEquationEXT"); + } + + return fn(commandBuffer, firstAttachment, attachmentCount, + pColorBlendEquations); } static void _vkCmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer, - VkBool32 depthClampEnable) { - static PFN_vkCmdSetDepthClampEnableEXT fn; + VkBool32 depthClampEnable) +{ + static PFN_vkCmdSetDepthClampEnableEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetDepthClampEnableEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetDepthClampEnableEXT"); - } + if (fn == nullptr) + { + fn = (PFN_vkCmdSetDepthClampEnableEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetDepthClampEnableEXT"); + } - return fn(commandBuffer, depthClampEnable); + return fn(commandBuffer, depthClampEnable); } static void _vkCmdSetLogicOpEXT(VkCommandBuffer commandBuffer, - VkLogicOp logicOp) { - static PFN_vkCmdSetLogicOpEXT fn; + VkLogicOp logicOp) +{ + static PFN_vkCmdSetLogicOpEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetLogicOpEXT)vkGetDeviceProcAddr(vk::g_vkDevice, - "vkCmdSetLogicOpEXT"); - } + if (fn == nullptr) + { + fn = (PFN_vkCmdSetLogicOpEXT)vkGetDeviceProcAddr(vk::g_vkDevice, + "vkCmdSetLogicOpEXT"); + } - return fn(commandBuffer, logicOp); + return fn(commandBuffer, logicOp); } static void _vkCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, - VkPolygonMode polygonMode) { - static PFN_vkCmdSetPolygonModeEXT fn; + VkPolygonMode polygonMode) +{ + static PFN_vkCmdSetPolygonModeEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetPolygonModeEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetPolygonModeEXT"); - } + if (fn == nullptr) + { + fn = (PFN_vkCmdSetPolygonModeEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetPolygonModeEXT"); + } - return fn(commandBuffer, polygonMode); + return fn(commandBuffer, polygonMode); } static void _vkCmdSetLogicOpEnableEXT(VkCommandBuffer commandBuffer, - VkBool32 logicOpEnable) { - static PFN_vkCmdSetLogicOpEnableEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetLogicOpEnableEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetLogicOpEnableEXT"); - } - - return fn(commandBuffer, logicOpEnable); + VkBool32 logicOpEnable) +{ + static PFN_vkCmdSetLogicOpEnableEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetLogicOpEnableEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetLogicOpEnableEXT"); + } + + return fn(commandBuffer, logicOpEnable); } static void _vkCmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer, - VkSampleCountFlagBits rasterizationSamples) { - static PFN_vkCmdSetRasterizationSamplesEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetRasterizationSamplesEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetRasterizationSamplesEXT"); - } - - return fn(commandBuffer, rasterizationSamples); + VkSampleCountFlagBits rasterizationSamples) +{ + static PFN_vkCmdSetRasterizationSamplesEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetRasterizationSamplesEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetRasterizationSamplesEXT"); + } + + return fn(commandBuffer, rasterizationSamples); } static void _vkCmdSetSampleMaskEXT(VkCommandBuffer commandBuffer, - VkSampleCountFlagBits samples, - const VkSampleMask *pSampleMask) { - static PFN_vkCmdSetSampleMaskEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetSampleMaskEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetSampleMaskEXT"); - } - - return fn(commandBuffer, samples, pSampleMask); + VkSampleCountFlagBits samples, + const VkSampleMask* pSampleMask) +{ + static PFN_vkCmdSetSampleMaskEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetSampleMaskEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetSampleMaskEXT"); + } + + return fn(commandBuffer, samples, pSampleMask); } static void _vkCmdSetTessellationDomainOriginEXT(VkCommandBuffer commandBuffer, - VkTessellationDomainOrigin domainOrigin) { - static PFN_vkCmdSetTessellationDomainOriginEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetTessellationDomainOriginEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetTessellationDomainOriginEXT"); - } - - return fn(commandBuffer, domainOrigin); + VkTessellationDomainOrigin domainOrigin) +{ + static PFN_vkCmdSetTessellationDomainOriginEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetTessellationDomainOriginEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetTessellationDomainOriginEXT"); + } + + return fn(commandBuffer, domainOrigin); } static void _vkCmdSetAlphaToCoverageEnableEXT(VkCommandBuffer commandBuffer, - VkBool32 alphaToCoverageEnable) { - static PFN_vkCmdSetAlphaToCoverageEnableEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetAlphaToCoverageEnableEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetAlphaToCoverageEnableEXT"); - } - - return fn(commandBuffer, alphaToCoverageEnable); + VkBool32 alphaToCoverageEnable) +{ + static PFN_vkCmdSetAlphaToCoverageEnableEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetAlphaToCoverageEnableEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetAlphaToCoverageEnableEXT"); + } + + return fn(commandBuffer, alphaToCoverageEnable); } static void _vkCmdSetVertexInputEXT( - VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, - const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions, - uint32_t vertexAttributeDescriptionCount, - const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions) { - static PFN_vkCmdSetVertexInputEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetVertexInputEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetVertexInputEXT"); - } - - return fn(commandBuffer, vertexBindingDescriptionCount, - pVertexBindingDescriptions, vertexAttributeDescriptionCount, - pVertexAttributeDescriptions); + VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, + const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, + uint32_t vertexAttributeDescriptionCount, + const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions) +{ + static PFN_vkCmdSetVertexInputEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetVertexInputEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetVertexInputEXT"); + } + + return fn(commandBuffer, vertexBindingDescriptionCount, + pVertexBindingDescriptions, vertexAttributeDescriptionCount, + pVertexAttributeDescriptions); } static void _vkCmdSetColorWriteMaskEXT(VkCommandBuffer commandBuffer, - uint32_t firstAttachment, uint32_t attachmentCount, - const VkColorComponentFlags *pColorWriteMasks) { - static PFN_vkCmdSetColorWriteMaskEXT fn; - if (fn == nullptr) { - fn = (PFN_vkCmdSetColorWriteMaskEXT)vkGetDeviceProcAddr( - vk::g_vkDevice, "vkCmdSetColorWriteMaskEXT"); - } - - return fn(commandBuffer, firstAttachment, attachmentCount, pColorWriteMasks); + uint32_t firstAttachment, uint32_t attachmentCount, + const VkColorComponentFlags* pColorWriteMasks) +{ + static PFN_vkCmdSetColorWriteMaskEXT fn; + if (fn == nullptr) + { + fn = (PFN_vkCmdSetColorWriteMaskEXT)vkGetDeviceProcAddr( + vk::g_vkDevice, "vkCmdSetColorWriteMaskEXT"); + } + + return fn(commandBuffer, firstAttachment, attachmentCount, pColorWriteMasks); } static util::MemoryAreaTable memoryAreaTable; void device::setVkDevice(VkDevice device, - VkPhysicalDeviceMemoryProperties memProperties, - VkPhysicalDeviceProperties devProperties) { - vk::g_vkDevice = device; - vk::g_physicalMemoryProperties = memProperties; - vk::g_physicalDeviceProperties = devProperties; + VkPhysicalDeviceMemoryProperties memProperties, + VkPhysicalDeviceProperties devProperties) +{ + vk::g_vkDevice = device; + vk::g_physicalMemoryProperties = memProperties; + vk::g_physicalDeviceProperties = devProperties; } -static VkBlendFactor blendMultiplierToVkBlendFactor(BlendMultiplier mul) { - switch (mul) { - case kBlendMultiplierZero: - return VK_BLEND_FACTOR_ZERO; - case kBlendMultiplierOne: - return VK_BLEND_FACTOR_ONE; - case kBlendMultiplierSrcColor: - return VK_BLEND_FACTOR_SRC_COLOR; - case kBlendMultiplierOneMinusSrcColor: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - case kBlendMultiplierSrcAlpha: - return VK_BLEND_FACTOR_SRC_ALPHA; - case kBlendMultiplierOneMinusSrcAlpha: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - case kBlendMultiplierDestAlpha: - return VK_BLEND_FACTOR_DST_ALPHA; - case kBlendMultiplierOneMinusDestAlpha: - return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; - case kBlendMultiplierDestColor: - return VK_BLEND_FACTOR_DST_COLOR; - case kBlendMultiplierOneMinusDestColor: - return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; - case kBlendMultiplierSrcAlphaSaturate: - return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; - case kBlendMultiplierConstantColor: - return VK_BLEND_FACTOR_CONSTANT_COLOR; - case kBlendMultiplierOneMinusConstantColor: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; - case kBlendMultiplierSrc1Color: - return VK_BLEND_FACTOR_SRC1_COLOR; - case kBlendMultiplierInverseSrc1Color: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; - case kBlendMultiplierSrc1Alpha: - return VK_BLEND_FACTOR_SRC1_ALPHA; - case kBlendMultiplierInverseSrc1Alpha: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; - case kBlendMultiplierConstantAlpha: - return VK_BLEND_FACTOR_CONSTANT_ALPHA; - case kBlendMultiplierOneMinusConstantAlpha: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; - } - - util::unreachable(); +static VkBlendFactor blendMultiplierToVkBlendFactor(BlendMultiplier mul) +{ + switch (mul) + { + case kBlendMultiplierZero: + return VK_BLEND_FACTOR_ZERO; + case kBlendMultiplierOne: + return VK_BLEND_FACTOR_ONE; + case kBlendMultiplierSrcColor: + return VK_BLEND_FACTOR_SRC_COLOR; + case kBlendMultiplierOneMinusSrcColor: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case kBlendMultiplierSrcAlpha: + return VK_BLEND_FACTOR_SRC_ALPHA; + case kBlendMultiplierOneMinusSrcAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case kBlendMultiplierDestAlpha: + return VK_BLEND_FACTOR_DST_ALPHA; + case kBlendMultiplierOneMinusDestAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case kBlendMultiplierDestColor: + return VK_BLEND_FACTOR_DST_COLOR; + case kBlendMultiplierOneMinusDestColor: + return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case kBlendMultiplierSrcAlphaSaturate: + return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + case kBlendMultiplierConstantColor: + return VK_BLEND_FACTOR_CONSTANT_COLOR; + case kBlendMultiplierOneMinusConstantColor: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + case kBlendMultiplierSrc1Color: + return VK_BLEND_FACTOR_SRC1_COLOR; + case kBlendMultiplierInverseSrc1Color: + return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; + case kBlendMultiplierSrc1Alpha: + return VK_BLEND_FACTOR_SRC1_ALPHA; + case kBlendMultiplierInverseSrc1Alpha: + return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; + case kBlendMultiplierConstantAlpha: + return VK_BLEND_FACTOR_CONSTANT_ALPHA; + case kBlendMultiplierOneMinusConstantAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + } + + util::unreachable(); } -static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { - switch (func) { - case kBlendFuncAdd: - return VK_BLEND_OP_ADD; - case kBlendFuncSubtract: - return VK_BLEND_OP_SUBTRACT; - case kBlendFuncMin: - return VK_BLEND_OP_MIN; - case kBlendFuncMax: - return VK_BLEND_OP_MAX; - case kBlendFuncReverseSubtract: - return VK_BLEND_OP_REVERSE_SUBTRACT; - } - - util::unreachable(); +static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) +{ + switch (func) + { + case kBlendFuncAdd: + return VK_BLEND_OP_ADD; + case kBlendFuncSubtract: + return VK_BLEND_OP_SUBTRACT; + case kBlendFuncMin: + return VK_BLEND_OP_MIN; + case kBlendFuncMax: + return VK_BLEND_OP_MAX; + case kBlendFuncReverseSubtract: + return VK_BLEND_OP_REVERSE_SUBTRACT; + } + + util::unreachable(); } -#define GNM_GET_FIELD(src, registername, field) \ - (((src) & (GNM_##registername##__##field##__MASK)) >> \ - (GNM_##registername##__##field##__SHIFT)) +#define GNM_GET_FIELD(src, registername, field) \ + (((src) & (GNM_##registername##__##field##__MASK)) >> \ + (GNM_##registername##__##field##__SHIFT)) #define mmSQ_BUF_RSRC_WORD0 0x23C0 #define GNM_SQ_BUF_RSRC_WORD0__BASE_ADDRESS__MASK 0xffffffffL // size:32 @@ -366,8 +410,8 @@ static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { #define mmSQ_BUF_RSRC_WORD1 0x23C1 #define GNM_SQ_BUF_RSRC_WORD1__BASE_ADDRESS_HI__MASK 0x00000fffL // size:12 -#define GNM_SQ_BUF_RSRC_WORD1__STRIDE__MASK 0x3fff0000L // size:14 -#define GNM_SQ_BUF_RSRC_WORD1__SWIZZLE_ENABLE__MASK 0x80000000L // size: 1 +#define GNM_SQ_BUF_RSRC_WORD1__STRIDE__MASK 0x3fff0000L // size:14 +#define GNM_SQ_BUF_RSRC_WORD1__SWIZZLE_ENABLE__MASK 0x80000000L // size: 1 #define GNM_SQ_BUF_RSRC_WORD1__BASE_ADDRESS_HI__SHIFT 0 #define GNM_SQ_BUF_RSRC_WORD1__STRIDE__SHIFT 16 #define GNM_SQ_BUF_RSRC_WORD1__SWIZZLE_ENABLE__SHIFT 31 @@ -377,13 +421,13 @@ static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { #define GNM_SQ_BUF_RSRC_WORD2__NUM_RECORDS__SHIFT 0 #define mmSQ_BUF_RSRC_WORD3 0x23C3 -#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_X__MASK 0x00000007L // size: 3 -#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Y__MASK 0x00000038L // size: 3 -#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Z__MASK 0x000001c0L // size: 3 -#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_W__MASK 0x00000e00L // size: 3 +#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_X__MASK 0x00000007L // size: 3 +#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Y__MASK 0x00000038L // size: 3 +#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Z__MASK 0x000001c0L // size: 3 +#define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_W__MASK 0x00000e00L // size: 3 #define GNM_SQ_BUF_RSRC_WORD3__ELEMENT_SIZE__MASK 0x00180000L // size: 2 #define GNM_SQ_BUF_RSRC_WORD3__INDEX_STRIDE__MASK 0x00600000L // size: 2 -#define GNM_SQ_BUF_RSRC_WORD3__TYPE__MASK 0xc0000000L // size: 2 +#define GNM_SQ_BUF_RSRC_WORD3__TYPE__MASK 0xc0000000L // size: 2 #define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_X__SHIFT 0 #define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Y__SHIFT 3 #define GNM_SQ_BUF_RSRC_WORD3__DST_SEL_Z__SHIFT 6 @@ -393,7 +437,7 @@ static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { #define GNM_SQ_BUF_RSRC_WORD3__TYPE__SHIFT 30 #define mmCB_COLOR0_PITCH 0xA319 -#define GNM_CB_COLOR0_PITCH__TILE_MAX__MASK 0x000007ffL // size:11 +#define GNM_CB_COLOR0_PITCH__TILE_MAX__MASK 0x000007ffL // size:11 #define GNM_CB_COLOR0_PITCH__FMASK_TILE_MAX__MASK 0x7ff00000L // size:11 #define GNM_CB_COLOR0_PITCH__TILE_MAX__SHIFT 0 #define GNM_CB_COLOR0_PITCH__FMASK_TILE_MAX__SHIFT 20 @@ -404,18 +448,18 @@ static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { #define mmCB_COLOR0_VIEW 0xA31B #define GNM_CB_COLOR0_VIEW__SLICE_START__MASK 0x000007ffL // size:11 -#define GNM_CB_COLOR0_VIEW__SLICE_MAX__MASK 0x00ffe000L // size:11 +#define GNM_CB_COLOR0_VIEW__SLICE_MAX__MASK 0x00ffe000L // size:11 #define GNM_CB_COLOR0_VIEW__SLICE_START__SHIFT 0 #define GNM_CB_COLOR0_VIEW__SLICE_MAX__SHIFT 13 #define mmCB_COLOR0_INFO 0xA31C -#define GNM_CB_COLOR0_INFO__FAST_CLEAR__MASK 0x00002000L // size: 1 -#define GNM_CB_COLOR0_INFO__COMPRESSION__MASK 0x00004000L // size: 1 -#define GNM_CB_COLOR0_INFO__CMASK_IS_LINEAR__MASK 0x00080000L // size: 1 +#define GNM_CB_COLOR0_INFO__FAST_CLEAR__MASK 0x00002000L // size: 1 +#define GNM_CB_COLOR0_INFO__COMPRESSION__MASK 0x00004000L // size: 1 +#define GNM_CB_COLOR0_INFO__CMASK_IS_LINEAR__MASK 0x00080000L // size: 1 #define GNM_CB_COLOR0_INFO__FMASK_COMPRESSION_MODE__MASK 0x0C000000L // size: 2 -#define GNM_CB_COLOR0_INFO__DCC_ENABLE__MASK 0x10000000L // size: 1 -#define GNM_CB_COLOR0_INFO__CMASK_ADDR_TYPE__MASK 0x60000000L // size: 2 -#define GNM_CB_COLOR0_INFO__ALT_TILE_MODE__MASK 0x80000000L // size: 1 +#define GNM_CB_COLOR0_INFO__DCC_ENABLE__MASK 0x10000000L // size: 1 +#define GNM_CB_COLOR0_INFO__CMASK_ADDR_TYPE__MASK 0x60000000L // size: 2 +#define GNM_CB_COLOR0_INFO__ALT_TILE_MODE__MASK 0x80000000L // size: 1 #define GNM_CB_COLOR0_INFO__FAST_CLEAR__SHIFT 13 #define GNM_CB_COLOR0_INFO__COMPRESSION__SHIFT 14 #define GNM_CB_COLOR0_INFO__CMASK_IS_LINEAR__SHIFT 19 @@ -429,36 +473,38 @@ static VkBlendOp blendFuncToVkBlendOp(BlendFunc func) { #define GNM_CB_COLOR0_INFO__ARRAY_MODE__MASK 0x0f << 8 #define GNM_CB_COLOR0_INFO__ARRAY_MODE__SHIFT 8 -enum { - ARRAY_LINEAR_GENERAL = 0x00, // Unaligned linear array - ARRAY_LINEAR_ALIGNED = 0x01, // Aligned linear array +enum +{ + ARRAY_LINEAR_GENERAL = 0x00, // Unaligned linear array + ARRAY_LINEAR_ALIGNED = 0x01, // Aligned linear array }; #define GNM_CB_COLOR0_INFO__NUMBER_TYPE__MASK 0x07 << 12 #define GNM_CB_COLOR0_INFO__NUMBER_TYPE__SHIFT 12 -enum { - NUMBER_UNORM = 0x00, // unsigned repeating fraction (urf): range [0..1], scale - // factor (2^n)-1 - NUMBER_SNORM = 0x01, // Microsoft-style signed rf: range [-1..1], scale factor - // (2^(n-1))-1 - NUMBER_USCALED = 0x02, // unsigned integer, converted to float in shader: - // range [0..(2^n)-1] - NUMBER_SSCALED = 0x03, // signed integer, converted to float in shader: range - // [-2^(n-1)..2^(n-1)-1] - NUMBER_UINT = 0x04, // zero-extended bit field, int in shader: not blendable - // or filterable - NUMBER_SINT = 0x05, // sign-extended bit field, int in shader: not blendable - // or filterable - NUMBER_SRGB = 0x06, // gamma corrected, range [0..1] (only suported for 8-bit - // components (always rounds color channels) - NUMBER_FLOAT = - 0x07, // floating point, depends on component size: 32-bit: IEEE float, - // SE8M23, bias 127, range (- 2^129..2^129) 24-bit: Depth float, - // E4M20, bias 15, range [0..1] 16-bit: Short float SE5M10, bias 15, - // range (-2^17..2^17) 11-bit: Packed float, E5M6 bias 15, range - // [0..2^17) 10-bit: Packed float, E5M5 bias 15, range [0..2^17) all - // other component sizes are treated as UINT +enum +{ + NUMBER_UNORM = 0x00, // unsigned repeating fraction (urf): range [0..1], scale + // factor (2^n)-1 + NUMBER_SNORM = 0x01, // Microsoft-style signed rf: range [-1..1], scale factor + // (2^(n-1))-1 + NUMBER_USCALED = 0x02, // unsigned integer, converted to float in shader: + // range [0..(2^n)-1] + NUMBER_SSCALED = 0x03, // signed integer, converted to float in shader: range + // [-2^(n-1)..2^(n-1)-1] + NUMBER_UINT = 0x04, // zero-extended bit field, int in shader: not blendable + // or filterable + NUMBER_SINT = 0x05, // sign-extended bit field, int in shader: not blendable + // or filterable + NUMBER_SRGB = 0x06, // gamma corrected, range [0..1] (only suported for 8-bit + // components (always rounds color channels) + NUMBER_FLOAT = + 0x07, // floating point, depends on component size: 32-bit: IEEE float, + // SE8M23, bias 127, range (- 2^129..2^129) 24-bit: Depth float, + // E4M20, bias 15, range [0..1] 16-bit: Short float SE5M10, bias 15, + // range (-2^17..2^17) 11-bit: Packed float, E5M6 bias 15, range + // [0..2^17) 10-bit: Packed float, E5M5 bias 15, range [0..2^17) all + // other component sizes are treated as UINT }; #define GNM_CB_COLOR0_INFO__READ_SIZE__MASK 1 << 15 @@ -497,11 +543,12 @@ enum { // #define GNM_CB_COLOR0_INFO__COMP_SWAP__MASK 0x03 << 16 #define GNM_CB_COLOR0_INFO__COMP_SWAP__SHIFT 16 -enum { - SWAP_STD = 0x00, // standard little-endian comp order - SWAP_ALT = 0x01, // alternate components or order - SWAP_STD_REV = 0x02, // reverses SWAP_STD order - SWAP_ALT_REV = 0x03, // reverses SWAP_ALT order +enum +{ + SWAP_STD = 0x00, // standard little-endian comp order + SWAP_ALT = 0x01, // alternate components or order + SWAP_STD_REV = 0x02, // reverses SWAP_STD order + SWAP_ALT_REV = 0x03, // reverses SWAP_ALT order }; // Specifies whether to clamp source data to the render target range prior to @@ -554,11 +601,11 @@ enum { #define GNM_CB_COLOR0_INFO__SOURCE_FORMAT__SHIFT 27 #define mmCB_COLOR0_ATTRIB 0xA31D -#define GNM_CB_COLOR0_ATTRIB__TILE_MODE_INDEX__MASK 0x0000001fL // size: 5 +#define GNM_CB_COLOR0_ATTRIB__TILE_MODE_INDEX__MASK 0x0000001fL // size: 5 #define GNM_CB_COLOR0_ATTRIB__FMASK_TILE_MODE_INDEX__MASK 0x000003e0L // size: 5 -#define GNM_CB_COLOR0_ATTRIB__NUM_SAMPLES__MASK 0x00007000L // size: 3 -#define GNM_CB_COLOR0_ATTRIB__NUM_FRAGMENTS__MASK 0x00018000L // size: 2 -#define GNM_CB_COLOR0_ATTRIB__FORCE_DST_ALPHA_1__MASK 0x00020000L // size: 1 +#define GNM_CB_COLOR0_ATTRIB__NUM_SAMPLES__MASK 0x00007000L // size: 3 +#define GNM_CB_COLOR0_ATTRIB__NUM_FRAGMENTS__MASK 0x00018000L // size: 2 +#define GNM_CB_COLOR0_ATTRIB__FORCE_DST_ALPHA_1__MASK 0x00020000L // size: 1 #define GNM_CB_COLOR0_ATTRIB__TILE_MODE_INDEX__SHIFT 0 #define GNM_CB_COLOR0_ATTRIB__FMASK_TILE_MODE_INDEX__SHIFT 5 #define GNM_CB_COLOR0_ATTRIB__NUM_SAMPLES__SHIFT 12 @@ -566,17 +613,17 @@ enum { #define GNM_CB_COLOR0_ATTRIB__FORCE_DST_ALPHA_1__SHIFT 17 #define mmCB_COLOR0_DCC_CONTROL 0xA31E -#define GNM_CB_COLOR0_DCC_CONTROL__OVERWRITE_COMBINER_DISABLE__MASK \ - 0x00000001L // size: 1 -#define GNM_CB_COLOR0_DCC_CONTROL__MAX_UNCOMPRESSED_BLOCK_SIZE__MASK \ - 0x0000000cL // size: 2 -#define GNM_CB_COLOR0_DCC_CONTROL__MIN_COMPRESSED_BLOCK_SIZE__MASK \ - 0x00000010L // size: 1 -#define GNM_CB_COLOR0_DCC_CONTROL__MAX_COMPRESSED_BLOCK_SIZE__MASK \ - 0x00000060L // size: 2 +#define GNM_CB_COLOR0_DCC_CONTROL__OVERWRITE_COMBINER_DISABLE__MASK \ + 0x00000001L // size: 1 +#define GNM_CB_COLOR0_DCC_CONTROL__MAX_UNCOMPRESSED_BLOCK_SIZE__MASK \ + 0x0000000cL // size: 2 +#define GNM_CB_COLOR0_DCC_CONTROL__MIN_COMPRESSED_BLOCK_SIZE__MASK \ + 0x00000010L // size: 1 +#define GNM_CB_COLOR0_DCC_CONTROL__MAX_COMPRESSED_BLOCK_SIZE__MASK \ + 0x00000060L // size: 2 #define GNM_CB_COLOR0_DCC_CONTROL__COLOR_TRANSFORM__MASK 0x00000180L // size: 2 -#define GNM_CB_COLOR0_DCC_CONTROL__INDEPENDENT_64B_BLOCKS__MASK \ - 0x00000200L // size: 1 +#define GNM_CB_COLOR0_DCC_CONTROL__INDEPENDENT_64B_BLOCKS__MASK \ + 0x00000200L // size: 1 #define GNM_CB_COLOR0_DCC_CONTROL__OVERWRITE_COMBINER_DISABLE__SHIFT 0 #define GNM_CB_COLOR0_DCC_CONTROL__MAX_UNCOMPRESSED_BLOCK_SIZE__SHIFT 2 #define GNM_CB_COLOR0_DCC_CONTROL__MIN_COMPRESSED_BLOCK_SIZE__SHIFT 4 @@ -614,171 +661,185 @@ enum { static constexpr auto CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK = genMask(0, 5); static constexpr auto CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK), 3); + genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK), 3); static constexpr auto CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK), 5); + genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK), 5); static constexpr auto CB_BLEND0_CONTROL_OPACITY_WEIGHT_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK), 1); + genMask(getMaskEnd(CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK), 1); static constexpr auto CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_OPACITY_WEIGHT_MASK) + 2, 5); + genMask(getMaskEnd(CB_BLEND0_CONTROL_OPACITY_WEIGHT_MASK) + 2, 5); static constexpr auto CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK), 3); + genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK), 3); static constexpr auto CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK), 5); + genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK), 5); static constexpr auto CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK), 1); + genMask(getMaskEnd(CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK), 1); static constexpr auto CB_BLEND0_CONTROL_BLEND_ENABLE_MASK = - genMask(getMaskEnd(CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK), 1); - -struct ColorBuffer { - std::uint64_t base; - std::uint8_t format; - std::uint8_t tileModeIndex; - - void setRegister(unsigned index, std::uint32_t value) { - switch (index) { - case CB_COLOR0_BASE - CB_COLOR0_BASE: - base = static_cast(value) << 8; - // std::printf(" * base = %lx\n", base); - break; - - case CB_COLOR0_PITCH - CB_COLOR0_BASE: { - auto pitchTileMax = GNM_GET_FIELD(value, CB_COLOR0_PITCH, TILE_MAX); - auto pitchFmaskTileMax = - GNM_GET_FIELD(value, CB_COLOR0_PITCH, FMASK_TILE_MAX); - // std::printf(" * TILE_MAX = %lx\n", pitchTileMax); - // std::printf(" * FMASK_TILE_MAX = %lx\n", pitchFmaskTileMax); - break; - } - case CB_COLOR0_SLICE - CB_COLOR0_BASE: { // SLICE - auto sliceTileMax = GNM_GET_FIELD(value, CB_COLOR0_SLICE, TILE_MAX); - // std::printf(" * TILE_MAX = %lx\n", sliceTileMax); - break; - } - case CB_COLOR0_VIEW - CB_COLOR0_BASE: { // VIEW - auto viewSliceStart = GNM_GET_FIELD(value, CB_COLOR0_VIEW, SLICE_START); - auto viewSliceMax = GNM_GET_FIELD(value, CB_COLOR0_VIEW, SLICE_MAX); - - // std::printf(" * SLICE_START = %lx\n", viewSliceStart); - // std::printf(" * SLICE_MAX = %lx\n", viewSliceMax); - break; - } - case CB_COLOR0_INFO - CB_COLOR0_BASE: { // INFO - auto fastClear = GNM_GET_FIELD(value, CB_COLOR0_INFO, FAST_CLEAR); - auto compression = GNM_GET_FIELD(value, CB_COLOR0_INFO, COMPRESSION); - auto cmaskIsLinear = - GNM_GET_FIELD(value, CB_COLOR0_INFO, CMASK_IS_LINEAR); - auto fmaskCompressionMode = - GNM_GET_FIELD(value, CB_COLOR0_INFO, FMASK_COMPRESSION_MODE); - auto dccEnable = GNM_GET_FIELD(value, CB_COLOR0_INFO, DCC_ENABLE); - auto cmaskAddrType = - GNM_GET_FIELD(value, CB_COLOR0_INFO, CMASK_ADDR_TYPE); - auto altTileMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ALT_TILE_MODE); - format = GNM_GET_FIELD(value, CB_COLOR0_INFO, FORMAT); - auto arrayMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ARRAY_MODE); - auto numberType = GNM_GET_FIELD(value, CB_COLOR0_INFO, NUMBER_TYPE); - auto readSize = GNM_GET_FIELD(value, CB_COLOR0_INFO, READ_SIZE); - auto compSwap = GNM_GET_FIELD(value, CB_COLOR0_INFO, COMP_SWAP); - auto blendClamp = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_CLAMP); - auto clearColor = GNM_GET_FIELD(value, CB_COLOR0_INFO, CLEAR_COLOR); - auto blendBypass = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_BYPASS); - auto blendFloat32 = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_FLOAT32); - auto simpleFloat = GNM_GET_FIELD(value, CB_COLOR0_INFO, SIMPLE_FLOAT); - auto roundMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ROUND_MODE); - auto sourceFormat = GNM_GET_FIELD(value, CB_COLOR0_INFO, SOURCE_FORMAT); - - // std::printf(" * FAST_CLEAR = %lu\n", fastClear); - // std::printf(" * COMPRESSION = %lu\n", compression); - // std::printf(" * CMASK_IS_LINEAR = %lu\n", cmaskIsLinear); - // std::printf(" * FMASK_COMPRESSION_MODE = %lu\n", - // fmaskCompressionMode); std::printf(" * DCC_ENABLE = %lu\n", - // dccEnable); std::printf(" * CMASK_ADDR_TYPE = %lu\n", cmaskAddrType); - // std::printf(" * ALT_TILE_MODE = %lu\n", altTileMode); - // std::printf(" * FORMAT = %x\n", format); - // std::printf(" * ARRAY_MODE = %u\n", arrayMode); - // std::printf(" * NUMBER_TYPE = %u\n", numberType); - // std::printf(" * READ_SIZE = %u\n", readSize); - // std::printf(" * COMP_SWAP = %u\n", compSwap); - // std::printf(" * BLEND_CLAMP = %u\n", blendClamp); - // std::printf(" * CLEAR_COLOR = %u\n", clearColor); - // std::printf(" * BLEND_BYPASS = %u\n", blendBypass); - // std::printf(" * BLEND_FLOAT32 = %u\n", blendFloat32); - // std::printf(" * SIMPLE_FLOAT = %u\n", simpleFloat); - // std::printf(" * ROUND_MODE = %u\n", roundMode); - // std::printf(" * SOURCE_FORMAT = %u\n", sourceFormat); - break; - } - - case CB_COLOR0_ATTRIB - CB_COLOR0_BASE: { // ATTRIB - tileModeIndex = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, TILE_MODE_INDEX); - auto fmaskTileModeIndex = - GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX); - auto numSamples = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, NUM_SAMPLES); - auto numFragments = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, NUM_FRAGMENTS); - auto forceDstAlpha1 = - GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, FORCE_DST_ALPHA_1); - - // std::printf(" * TILE_MODE_INDEX = %u\n", tileModeIndex); - // std::printf(" * FMASK_TILE_MODE_INDEX = %lu\n", fmaskTileModeIndex); - // std::printf(" * NUM_SAMPLES = %lu\n", numSamples); - // std::printf(" * NUM_FRAGMENTS = %lu\n", numFragments); - // std::printf(" * FORCE_DST_ALPHA_1 = %lu\n", forceDstAlpha1); - break; - } - case CB_COLOR0_CMASK - CB_COLOR0_BASE: { // CMASK - auto cmaskBase = GNM_GET_FIELD(value, CB_COLOR0_CMASK, BASE_256B) << 8; - // std::printf(" * cmaskBase = %lx\n", cmaskBase); - break; - } - case CB_COLOR0_CMASK_SLICE - CB_COLOR0_BASE: { // CMASK_SLICE - auto cmaskSliceTileMax = - GNM_GET_FIELD(value, CB_COLOR0_CMASK_SLICE, TILE_MAX); - // std::printf(" * cmaskSliceTileMax = %lx\n", cmaskSliceTileMax); - break; - } - case CB_COLOR0_FMASK - CB_COLOR0_BASE: { // FMASK - auto fmaskBase = GNM_GET_FIELD(value, CB_COLOR0_FMASK, BASE_256B) << 8; - // std::printf(" * fmaskBase = %lx\n", fmaskBase); - break; - } - case CB_COLOR0_FMASK_SLICE - CB_COLOR0_BASE: { // FMASK_SLICE - auto fmaskSliceTileMax = - GNM_GET_FIELD(value, CB_COLOR0_FMASK_SLICE, TILE_MAX); - // std::printf(" * fmaskSliceTileMax = %lx\n", fmaskSliceTileMax); - break; - } - case CB_COLOR0_CLEAR_WORD0 - CB_COLOR0_BASE: // CLEAR_WORD0 - break; - case CB_COLOR1_CLEAR_WORD0 - CB_COLOR0_BASE: // CLEAR_WORD1 - break; - } - } + genMask(getMaskEnd(CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK), 1); + +struct ColorBuffer +{ + std::uint64_t base; + std::uint8_t format; + std::uint8_t tileModeIndex; + + void setRegister(unsigned index, std::uint32_t value) + { + switch (index) + { + case CB_COLOR0_BASE - CB_COLOR0_BASE: + base = static_cast(value) << 8; + // std::printf(" * base = %lx\n", base); + break; + + case CB_COLOR0_PITCH - CB_COLOR0_BASE: + { + auto pitchTileMax = GNM_GET_FIELD(value, CB_COLOR0_PITCH, TILE_MAX); + auto pitchFmaskTileMax = + GNM_GET_FIELD(value, CB_COLOR0_PITCH, FMASK_TILE_MAX); + // std::printf(" * TILE_MAX = %lx\n", pitchTileMax); + // std::printf(" * FMASK_TILE_MAX = %lx\n", pitchFmaskTileMax); + break; + } + case CB_COLOR0_SLICE - CB_COLOR0_BASE: + { // SLICE + auto sliceTileMax = GNM_GET_FIELD(value, CB_COLOR0_SLICE, TILE_MAX); + // std::printf(" * TILE_MAX = %lx\n", sliceTileMax); + break; + } + case CB_COLOR0_VIEW - CB_COLOR0_BASE: + { // VIEW + auto viewSliceStart = GNM_GET_FIELD(value, CB_COLOR0_VIEW, SLICE_START); + auto viewSliceMax = GNM_GET_FIELD(value, CB_COLOR0_VIEW, SLICE_MAX); + + // std::printf(" * SLICE_START = %lx\n", viewSliceStart); + // std::printf(" * SLICE_MAX = %lx\n", viewSliceMax); + break; + } + case CB_COLOR0_INFO - CB_COLOR0_BASE: + { // INFO + auto fastClear = GNM_GET_FIELD(value, CB_COLOR0_INFO, FAST_CLEAR); + auto compression = GNM_GET_FIELD(value, CB_COLOR0_INFO, COMPRESSION); + auto cmaskIsLinear = + GNM_GET_FIELD(value, CB_COLOR0_INFO, CMASK_IS_LINEAR); + auto fmaskCompressionMode = + GNM_GET_FIELD(value, CB_COLOR0_INFO, FMASK_COMPRESSION_MODE); + auto dccEnable = GNM_GET_FIELD(value, CB_COLOR0_INFO, DCC_ENABLE); + auto cmaskAddrType = + GNM_GET_FIELD(value, CB_COLOR0_INFO, CMASK_ADDR_TYPE); + auto altTileMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ALT_TILE_MODE); + format = GNM_GET_FIELD(value, CB_COLOR0_INFO, FORMAT); + auto arrayMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ARRAY_MODE); + auto numberType = GNM_GET_FIELD(value, CB_COLOR0_INFO, NUMBER_TYPE); + auto readSize = GNM_GET_FIELD(value, CB_COLOR0_INFO, READ_SIZE); + auto compSwap = GNM_GET_FIELD(value, CB_COLOR0_INFO, COMP_SWAP); + auto blendClamp = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_CLAMP); + auto clearColor = GNM_GET_FIELD(value, CB_COLOR0_INFO, CLEAR_COLOR); + auto blendBypass = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_BYPASS); + auto blendFloat32 = GNM_GET_FIELD(value, CB_COLOR0_INFO, BLEND_FLOAT32); + auto simpleFloat = GNM_GET_FIELD(value, CB_COLOR0_INFO, SIMPLE_FLOAT); + auto roundMode = GNM_GET_FIELD(value, CB_COLOR0_INFO, ROUND_MODE); + auto sourceFormat = GNM_GET_FIELD(value, CB_COLOR0_INFO, SOURCE_FORMAT); + + // std::printf(" * FAST_CLEAR = %lu\n", fastClear); + // std::printf(" * COMPRESSION = %lu\n", compression); + // std::printf(" * CMASK_IS_LINEAR = %lu\n", cmaskIsLinear); + // std::printf(" * FMASK_COMPRESSION_MODE = %lu\n", + // fmaskCompressionMode); std::printf(" * DCC_ENABLE = %lu\n", + // dccEnable); std::printf(" * CMASK_ADDR_TYPE = %lu\n", cmaskAddrType); + // std::printf(" * ALT_TILE_MODE = %lu\n", altTileMode); + // std::printf(" * FORMAT = %x\n", format); + // std::printf(" * ARRAY_MODE = %u\n", arrayMode); + // std::printf(" * NUMBER_TYPE = %u\n", numberType); + // std::printf(" * READ_SIZE = %u\n", readSize); + // std::printf(" * COMP_SWAP = %u\n", compSwap); + // std::printf(" * BLEND_CLAMP = %u\n", blendClamp); + // std::printf(" * CLEAR_COLOR = %u\n", clearColor); + // std::printf(" * BLEND_BYPASS = %u\n", blendBypass); + // std::printf(" * BLEND_FLOAT32 = %u\n", blendFloat32); + // std::printf(" * SIMPLE_FLOAT = %u\n", simpleFloat); + // std::printf(" * ROUND_MODE = %u\n", roundMode); + // std::printf(" * SOURCE_FORMAT = %u\n", sourceFormat); + break; + } + + case CB_COLOR0_ATTRIB - CB_COLOR0_BASE: + { // ATTRIB + tileModeIndex = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, TILE_MODE_INDEX); + auto fmaskTileModeIndex = + GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX); + auto numSamples = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, NUM_SAMPLES); + auto numFragments = GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, NUM_FRAGMENTS); + auto forceDstAlpha1 = + GNM_GET_FIELD(value, CB_COLOR0_ATTRIB, FORCE_DST_ALPHA_1); + + // std::printf(" * TILE_MODE_INDEX = %u\n", tileModeIndex); + // std::printf(" * FMASK_TILE_MODE_INDEX = %lu\n", fmaskTileModeIndex); + // std::printf(" * NUM_SAMPLES = %lu\n", numSamples); + // std::printf(" * NUM_FRAGMENTS = %lu\n", numFragments); + // std::printf(" * FORCE_DST_ALPHA_1 = %lu\n", forceDstAlpha1); + break; + } + case CB_COLOR0_CMASK - CB_COLOR0_BASE: + { // CMASK + auto cmaskBase = GNM_GET_FIELD(value, CB_COLOR0_CMASK, BASE_256B) << 8; + // std::printf(" * cmaskBase = %lx\n", cmaskBase); + break; + } + case CB_COLOR0_CMASK_SLICE - CB_COLOR0_BASE: + { // CMASK_SLICE + auto cmaskSliceTileMax = + GNM_GET_FIELD(value, CB_COLOR0_CMASK_SLICE, TILE_MAX); + // std::printf(" * cmaskSliceTileMax = %lx\n", cmaskSliceTileMax); + break; + } + case CB_COLOR0_FMASK - CB_COLOR0_BASE: + { // FMASK + auto fmaskBase = GNM_GET_FIELD(value, CB_COLOR0_FMASK, BASE_256B) << 8; + // std::printf(" * fmaskBase = %lx\n", fmaskBase); + break; + } + case CB_COLOR0_FMASK_SLICE - CB_COLOR0_BASE: + { // FMASK_SLICE + auto fmaskSliceTileMax = + GNM_GET_FIELD(value, CB_COLOR0_FMASK_SLICE, TILE_MAX); + // std::printf(" * fmaskSliceTileMax = %lx\n", fmaskSliceTileMax); + break; + } + case CB_COLOR0_CLEAR_WORD0 - CB_COLOR0_BASE: // CLEAR_WORD0 + break; + case CB_COLOR1_CLEAR_WORD0 - CB_COLOR0_BASE: // CLEAR_WORD1 + break; + } + } }; static constexpr std::size_t colorBuffersCount = 6; -enum class CbRasterOp { - Blackness = 0x00, - Nor = 0x05, // ~(src | dst) - AndInverted = 0x0a, // ~src & dst - CopyInverted = 0x0f, // ~src - NotSrcErase = 0x11, // ~src & ~dst - SrcErase = 0x44, // src & ~dst - DstInvert = 0x55, // ~dst - Xor = 0x5a, // src ^ dst - Nand = 0x5f, // ~(src & dst) - And = 0x88, // src & dst - Equiv = 0x99, // ~(src ^ dst) - Noop = 0xaa, // dst - OrInverted = 0xaf, // ~src | dst - Copy = 0xcc, // src - OrReverse = 0xdd, // src | ~dst - Or = 0xEE, // src | dst - Whiteness = 0xff, +enum class CbRasterOp +{ + Blackness = 0x00, + Nor = 0x05, // ~(src | dst) + AndInverted = 0x0a, // ~src & dst + CopyInverted = 0x0f, // ~src + NotSrcErase = 0x11, // ~src & ~dst + SrcErase = 0x44, // src & ~dst + DstInvert = 0x55, // ~dst + Xor = 0x5a, // src ^ dst + Nand = 0x5f, // ~(src & dst) + And = 0x88, // src & dst + Equiv = 0x99, // ~(src ^ dst) + Noop = 0xaa, // dst + OrInverted = 0xaf, // ~src | dst + Copy = 0xcc, // src + OrReverse = 0xdd, // src | ~dst + Or = 0xEE, // src | dst + Whiteness = 0xff, }; -enum class CbColorFormat { - /* +enum class CbColorFormat +{ + /* 00 - CB_DISABLE: Disables drawing to color buffer. Causes DB to not send tiles/quads to CB. CB itself ignores this field. @@ -793,222 +854,228 @@ enum class CbColorFormat { should send only tiles. 04 - CB_DECOMPRESS: Decompress MRT0 to a */ - Disable, - Normal, - EliminateFastClear, - Resolve, + Disable, + Normal, + EliminateFastClear, + Resolve, }; -struct QueueRegisters { - std::uint64_t pgmPsAddress = 0; - std::uint64_t pgmVsAddress = 0; - std::uint64_t pgmComputeAddress = 0; - std::uint32_t userVsData[16]; - std::uint32_t userPsData[16]; - std::uint32_t userComputeData[16]; - std::uint32_t computeNumThreadX = 1; - std::uint32_t computeNumThreadY = 1; - std::uint32_t computeNumThreadZ = 1; - std::uint8_t psUserSpgrs; - std::uint8_t vsUserSpgrs; - std::uint8_t computeUserSpgrs; - - ColorBuffer colorBuffers[colorBuffersCount]; - - std::uint32_t indexType; - std::uint64_t indexBase; - - std::uint32_t screenScissorX = 0; - std::uint32_t screenScissorY = 0; - std::uint32_t screenScissorW = 0; - std::uint32_t screenScissorH = 0; - - CbColorFormat cbColorFormat = CbColorFormat::Normal; - - CbRasterOp cbRasterOp = CbRasterOp::Copy; - - std::uint32_t vgtPrimitiveType = 0; - bool stencilEnable = false; - bool depthEnable = false; - bool depthWriteEnable = false; - bool depthBoundsEnable = false; - int zFunc = 0; - bool backFaceEnable = false; - int stencilFunc = 0; - int stencilFuncBackFace = 0; - - float depthClear = 1.f; - - bool cullFront = false; - bool cullBack = false; - int face = 0; // 0 - CCW, 1 - CW - bool polyMode = false; - int polyModeFrontPType = 0; - int polyModeBackPType = 0; - bool polyOffsetFrontEnable = false; - bool polyOffsetBackEnable = false; - bool polyOffsetParaEnable = false; - bool vtxWindowOffsetEnable = false; - bool provokingVtxLast = false; - bool erspCorrDis = false; - bool multiPrimIbEna = false; - - bool depthClearEnable = false; - bool stencilClearEnable = false; - bool depthCopy = false; - bool stencilCopy = false; - bool resummarizeEnable = false; - bool stencilCompressDisable = false; - bool depthCompressDisable = false; - bool copyCentroid = false; - int copySample = 0; - bool zpassIncrementDisable = false; - - std::uint64_t zReadBase = 0; - std::uint64_t zWriteBase = 0; - - BlendMultiplier blendColorSrc = {}; - BlendFunc blendColorFn = {}; - BlendMultiplier blendColorDst = {}; - BlendMultiplier blendAlphaSrc = {}; - BlendFunc blendAlphaFn = {}; - BlendMultiplier blendAlphaDst = {}; - bool blendSeparateAlpha = false; - bool blendEnable = false; - std::uint32_t cbRenderTargetMask = 0; - - void setRegister(std::uint32_t regId, std::uint32_t value) { - switch (regId) { - case SPI_SHADER_PGM_LO_PS: - pgmPsAddress &= ~((1ull << 40) - 1); - pgmPsAddress |= static_cast(value) << 8; - break; - case SPI_SHADER_PGM_HI_PS: - pgmPsAddress &= (1ull << 40) - 1; - pgmPsAddress |= static_cast(value) << 40; - break; - case SPI_SHADER_PGM_LO_VS: - pgmVsAddress &= ~((1ull << 40) - 1); - pgmVsAddress |= static_cast(value) << 8; - break; - case SPI_SHADER_PGM_HI_VS: - pgmVsAddress &= (1ull << 40) - 1; - pgmVsAddress |= static_cast(value) << 40; - break; - - case SPI_SHADER_USER_DATA_VS_0: - case SPI_SHADER_USER_DATA_VS_1: - case SPI_SHADER_USER_DATA_VS_2: - case SPI_SHADER_USER_DATA_VS_3: - case SPI_SHADER_USER_DATA_VS_4: - case SPI_SHADER_USER_DATA_VS_5: - case SPI_SHADER_USER_DATA_VS_6: - case SPI_SHADER_USER_DATA_VS_7: - case SPI_SHADER_USER_DATA_VS_8: - case SPI_SHADER_USER_DATA_VS_9: - case SPI_SHADER_USER_DATA_VS_10: - case SPI_SHADER_USER_DATA_VS_11: - case SPI_SHADER_USER_DATA_VS_12: - case SPI_SHADER_USER_DATA_VS_13: - case SPI_SHADER_USER_DATA_VS_14: - case SPI_SHADER_USER_DATA_VS_15: - userVsData[regId - SPI_SHADER_USER_DATA_VS_0] = value; - break; - - case SPI_SHADER_USER_DATA_PS_0: - case SPI_SHADER_USER_DATA_PS_1: - case SPI_SHADER_USER_DATA_PS_2: - case SPI_SHADER_USER_DATA_PS_3: - case SPI_SHADER_USER_DATA_PS_4: - case SPI_SHADER_USER_DATA_PS_5: - case SPI_SHADER_USER_DATA_PS_6: - case SPI_SHADER_USER_DATA_PS_7: - case SPI_SHADER_USER_DATA_PS_8: - case SPI_SHADER_USER_DATA_PS_9: - case SPI_SHADER_USER_DATA_PS_10: - case SPI_SHADER_USER_DATA_PS_11: - case SPI_SHADER_USER_DATA_PS_12: - case SPI_SHADER_USER_DATA_PS_13: - case SPI_SHADER_USER_DATA_PS_14: - case SPI_SHADER_USER_DATA_PS_15: - userPsData[regId - SPI_SHADER_USER_DATA_PS_0] = value; - break; - - case SPI_SHADER_PGM_RSRC2_PS: - psUserSpgrs = (value >> 1) & 0x1f; - break; - - case SPI_SHADER_PGM_RSRC2_VS: - vsUserSpgrs = (value >> 1) & 0x1f; - break; - - case CB_COLOR0_BASE ... CB_COLOR6_DCC_BASE: { - auto buffer = - (regId - CB_COLOR0_BASE) / (CB_COLOR1_BASE - CB_COLOR0_BASE); - auto index = (regId - CB_COLOR0_BASE) % (CB_COLOR1_BASE - CB_COLOR0_BASE); - colorBuffers[buffer].setRegister(index, value); - break; - } - - case DB_RENDER_CONTROL: - depthClearEnable = getBit(value, 0); - stencilClearEnable = getBit(value, 1); - depthCopy = getBit(value, 2); - stencilCopy = getBit(value, 3); - resummarizeEnable = getBit(value, 4); - stencilCompressDisable = getBit(value, 5); - depthCompressDisable = getBit(value, 6); - copyCentroid = getBit(value, 7); - copySample = getBits(value, 10, 8); - zpassIncrementDisable = getBit(value, 11); - break; - - case DB_Z_READ_BASE: - zReadBase = static_cast(value) << 8; - break; - - case DB_Z_WRITE_BASE: - zWriteBase = static_cast(value) << 8; - break; - - case DB_DEPTH_CLEAR: - depthClear = std::bit_cast(value); - break; - - case DB_DEPTH_CONTROL: - stencilEnable = getBit(value, 0) != 0; - depthEnable = getBit(value, 1) != 0; - depthWriteEnable = getBit(value, 2) != 0; - depthBoundsEnable = getBit(value, 3) != 0; - zFunc = getBits(value, 6, 4); - backFaceEnable = getBit(value, 7); - stencilFunc = getBits(value, 11, 8); - stencilFuncBackFace = getBits(value, 23, 20); - - // std::printf("stencilEnable=%u, depthEnable=%u, depthWriteEnable=%u, " - // "depthBoundsEnable=%u, zFunc=%u, backFaceEnable=%u, " - // "stencilFunc=%u, stencilFuncBackFace=%u\n", - // stencilEnable, depthEnable, depthWriteEnable, - // depthBoundsEnable, zFunc, backFaceEnable, stencilFunc, - // stencilFuncBackFace); - break; - - case CB_TARGET_MASK: { - cbRenderTargetMask = value; - break; - } - - case CB_COLOR_CONTROL: { - /* +struct QueueRegisters +{ + std::uint64_t pgmPsAddress = 0; + std::uint64_t pgmVsAddress = 0; + std::uint64_t pgmComputeAddress = 0; + std::uint32_t userVsData[16]; + std::uint32_t userPsData[16]; + std::uint32_t userComputeData[16]; + std::uint32_t computeNumThreadX = 1; + std::uint32_t computeNumThreadY = 1; + std::uint32_t computeNumThreadZ = 1; + std::uint8_t psUserSpgrs; + std::uint8_t vsUserSpgrs; + std::uint8_t computeUserSpgrs; + + ColorBuffer colorBuffers[colorBuffersCount]; + + std::uint32_t indexType; + std::uint64_t indexBase; + + std::uint32_t screenScissorX = 0; + std::uint32_t screenScissorY = 0; + std::uint32_t screenScissorW = 0; + std::uint32_t screenScissorH = 0; + + CbColorFormat cbColorFormat = CbColorFormat::Normal; + + CbRasterOp cbRasterOp = CbRasterOp::Copy; + + std::uint32_t vgtPrimitiveType = 0; + bool stencilEnable = false; + bool depthEnable = false; + bool depthWriteEnable = false; + bool depthBoundsEnable = false; + int zFunc = 0; + bool backFaceEnable = false; + int stencilFunc = 0; + int stencilFuncBackFace = 0; + + float depthClear = 1.f; + + bool cullFront = false; + bool cullBack = false; + int face = 0; // 0 - CCW, 1 - CW + bool polyMode = false; + int polyModeFrontPType = 0; + int polyModeBackPType = 0; + bool polyOffsetFrontEnable = false; + bool polyOffsetBackEnable = false; + bool polyOffsetParaEnable = false; + bool vtxWindowOffsetEnable = false; + bool provokingVtxLast = false; + bool erspCorrDis = false; + bool multiPrimIbEna = false; + + bool depthClearEnable = false; + bool stencilClearEnable = false; + bool depthCopy = false; + bool stencilCopy = false; + bool resummarizeEnable = false; + bool stencilCompressDisable = false; + bool depthCompressDisable = false; + bool copyCentroid = false; + int copySample = 0; + bool zpassIncrementDisable = false; + + std::uint64_t zReadBase = 0; + std::uint64_t zWriteBase = 0; + + BlendMultiplier blendColorSrc = {}; + BlendFunc blendColorFn = {}; + BlendMultiplier blendColorDst = {}; + BlendMultiplier blendAlphaSrc = {}; + BlendFunc blendAlphaFn = {}; + BlendMultiplier blendAlphaDst = {}; + bool blendSeparateAlpha = false; + bool blendEnable = false; + std::uint32_t cbRenderTargetMask = 0; + + void setRegister(std::uint32_t regId, std::uint32_t value) + { + switch (regId) + { + case SPI_SHADER_PGM_LO_PS: + pgmPsAddress &= ~((1ull << 40) - 1); + pgmPsAddress |= static_cast(value) << 8; + break; + case SPI_SHADER_PGM_HI_PS: + pgmPsAddress &= (1ull << 40) - 1; + pgmPsAddress |= static_cast(value) << 40; + break; + case SPI_SHADER_PGM_LO_VS: + pgmVsAddress &= ~((1ull << 40) - 1); + pgmVsAddress |= static_cast(value) << 8; + break; + case SPI_SHADER_PGM_HI_VS: + pgmVsAddress &= (1ull << 40) - 1; + pgmVsAddress |= static_cast(value) << 40; + break; + + case SPI_SHADER_USER_DATA_VS_0: + case SPI_SHADER_USER_DATA_VS_1: + case SPI_SHADER_USER_DATA_VS_2: + case SPI_SHADER_USER_DATA_VS_3: + case SPI_SHADER_USER_DATA_VS_4: + case SPI_SHADER_USER_DATA_VS_5: + case SPI_SHADER_USER_DATA_VS_6: + case SPI_SHADER_USER_DATA_VS_7: + case SPI_SHADER_USER_DATA_VS_8: + case SPI_SHADER_USER_DATA_VS_9: + case SPI_SHADER_USER_DATA_VS_10: + case SPI_SHADER_USER_DATA_VS_11: + case SPI_SHADER_USER_DATA_VS_12: + case SPI_SHADER_USER_DATA_VS_13: + case SPI_SHADER_USER_DATA_VS_14: + case SPI_SHADER_USER_DATA_VS_15: + userVsData[regId - SPI_SHADER_USER_DATA_VS_0] = value; + break; + + case SPI_SHADER_USER_DATA_PS_0: + case SPI_SHADER_USER_DATA_PS_1: + case SPI_SHADER_USER_DATA_PS_2: + case SPI_SHADER_USER_DATA_PS_3: + case SPI_SHADER_USER_DATA_PS_4: + case SPI_SHADER_USER_DATA_PS_5: + case SPI_SHADER_USER_DATA_PS_6: + case SPI_SHADER_USER_DATA_PS_7: + case SPI_SHADER_USER_DATA_PS_8: + case SPI_SHADER_USER_DATA_PS_9: + case SPI_SHADER_USER_DATA_PS_10: + case SPI_SHADER_USER_DATA_PS_11: + case SPI_SHADER_USER_DATA_PS_12: + case SPI_SHADER_USER_DATA_PS_13: + case SPI_SHADER_USER_DATA_PS_14: + case SPI_SHADER_USER_DATA_PS_15: + userPsData[regId - SPI_SHADER_USER_DATA_PS_0] = value; + break; + + case SPI_SHADER_PGM_RSRC2_PS: + psUserSpgrs = (value >> 1) & 0x1f; + break; + + case SPI_SHADER_PGM_RSRC2_VS: + vsUserSpgrs = (value >> 1) & 0x1f; + break; + + case CB_COLOR0_BASE ... CB_COLOR6_DCC_BASE: + { + auto buffer = + (regId - CB_COLOR0_BASE) / (CB_COLOR1_BASE - CB_COLOR0_BASE); + auto index = (regId - CB_COLOR0_BASE) % (CB_COLOR1_BASE - CB_COLOR0_BASE); + colorBuffers[buffer].setRegister(index, value); + break; + } + + case DB_RENDER_CONTROL: + depthClearEnable = getBit(value, 0); + stencilClearEnable = getBit(value, 1); + depthCopy = getBit(value, 2); + stencilCopy = getBit(value, 3); + resummarizeEnable = getBit(value, 4); + stencilCompressDisable = getBit(value, 5); + depthCompressDisable = getBit(value, 6); + copyCentroid = getBit(value, 7); + copySample = getBits(value, 10, 8); + zpassIncrementDisable = getBit(value, 11); + break; + + case DB_Z_READ_BASE: + zReadBase = static_cast(value) << 8; + break; + + case DB_Z_WRITE_BASE: + zWriteBase = static_cast(value) << 8; + break; + + case DB_DEPTH_CLEAR: + depthClear = std::bit_cast(value); + break; + + case DB_DEPTH_CONTROL: + stencilEnable = getBit(value, 0) != 0; + depthEnable = getBit(value, 1) != 0; + depthWriteEnable = getBit(value, 2) != 0; + depthBoundsEnable = getBit(value, 3) != 0; + zFunc = getBits(value, 6, 4); + backFaceEnable = getBit(value, 7); + stencilFunc = getBits(value, 11, 8); + stencilFuncBackFace = getBits(value, 23, 20); + + // std::printf("stencilEnable=%u, depthEnable=%u, depthWriteEnable=%u, " + // "depthBoundsEnable=%u, zFunc=%u, backFaceEnable=%u, " + // "stencilFunc=%u, stencilFuncBackFace=%u\n", + // stencilEnable, depthEnable, depthWriteEnable, + // depthBoundsEnable, zFunc, backFaceEnable, stencilFunc, + // stencilFuncBackFace); + break; + + case CB_TARGET_MASK: + { + cbRenderTargetMask = value; + break; + } + + case CB_COLOR_CONTROL: + { + /* If true, then each UNORM format COLOR_8_8_8_8 MRT is treated as an SRGB format instead. This affects both normal draw and resolve. This bit exists for compatibility with older architectures that did not have an SRGB number type. */ - auto degammaEnable = getBits(value, 3, 0); + auto degammaEnable = getBits(value, 3, 0); - /* + /* This field selects standard color processing or one of several major operation modes. @@ -1036,9 +1103,9 @@ struct QueueRegisters { CB_ELIMINATE_FAST_CLEAR pass before this is unnecessary. DB should send only tiles. */ - auto mode = getBits(value, 6, 4); + auto mode = getBits(value, 6, 4); - /* + /* This field supports the 28 boolean ops that combine either source and dest or brush and dest, with brush provided by the shader in place of source. The code @@ -1076,3856 +1143,4212 @@ struct QueueRegisters { 250 - 0xFA 255 - 0xFF: WHITENESS */ - auto rop3 = getBits(value, 23, 16); - - // std::printf(" * degammaEnable = %x\n", degammaEnable); - // std::printf(" * mode = %x\n", mode); - // std::printf(" * rop3 = %x\n", rop3); - - cbColorFormat = static_cast(mode); - cbRasterOp = static_cast(rop3); - break; - } - - case PA_CL_CLIP_CNTL: - cullFront = getBit(value, 0); - cullBack = getBit(value, 1); - face = getBit(value, 2); - polyMode = getBits(value, 4, 3); - polyModeFrontPType = getBits(value, 7, 5); - polyModeBackPType = getBits(value, 10, 8); - polyOffsetFrontEnable = getBit(value, 11); - polyOffsetBackEnable = getBit(value, 12); - polyOffsetParaEnable = getBit(value, 13); - vtxWindowOffsetEnable = getBit(value, 16); - provokingVtxLast = getBit(value, 19); - erspCorrDis = getBit(value, 20); - multiPrimIbEna = getBit(value, 21); - break; - - case PA_SC_SCREEN_SCISSOR_TL: - screenScissorX = static_cast(value); - screenScissorY = static_cast(value >> 16); - break; - - case PA_SC_SCREEN_SCISSOR_BR: - screenScissorW = static_cast(value) - screenScissorX; - screenScissorH = static_cast(value >> 16) - screenScissorY; - break; - - case VGT_PRIMITIVE_TYPE: - vgtPrimitiveType = value; - break; - - case COMPUTE_NUM_THREAD_X: - computeNumThreadX = value; - break; - - case COMPUTE_NUM_THREAD_Y: - computeNumThreadY = value; - break; - - case COMPUTE_NUM_THREAD_Z: - computeNumThreadZ = value; - break; - - case COMPUTE_PGM_LO: - pgmComputeAddress &= ~((1ull << 40) - 1); - pgmComputeAddress |= static_cast(value) << 8; - break; - - case COMPUTE_PGM_HI: - pgmComputeAddress &= (1ull << 40) - 1; - pgmComputeAddress |= static_cast(value) << 40; - break; - - case COMPUTE_PGM_RSRC1: - break; - case COMPUTE_PGM_RSRC2: - computeUserSpgrs = (value >> 1) & 0x1f; - break; - - case COMPUTE_USER_DATA_0: - case COMPUTE_USER_DATA_1: - case COMPUTE_USER_DATA_2: - case COMPUTE_USER_DATA_3: - case COMPUTE_USER_DATA_4: - case COMPUTE_USER_DATA_5: - case COMPUTE_USER_DATA_6: - case COMPUTE_USER_DATA_7: - case COMPUTE_USER_DATA_8: - case COMPUTE_USER_DATA_9: - case COMPUTE_USER_DATA_10: - case COMPUTE_USER_DATA_11: - case COMPUTE_USER_DATA_12: - case COMPUTE_USER_DATA_13: - case COMPUTE_USER_DATA_14: - case COMPUTE_USER_DATA_15: - userComputeData[regId - COMPUTE_USER_DATA_0] = value; - break; - - case CB_BLEND0_CONTROL: { - blendColorSrc = (BlendMultiplier)fetchMaskedValue( - value, CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK); - blendColorFn = (BlendFunc)fetchMaskedValue( - value, CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK); - blendColorDst = (BlendMultiplier)fetchMaskedValue( - value, CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK); - auto opacity_weight = - fetchMaskedValue(value, CB_BLEND0_CONTROL_OPACITY_WEIGHT_MASK); - blendAlphaSrc = (BlendMultiplier)fetchMaskedValue( - value, CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK); - blendAlphaFn = (BlendFunc)fetchMaskedValue( - value, CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK); - blendAlphaDst = (BlendMultiplier)fetchMaskedValue( - value, CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK); - blendSeparateAlpha = - fetchMaskedValue(value, - CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK) != 0; - blendEnable = - fetchMaskedValue(value, CB_BLEND0_CONTROL_BLEND_ENABLE_MASK) != 0; - - // std::printf(" * COLOR_SRCBLEND = %x\n", blendColorSrc); - // std::printf(" * COLOR_COMB_FCN = %x\n", blendColorFn); - // std::printf(" * COLOR_DESTBLEND = %x\n", blendColorDst); - // std::printf(" * OPACITY_WEIGHT = %x\n", opacity_weight); - // std::printf(" * ALPHA_SRCBLEND = %x\n", blendAlphaSrc); - // std::printf(" * ALPHA_COMB_FCN = %x\n", blendAlphaFn); - // std::printf(" * ALPHA_DESTBLEND = %x\n", blendAlphaDst); - // std::printf(" * SEPARATE_ALPHA_BLEND = %x\n", blendSeparateAlpha); - // std::printf(" * BLEND_ENABLE = %x\n", blendEnable); - break; - } - } - } + auto rop3 = getBits(value, 23, 16); + + // std::printf(" * degammaEnable = %x\n", degammaEnable); + // std::printf(" * mode = %x\n", mode); + // std::printf(" * rop3 = %x\n", rop3); + + cbColorFormat = static_cast(mode); + cbRasterOp = static_cast(rop3); + break; + } + + case PA_CL_CLIP_CNTL: + cullFront = getBit(value, 0); + cullBack = getBit(value, 1); + face = getBit(value, 2); + polyMode = getBits(value, 4, 3); + polyModeFrontPType = getBits(value, 7, 5); + polyModeBackPType = getBits(value, 10, 8); + polyOffsetFrontEnable = getBit(value, 11); + polyOffsetBackEnable = getBit(value, 12); + polyOffsetParaEnable = getBit(value, 13); + vtxWindowOffsetEnable = getBit(value, 16); + provokingVtxLast = getBit(value, 19); + erspCorrDis = getBit(value, 20); + multiPrimIbEna = getBit(value, 21); + break; + + case PA_SC_SCREEN_SCISSOR_TL: + screenScissorX = static_cast(value); + screenScissorY = static_cast(value >> 16); + break; + + case PA_SC_SCREEN_SCISSOR_BR: + screenScissorW = static_cast(value) - screenScissorX; + screenScissorH = static_cast(value >> 16) - screenScissorY; + break; + + case VGT_PRIMITIVE_TYPE: + vgtPrimitiveType = value; + break; + + case COMPUTE_NUM_THREAD_X: + computeNumThreadX = value; + break; + + case COMPUTE_NUM_THREAD_Y: + computeNumThreadY = value; + break; + + case COMPUTE_NUM_THREAD_Z: + computeNumThreadZ = value; + break; + + case COMPUTE_PGM_LO: + pgmComputeAddress &= ~((1ull << 40) - 1); + pgmComputeAddress |= static_cast(value) << 8; + break; + + case COMPUTE_PGM_HI: + pgmComputeAddress &= (1ull << 40) - 1; + pgmComputeAddress |= static_cast(value) << 40; + break; + + case COMPUTE_PGM_RSRC1: + break; + case COMPUTE_PGM_RSRC2: + computeUserSpgrs = (value >> 1) & 0x1f; + break; + + case COMPUTE_USER_DATA_0: + case COMPUTE_USER_DATA_1: + case COMPUTE_USER_DATA_2: + case COMPUTE_USER_DATA_3: + case COMPUTE_USER_DATA_4: + case COMPUTE_USER_DATA_5: + case COMPUTE_USER_DATA_6: + case COMPUTE_USER_DATA_7: + case COMPUTE_USER_DATA_8: + case COMPUTE_USER_DATA_9: + case COMPUTE_USER_DATA_10: + case COMPUTE_USER_DATA_11: + case COMPUTE_USER_DATA_12: + case COMPUTE_USER_DATA_13: + case COMPUTE_USER_DATA_14: + case COMPUTE_USER_DATA_15: + userComputeData[regId - COMPUTE_USER_DATA_0] = value; + break; + + case CB_BLEND0_CONTROL: + { + blendColorSrc = (BlendMultiplier)fetchMaskedValue( + value, CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK); + blendColorFn = (BlendFunc)fetchMaskedValue( + value, CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK); + blendColorDst = (BlendMultiplier)fetchMaskedValue( + value, CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK); + auto opacity_weight = + fetchMaskedValue(value, CB_BLEND0_CONTROL_OPACITY_WEIGHT_MASK); + blendAlphaSrc = (BlendMultiplier)fetchMaskedValue( + value, CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK); + blendAlphaFn = (BlendFunc)fetchMaskedValue( + value, CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK); + blendAlphaDst = (BlendMultiplier)fetchMaskedValue( + value, CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK); + blendSeparateAlpha = + fetchMaskedValue(value, + CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK) != 0; + blendEnable = + fetchMaskedValue(value, CB_BLEND0_CONTROL_BLEND_ENABLE_MASK) != 0; + + // std::printf(" * COLOR_SRCBLEND = %x\n", blendColorSrc); + // std::printf(" * COLOR_COMB_FCN = %x\n", blendColorFn); + // std::printf(" * COLOR_DESTBLEND = %x\n", blendColorDst); + // std::printf(" * OPACITY_WEIGHT = %x\n", opacity_weight); + // std::printf(" * ALPHA_SRCBLEND = %x\n", blendAlphaSrc); + // std::printf(" * ALPHA_COMB_FCN = %x\n", blendAlphaFn); + // std::printf(" * ALPHA_DESTBLEND = %x\n", blendAlphaDst); + // std::printf(" * SEPARATE_ALPHA_BLEND = %x\n", blendSeparateAlpha); + // std::printf(" * BLEND_ENABLE = %x\n", blendEnable); + break; + } + } + } }; static void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, - VkImageAspectFlags aspectFlags, - VkImageLayout oldLayout, - VkImageLayout newLayout) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = aspectFlags; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - auto layoutToStageAccess = [](VkImageLayout layout) - -> std::pair { - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT}; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; - - default: - util::unreachable("unsupported layout transition! %d", layout); - } - }; - - auto [sourceStage, sourceAccess] = layoutToStageAccess(oldLayout); - auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); - - barrier.srcAccessMask = sourceAccess; - barrier.dstAccessMask = destinationAccess; - - vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, - nullptr, 0, nullptr, 1, &barrier); + VkImageAspectFlags aspectFlags, + VkImageLayout oldLayout, + VkImageLayout newLayout) +{ + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = aspectFlags; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + auto layoutToStageAccess = [](VkImageLayout layout) + -> std::pair { + switch (layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT}; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; + + default: + util::unreachable("unsupported layout transition! %d", layout); + } + }; + + auto [sourceStage, sourceAccess] = layoutToStageAccess(oldLayout); + auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); + + barrier.srcAccessMask = sourceAccess; + barrier.dstAccessMask = destinationAccess; + + vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, + nullptr, 0, nullptr, 1, &barrier); } -static int getBitWidthOfSurfaceFormat(SurfaceFormat format) { - switch (format) { - case kSurfaceFormatInvalid: - return 0; - case kSurfaceFormat8: - return 8; - case kSurfaceFormat16: - return 16; - case kSurfaceFormat8_8: - return 8 + 8; - case kSurfaceFormat32: - return 32; - case kSurfaceFormat16_16: - return 16 + 16; - case kSurfaceFormat10_11_11: - return 10 + 11 + 11; - case kSurfaceFormat11_11_10: - return 11 + 11 + 10; - case kSurfaceFormat10_10_10_2: - return 10 + 10 + 10 + 2; - case kSurfaceFormat2_10_10_10: - return 2 + 10 + 10 + 10; - case kSurfaceFormat8_8_8_8: - return 8 + 8 + 8 + 8; - case kSurfaceFormat32_32: - return 32 + 32; - case kSurfaceFormat16_16_16_16: - return 16 + 16 + 16 + 16; - case kSurfaceFormat32_32_32: - return 32 + 32 + 32; - case kSurfaceFormat32_32_32_32: - return 32 + 32 + 32 + 32; - case kSurfaceFormat5_6_5: - return 5 + 6 + 5; - case kSurfaceFormat1_5_5_5: - return 1 + 5 + 5 + 5; - case kSurfaceFormat5_5_5_1: - return 5 + 5 + 5 + 1; - case kSurfaceFormat4_4_4_4: - return 4 + 4 + 4 + 4; - case kSurfaceFormat8_24: - return 8 + 24; - case kSurfaceFormat24_8: - return 24 + 8; - case kSurfaceFormatX24_8_32: - return 24 + 8 + 32; - case kSurfaceFormatGB_GR: - return 2 + 2; - case kSurfaceFormatBG_RG: - return 0; - case kSurfaceFormat5_9_9_9: - return 5 + 9 + 9 + 9; - case kSurfaceFormatBc1: - return 8; - case kSurfaceFormatBc2: - return 8; - case kSurfaceFormatBc3: - return 8; - case kSurfaceFormatBc4: - return 8; - case kSurfaceFormatBc5: - return 8; - case kSurfaceFormatBc6: - return 8; - case kSurfaceFormatBc7: - return 8; - case kSurfaceFormatFmask8_S2_F1: - return 0; - case kSurfaceFormatFmask8_S4_F1: - return 0; - case kSurfaceFormatFmask8_S8_F1: - return 0; - case kSurfaceFormatFmask8_S2_F2: - return 0; - case kSurfaceFormatFmask8_S4_F2: - return 0; - case kSurfaceFormatFmask8_S4_F4: - return 0; - case kSurfaceFormatFmask16_S16_F1: - return 0; - case kSurfaceFormatFmask16_S8_F2: - return 0; - case kSurfaceFormatFmask32_S16_F2: - return 0; - case kSurfaceFormatFmask32_S8_F4: - return 0; - case kSurfaceFormatFmask32_S8_F8: - return 0; - case kSurfaceFormatFmask64_S16_F4: - return 0; - case kSurfaceFormatFmask64_S16_F8: - return 0; - case kSurfaceFormat4_4: - return 4 + 4; - case kSurfaceFormat6_5_5: - return 6 + 5 + 5; - case kSurfaceFormat1: - return 1; - case kSurfaceFormat1Reversed: - return 0; - } - - return 0; +static int getBitWidthOfSurfaceFormat(SurfaceFormat format) +{ + switch (format) + { + case kSurfaceFormatInvalid: + return 0; + case kSurfaceFormat8: + return 8; + case kSurfaceFormat16: + return 16; + case kSurfaceFormat8_8: + return 8 + 8; + case kSurfaceFormat32: + return 32; + case kSurfaceFormat16_16: + return 16 + 16; + case kSurfaceFormat10_11_11: + return 10 + 11 + 11; + case kSurfaceFormat11_11_10: + return 11 + 11 + 10; + case kSurfaceFormat10_10_10_2: + return 10 + 10 + 10 + 2; + case kSurfaceFormat2_10_10_10: + return 2 + 10 + 10 + 10; + case kSurfaceFormat8_8_8_8: + return 8 + 8 + 8 + 8; + case kSurfaceFormat32_32: + return 32 + 32; + case kSurfaceFormat16_16_16_16: + return 16 + 16 + 16 + 16; + case kSurfaceFormat32_32_32: + return 32 + 32 + 32; + case kSurfaceFormat32_32_32_32: + return 32 + 32 + 32 + 32; + case kSurfaceFormat5_6_5: + return 5 + 6 + 5; + case kSurfaceFormat1_5_5_5: + return 1 + 5 + 5 + 5; + case kSurfaceFormat5_5_5_1: + return 5 + 5 + 5 + 1; + case kSurfaceFormat4_4_4_4: + return 4 + 4 + 4 + 4; + case kSurfaceFormat8_24: + return 8 + 24; + case kSurfaceFormat24_8: + return 24 + 8; + case kSurfaceFormatX24_8_32: + return 24 + 8 + 32; + case kSurfaceFormatGB_GR: + return 2 + 2; + case kSurfaceFormatBG_RG: + return 0; + case kSurfaceFormat5_9_9_9: + return 5 + 9 + 9 + 9; + case kSurfaceFormatBc1: + return 8; + case kSurfaceFormatBc2: + return 8; + case kSurfaceFormatBc3: + return 8; + case kSurfaceFormatBc4: + return 8; + case kSurfaceFormatBc5: + return 8; + case kSurfaceFormatBc6: + return 8; + case kSurfaceFormatBc7: + return 8; + case kSurfaceFormatFmask8_S2_F1: + return 0; + case kSurfaceFormatFmask8_S4_F1: + return 0; + case kSurfaceFormatFmask8_S8_F1: + return 0; + case kSurfaceFormatFmask8_S2_F2: + return 0; + case kSurfaceFormatFmask8_S4_F2: + return 0; + case kSurfaceFormatFmask8_S4_F4: + return 0; + case kSurfaceFormatFmask16_S16_F1: + return 0; + case kSurfaceFormatFmask16_S8_F2: + return 0; + case kSurfaceFormatFmask32_S16_F2: + return 0; + case kSurfaceFormatFmask32_S8_F4: + return 0; + case kSurfaceFormatFmask32_S8_F8: + return 0; + case kSurfaceFormatFmask64_S16_F4: + return 0; + case kSurfaceFormatFmask64_S16_F8: + return 0; + case kSurfaceFormat4_4: + return 4 + 4; + case kSurfaceFormat6_5_5: + return 6 + 5 + 5; + case kSurfaceFormat1: + return 1; + case kSurfaceFormat1Reversed: + return 0; + } + + return 0; } static VkFormat surfaceFormatToVkFormat(SurfaceFormat surface, - TextureChannelType channel) { - switch (surface) { - case kSurfaceFormat8: { - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_R8_UNORM; - case kTextureChannelTypeSNorm: - return VK_FORMAT_R8_SNORM; - case kTextureChannelTypeUInt: - return VK_FORMAT_R8_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R8_SINT; - case kTextureChannelTypeSrgb: - return VK_FORMAT_R8_SRGB; - default: - break; - } - - break; - } - case kSurfaceFormat32: - switch (channel) { - case kTextureChannelTypeUInt: - return VK_FORMAT_R32_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R32_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R32_SFLOAT; - case kTextureChannelTypeSrgb: - return VK_FORMAT_R32_UINT; // FIXME - default: - break; - } - break; - - case kSurfaceFormat8_8: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_R8G8_UNORM; - case kTextureChannelTypeSNorm: - return VK_FORMAT_R8G8_SNORM; - case kTextureChannelTypeUInt: - return VK_FORMAT_R8G8_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R8G8_SINT; - default: - break; - } - break; - - case kSurfaceFormat5_6_5: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_R5G6B5_UNORM_PACK16; - - default: - break; - } - break; - - case kSurfaceFormat16_16: - switch (channel) { - case kTextureChannelTypeUInt: - return VK_FORMAT_R16G16_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R16G16_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R16G16_SFLOAT; - default: - break; - } - break; - - case kSurfaceFormat32_32: - switch (channel) { - case kTextureChannelTypeUInt: - return VK_FORMAT_R32G32_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R32G32_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R32G32_SFLOAT; - default: - break; - } - break; - - case kSurfaceFormat16_16_16_16: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_R16G16B16A16_UNORM; - case kTextureChannelTypeSNorm: - return VK_FORMAT_R16G16B16A16_SNORM; - case kTextureChannelTypeUScaled: - return VK_FORMAT_R16G16B16A16_USCALED; - case kTextureChannelTypeSScaled: - return VK_FORMAT_R16G16B16A16_SSCALED; - case kTextureChannelTypeUInt: - return VK_FORMAT_R16G16B16A16_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R16G16B16A16_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R16G16B16A16_SFLOAT; - case kTextureChannelTypeSrgb: - return VK_FORMAT_R16G16B16A16_UNORM; // FIXME: wrong - - default: - break; - } - break; - - case kSurfaceFormat32_32_32: - switch (channel) { - case kTextureChannelTypeUInt: - return VK_FORMAT_R32G32B32_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R32G32B32_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R32G32B32_SFLOAT; - default: - break; - } - break; - case kSurfaceFormat32_32_32_32: - switch (channel) { - case kTextureChannelTypeUInt: - return VK_FORMAT_R32G32B32A32_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R32G32B32A32_SINT; - case kTextureChannelTypeFloat: - return VK_FORMAT_R32G32B32A32_SFLOAT; - default: - break; - } - break; - - case kSurfaceFormat24_8: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_D32_SFLOAT_S8_UINT; // HACK for amdgpu - - default: - break; - } - - break; - - case kSurfaceFormat8_8_8_8: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_R8G8B8A8_UNORM; - case kTextureChannelTypeSNorm: - return VK_FORMAT_R8G8B8A8_SNORM; - case kTextureChannelTypeUScaled: - return VK_FORMAT_R8G8B8A8_USCALED; - case kTextureChannelTypeSScaled: - return VK_FORMAT_R8G8B8A8_SSCALED; - case kTextureChannelTypeUInt: - return VK_FORMAT_R8G8B8A8_UINT; - case kTextureChannelTypeSInt: - return VK_FORMAT_R8G8B8A8_SINT; - // case kTextureChannelTypeSNormNoZero: - // return VK_FORMAT_R8G8B8A8_SNORM; - case kTextureChannelTypeSrgb: - return VK_FORMAT_R8G8B8A8_SRGB; - // case kTextureChannelTypeUBNorm: - // return VK_FORMAT_R8G8B8A8_UNORM; - // case kTextureChannelTypeUBNormNoZero: - // return VK_FORMAT_R8G8B8A8_UNORM; - // case kTextureChannelTypeUBInt: - // return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; - // case kTextureChannelTypeUBScaled: - // return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; - - default: - break; - } - break; - - case kSurfaceFormatBc1: - switch (channel) { - case kTextureChannelTypeSrgb: - return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; - default: - break; - } - - case kSurfaceFormatBc3: - switch (channel) { - case kTextureChannelTypeSrgb: - return VK_FORMAT_BC3_SRGB_BLOCK; - default: - break; - } - - case kSurfaceFormatBc4: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_BC4_UNORM_BLOCK; - - case kTextureChannelTypeSNorm: - return VK_FORMAT_BC4_SNORM_BLOCK; - - default: - break; - } - case kSurfaceFormatBc5: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_BC5_UNORM_BLOCK; - - case kTextureChannelTypeSNorm: - return VK_FORMAT_BC5_SNORM_BLOCK; - - default: - break; - } - - case kSurfaceFormatBc7: - switch (channel) { - case kTextureChannelTypeUNorm: - return VK_FORMAT_BC7_UNORM_BLOCK; - - case kTextureChannelTypeSrgb: - return VK_FORMAT_BC7_SRGB_BLOCK; - - default: - break; - } - - default: - break; - } - - util::unreachable("unimplemented surface format. %x.%x\n", (int)surface, - (int)channel); + TextureChannelType channel) +{ + switch (surface) + { + case kSurfaceFormat8: + { + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_R8_UNORM; + case kTextureChannelTypeSNorm: + return VK_FORMAT_R8_SNORM; + case kTextureChannelTypeUInt: + return VK_FORMAT_R8_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R8_SINT; + case kTextureChannelTypeSrgb: + return VK_FORMAT_R8_SRGB; + default: + break; + } + + break; + } + case kSurfaceFormat32: + switch (channel) + { + case kTextureChannelTypeUInt: + return VK_FORMAT_R32_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R32_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R32_SFLOAT; + case kTextureChannelTypeSrgb: + return VK_FORMAT_R32_UINT; // FIXME + default: + break; + } + break; + + case kSurfaceFormat8_8: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_R8G8_UNORM; + case kTextureChannelTypeSNorm: + return VK_FORMAT_R8G8_SNORM; + case kTextureChannelTypeUInt: + return VK_FORMAT_R8G8_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R8G8_SINT; + default: + break; + } + break; + + case kSurfaceFormat5_6_5: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_R5G6B5_UNORM_PACK16; + + default: + break; + } + break; + + case kSurfaceFormat16_16: + switch (channel) + { + case kTextureChannelTypeUInt: + return VK_FORMAT_R16G16_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R16G16_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R16G16_SFLOAT; + default: + break; + } + break; + + case kSurfaceFormat32_32: + switch (channel) + { + case kTextureChannelTypeUInt: + return VK_FORMAT_R32G32_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R32G32_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R32G32_SFLOAT; + default: + break; + } + break; + + case kSurfaceFormat16_16_16_16: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_R16G16B16A16_UNORM; + case kTextureChannelTypeSNorm: + return VK_FORMAT_R16G16B16A16_SNORM; + case kTextureChannelTypeUScaled: + return VK_FORMAT_R16G16B16A16_USCALED; + case kTextureChannelTypeSScaled: + return VK_FORMAT_R16G16B16A16_SSCALED; + case kTextureChannelTypeUInt: + return VK_FORMAT_R16G16B16A16_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R16G16B16A16_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R16G16B16A16_SFLOAT; + case kTextureChannelTypeSrgb: + return VK_FORMAT_R16G16B16A16_UNORM; // FIXME: wrong + + default: + break; + } + break; + + case kSurfaceFormat32_32_32: + switch (channel) + { + case kTextureChannelTypeUInt: + return VK_FORMAT_R32G32B32_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R32G32B32_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R32G32B32_SFLOAT; + default: + break; + } + break; + case kSurfaceFormat32_32_32_32: + switch (channel) + { + case kTextureChannelTypeUInt: + return VK_FORMAT_R32G32B32A32_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R32G32B32A32_SINT; + case kTextureChannelTypeFloat: + return VK_FORMAT_R32G32B32A32_SFLOAT; + default: + break; + } + break; + + case kSurfaceFormat24_8: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_D32_SFLOAT_S8_UINT; // HACK for amdgpu + + default: + break; + } + + break; + + case kSurfaceFormat8_8_8_8: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_R8G8B8A8_UNORM; + case kTextureChannelTypeSNorm: + return VK_FORMAT_R8G8B8A8_SNORM; + case kTextureChannelTypeUScaled: + return VK_FORMAT_R8G8B8A8_USCALED; + case kTextureChannelTypeSScaled: + return VK_FORMAT_R8G8B8A8_SSCALED; + case kTextureChannelTypeUInt: + return VK_FORMAT_R8G8B8A8_UINT; + case kTextureChannelTypeSInt: + return VK_FORMAT_R8G8B8A8_SINT; + // case kTextureChannelTypeSNormNoZero: + // return VK_FORMAT_R8G8B8A8_SNORM; + case kTextureChannelTypeSrgb: + return VK_FORMAT_R8G8B8A8_SRGB; + // case kTextureChannelTypeUBNorm: + // return VK_FORMAT_R8G8B8A8_UNORM; + // case kTextureChannelTypeUBNormNoZero: + // return VK_FORMAT_R8G8B8A8_UNORM; + // case kTextureChannelTypeUBInt: + // return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + // case kTextureChannelTypeUBScaled: + // return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + + default: + break; + } + break; + + case kSurfaceFormatBc1: + switch (channel) + { + case kTextureChannelTypeSrgb: + return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + default: + break; + } + + case kSurfaceFormatBc3: + switch (channel) + { + case kTextureChannelTypeSrgb: + return VK_FORMAT_BC3_SRGB_BLOCK; + default: + break; + } + + case kSurfaceFormatBc4: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_BC4_UNORM_BLOCK; + + case kTextureChannelTypeSNorm: + return VK_FORMAT_BC4_SNORM_BLOCK; + + default: + break; + } + case kSurfaceFormatBc5: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_BC5_UNORM_BLOCK; + + case kTextureChannelTypeSNorm: + return VK_FORMAT_BC5_SNORM_BLOCK; + + default: + break; + } + + case kSurfaceFormatBc7: + switch (channel) + { + case kTextureChannelTypeUNorm: + return VK_FORMAT_BC7_UNORM_BLOCK; + + case kTextureChannelTypeSrgb: + return VK_FORMAT_BC7_SRGB_BLOCK; + + default: + break; + } + + default: + break; + } + + util::unreachable("unimplemented surface format. %x.%x\n", (int)surface, + (int)channel); } -static VkPrimitiveTopology getVkPrimitiveType(PrimitiveType type) { - switch (type) { - case kPrimitiveTypePointList: - return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - case kPrimitiveTypeLineList: - return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - case kPrimitiveTypeLineStrip: - return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; - case kPrimitiveTypeTriList: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - case kPrimitiveTypeTriFan: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; - case kPrimitiveTypeTriStrip: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - case kPrimitiveTypePatch: - return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; - case kPrimitiveTypeLineListAdjacency: - return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY; - case kPrimitiveTypeLineStripAdjacency: - return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY; - case kPrimitiveTypeTriListAdjacency: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY; - case kPrimitiveTypeTriStripAdjacency: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY; - case kPrimitiveTypeLineLoop: - return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; // FIXME - - case kPrimitiveTypeRectList: - case kPrimitiveTypeQuadList: - case kPrimitiveTypeQuadStrip: - case kPrimitiveTypePolygon: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - default: - util::unreachable(); - } +static VkPrimitiveTopology getVkPrimitiveType(PrimitiveType type) +{ + switch (type) + { + case kPrimitiveTypePointList: + return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + case kPrimitiveTypeLineList: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case kPrimitiveTypeLineStrip: + return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case kPrimitiveTypeTriList: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case kPrimitiveTypeTriFan: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; + case kPrimitiveTypeTriStrip: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + case kPrimitiveTypePatch: + return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; + case kPrimitiveTypeLineListAdjacency: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY; + case kPrimitiveTypeLineStripAdjacency: + return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY; + case kPrimitiveTypeTriListAdjacency: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY; + case kPrimitiveTypeTriStripAdjacency: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY; + case kPrimitiveTypeLineLoop: + return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; // FIXME + + case kPrimitiveTypeRectList: + case kPrimitiveTypeQuadList: + case kPrimitiveTypeQuadStrip: + case kPrimitiveTypePolygon: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + default: + util::unreachable(); + } } static std::pair -quadListPrimConverter(std::uint64_t index) { - static constexpr int indecies[] = {0, 1, 2, 2, 3, 0}; - return {index, index / 6 + indecies[index % 6]}; +quadListPrimConverter(std::uint64_t index) +{ + static constexpr int indecies[] = {0, 1, 2, 2, 3, 0}; + return {index, index / 6 + indecies[index % 6]}; } static std::pair -quadStripPrimConverter(std::uint64_t index) { - static constexpr int indecies[] = {0, 1, 3, 0, 3, 2}; - return {index, (index / 6) * 4 + indecies[index % 6]}; +quadStripPrimConverter(std::uint64_t index) +{ + static constexpr int indecies[] = {0, 1, 3, 0, 3, 2}; + return {index, (index / 6) * 4 + indecies[index % 6]}; } using ConverterFn = - std::pair(std::uint64_t index); - -static ConverterFn *getPrimConverterFn(PrimitiveType primType, - std::uint32_t *count) { - switch (primType) { - case kPrimitiveTypeQuadList: - *count = *count / 4 * 6; - return quadListPrimConverter; - - case kPrimitiveTypeQuadStrip: - *count = *count / 4 * 6; - return quadStripPrimConverter; - - default: - util::unreachable(); - } + std::pair(std::uint64_t index); + +static ConverterFn* getPrimConverterFn(PrimitiveType primType, + std::uint32_t* count) +{ + switch (primType) + { + case kPrimitiveTypeQuadList: + *count = *count / 4 * 6; + return quadListPrimConverter; + + case kPrimitiveTypeQuadStrip: + *count = *count / 4 * 6; + return quadStripPrimConverter; + + default: + util::unreachable(); + } } -static bool isPrimRequiresConversion(PrimitiveType primType) { - switch (primType) { - case kPrimitiveTypePointList: - case kPrimitiveTypeLineList: - case kPrimitiveTypeLineStrip: - case kPrimitiveTypeTriList: - case kPrimitiveTypeTriFan: - case kPrimitiveTypeTriStrip: - case kPrimitiveTypePatch: - case kPrimitiveTypeLineListAdjacency: - case kPrimitiveTypeLineStripAdjacency: - case kPrimitiveTypeTriListAdjacency: - case kPrimitiveTypeTriStripAdjacency: - return false; - case kPrimitiveTypeLineLoop: // FIXME - util::unreachable(); - return false; - - case kPrimitiveTypeRectList: - return false; // handled by geometry shader - - case kPrimitiveTypeQuadList: - case kPrimitiveTypeQuadStrip: - case kPrimitiveTypePolygon: - return true; - - default: - util::unreachable(); - } +static bool isPrimRequiresConversion(PrimitiveType primType) +{ + switch (primType) + { + case kPrimitiveTypePointList: + case kPrimitiveTypeLineList: + case kPrimitiveTypeLineStrip: + case kPrimitiveTypeTriList: + case kPrimitiveTypeTriFan: + case kPrimitiveTypeTriStrip: + case kPrimitiveTypePatch: + case kPrimitiveTypeLineListAdjacency: + case kPrimitiveTypeLineStripAdjacency: + case kPrimitiveTypeTriListAdjacency: + case kPrimitiveTypeTriStripAdjacency: + return false; + case kPrimitiveTypeLineLoop: // FIXME + util::unreachable(); + return false; + + case kPrimitiveTypeRectList: + return false; // handled by geometry shader + + case kPrimitiveTypeQuadList: + case kPrimitiveTypeQuadStrip: + case kPrimitiveTypePolygon: + return true; + + default: + util::unreachable(); + } } -static bool validateSpirv(const std::vector &bin) { - spv_target_env target_env = SPV_ENV_VULKAN_1_3; - spv_context spvContext = spvContextCreate(target_env); - spv_diagnostic diagnostic = nullptr; - spv_const_binary_t binary = {bin.data(), bin.size()}; - spv_result_t error = spvValidate(spvContext, &binary, &diagnostic); - if (error != 0) - spvDiagnosticPrint(diagnostic); - spvDiagnosticDestroy(diagnostic); - spvContextDestroy(spvContext); - return error == 0; +static bool validateSpirv(const std::vector& bin) +{ + spv_target_env target_env = SPV_ENV_VULKAN_1_3; + spv_context spvContext = spvContextCreate(target_env); + spv_diagnostic diagnostic = nullptr; + spv_const_binary_t binary = {bin.data(), bin.size()}; + spv_result_t error = spvValidate(spvContext, &binary, &diagnostic); + if (error != 0) + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + spvContextDestroy(spvContext); + return error == 0; } -static void printSpirv(const std::vector &bin) { - spv_target_env target_env = SPV_ENV_VULKAN_1_3; - spv_context spvContext = spvContextCreate(target_env); - spv_diagnostic diagnostic = nullptr; - - spv_result_t error = spvBinaryToText( - spvContext, bin.data(), bin.size(), - SPV_BINARY_TO_TEXT_OPTION_PRINT | // SPV_BINARY_TO_TEXT_OPTION_COLOR | - // SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES - // | - SPV_BINARY_TO_TEXT_OPTION_COMMENT | SPV_BINARY_TO_TEXT_OPTION_INDENT, - nullptr, &diagnostic); - - if (error != 0) { - spvDiagnosticPrint(diagnostic); - } - - spvDiagnosticDestroy(diagnostic); - spvContextDestroy(spvContext); - - if (error != 0) { - return; - } - - spirv_cross::CompilerGLSL glsl(bin); - spirv_cross::CompilerGLSL::Options options; - options.version = 460; - options.es = false; - options.vulkan_semantics = true; - glsl.set_common_options(options); - std::printf("%s\n", glsl.compile().c_str()); +static void printSpirv(const std::vector& bin) +{ + spv_target_env target_env = SPV_ENV_VULKAN_1_3; + spv_context spvContext = spvContextCreate(target_env); + spv_diagnostic diagnostic = nullptr; + + spv_result_t error = spvBinaryToText( + spvContext, bin.data(), bin.size(), + SPV_BINARY_TO_TEXT_OPTION_PRINT | // SPV_BINARY_TO_TEXT_OPTION_COLOR | + // SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES + // | + SPV_BINARY_TO_TEXT_OPTION_COMMENT | SPV_BINARY_TO_TEXT_OPTION_INDENT, + nullptr, &diagnostic); + + if (error != 0) + { + spvDiagnosticPrint(diagnostic); + } + + spvDiagnosticDestroy(diagnostic); + spvContextDestroy(spvContext); + + if (error != 0) + { + return; + } + + spirv_cross::CompilerGLSL glsl(bin); + spirv_cross::CompilerGLSL::Options options; + options.version = 460; + options.es = false; + options.vulkan_semantics = true; + glsl.set_common_options(options); + std::printf("%s\n", glsl.compile().c_str()); } static std::optional> -optimizeSpirv(std::span spirv) { - spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_3); - optimizer.RegisterPerformancePasses(); - optimizer.RegisterPass(spvtools::CreateSimplificationPass()); - - std::vector result; - if (optimizer.Run(spirv.data(), spirv.size(), &result)) { - return result; - } - - util::unreachable(); - return {}; +optimizeSpirv(std::span spirv) +{ + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_3); + optimizer.RegisterPerformancePasses(); + optimizer.RegisterPass(spvtools::CreateSimplificationPass()); + + std::vector result; + if (optimizer.Run(spirv.data(), spirv.size(), &result)) + { + return result; + } + + util::unreachable(); + return {}; } -static VkShaderStageFlagBits shaderStageToVk(amdgpu::shader::Stage stage) { - switch (stage) { - case amdgpu::shader::Stage::None: - break; - case amdgpu::shader::Stage::Fragment: - return VK_SHADER_STAGE_FRAGMENT_BIT; - case amdgpu::shader::Stage::Vertex: - return VK_SHADER_STAGE_VERTEX_BIT; - case amdgpu::shader::Stage::Geometry: - return VK_SHADER_STAGE_GEOMETRY_BIT; - case amdgpu::shader::Stage::Compute: - return VK_SHADER_STAGE_COMPUTE_BIT; - } - - return VK_SHADER_STAGE_ALL; +static VkShaderStageFlagBits shaderStageToVk(amdgpu::shader::Stage stage) +{ + switch (stage) + { + case amdgpu::shader::Stage::None: + break; + case amdgpu::shader::Stage::Fragment: + return VK_SHADER_STAGE_FRAGMENT_BIT; + case amdgpu::shader::Stage::Vertex: + return VK_SHADER_STAGE_VERTEX_BIT; + case amdgpu::shader::Stage::Geometry: + return VK_SHADER_STAGE_GEOMETRY_BIT; + case amdgpu::shader::Stage::Compute: + return VK_SHADER_STAGE_COMPUTE_BIT; + } + + return VK_SHADER_STAGE_ALL; } static vk::MemoryResource hostVisibleMemory; static vk::MemoryResource deviceLocalMemory; -static vk::MemoryResource &getHostVisibleMemory() { - if (!hostVisibleMemory) { - hostVisibleMemory.initHostVisible(1024 * 1024 * 512); - } +static vk::MemoryResource& getHostVisibleMemory() +{ + if (!hostVisibleMemory) + { + hostVisibleMemory.initHostVisible(1024 * 1024 * 512); + } - return hostVisibleMemory; + return hostVisibleMemory; } -static vk::MemoryResource &getDeviceLocalMemory() { - if (!deviceLocalMemory) { - deviceLocalMemory.initDeviceLocal(1024 * 1024 * 512); - } +static vk::MemoryResource& getDeviceLocalMemory() +{ + if (!deviceLocalMemory) + { + deviceLocalMemory.initDeviceLocal(1024 * 1024 * 512); + } - return deviceLocalMemory; + return deviceLocalMemory; } static std::uint64_t nextImageId = 0; -static void saveImage(const char *name, vk::Image2D &image) { - vk::ImageRef imageRef(image); - vk::Image2D transferImage(imageRef.getWidth(), imageRef.getHeight(), - VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL | - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - auto transferImageMemory = - vk::DeviceMemory::Allocate(transferImage.getMemoryRequirements(), - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - transferImage.bindMemory(vk::DeviceMemoryRef{ - .deviceMemory = transferImageMemory.getHandle(), - .offset = 0, - .size = transferImageMemory.getSize(), - }); - - auto transferImageRef = vk::ImageRef(transferImage); - - auto imageSize = transferImageRef.getMemoryRequirements().size; - - auto transferBuffer = vk::Buffer::Allocate( - getHostVisibleMemory(), imageSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - auto taskChain = TaskChain::Create(); - auto blitTask = taskChain->add( - ProcessQueue::Graphics, - [&, transferBuffer = transferBuffer.getHandle(), - imageRef = vk::ImageRef(image)](VkCommandBuffer commandBuffer) mutable { - imageRef.transitionLayout(commandBuffer, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - VkImageBlit region{ - .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1}, - .srcOffsets = {{}, - {static_cast(imageRef.getWidth()), - static_cast(imageRef.getHeight()), 1}}, - .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1}, - .dstOffsets = {{}, - {static_cast(imageRef.getWidth()), - static_cast(imageRef.getHeight()), 1}}, - }; - - transferImageRef.transitionLayout(commandBuffer, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - vkCmdBlitImage(commandBuffer, imageRef.getHandle(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - transferImage.getHandle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, - VK_FILTER_NEAREST); - - transferImageRef.transitionLayout(commandBuffer, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - transferImageRef.writeToBuffer(commandBuffer, transferBuffer, - VK_IMAGE_ASPECT_COLOR_BIT); - imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); - }); - taskChain->add(blitTask, [&, name = std::string(name)] { - std::ofstream file(name, std::ios::out | std::ios::binary); - auto data = (unsigned int *)transferBuffer.getData(); - - file << "P6\n" - << transferImageRef.getWidth() << "\n" - << transferImageRef.getHeight() << "\n" - << 255 << "\n"; - - for (uint32_t y = 0; y < transferImageRef.getHeight(); y++) { - for (uint32_t x = 0; x < transferImageRef.getWidth(); x++) { - file.write((char *)data, 3); - data++; - } - } - }); - - taskChain->wait(); +static void saveImage(const char* name, vk::Image2D& image) +{ + vk::ImageRef imageRef(image); + vk::Image2D transferImage(imageRef.getWidth(), imageRef.getHeight(), + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL | + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + auto transferImageMemory = + vk::DeviceMemory::Allocate(transferImage.getMemoryRequirements(), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + transferImage.bindMemory(vk::DeviceMemoryRef{ + .deviceMemory = transferImageMemory.getHandle(), + .offset = 0, + .size = transferImageMemory.getSize(), + }); + + auto transferImageRef = vk::ImageRef(transferImage); + + auto imageSize = transferImageRef.getMemoryRequirements().size; + + auto transferBuffer = vk::Buffer::Allocate( + getHostVisibleMemory(), imageSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + + auto taskChain = TaskChain::Create(); + auto blitTask = taskChain->add( + ProcessQueue::Graphics, + [&, transferBuffer = transferBuffer.getHandle(), + imageRef = vk::ImageRef(image)](VkCommandBuffer commandBuffer) mutable { + imageRef.transitionLayout(commandBuffer, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + VkImageBlit region{ + .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1}, + .srcOffsets = {{}, + {static_cast(imageRef.getWidth()), + static_cast(imageRef.getHeight()), 1}}, + .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1}, + .dstOffsets = {{}, + {static_cast(imageRef.getWidth()), + static_cast(imageRef.getHeight()), 1}}, + }; + + transferImageRef.transitionLayout(commandBuffer, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vkCmdBlitImage(commandBuffer, imageRef.getHandle(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + transferImage.getHandle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, + VK_FILTER_NEAREST); + + transferImageRef.transitionLayout(commandBuffer, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + transferImageRef.writeToBuffer(commandBuffer, transferBuffer, + VK_IMAGE_ASPECT_COLOR_BIT); + imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + }); + taskChain->add(blitTask, [&, name = std::string(name)] { + std::ofstream file(name, std::ios::out | std::ios::binary); + auto data = (unsigned int*)transferBuffer.getData(); + + file << "P6\n" + << transferImageRef.getWidth() << "\n" + << transferImageRef.getHeight() << "\n" + << 255 << "\n"; + + for (uint32_t y = 0; y < transferImageRef.getHeight(); y++) + { + for (uint32_t x = 0; x < transferImageRef.getWidth(); x++) + { + file.write((char*)data, 3); + data++; + } + } + }); + + taskChain->wait(); } -struct BufferRef { - VkBuffer buffer = VK_NULL_HANDLE; - VkDeviceSize offset = 0; - VkDeviceSize size = 0; +struct BufferRef +{ + VkBuffer buffer = VK_NULL_HANDLE; + VkDeviceSize offset = 0; + VkDeviceSize size = 0; }; -static constexpr bool isAligned(std::uint64_t offset, std::uint64_t alignment) { - return (offset & (alignment - 1)) == 0; +static constexpr bool isAligned(std::uint64_t offset, std::uint64_t alignment) +{ + return (offset & (alignment - 1)) == 0; } static void -fillStageBindings(std::vector &bindings, - shader::Stage stage) { - for (std::size_t i = 0; i < shader::UniformBindings::kBufferSlots; ++i) { - auto binding = shader::UniformBindings::getBufferBinding(stage, i); - bindings[binding] = VkDescriptorSetLayoutBinding{ - .binding = binding, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = 1, - .stageFlags = shaderStageToVk(stage), - .pImmutableSamplers = nullptr}; - } - - for (std::size_t i = 0; i < shader::UniformBindings::kImageSlots; ++i) { - auto binding = shader::UniformBindings::getImageBinding(stage, i); - bindings[binding] = VkDescriptorSetLayoutBinding{ - .binding = binding, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = 1, - .stageFlags = shaderStageToVk(stage), - .pImmutableSamplers = nullptr}; - } - - for (std::size_t i = 0; i < shader::UniformBindings::kSamplerSlots; ++i) { - auto binding = shader::UniformBindings::getSamplerBinding(stage, i); - bindings[binding] = VkDescriptorSetLayoutBinding{ - .binding = binding, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = 1, - .stageFlags = shaderStageToVk(stage), - .pImmutableSamplers = nullptr}; - } - - for (std::size_t i = 0; i < shader::UniformBindings::kStorageImageSlots; - ++i) { - auto binding = shader::UniformBindings::getStorageImageBinding(stage, i); - bindings[binding] = VkDescriptorSetLayoutBinding{ - .binding = binding, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = 1, - .stageFlags = shaderStageToVk(stage), - .pImmutableSamplers = nullptr}; - } +fillStageBindings(std::vector& bindings, + shader::Stage stage) +{ + for (std::size_t i = 0; i < shader::UniformBindings::kBufferSlots; ++i) + { + auto binding = shader::UniformBindings::getBufferBinding(stage, i); + bindings[binding] = VkDescriptorSetLayoutBinding{ + .binding = binding, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = shaderStageToVk(stage), + .pImmutableSamplers = nullptr}; + } + + for (std::size_t i = 0; i < shader::UniformBindings::kImageSlots; ++i) + { + auto binding = shader::UniformBindings::getImageBinding(stage, i); + bindings[binding] = VkDescriptorSetLayoutBinding{ + .binding = binding, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = shaderStageToVk(stage), + .pImmutableSamplers = nullptr}; + } + + for (std::size_t i = 0; i < shader::UniformBindings::kSamplerSlots; ++i) + { + auto binding = shader::UniformBindings::getSamplerBinding(stage, i); + bindings[binding] = VkDescriptorSetLayoutBinding{ + .binding = binding, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = shaderStageToVk(stage), + .pImmutableSamplers = nullptr}; + } + + for (std::size_t i = 0; i < shader::UniformBindings::kStorageImageSlots; + ++i) + { + auto binding = shader::UniformBindings::getStorageImageBinding(stage, i); + bindings[binding] = VkDescriptorSetLayoutBinding{ + .binding = binding, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = shaderStageToVk(stage), + .pImmutableSamplers = nullptr}; + } } -static std::pair getGraphicsLayout() { - static std::pair result{}; - - if (result.first != VK_NULL_HANDLE) { - return result; - } - - std::vector bindings( - shader::UniformBindings::kStageSize * 2); - - for (auto stage : {shader::Stage::Vertex, shader::Stage::Fragment}) { - fillStageBindings(bindings, stage); - } - - VkDescriptorSetLayoutCreateInfo descLayoutInfo{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = static_cast(bindings.size()), - .pBindings = bindings.data(), - }; - - Verify() << vkCreateDescriptorSetLayout(vk::g_vkDevice, &descLayoutInfo, - vk::g_vkAllocator, &result.first); - - VkPipelineLayoutCreateInfo piplineLayoutInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 1, - .pSetLayouts = &result.first, - }; - - Verify() << vkCreatePipelineLayout(vk::g_vkDevice, &piplineLayoutInfo, - vk::g_vkAllocator, &result.second); - - return result; +static std::pair getGraphicsLayout() +{ + static std::pair result{}; + + if (result.first != VK_NULL_HANDLE) + { + return result; + } + + std::vector bindings( + shader::UniformBindings::kStageSize * 2); + + for (auto stage : {shader::Stage::Vertex, shader::Stage::Fragment}) + { + fillStageBindings(bindings, stage); + } + + VkDescriptorSetLayoutCreateInfo descLayoutInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = static_cast(bindings.size()), + .pBindings = bindings.data(), + }; + + Verify() << vkCreateDescriptorSetLayout(vk::g_vkDevice, &descLayoutInfo, + vk::g_vkAllocator, &result.first); + + VkPipelineLayoutCreateInfo piplineLayoutInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 1, + .pSetLayouts = &result.first, + }; + + Verify() << vkCreatePipelineLayout(vk::g_vkDevice, &piplineLayoutInfo, + vk::g_vkAllocator, &result.second); + + return result; } -static std::pair getComputeLayout() { - static std::pair result{}; +static std::pair getComputeLayout() +{ + static std::pair result{}; - if (result.first != VK_NULL_HANDLE) { - return result; - } + if (result.first != VK_NULL_HANDLE) + { + return result; + } - std::vector bindings( - shader::UniformBindings::kStageSize); + std::vector bindings( + shader::UniformBindings::kStageSize); - fillStageBindings(bindings, shader::Stage::Compute); + fillStageBindings(bindings, shader::Stage::Compute); - VkDescriptorSetLayoutCreateInfo layoutInfo{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = static_cast(bindings.size()), - .pBindings = bindings.data(), - }; + VkDescriptorSetLayoutCreateInfo layoutInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = static_cast(bindings.size()), + .pBindings = bindings.data(), + }; - Verify() << vkCreateDescriptorSetLayout(vk::g_vkDevice, &layoutInfo, nullptr, - &result.first); + Verify() << vkCreateDescriptorSetLayout(vk::g_vkDevice, &layoutInfo, nullptr, + &result.first); - VkPipelineLayoutCreateInfo piplineLayoutInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 1, - .pSetLayouts = &result.first, - }; + VkPipelineLayoutCreateInfo piplineLayoutInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 1, + .pSetLayouts = &result.first, + }; - Verify() << vkCreatePipelineLayout(vk::g_vkDevice, &piplineLayoutInfo, - vk::g_vkAllocator, &result.second); - return result; + Verify() << vkCreatePipelineLayout(vk::g_vkDevice, &piplineLayoutInfo, + vk::g_vkAllocator, &result.second); + return result; } -struct ShaderKey { - std::uint64_t address; - std::uint16_t dimX; - std::uint16_t dimY; - std::uint16_t dimZ; - shader::Stage stage; - std::uint8_t userSgprCount; - std::uint32_t userSgprs[16]; - - auto operator<=>(const ShaderKey &other) const { - auto result = address <=> other.address; - if (result != std::strong_ordering::equal) { - return result; - } - - result = dimX <=> other.dimX; - if (result != std::strong_ordering::equal) { - return result; - } - - result = dimY <=> other.dimY; - if (result != std::strong_ordering::equal) { - return result; - } - - result = dimZ <=> other.dimZ; - if (result != std::strong_ordering::equal) { - return result; - } - - result = stage <=> other.stage; - if (result != std::strong_ordering::equal) { - return result; - } - - result = userSgprCount <=> other.userSgprCount; - if (result != std::strong_ordering::equal) { - return result; - } - - for (std::size_t i = 0; i < std::size(userSgprs); ++i) { - if (i >= userSgprCount) { - break; - } - - result = userSgprs[i] <=> other.userSgprs[i]; - if (result != std::strong_ordering::equal) { - return result; - } - } - - return result; - } +struct ShaderKey +{ + std::uint64_t address; + std::uint16_t dimX; + std::uint16_t dimY; + std::uint16_t dimZ; + shader::Stage stage; + std::uint8_t userSgprCount; + std::uint32_t userSgprs[16]; + + auto operator<=>(const ShaderKey& other) const + { + auto result = address <=> other.address; + if (result != std::strong_ordering::equal) + { + return result; + } + + result = dimX <=> other.dimX; + if (result != std::strong_ordering::equal) + { + return result; + } + + result = dimY <=> other.dimY; + if (result != std::strong_ordering::equal) + { + return result; + } + + result = dimZ <=> other.dimZ; + if (result != std::strong_ordering::equal) + { + return result; + } + + result = stage <=> other.stage; + if (result != std::strong_ordering::equal) + { + return result; + } + + result = userSgprCount <=> other.userSgprCount; + if (result != std::strong_ordering::equal) + { + return result; + } + + for (std::size_t i = 0; i < std::size(userSgprs); ++i) + { + if (i >= userSgprCount) + { + break; + } + + result = userSgprs[i] <=> other.userSgprs[i]; + if (result != std::strong_ordering::equal) + { + return result; + } + } + + return result; + } }; -struct CachedShader { - std::map> cachedData; - shader::Shader info; - VkShaderEXT shader; +struct CachedShader +{ + std::map> cachedData; + shader::Shader info; + VkShaderEXT shader; - ~CachedShader() { - _vkDestroyShaderEXT(vk::g_vkDevice, shader, vk::g_vkAllocator); - } + ~CachedShader() + { + _vkDestroyShaderEXT(vk::g_vkDevice, shader, vk::g_vkAllocator); + } }; struct CacheOverlayBase; struct CacheBufferOverlay; struct CacheImageOverlay; -struct CacheSyncEntry { - std::uint64_t tag; - Ref overlay; +struct CacheSyncEntry +{ + std::uint64_t tag; + Ref overlay; - auto operator<=>(const CacheSyncEntry &) const = default; + auto operator<=>(const CacheSyncEntry&) const = default; }; -enum class CacheMode { None, AsyncWrite, LazyWrite }; - -struct CacheOverlayBase { - std::mutex mtx; - Ref writeBackTaskCtl; - std::function unlockMutableTask; - std::uint64_t lockTag = 0; - std::uint64_t lockCount = 0; - shader::AccessOp lockOp = shader::AccessOp::None; - CacheMode cacheMode = CacheMode::None; - util::MemoryTableWithPayload syncState; - - std::atomic refs{0}; - virtual ~CacheOverlayBase() = default; - - void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } - void decRef() { - if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) { - delete this; - } - } - - struct LockInfo { - bool isLocked; - shader::AccessOp prevLockOps; - }; - - LockInfo tryLock(std::uint64_t tag, shader::AccessOp op) { - std::lock_guard lock(mtx); - if (lockTag != tag && lockTag != 0) { - return {false, {}}; - } - - lockTag = tag; - ++lockCount; - auto prevLockOps = lockOp; - lockOp |= op; - return {true, prevLockOps}; - } - - void unlock(std::uint64_t tag) { - Ref waitTask; - - { - std::lock_guard lock(mtx); - if (lockTag != tag) { - util::unreachable(); - } - - if (--lockCount != 0) { - return; - } - - release(tag); - lockTag = 0; - auto result = lockOp; - lockOp = shader::AccessOp::None; - - if ((result & shader::AccessOp::Store) == shader::AccessOp::Store) { - if (unlockMutableTask) { - unlockMutableTask(); - unlockMutableTask = nullptr; - } - - if (writeBackTaskCtl) { - getCpuScheduler().enqueue(writeBackTaskCtl); - if (cacheMode == CacheMode::None) { - waitTask = std::move(writeBackTaskCtl); - writeBackTaskCtl = nullptr; - } - } - } - } - - if (waitTask) { - waitTask->wait(); - } - } - - virtual void release(std::uint64_t tag) {} - - std::optional getSyncTag(std::uint64_t address, - std::uint64_t size) { - std::lock_guard lock(mtx); - auto it = syncState.queryArea(address); - if (it == syncState.end()) { - return {}; - } - - auto state = *it; - - if (state.endAddress < address + size || state.beginAddress > address) { - // has no single sync state - return {}; - } - - return state; - } - - bool isInSync(util::MemoryTableWithPayload &table, - std::mutex &tableMutex, std::uint64_t address, - std::uint64_t size) { - auto optSyncTag = getSyncTag(address, size); - if (!optSyncTag) { - return false; - } - - auto syncTag = *optSyncTag; - - std::lock_guard lock(tableMutex); - auto tableArea = table.queryArea(address); - - if (tableArea == table.end()) { - return false; - } - - auto tableTag = *tableArea; - - if (tableTag.beginAddress > address || - tableTag.endAddress < address + size) { - return false; - } - - return tableTag.payload.tag == syncTag.payload; - } - - virtual void writeBuffer(TaskChain &taskChain, - Ref sourceBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) { - std::printf("cache: unimplemented buffer write to %lx-%lx\n", address, - address + size); - } - - virtual void readBuffer(TaskChain &taskChain, - Ref targetBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) { - std::printf("cache: unimplemented buffer read from %lx-%lx\n", address, - address + size); - } +enum class CacheMode +{ + None, + AsyncWrite, + LazyWrite }; -struct CacheBufferOverlay : CacheOverlayBase { - vk::Buffer buffer; - std::uint64_t bufferAddress; - - void read(TaskChain &taskChain, - util::MemoryTableWithPayload &table, - std::mutex &tableMtx, std::uint64_t address, - std::uint32_t elementCount, std::uint32_t stride, - std::uint32_t elementSize, bool cache, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId, - bool tableLocked = false) { - std::lock_guard lock(mtx); - auto size = stride == 0 - ? static_cast(elementCount) * elementSize - : static_cast(elementCount) * stride; - auto doRead = [&](std::uint64_t address, std::uint64_t size, - std::uint64_t tag, Ref overlay) { - overlay->readBuffer(taskChain, this, address, size, waitTask); - syncState.map(address, address + size, tag); - }; - - auto getAreaInfo = [&](std::uint64_t address) { - if (tableLocked) { - auto it = table.queryArea(address); - if (it == table.end()) { - util::unreachable(); - } - - return *it; - } - - std::lock_guard lock(tableMtx); - auto it = table.queryArea(address); - if (it == table.end()) { - util::unreachable(); - } - return *it; - }; - - while (size > 0) { - auto state = getAreaInfo(address); - - assert(state.endAddress > address); - auto origAreaSize = std::min(state.endAddress - address, size); - auto areaSize = origAreaSize; - - if (!cache) { - state.payload.overlay->readBuffer(taskChain, this, address, areaSize, - waitTask); - size -= areaSize; - address += areaSize; - continue; - } - - while (areaSize > 0) { - auto blockSyncStateIt = syncState.queryArea(address); - - if (blockSyncStateIt == syncState.end()) { - doRead(address, areaSize, state.payload.tag, state.payload.overlay); - address += areaSize; - break; - } - - auto blockSyncState = *blockSyncStateIt; - auto blockSize = - std::min(blockSyncState.endAddress - address, areaSize); - - if (blockSyncState.payload != state.payload.tag) { - doRead(address, areaSize, state.payload.tag, state.payload.overlay); - } - - areaSize -= blockSize; - address += blockSize; - } - - size -= origAreaSize; - } - } - - void readBuffer(TaskChain &taskChain, Ref targetBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override { - auto readTask = [=, self = Ref(this)] { - auto targetOffset = address - targetBuffer->bufferAddress; - auto sourceOffset = address - self->bufferAddress; - std::memcpy((char *)targetBuffer->buffer.getData() + targetOffset, - (char *)self->buffer.getData() + sourceOffset, size); - }; - - if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) { - readTask(); - } else { - taskChain.add(waitTask, std::move(readTask)); - } - } +struct CacheOverlayBase +{ + std::mutex mtx; + Ref writeBackTaskCtl; + std::function unlockMutableTask; + std::uint64_t lockTag = 0; + std::uint64_t lockCount = 0; + shader::AccessOp lockOp = shader::AccessOp::None; + CacheMode cacheMode = CacheMode::None; + util::MemoryTableWithPayload syncState; + + std::atomic refs{0}; + virtual ~CacheOverlayBase() = default; + + void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } + void decRef() + { + if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) + { + delete this; + } + } + + struct LockInfo + { + bool isLocked; + shader::AccessOp prevLockOps; + }; + + LockInfo tryLock(std::uint64_t tag, shader::AccessOp op) + { + std::lock_guard lock(mtx); + if (lockTag != tag && lockTag != 0) + { + return {false, {}}; + } + + lockTag = tag; + ++lockCount; + auto prevLockOps = lockOp; + lockOp |= op; + return {true, prevLockOps}; + } + + void unlock(std::uint64_t tag) + { + Ref waitTask; + + { + std::lock_guard lock(mtx); + if (lockTag != tag) + { + util::unreachable(); + } + + if (--lockCount != 0) + { + return; + } + + release(tag); + lockTag = 0; + auto result = lockOp; + lockOp = shader::AccessOp::None; + + if ((result & shader::AccessOp::Store) == shader::AccessOp::Store) + { + if (unlockMutableTask) + { + unlockMutableTask(); + unlockMutableTask = nullptr; + } + + if (writeBackTaskCtl) + { + getCpuScheduler().enqueue(writeBackTaskCtl); + if (cacheMode == CacheMode::None) + { + waitTask = std::move(writeBackTaskCtl); + writeBackTaskCtl = nullptr; + } + } + } + } + + if (waitTask) + { + waitTask->wait(); + } + } + + virtual void release(std::uint64_t tag) {} + + std::optional getSyncTag(std::uint64_t address, + std::uint64_t size) + { + std::lock_guard lock(mtx); + auto it = syncState.queryArea(address); + if (it == syncState.end()) + { + return {}; + } + + auto state = *it; + + if (state.endAddress < address + size || state.beginAddress > address) + { + // has no single sync state + return {}; + } + + return state; + } + + bool isInSync(util::MemoryTableWithPayload& table, + std::mutex& tableMutex, std::uint64_t address, + std::uint64_t size) + { + auto optSyncTag = getSyncTag(address, size); + if (!optSyncTag) + { + return false; + } + + auto syncTag = *optSyncTag; + + std::lock_guard lock(tableMutex); + auto tableArea = table.queryArea(address); + + if (tableArea == table.end()) + { + return false; + } + + auto tableTag = *tableArea; + + if (tableTag.beginAddress > address || + tableTag.endAddress < address + size) + { + return false; + } + + return tableTag.payload.tag == syncTag.payload; + } + + virtual void writeBuffer(TaskChain& taskChain, + Ref sourceBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) + { + std::printf("cache: unimplemented buffer write to %lx-%lx\n", address, + address + size); + } + + virtual void readBuffer(TaskChain& taskChain, + Ref targetBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) + { + std::printf("cache: unimplemented buffer read from %lx-%lx\n", address, + address + size); + } }; -struct CacheImageOverlay : CacheOverlayBase { - vk::Image2D image; - - vk::Buffer trasferBuffer; // TODO: remove - VkImageView view = VK_NULL_HANDLE; - std::uint32_t dataWidth; - std::uint32_t dataPitch; - std::uint32_t dataHeight; - std::uint8_t bpp; - TileMode tileMode; - VkImageAspectFlags aspect; - Ref usedBuffer; - - ~CacheImageOverlay() { - if (view != VK_NULL_HANDLE) { - vkDestroyImageView(vk::g_vkDevice, view, vk::g_vkAllocator); - } - } - - void release(std::uint64_t tag) override { - if (false && (aspect & VK_IMAGE_ASPECT_COLOR_BIT)) { - saveImage(("images/" + std::to_string(nextImageId++) + ".ppm").c_str(), - image); - } - - if (usedBuffer) { - usedBuffer->unlock(tag); - usedBuffer = nullptr; - } - } - - void read(TaskChain &taskChain, std::uint64_t address, - Ref srcBuffer, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) { - if (usedBuffer != nullptr) { - util::unreachable(); - } - - usedBuffer = srcBuffer; - auto offset = address - srcBuffer->bufferAddress; - auto size = dataHeight * dataPitch * bpp; - - if (dataPitch == dataWidth && - (tileMode == kTileModeDisplay_2dThin || - tileMode == kTileModeDisplay_LinearAligned)) { - taskChain.add( - ProcessQueue::Graphics, waitTask, - [=, self = Ref(this)](VkCommandBuffer commandBuffer) { - vk::ImageRef imageRef(self->image); - imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); - - VkBufferImageCopy region{ - .bufferOffset = offset, - .bufferRowLength = 0, - .bufferImageHeight = 0, - .imageSubresource = - { - .aspectMask = self->aspect, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = {0, 0, 0}, - .imageExtent = {imageRef.getWidth(), imageRef.getHeight(), 1}, - }; - - vkCmdCopyBufferToImage(commandBuffer, srcBuffer->buffer.getHandle(), - self->image.getHandle(), - VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); - auto tag = *srcBuffer->getSyncTag(address, size); - std::lock_guard lock(self->mtx); - self->syncState.map(address, address + size, tag.payload); - }); - - return; - } - - auto transferBufferReadId = taskChain.add(waitTask, [=, self = Ref(this)] { - auto bufferData = (char *)srcBuffer->buffer.getData() + offset; - - self->trasferBuffer.readFromImage(bufferData, self->bpp, self->tileMode, - self->dataWidth, self->dataHeight, 1, - self->dataPitch); - }); - - taskChain.add( - ProcessQueue::Graphics, transferBufferReadId, - [=, self = Ref(this)](VkCommandBuffer commandBuffer) { - vk::ImageRef imageRef(self->image); - imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); - imageRef.readFromBuffer( - commandBuffer, self->trasferBuffer.getHandle(), self->aspect); - - auto tag = *srcBuffer->getSyncTag(address, size); - std::lock_guard lock(self->mtx); - self->syncState.map(address, address + size, tag.payload); - }); - } - - void readBuffer(TaskChain &taskChain, Ref targetBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override { - auto offset = address - targetBuffer->bufferAddress; - - if (dataPitch == dataWidth && - (tileMode == kTileModeDisplay_2dThin || - tileMode == kTileModeDisplay_LinearAligned)) { - auto linearReadTask = [=, - self = Ref(this)](VkCommandBuffer commandBuffer) { - vk::ImageRef imageRef(self->image); - imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); - - VkBufferImageCopy region{ - .bufferOffset = offset, - .bufferRowLength = 0, - .bufferImageHeight = 0, - .imageSubresource = - { - .aspectMask = self->aspect, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = {0, 0, 0}, - .imageExtent = {imageRef.getWidth(), imageRef.getHeight(), - imageRef.getDepth()}, - }; - - vkCmdCopyImageToBuffer(commandBuffer, imageRef.getHandle(), - VK_IMAGE_LAYOUT_GENERAL, - targetBuffer->buffer.getHandle(), 1, ®ion); - }; - taskChain.add(ProcessQueue::Graphics, waitTask, - std::move(linearReadTask)); - return; - } - - auto writeToTransferBufferTask = taskChain.add( - ProcessQueue::Graphics, waitTask, - [=, self = Ref(this)](VkCommandBuffer commandBuffer) { - vk::ImageRef imageRef(self->image); - imageRef.writeToBuffer(commandBuffer, self->trasferBuffer.getHandle(), - self->aspect); - }); - - taskChain.add(writeToTransferBufferTask, [=, self = Ref(this)] { - auto targetData = (char *)targetBuffer->buffer.getData() + offset; - self->trasferBuffer.writeAsImageTo(targetData, self->bpp, self->tileMode, - self->dataWidth, self->dataHeight, 1, - self->dataPitch); - }); - } +struct CacheBufferOverlay : CacheOverlayBase +{ + vk::Buffer buffer; + std::uint64_t bufferAddress; + + void read(TaskChain& taskChain, + util::MemoryTableWithPayload& table, + std::mutex& tableMtx, std::uint64_t address, + std::uint32_t elementCount, std::uint32_t stride, + std::uint32_t elementSize, bool cache, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId, + bool tableLocked = false) + { + std::lock_guard lock(mtx); + auto size = stride == 0 ? static_cast(elementCount) * elementSize : static_cast(elementCount) * stride; + auto doRead = [&](std::uint64_t address, std::uint64_t size, + std::uint64_t tag, Ref overlay) { + overlay->readBuffer(taskChain, this, address, size, waitTask); + syncState.map(address, address + size, tag); + }; + + auto getAreaInfo = [&](std::uint64_t address) { + if (tableLocked) + { + auto it = table.queryArea(address); + if (it == table.end()) + { + util::unreachable(); + } + + return *it; + } + + std::lock_guard lock(tableMtx); + auto it = table.queryArea(address); + if (it == table.end()) + { + util::unreachable(); + } + return *it; + }; + + while (size > 0) + { + auto state = getAreaInfo(address); + + assert(state.endAddress > address); + auto origAreaSize = std::min(state.endAddress - address, size); + auto areaSize = origAreaSize; + + if (!cache) + { + state.payload.overlay->readBuffer(taskChain, this, address, areaSize, + waitTask); + size -= areaSize; + address += areaSize; + continue; + } + + while (areaSize > 0) + { + auto blockSyncStateIt = syncState.queryArea(address); + + if (blockSyncStateIt == syncState.end()) + { + doRead(address, areaSize, state.payload.tag, state.payload.overlay); + address += areaSize; + break; + } + + auto blockSyncState = *blockSyncStateIt; + auto blockSize = + std::min(blockSyncState.endAddress - address, areaSize); + + if (blockSyncState.payload != state.payload.tag) + { + doRead(address, areaSize, state.payload.tag, state.payload.overlay); + } + + areaSize -= blockSize; + address += blockSize; + } + + size -= origAreaSize; + } + } + + void readBuffer(TaskChain& taskChain, Ref targetBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override + { + auto readTask = [=, self = Ref(this)] { + auto targetOffset = address - targetBuffer->bufferAddress; + auto sourceOffset = address - self->bufferAddress; + std::memcpy((char*)targetBuffer->buffer.getData() + targetOffset, + (char*)self->buffer.getData() + sourceOffset, size); + }; + + if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) + { + readTask(); + } + else + { + taskChain.add(waitTask, std::move(readTask)); + } + } }; -struct MemoryOverlay : CacheOverlayBase { - void readBuffer(TaskChain &taskChain, Ref targetBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override { - auto readTask = [=] { - auto offset = address - targetBuffer->bufferAddress; - auto targetData = (char *)targetBuffer->buffer.getData() + offset; - - std::memcpy(targetData, g_hostMemory.getPointer(address), size); - }; - - if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) { - readTask(); - } else { - taskChain.add(waitTask, std::move(readTask)); - } - } - - void - writeBuffer(TaskChain &taskChain, Ref sourceBuffer, - std::uint64_t address, std::uint64_t size, - std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override { - auto writeTask = [=] { - auto offset = address - sourceBuffer->bufferAddress; - auto sourceData = (char *)sourceBuffer->buffer.getData() + offset; - - std::memcpy(g_hostMemory.getPointer(address), sourceData, size); - }; - - if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) { - writeTask(); - } else { - taskChain.add(waitTask, std::move(writeTask)); - } - } +struct CacheImageOverlay : CacheOverlayBase +{ + vk::Image2D image; + + vk::Buffer trasferBuffer; // TODO: remove + VkImageView view = VK_NULL_HANDLE; + std::uint32_t dataWidth; + std::uint32_t dataPitch; + std::uint32_t dataHeight; + std::uint8_t bpp; + TileMode tileMode; + VkImageAspectFlags aspect; + Ref usedBuffer; + + ~CacheImageOverlay() + { + if (view != VK_NULL_HANDLE) + { + vkDestroyImageView(vk::g_vkDevice, view, vk::g_vkAllocator); + } + } + + void release(std::uint64_t tag) override + { + if (false && (aspect & VK_IMAGE_ASPECT_COLOR_BIT)) + { + saveImage(("images/" + std::to_string(nextImageId++) + ".ppm").c_str(), + image); + } + + if (usedBuffer) + { + usedBuffer->unlock(tag); + usedBuffer = nullptr; + } + } + + void read(TaskChain& taskChain, std::uint64_t address, + Ref srcBuffer, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) + { + if (usedBuffer != nullptr) + { + util::unreachable(); + } + + usedBuffer = srcBuffer; + auto offset = address - srcBuffer->bufferAddress; + auto size = dataHeight * dataPitch * bpp; + + if (dataPitch == dataWidth && + (tileMode == kTileModeDisplay_2dThin || + tileMode == kTileModeDisplay_LinearAligned)) + { + taskChain.add( + ProcessQueue::Graphics, waitTask, + [=, self = Ref(this)](VkCommandBuffer commandBuffer) { + vk::ImageRef imageRef(self->image); + imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + + VkBufferImageCopy region{ + .bufferOffset = offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = + { + .aspectMask = self->aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = {imageRef.getWidth(), imageRef.getHeight(), 1}, + }; + + vkCmdCopyBufferToImage(commandBuffer, srcBuffer->buffer.getHandle(), + self->image.getHandle(), + VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); + auto tag = *srcBuffer->getSyncTag(address, size); + std::lock_guard lock(self->mtx); + self->syncState.map(address, address + size, tag.payload); + }); + + return; + } + + auto transferBufferReadId = taskChain.add(waitTask, [=, self = Ref(this)] { + auto bufferData = (char*)srcBuffer->buffer.getData() + offset; + + self->trasferBuffer.readFromImage(bufferData, self->bpp, self->tileMode, + self->dataWidth, self->dataHeight, 1, + self->dataPitch); + }); + + taskChain.add( + ProcessQueue::Graphics, transferBufferReadId, + [=, self = Ref(this)](VkCommandBuffer commandBuffer) { + vk::ImageRef imageRef(self->image); + imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + imageRef.readFromBuffer( + commandBuffer, self->trasferBuffer.getHandle(), self->aspect); + + auto tag = *srcBuffer->getSyncTag(address, size); + std::lock_guard lock(self->mtx); + self->syncState.map(address, address + size, tag.payload); + }); + } + + void readBuffer(TaskChain& taskChain, Ref targetBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override + { + auto offset = address - targetBuffer->bufferAddress; + + if (dataPitch == dataWidth && + (tileMode == kTileModeDisplay_2dThin || + tileMode == kTileModeDisplay_LinearAligned)) + { + auto linearReadTask = [=, + self = Ref(this)](VkCommandBuffer commandBuffer) { + vk::ImageRef imageRef(self->image); + imageRef.transitionLayout(commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + + VkBufferImageCopy region{ + .bufferOffset = offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = + { + .aspectMask = self->aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = {imageRef.getWidth(), imageRef.getHeight(), + imageRef.getDepth()}, + }; + + vkCmdCopyImageToBuffer(commandBuffer, imageRef.getHandle(), + VK_IMAGE_LAYOUT_GENERAL, + targetBuffer->buffer.getHandle(), 1, ®ion); + }; + taskChain.add(ProcessQueue::Graphics, waitTask, + std::move(linearReadTask)); + return; + } + + auto writeToTransferBufferTask = taskChain.add( + ProcessQueue::Graphics, waitTask, + [=, self = Ref(this)](VkCommandBuffer commandBuffer) { + vk::ImageRef imageRef(self->image); + imageRef.writeToBuffer(commandBuffer, self->trasferBuffer.getHandle(), + self->aspect); + }); + + taskChain.add(writeToTransferBufferTask, [=, self = Ref(this)] { + auto targetData = (char*)targetBuffer->buffer.getData() + offset; + self->trasferBuffer.writeAsImageTo(targetData, self->bpp, self->tileMode, + self->dataWidth, self->dataHeight, 1, + self->dataPitch); + }); + } +}; + +struct MemoryOverlay : CacheOverlayBase +{ + void readBuffer(TaskChain& taskChain, Ref targetBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override + { + auto readTask = [=] { + auto offset = address - targetBuffer->bufferAddress; + auto targetData = (char*)targetBuffer->buffer.getData() + offset; + + std::memcpy(targetData, g_hostMemory.getPointer(address), size); + }; + + if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) + { + readTask(); + } + else + { + taskChain.add(waitTask, std::move(readTask)); + } + } + + void + writeBuffer(TaskChain& taskChain, Ref sourceBuffer, + std::uint64_t address, std::uint64_t size, + std::uint64_t waitTask = GpuTaskLayout::kInvalidId) override + { + auto writeTask = [=] { + auto offset = address - sourceBuffer->bufferAddress; + auto sourceData = (char*)sourceBuffer->buffer.getData() + offset; + + std::memcpy(g_hostMemory.getPointer(address), sourceData, size); + }; + + if (size < bridge::kHostPageSize && waitTask == GpuTaskLayout::kInvalidId) + { + writeTask(); + } + else + { + taskChain.add(waitTask, std::move(writeTask)); + } + } }; static void notifyPageChanges(std::uint32_t firstPage, - std::uint32_t pageCount) { - std::uint64_t command = - (static_cast(pageCount - 1) << 32) | firstPage; - - while (true) { - for (std::size_t i = 0; i < std::size(g_bridge->cacheCommands); ++i) { - std::uint64_t expCommand = 0; - if (g_bridge->cacheCommands[i].compare_exchange_strong( - expCommand, command, std::memory_order::acquire, - std::memory_order::relaxed)) { - return; - } - } - } + std::uint32_t pageCount) +{ + std::uint64_t command = + (static_cast(pageCount - 1) << 32) | firstPage; + + while (true) + { + for (std::size_t i = 0; i < std::size(g_bridge->cacheCommands); ++i) + { + std::uint64_t expCommand = 0; + if (g_bridge->cacheCommands[i].compare_exchange_strong( + expCommand, command, std::memory_order::acquire, + std::memory_order::relaxed)) + { + return; + } + } + } } static void modifyWatchFlags(std::uint64_t address, std::uint64_t size, - std::uint8_t addFlags, std::uint8_t removeFlags) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; - bool hasChanges = false; - for (auto page = firstPage; page < lastPage; ++page) { - auto prevValue = - g_bridge->cachePages[page].load(std::memory_order::relaxed); - auto newValue = (prevValue & ~removeFlags) | addFlags; - - if (newValue == prevValue) { - continue; - } - - while (!g_bridge->cachePages[page].compare_exchange_weak( - prevValue, newValue, std::memory_order::relaxed)) { - newValue = (prevValue & ~removeFlags) | addFlags; - } - - if (newValue != prevValue) { - hasChanges = true; - } - } - - if (hasChanges) { - notifyPageChanges(firstPage, lastPage - firstPage); - } + std::uint8_t addFlags, std::uint8_t removeFlags) +{ + auto firstPage = address / bridge::kHostPageSize; + auto lastPage = + (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; + bool hasChanges = false; + for (auto page = firstPage; page < lastPage; ++page) + { + auto prevValue = + g_bridge->cachePages[page].load(std::memory_order::relaxed); + auto newValue = (prevValue & ~removeFlags) | addFlags; + + if (newValue == prevValue) + { + continue; + } + + while (!g_bridge->cachePages[page].compare_exchange_weak( + prevValue, newValue, std::memory_order::relaxed)) + { + newValue = (prevValue & ~removeFlags) | addFlags; + } + + if (newValue != prevValue) + { + hasChanges = true; + } + } + + if (hasChanges) + { + notifyPageChanges(firstPage, lastPage - firstPage); + } } -static void watchWrites(std::uint64_t address, std::uint64_t size) { - modifyWatchFlags(address, size, bridge::kPageWriteWatch, - bridge::kPageInvalidated); +static void watchWrites(std::uint64_t address, std::uint64_t size) +{ + modifyWatchFlags(address, size, bridge::kPageWriteWatch, + bridge::kPageInvalidated); } static void lockReadWrite(std::uint64_t address, std::uint64_t size, - bool isLazy) { - modifyWatchFlags(address, size, - bridge::kPageReadWriteLock | - (isLazy ? bridge::kPageLazyLock : 0), - bridge::kPageInvalidated); + bool isLazy) +{ + modifyWatchFlags(address, size, + bridge::kPageReadWriteLock | + (isLazy ? bridge::kPageLazyLock : 0), + bridge::kPageInvalidated); } -static void unlockReadWrite(std::uint64_t address, std::uint64_t size) { - modifyWatchFlags(address, size, bridge::kPageWriteWatch, - bridge::kPageReadWriteLock | bridge::kPageLazyLock); +static void unlockReadWrite(std::uint64_t address, std::uint64_t size) +{ + modifyWatchFlags(address, size, bridge::kPageWriteWatch, + bridge::kPageReadWriteLock | bridge::kPageLazyLock); } -struct CacheLine { - std::uint64_t areaAddress; - std::uint64_t areaSize; - - Ref memoryOverlay; - - // TODO: flat image storage - struct ImageKey { - std::uint64_t address; - SurfaceFormat dataFormat; - TextureChannelType channelType; - TileMode tileMode; - std::uint32_t width; - std::uint32_t height; - std::uint32_t depth; - std::uint32_t pitch; - bool isStorage; - - auto operator<=>(const ImageKey &other) const = default; - }; - - std::mutex hostSyncMtx; - util::MemoryTableWithPayload hostSyncTable; - - std::mutex bufferTableMtx; - std::unordered_map>> - bufferTable; - - std::mutex imageTableMtx; - std::map> imageTable; - - std::mutex writeBackTableMtx; - util::MemoryTableWithPayload> writeBackTable; - - CacheLine(std::uint64_t areaAddress, std::uint64_t areaSize) - : areaAddress(areaAddress), areaSize(areaSize) { - memoryOverlay = new MemoryOverlay(); - hostSyncTable.map(areaAddress, areaAddress + areaSize, {1, memoryOverlay}); - } - - void markHostInvalidated(std::uint64_t tag, std::uint64_t address, - std::uint64_t size) { - std::scoped_lock lock(hostSyncMtx, memoryOverlay->mtx); - - hostSyncTable.map(address, address + size, {tag, memoryOverlay}); - memoryOverlay->syncState.map(address, address + size, tag); - } - - bool handleHostInvalidations(std::uint64_t tag, std::uint64_t address, - std::uint64_t size) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; - - bool hasInvalidations = false; - - for (auto page = firstPage; page < lastPage; ++page) { - auto prevValue = - g_bridge->cachePages[page].load(std::memory_order::relaxed); - - if (~prevValue & bridge::kPageInvalidated) { - continue; - } - - while (!g_bridge->cachePages[page].compare_exchange_weak( - prevValue, prevValue & ~bridge::kPageInvalidated, - std::memory_order::relaxed)) { - } - - markHostInvalidated(tag, page * bridge::kHostPageSize, - bridge::kHostPageSize); - hasInvalidations = true; - } - - return hasInvalidations; - } - - void trackCacheRead(std::uint64_t address, std::uint64_t size) { - watchWrites(address, size); - } - - void setWriteBackTask(std::uint64_t address, std::uint64_t size, - Ref task) { - std::lock_guard lock(writeBackTableMtx); - auto it = writeBackTable.queryArea(address); - - while (it != writeBackTable.end()) { - auto taskInfo = *it; - - if (taskInfo.beginAddress >= address + size) { - break; - } - - if (taskInfo.beginAddress >= address && - taskInfo.endAddress <= address + size) { - if (taskInfo.payload != nullptr) { - // another task with smaller range already in progress, we can - // cancel it - - // std::printf("prev upload task cancelation\n"); - taskInfo.payload->cancel(); - } - } - - if (taskInfo.payload != nullptr) { - taskInfo.payload->wait(); - } - - ++it; - } - - writeBackTable.map(address, address + size, std::move(task)); - } - - std::atomic writeBackTag{1}; - - void lazyMemoryUpdate(std::uint64_t tag, std::uint64_t address) { - // std::printf("memory lazy update, address %lx\n", address); - decltype(hostSyncTable)::AreaInfo area; - - { - std::lock_guard lock(hostSyncMtx); - auto it = hostSyncTable.queryArea(address); - - if (it == hostSyncTable.end()) { - util::unreachable(); - } - - area = *it; - } - - auto areaSize = area.endAddress - area.beginAddress; - - auto updateTaskChain = TaskChain::Create(); - auto uploadBuffer = - getBuffer(tag, *updateTaskChain.get(), area.beginAddress, areaSize, 1, - 1, shader::AccessOp::Load); - memoryOverlay->writeBuffer(*updateTaskChain.get(), uploadBuffer, - area.beginAddress, areaSize); - updateTaskChain->wait(); - uploadBuffer->unlock(tag); - unlockReadWrite(area.beginAddress, areaSize); - // std::printf("memory lazy update, %lx finish\n", address); - } - - void trackCacheWrite(std::uint64_t address, std::uint64_t size, - std::uint64_t tag, Ref entry) { - - entry->unlockMutableTask = [=, this] { - if (entry->cacheMode != CacheMode::None) { - lockReadWrite(address, size, entry->cacheMode == CacheMode::LazyWrite); - entry->syncState.map(address, address + size, tag); - - std::lock_guard lock(hostSyncMtx); - hostSyncTable.map(address, address + size, - {.tag = tag, .overlay = entry}); - } else { - std::lock_guard lock(hostSyncMtx); - hostSyncTable.map(address, address + size, - {.tag = tag, .overlay = memoryOverlay}); - } - }; - - if (entry->cacheMode != CacheMode::LazyWrite) { - auto writeBackTask = createCpuTask([=, this]( - const AsyncTaskCtl &ctl) mutable { - if (ctl.isCancelRequested()) { - return TaskResult::Canceled; - } - - auto taskChain = TaskChain::Create(); - Ref uploadBuffer; - auto tag = writeBackTag.fetch_add(1, std::memory_order::relaxed); - - if (entry->cacheMode == CacheMode::None) { - uploadBuffer = static_cast(entry.get()); - if (!uploadBuffer->tryLock(tag, shader::AccessOp::None).isLocked) { - taskChain->add([&] { - return uploadBuffer->tryLock(tag, shader::AccessOp::None).isLocked - ? TaskResult::Complete - : TaskResult::Reschedule; - }); - } - } else { - uploadBuffer = getBuffer(tag, *taskChain.get(), address, size, 1, 1, - shader::AccessOp::Load); - } - taskChain->wait(); - - if (ctl.isCancelRequested()) { - uploadBuffer->unlock(tag); - return TaskResult::Canceled; - } - - memoryOverlay->writeBuffer(*taskChain.get(), uploadBuffer, address, - size); - uploadBuffer->unlock(tag); - - if (ctl.isCancelRequested()) { - return TaskResult::Canceled; - } - - taskChain->wait(); - - if (entry->cacheMode != CacheMode::None) { - unlockReadWrite(address, size); - } - return TaskResult::Complete; - }); - - { - std::lock_guard lock(entry->mtx); - entry->writeBackTaskCtl = writeBackTask; - } - setWriteBackTask(address, size, std::move(writeBackTask)); - } - } - - Ref - getBuffer(std::uint64_t tag, TaskChain &initTaskSet, std::uint64_t address, - std::uint32_t elementCount, std::uint32_t stride, - std::uint32_t elementSize, shader::AccessOp access) { - auto size = stride == 0 - ? static_cast(elementCount) * elementSize - : static_cast(elementCount) * stride; - - auto result = getBufferInternal(address, size); - - if (auto [isLocked, prevLockAccess] = result->tryLock(tag, access); - isLocked) { - initLockedBuffer(result, tag, initTaskSet, address, elementCount, stride, - elementSize, access & ~prevLockAccess); - return result; - } - - auto lockTaskId = initTaskSet.createExternalTask(); - auto waitForLockTask = createCpuTask([=, this, - initTaskSet = Ref(&initTaskSet)] { - auto [isLocked, prevLockAccess] = result->tryLock(tag, access); - if (!isLocked) { - return TaskResult::Reschedule; - } - - auto initTaskChain = TaskChain::Create(); - initLockedBuffer(result, tag, *initTaskChain.get(), address, elementCount, - stride, elementSize, access & ~prevLockAccess); - - initTaskChain->wait(); - initTaskSet->notifyExternalTaskComplete(lockTaskId); - return TaskResult::Complete; - }); - - getCpuScheduler().enqueue(std::move(waitForLockTask)); - return result; - } - - Ref - getImage(std::uint64_t tag, TaskChain &initTaskChain, std::uint64_t address, - SurfaceFormat dataFormat, TextureChannelType channelType, - TileMode tileMode, std::uint32_t width, std::uint32_t height, - std::uint32_t depth, std::uint32_t pitch, shader::AccessOp access, - bool isColor, bool isStorage) { - auto result = - getImageInternal(address, dataFormat, channelType, tileMode, width, - height, depth, pitch, isColor, isStorage); - - auto size = result->bpp * result->dataHeight * result->dataPitch; - - if (auto [isLocked, prevLockAccess] = result->tryLock(tag, access); - isLocked) { - initLockedImage(result, tag, initTaskChain, address, size, - access & ~prevLockAccess); - return result; - } - - auto lockTaskId = initTaskChain.createExternalTask(); - auto waitForLockTask = - createCpuTask([=, this, pipelineInitChain = Ref(&initTaskChain)] { - auto [isLocked, prevLockAccess] = result->tryLock(tag, access); - if (!isLocked) { - return TaskResult::Reschedule; - } - - auto initTaskChain = TaskChain::Create(); - initLockedImage(result, tag, *initTaskChain.get(), address, size, - access & ~prevLockAccess); - - initTaskChain->wait(); - pipelineInitChain->notifyExternalTaskComplete(lockTaskId); - return TaskResult::Complete; - }); - - getCpuScheduler().enqueue(std::move(waitForLockTask)); - return result; - } +struct CacheLine +{ + std::uint64_t areaAddress; + std::uint64_t areaSize; + + Ref memoryOverlay; + + // TODO: flat image storage + struct ImageKey + { + std::uint64_t address; + SurfaceFormat dataFormat; + TextureChannelType channelType; + TileMode tileMode; + std::uint32_t width; + std::uint32_t height; + std::uint32_t depth; + std::uint32_t pitch; + bool isStorage; + + auto operator<=>(const ImageKey& other) const = default; + }; + + std::mutex hostSyncMtx; + util::MemoryTableWithPayload hostSyncTable; + + std::mutex bufferTableMtx; + std::unordered_map>> + bufferTable; + + std::mutex imageTableMtx; + std::map> imageTable; + + std::mutex writeBackTableMtx; + util::MemoryTableWithPayload> writeBackTable; + + CacheLine(std::uint64_t areaAddress, std::uint64_t areaSize) + : areaAddress(areaAddress) + , areaSize(areaSize) + { + memoryOverlay = new MemoryOverlay(); + hostSyncTable.map(areaAddress, areaAddress + areaSize, {1, memoryOverlay}); + } + + void markHostInvalidated(std::uint64_t tag, std::uint64_t address, + std::uint64_t size) + { + std::scoped_lock lock(hostSyncMtx, memoryOverlay->mtx); + + hostSyncTable.map(address, address + size, {tag, memoryOverlay}); + memoryOverlay->syncState.map(address, address + size, tag); + } + + bool handleHostInvalidations(std::uint64_t tag, std::uint64_t address, + std::uint64_t size) + { + auto firstPage = address / bridge::kHostPageSize; + auto lastPage = + (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; + + bool hasInvalidations = false; + + for (auto page = firstPage; page < lastPage; ++page) + { + auto prevValue = + g_bridge->cachePages[page].load(std::memory_order::relaxed); + + if (~prevValue & bridge::kPageInvalidated) + { + continue; + } + + while (!g_bridge->cachePages[page].compare_exchange_weak( + prevValue, prevValue & ~bridge::kPageInvalidated, + std::memory_order::relaxed)) + { + } + + markHostInvalidated(tag, page * bridge::kHostPageSize, + bridge::kHostPageSize); + hasInvalidations = true; + } + + return hasInvalidations; + } + + void trackCacheRead(std::uint64_t address, std::uint64_t size) + { + watchWrites(address, size); + } + + void setWriteBackTask(std::uint64_t address, std::uint64_t size, + Ref task) + { + std::lock_guard lock(writeBackTableMtx); + auto it = writeBackTable.queryArea(address); + + while (it != writeBackTable.end()) + { + auto taskInfo = *it; + + if (taskInfo.beginAddress >= address + size) + { + break; + } + + if (taskInfo.beginAddress >= address && + taskInfo.endAddress <= address + size) + { + if (taskInfo.payload != nullptr) + { + // another task with smaller range already in progress, we can + // cancel it + + // std::printf("prev upload task cancelation\n"); + taskInfo.payload->cancel(); + } + } + + if (taskInfo.payload != nullptr) + { + taskInfo.payload->wait(); + } + + ++it; + } + + writeBackTable.map(address, address + size, std::move(task)); + } + + std::atomic writeBackTag{1}; + + void lazyMemoryUpdate(std::uint64_t tag, std::uint64_t address) + { + // std::printf("memory lazy update, address %lx\n", address); + decltype(hostSyncTable)::AreaInfo area; + + { + std::lock_guard lock(hostSyncMtx); + auto it = hostSyncTable.queryArea(address); + + if (it == hostSyncTable.end()) + { + util::unreachable(); + } + + area = *it; + } + + auto areaSize = area.endAddress - area.beginAddress; + + auto updateTaskChain = TaskChain::Create(); + auto uploadBuffer = + getBuffer(tag, *updateTaskChain.get(), area.beginAddress, areaSize, 1, + 1, shader::AccessOp::Load); + memoryOverlay->writeBuffer(*updateTaskChain.get(), uploadBuffer, + area.beginAddress, areaSize); + updateTaskChain->wait(); + uploadBuffer->unlock(tag); + unlockReadWrite(area.beginAddress, areaSize); + // std::printf("memory lazy update, %lx finish\n", address); + } + + void trackCacheWrite(std::uint64_t address, std::uint64_t size, + std::uint64_t tag, Ref entry) + { + + entry->unlockMutableTask = [=, this] { + if (entry->cacheMode != CacheMode::None) + { + lockReadWrite(address, size, entry->cacheMode == CacheMode::LazyWrite); + entry->syncState.map(address, address + size, tag); + + std::lock_guard lock(hostSyncMtx); + hostSyncTable.map(address, address + size, + {.tag = tag, .overlay = entry}); + } + else + { + std::lock_guard lock(hostSyncMtx); + hostSyncTable.map(address, address + size, + {.tag = tag, .overlay = memoryOverlay}); + } + }; + + if (entry->cacheMode != CacheMode::LazyWrite) + { + auto writeBackTask = createCpuTask([=, this]( + const AsyncTaskCtl& ctl) mutable { + if (ctl.isCancelRequested()) + { + return TaskResult::Canceled; + } + + auto taskChain = TaskChain::Create(); + Ref uploadBuffer; + auto tag = writeBackTag.fetch_add(1, std::memory_order::relaxed); + + if (entry->cacheMode == CacheMode::None) + { + uploadBuffer = static_cast(entry.get()); + if (!uploadBuffer->tryLock(tag, shader::AccessOp::None).isLocked) + { + taskChain->add([&] { + return uploadBuffer->tryLock(tag, shader::AccessOp::None).isLocked ? TaskResult::Complete : TaskResult::Reschedule; + }); + } + } + else + { + uploadBuffer = getBuffer(tag, *taskChain.get(), address, size, 1, 1, + shader::AccessOp::Load); + } + taskChain->wait(); + + if (ctl.isCancelRequested()) + { + uploadBuffer->unlock(tag); + return TaskResult::Canceled; + } + + memoryOverlay->writeBuffer(*taskChain.get(), uploadBuffer, address, + size); + uploadBuffer->unlock(tag); + + if (ctl.isCancelRequested()) + { + return TaskResult::Canceled; + } + + taskChain->wait(); + + if (entry->cacheMode != CacheMode::None) + { + unlockReadWrite(address, size); + } + return TaskResult::Complete; + }); + + { + std::lock_guard lock(entry->mtx); + entry->writeBackTaskCtl = writeBackTask; + } + setWriteBackTask(address, size, std::move(writeBackTask)); + } + } + + Ref + getBuffer(std::uint64_t tag, TaskChain& initTaskSet, std::uint64_t address, + std::uint32_t elementCount, std::uint32_t stride, + std::uint32_t elementSize, shader::AccessOp access) + { + auto size = stride == 0 ? static_cast(elementCount) * elementSize : static_cast(elementCount) * stride; + + auto result = getBufferInternal(address, size); + + if (auto [isLocked, prevLockAccess] = result->tryLock(tag, access); + isLocked) + { + initLockedBuffer(result, tag, initTaskSet, address, elementCount, stride, + elementSize, access & ~prevLockAccess); + return result; + } + + auto lockTaskId = initTaskSet.createExternalTask(); + auto waitForLockTask = createCpuTask([=, this, + initTaskSet = Ref(&initTaskSet)] { + auto [isLocked, prevLockAccess] = result->tryLock(tag, access); + if (!isLocked) + { + return TaskResult::Reschedule; + } + + auto initTaskChain = TaskChain::Create(); + initLockedBuffer(result, tag, *initTaskChain.get(), address, elementCount, + stride, elementSize, access & ~prevLockAccess); + + initTaskChain->wait(); + initTaskSet->notifyExternalTaskComplete(lockTaskId); + return TaskResult::Complete; + }); + + getCpuScheduler().enqueue(std::move(waitForLockTask)); + return result; + } + + Ref + getImage(std::uint64_t tag, TaskChain& initTaskChain, std::uint64_t address, + SurfaceFormat dataFormat, TextureChannelType channelType, + TileMode tileMode, std::uint32_t width, std::uint32_t height, + std::uint32_t depth, std::uint32_t pitch, shader::AccessOp access, + bool isColor, bool isStorage) + { + auto result = + getImageInternal(address, dataFormat, channelType, tileMode, width, + height, depth, pitch, isColor, isStorage); + + auto size = result->bpp * result->dataHeight * result->dataPitch; + + if (auto [isLocked, prevLockAccess] = result->tryLock(tag, access); + isLocked) + { + initLockedImage(result, tag, initTaskChain, address, size, + access & ~prevLockAccess); + return result; + } + + auto lockTaskId = initTaskChain.createExternalTask(); + auto waitForLockTask = + createCpuTask([=, this, pipelineInitChain = Ref(&initTaskChain)] { + auto [isLocked, prevLockAccess] = result->tryLock(tag, access); + if (!isLocked) + { + return TaskResult::Reschedule; + } + + auto initTaskChain = TaskChain::Create(); + initLockedImage(result, tag, *initTaskChain.get(), address, size, + access & ~prevLockAccess); + + initTaskChain->wait(); + pipelineInitChain->notifyExternalTaskComplete(lockTaskId); + return TaskResult::Complete; + }); + + getCpuScheduler().enqueue(std::move(waitForLockTask)); + return result; + } private: - void initLockedImage(Ref result, std::uint64_t writeTag, - TaskChain &initTaskChain, std::uint64_t address, - std::uint64_t size, shader::AccessOp access) { - auto cacheBeginAddress = - (address + bridge::kHostPageSize - 1) & ~(bridge::kHostPageSize - 1); - auto cacheEndAddress = (address + size) & ~(bridge::kHostPageSize - 1); - - if (cacheBeginAddress == cacheEndAddress) { - cacheBeginAddress = address; - cacheEndAddress = address + size; - } - - auto cacheSize = cacheEndAddress - cacheBeginAddress; - - if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) { - if (result->writeBackTaskCtl) { - result->writeBackTaskCtl->cancel(); - result->writeBackTaskCtl->wait(); - } - } - - if ((access & shader::AccessOp::Load) == shader::AccessOp::Load) { - if (handleHostInvalidations(writeTag - 1, cacheBeginAddress, cacheSize) || - !result->isInSync(hostSyncTable, hostSyncMtx, address, size)) { - auto buffer = getBuffer(writeTag, initTaskChain, address, size, 0, 1, - shader::AccessOp::Load); - auto bufferInitTask = initTaskChain.getLastTaskId(); - - result->read(initTaskChain, address, std::move(buffer), bufferInitTask); - trackCacheRead(cacheBeginAddress, cacheSize); - } - } - - if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) { - trackCacheWrite(address, size, writeTag, result); - } - } - - void initLockedBuffer(Ref result, std::uint64_t writeTag, - TaskChain &readTaskSet, std::uint64_t address, - std::uint32_t elementCount, std::uint32_t stride, - std::uint32_t elementSize, shader::AccessOp access) { - auto size = stride == 0 - ? static_cast(elementCount) * elementSize - : static_cast(elementCount) * stride; - - if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) { - if (result->writeBackTaskCtl) { - result->writeBackTaskCtl->cancel(); - result->writeBackTaskCtl->wait(); - } - } - - if ((access & shader::AccessOp::Load) == shader::AccessOp::Load) { - if (result->cacheMode == CacheMode::None || - handleHostInvalidations(writeTag - 1, address, size) || - !result->isInSync(hostSyncTable, hostSyncMtx, address, size)) { - result->read(readTaskSet, hostSyncTable, hostSyncMtx, address, - elementCount, stride, elementSize, - result->cacheMode != CacheMode::None); - - if (result->cacheMode != CacheMode::None) { - // std::printf("caching %lx-%lx\n", address, size); - trackCacheRead(address, size); - } - } - } - - if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) { - trackCacheWrite(address, size, writeTag, result); - } - } - - Ref getBufferInternal(std::uint64_t address, - std::uint64_t size) { - auto alignment = - vk::g_physicalDeviceProperties.limits.minStorageBufferOffsetAlignment; - - if (address + size > areaAddress + areaSize) { - util::unreachable(); - } - - auto offset = (address - areaAddress) & (alignment - 1); - - std::lock_guard lock(bufferTableMtx); - auto &table = bufferTable[offset]; - - if (auto it = table.queryArea(address); it != table.end()) { - auto bufferInfo = *it; - - if (bufferInfo.beginAddress <= address && - bufferInfo.endAddress >= address + size) { - if (!isAligned(address - bufferInfo.beginAddress, alignment)) { - util::unreachable(); - } - - return bufferInfo.payload; - } - - assert(bufferInfo.beginAddress <= address); - - auto endAddress = std::max(bufferInfo.endAddress, address + size); - address = bufferInfo.beginAddress; - - while (it != table.end()) { - bufferInfo = *it; - if (endAddress > bufferInfo.endAddress) { - auto nextIt = it; - if (++nextIt != table.end()) { - auto nextInfo = *nextIt; - if (nextInfo.beginAddress >= endAddress) { - break; - } - endAddress = nextInfo.endAddress; - } - } - ++it; - } - - size = endAddress - address; - } - - auto bufferOverlay = new CacheBufferOverlay(); - bufferOverlay->buffer = vk::Buffer::Allocate( - getHostVisibleMemory(), size, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT); - bufferOverlay->bufferAddress = address; - bufferOverlay->cacheMode = - size >= 3 * bridge::kHostPageSize - ? CacheMode::LazyWrite - : (size >= bridge::kHostPageSize ? CacheMode::AsyncWrite - : CacheMode::None); - - table.map(address, address + size, bufferOverlay); - return bufferOverlay; - } - - Ref - getImageInternal(std::uint64_t address, SurfaceFormat dataFormat, - TextureChannelType channelType, TileMode tileMode, - std::uint32_t width, std::uint32_t height, - std::uint32_t depth, std::uint32_t pitch, bool isColor, - bool isStorage) { - ImageKey key{ - .address = address, - .dataFormat = dataFormat, - .channelType = channelType, - .tileMode = tileMode, - .width = width, - .height = height, - .depth = depth, - .pitch = pitch, - .isStorage = isStorage, - }; - - decltype(imageTable)::iterator it; - { - std::lock_guard lock(imageTableMtx); - - auto [emplacedIt, inserted] = - imageTable.try_emplace(key, Ref{}); - - if (!inserted) { - return emplacedIt->second; - } - - it = emplacedIt; - } - - std::printf( - "Image cache miss: address: %lx, dataFormat: %u, channelType: %u, " - "tileMode: %u, width: %u, height: %u, depth: %u, pitch: %u\n", - address, dataFormat, channelType, tileMode, width, height, depth, - pitch); - - auto colorFormat = surfaceFormatToVkFormat(dataFormat, channelType); - auto usage = - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - - if (isStorage) { - usage |= VK_IMAGE_USAGE_STORAGE_BIT; - } else { - usage |= VK_IMAGE_USAGE_SAMPLED_BIT; - } - - bool isCompressed = - dataFormat == kSurfaceFormatBc1 || dataFormat == kSurfaceFormatBc2 || - dataFormat == kSurfaceFormatBc3 || dataFormat == kSurfaceFormatBc4 || - dataFormat == kSurfaceFormatBc5 || dataFormat == kSurfaceFormatBc6 || - dataFormat == kSurfaceFormatBc7; - if (!isCompressed) { - if (isColor) { - usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } else { - usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - } - - if (isStorage) { - if (colorFormat == VK_FORMAT_R8G8B8A8_SRGB) { - colorFormat = VK_FORMAT_R8G8B8A8_UNORM; - } - } - - auto newOverlay = new CacheImageOverlay(); - - newOverlay->image = vk::Image2D::Allocate(getDeviceLocalMemory(), width, - height, colorFormat, usage); - - auto bpp = getBitWidthOfSurfaceFormat(dataFormat) / 8; - - std::uint32_t dataWidth = width; - std::uint32_t dataPitch = pitch; - std::uint32_t dataHeight = height; - - /*if (dataFormat == kSurfaceFormatBc1) { + void initLockedImage(Ref result, std::uint64_t writeTag, + TaskChain& initTaskChain, std::uint64_t address, + std::uint64_t size, shader::AccessOp access) + { + auto cacheBeginAddress = + (address + bridge::kHostPageSize - 1) & ~(bridge::kHostPageSize - 1); + auto cacheEndAddress = (address + size) & ~(bridge::kHostPageSize - 1); + + if (cacheBeginAddress == cacheEndAddress) + { + cacheBeginAddress = address; + cacheEndAddress = address + size; + } + + auto cacheSize = cacheEndAddress - cacheBeginAddress; + + if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) + { + if (result->writeBackTaskCtl) + { + result->writeBackTaskCtl->cancel(); + result->writeBackTaskCtl->wait(); + } + } + + if ((access & shader::AccessOp::Load) == shader::AccessOp::Load) + { + if (handleHostInvalidations(writeTag - 1, cacheBeginAddress, cacheSize) || + !result->isInSync(hostSyncTable, hostSyncMtx, address, size)) + { + auto buffer = getBuffer(writeTag, initTaskChain, address, size, 0, 1, + shader::AccessOp::Load); + auto bufferInitTask = initTaskChain.getLastTaskId(); + + result->read(initTaskChain, address, std::move(buffer), bufferInitTask); + trackCacheRead(cacheBeginAddress, cacheSize); + } + } + + if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) + { + trackCacheWrite(address, size, writeTag, result); + } + } + + void initLockedBuffer(Ref result, std::uint64_t writeTag, + TaskChain& readTaskSet, std::uint64_t address, + std::uint32_t elementCount, std::uint32_t stride, + std::uint32_t elementSize, shader::AccessOp access) + { + auto size = stride == 0 ? static_cast(elementCount) * elementSize : static_cast(elementCount) * stride; + + if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) + { + if (result->writeBackTaskCtl) + { + result->writeBackTaskCtl->cancel(); + result->writeBackTaskCtl->wait(); + } + } + + if ((access & shader::AccessOp::Load) == shader::AccessOp::Load) + { + if (result->cacheMode == CacheMode::None || + handleHostInvalidations(writeTag - 1, address, size) || + !result->isInSync(hostSyncTable, hostSyncMtx, address, size)) + { + result->read(readTaskSet, hostSyncTable, hostSyncMtx, address, + elementCount, stride, elementSize, + result->cacheMode != CacheMode::None); + + if (result->cacheMode != CacheMode::None) + { + // std::printf("caching %lx-%lx\n", address, size); + trackCacheRead(address, size); + } + } + } + + if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) + { + trackCacheWrite(address, size, writeTag, result); + } + } + + Ref getBufferInternal(std::uint64_t address, + std::uint64_t size) + { + auto alignment = + vk::g_physicalDeviceProperties.limits.minStorageBufferOffsetAlignment; + + if (address + size > areaAddress + areaSize) + { + util::unreachable(); + } + + auto offset = (address - areaAddress) & (alignment - 1); + + std::lock_guard lock(bufferTableMtx); + auto& table = bufferTable[offset]; + + if (auto it = table.queryArea(address); it != table.end()) + { + auto bufferInfo = *it; + + if (bufferInfo.beginAddress <= address && + bufferInfo.endAddress >= address + size) + { + if (!isAligned(address - bufferInfo.beginAddress, alignment)) + { + util::unreachable(); + } + + return bufferInfo.payload; + } + + assert(bufferInfo.beginAddress <= address); + + auto endAddress = std::max(bufferInfo.endAddress, address + size); + address = bufferInfo.beginAddress; + + while (it != table.end()) + { + bufferInfo = *it; + if (endAddress > bufferInfo.endAddress) + { + auto nextIt = it; + if (++nextIt != table.end()) + { + auto nextInfo = *nextIt; + if (nextInfo.beginAddress >= endAddress) + { + break; + } + endAddress = nextInfo.endAddress; + } + } + ++it; + } + + size = endAddress - address; + } + + auto bufferOverlay = new CacheBufferOverlay(); + bufferOverlay->buffer = vk::Buffer::Allocate( + getHostVisibleMemory(), size, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + bufferOverlay->bufferAddress = address; + bufferOverlay->cacheMode = + size >= 3 * bridge::kHostPageSize ? CacheMode::LazyWrite : (size >= bridge::kHostPageSize ? CacheMode::AsyncWrite : CacheMode::None); + + table.map(address, address + size, bufferOverlay); + return bufferOverlay; + } + + Ref + getImageInternal(std::uint64_t address, SurfaceFormat dataFormat, + TextureChannelType channelType, TileMode tileMode, + std::uint32_t width, std::uint32_t height, + std::uint32_t depth, std::uint32_t pitch, bool isColor, + bool isStorage) + { + ImageKey key{ + .address = address, + .dataFormat = dataFormat, + .channelType = channelType, + .tileMode = tileMode, + .width = width, + .height = height, + .depth = depth, + .pitch = pitch, + .isStorage = isStorage, + }; + + decltype(imageTable)::iterator it; + { + std::lock_guard lock(imageTableMtx); + + auto [emplacedIt, inserted] = + imageTable.try_emplace(key, Ref{}); + + if (!inserted) + { + return emplacedIt->second; + } + + it = emplacedIt; + } + + std::printf( + "Image cache miss: address: %lx, dataFormat: %u, channelType: %u, " + "tileMode: %u, width: %u, height: %u, depth: %u, pitch: %u\n", + address, dataFormat, channelType, tileMode, width, height, depth, + pitch); + + auto colorFormat = surfaceFormatToVkFormat(dataFormat, channelType); + auto usage = + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + if (isStorage) + { + usage |= VK_IMAGE_USAGE_STORAGE_BIT; + } + else + { + usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + + bool isCompressed = + dataFormat == kSurfaceFormatBc1 || dataFormat == kSurfaceFormatBc2 || + dataFormat == kSurfaceFormatBc3 || dataFormat == kSurfaceFormatBc4 || + dataFormat == kSurfaceFormatBc5 || dataFormat == kSurfaceFormatBc6 || + dataFormat == kSurfaceFormatBc7; + if (!isCompressed) + { + if (isColor) + { + usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + else + { + usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + } + + if (isStorage) + { + if (colorFormat == VK_FORMAT_R8G8B8A8_SRGB) + { + colorFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + } + + auto newOverlay = new CacheImageOverlay(); + + newOverlay->image = vk::Image2D::Allocate(getDeviceLocalMemory(), width, + height, colorFormat, usage); + + auto bpp = getBitWidthOfSurfaceFormat(dataFormat) / 8; + + std::uint32_t dataWidth = width; + std::uint32_t dataPitch = pitch; + std::uint32_t dataHeight = height; + + /*if (dataFormat == kSurfaceFormatBc1) { width = (width + 7) / 8; height = (height + 7) / 8; pitch = (pitch + 7) / 8; bpp = 8; } else */ - if (isCompressed) { - dataWidth = (width + 3) / 4; - dataPitch = (height + 3) / 4; - dataHeight = (pitch + 3) / 4; - bpp = 16; - } - - auto memSize = vk::ImageRef(newOverlay->image).getMemoryRequirements().size; - - newOverlay->trasferBuffer = vk::Buffer::Allocate( - getHostVisibleMemory(), memSize, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT); - - newOverlay->dataWidth = dataWidth; - newOverlay->dataPitch = dataPitch; - newOverlay->dataHeight = dataHeight; - newOverlay->bpp = bpp; - newOverlay->tileMode = tileMode; - - VkImageViewCreateInfo viewInfo{ - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = newOverlay->image.getHandle(), - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = colorFormat, - .components = {}, // TODO - .subresourceRange = - { - .aspectMask = static_cast( - isColor ? VK_IMAGE_ASPECT_COLOR_BIT - : VK_IMAGE_ASPECT_DEPTH_BIT | - VK_IMAGE_ASPECT_STENCIL_BIT), - .baseMipLevel = 0, // TODO - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - - Verify() << vkCreateImageView(vk::g_vkDevice, &viewInfo, nullptr, - &newOverlay->view); - - newOverlay->aspect = - isColor ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; - newOverlay->cacheMode = memSize >= bridge::kHostPageSize * 3 - ? CacheMode::LazyWrite - : CacheMode::AsyncWrite; - it->second = newOverlay; - return it->second; - } + if (isCompressed) + { + dataWidth = (width + 3) / 4; + dataPitch = (height + 3) / 4; + dataHeight = (pitch + 3) / 4; + bpp = 16; + } + + auto memSize = vk::ImageRef(newOverlay->image).getMemoryRequirements().size; + + newOverlay->trasferBuffer = vk::Buffer::Allocate( + getHostVisibleMemory(), memSize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + + newOverlay->dataWidth = dataWidth; + newOverlay->dataPitch = dataPitch; + newOverlay->dataHeight = dataHeight; + newOverlay->bpp = bpp; + newOverlay->tileMode = tileMode; + + VkImageViewCreateInfo viewInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = newOverlay->image.getHandle(), + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = colorFormat, + .components = {}, // TODO + .subresourceRange = + { + .aspectMask = static_cast( + isColor ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), + .baseMipLevel = 0, // TODO + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + Verify() << vkCreateImageView(vk::g_vkDevice, &viewInfo, nullptr, + &newOverlay->view); + + newOverlay->aspect = + isColor ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + newOverlay->cacheMode = memSize >= bridge::kHostPageSize * 3 ? CacheMode::LazyWrite : CacheMode::AsyncWrite; + it->second = newOverlay; + return it->second; + } }; -struct Cache { - // TODO: use descriptor buffer instead - VkDescriptorPool graphicsDescriptorPool{}; - VkDescriptorPool computeDescriptorPool{}; - std::vector graphicsDecsriptorSets; - std::vector computeDecsriptorSets; - - struct DetachedImageKey { - SurfaceFormat dataFormat; - TextureChannelType channelType; - std::uint32_t width; - std::uint32_t height; - std::uint32_t depth; - - auto operator<=>(const DetachedImageKey &other) const = default; - }; - - // TODO: read S# - VkSampler sampler{}; - std::map> datachedImages; - std::map> cacheLines; - std::atomic nextTag{2}; - std::map> shaders; - - std::mutex mtx; - - Cache() { - getCpuScheduler().enqueue([this] { - auto page = g_bridge->gpuCacheCommand.load(std::memory_order::relaxed); - if (page == 0) { - return TaskResult::Reschedule; - } - - g_bridge->gpuCacheCommand.store(0, std::memory_order::relaxed); - auto address = static_cast(page) * bridge::kHostPageSize; - - auto &line = getLine(address, bridge::kHostPageSize); - line.lazyMemoryUpdate(createTag(), address); - return TaskResult::Reschedule; - }); - } - - void clear() { - vkDestroyDescriptorPool(vk::g_vkDevice, graphicsDescriptorPool, - vk::g_vkAllocator); - vkDestroyDescriptorPool(vk::g_vkDevice, computeDescriptorPool, - vk::g_vkAllocator); - vkDestroySampler(vk::g_vkDevice, sampler, vk::g_vkAllocator); - graphicsDescriptorPool = VK_NULL_HANDLE; - computeDescriptorPool = VK_NULL_HANDLE; - sampler = VK_NULL_HANDLE; - - graphicsDecsriptorSets.clear(); - computeDecsriptorSets.clear(); - datachedImages.clear(); - cacheLines.clear(); - nextTag = 2; - } - - void syncLines() { - std::lock_guard lock(mtx); - - auto areas = std::exchange(memoryAreaTable.invalidated, {}); - auto it = cacheLines.begin(); - - if (it == cacheLines.end()) { - return; - } - - for (auto area : areas) { - while (it->first > area) { - if (++it == cacheLines.end()) { - return; - } - } - - if (it->first == area) { - it = cacheLines.erase(it); - - if (it == cacheLines.end()) { - return; - } - } - } - } - - VkDescriptorSet getComputeDescriptorSet() { - { - std::lock_guard lock(mtx); - if (computeDescriptorPool == nullptr) { - VkDescriptorPoolSize poolSizes[]{ - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = shader::UniformBindings::kBufferSlots, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = shader::UniformBindings::kImageSlots, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = shader::UniformBindings::kSamplerSlots, - }, - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = shader::UniformBindings::kStorageImageSlots, - }, - }; - - VkDescriptorPoolCreateInfo info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = 32, - .poolSizeCount = static_cast(std::size(poolSizes)), - .pPoolSizes = poolSizes, - }; - - Verify() << vkCreateDescriptorPool( - vk::g_vkDevice, &info, vk::g_vkAllocator, &computeDescriptorPool); - } - - if (!computeDecsriptorSets.empty()) { - auto result = computeDecsriptorSets.back(); - computeDecsriptorSets.pop_back(); - return result; - } - } - - auto layout = getComputeLayout().first; - - VkDescriptorSetAllocateInfo info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = computeDescriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &layout, - }; - - VkDescriptorSet result; - Verify() << vkAllocateDescriptorSets(vk::g_vkDevice, &info, &result); - return result; - } - - std::uint64_t createTag() { return nextTag.fetch_add(2); } - - VkSampler getSampler() { - if (sampler != VK_NULL_HANDLE) { - return sampler; - } - - std::lock_guard lock(mtx); - VkSamplerCreateInfo samplerInfo{ - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .magFilter = VK_FILTER_LINEAR, - .minFilter = VK_FILTER_LINEAR, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, - .addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - .addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - .addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - .mipLodBias = 0.0f, - .anisotropyEnable = VK_FALSE, - .maxAnisotropy = 1.0, - .compareOp = VK_COMPARE_OP_NEVER, - .minLod = 0.0f, - .maxLod = 0.0f, - .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, - }; - - Verify() << vkCreateSampler(vk::g_vkDevice, &samplerInfo, nullptr, - &sampler); - return sampler; - } - - VkDescriptorSet getGraphicsDescriptorSet() { - { - std::lock_guard lock(mtx); - if (graphicsDescriptorPool == nullptr) { - VkDescriptorPoolSize poolSizes[]{ - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = shader::UniformBindings::kBufferSlots * 2, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = shader::UniformBindings::kImageSlots * 2, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = shader::UniformBindings::kSamplerSlots * 2, - }, - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = - shader::UniformBindings::kStorageImageSlots * 2, - }, - }; - - VkDescriptorPoolCreateInfo info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = 32, - .poolSizeCount = static_cast(std::size(poolSizes)), - .pPoolSizes = poolSizes, - }; - - Verify() << vkCreateDescriptorPool( - vk::g_vkDevice, &info, vk::g_vkAllocator, &graphicsDescriptorPool); - } - - if (!graphicsDecsriptorSets.empty()) { - auto result = graphicsDecsriptorSets.back(); - graphicsDecsriptorSets.pop_back(); - return result; - } - } - - auto layout = getGraphicsLayout().first; - - VkDescriptorSetAllocateInfo info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = graphicsDescriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &layout, - }; - - VkDescriptorSet result; - Verify() << vkAllocateDescriptorSets(vk::g_vkDevice, &info, &result); - return result; - } - - void releaseGraphicsDescriptorSet(VkDescriptorSet descSet) { - std::lock_guard lock(mtx); - graphicsDecsriptorSets.push_back(descSet); - } - - void releaseComputeDescriptorSet(VkDescriptorSet descSet) { - std::lock_guard lock(mtx); - computeDecsriptorSets.push_back(descSet); - } - - const CachedShader &getShader(TaskSet &taskSet, - VkDescriptorSetLayout descriptorSetLayout, - shader::Stage stage, std::uint64_t address, - std::uint32_t *userSgprs, - std::uint8_t userSgprsCount, - std::uint16_t dimX = 1, std::uint16_t dimY = 1, - std::uint16_t dimZ = 1) { - ShaderKey key{.address = address, - .dimX = dimX, - .dimY = dimY, - .dimZ = dimZ, - .stage = stage, - .userSgprCount = userSgprsCount}; - - std::memcpy(key.userSgprs, userSgprs, - userSgprsCount * sizeof(std::uint32_t)); - - decltype(shaders)::iterator it; - CachedShader *entry; - { - std::lock_guard lock(mtx); - - auto [emplacedIt, inserted] = - shaders.try_emplace(key, std::forward_list{}); - - if (!inserted) { - for (auto &shader : emplacedIt->second) { - bool isAllSame = true; - for (auto &[startAddress, bytes] : shader.cachedData) { - if (std::memcmp(g_hostMemory.getPointer(startAddress), bytes.data(), - bytes.size()) != 0) { - isAllSame = false; - break; - } - } - - if (isAllSame) { - return shader; - } - } - - std::printf("cache: found shader with different data, recompiling\n"); - } - - it = emplacedIt; - entry = &it->second.emplace_front(); - } - - taskSet.append( - getCpuScheduler(), createCpuTask([=](const AsyncTaskCtl &) { - util::MemoryAreaTable<> dependencies; - flockfile(stdout); - auto info = shader::convert( - g_hostMemory, stage, address, - std::span(userSgprs, userSgprsCount), dimX, - dimY, dimZ, dependencies); - - if (!validateSpirv(info.spirv)) { - printSpirv(info.spirv); - dumpShader(g_hostMemory.getPointer(address)); - util::unreachable(); - } - - // if (auto opt = optimizeSpirv(info.spirv)) { - // info.spirv = std::move(*opt); - // } - - printSpirv(info.spirv); - funlockfile(stdout); - - for (auto [startAddress, endAddress] : dependencies) { - auto ptr = g_hostMemory.getPointer(startAddress); - auto &target = entry->cachedData[startAddress]; - target.resize(endAddress - startAddress); - - // std::printf("shader dependency %lx-%lx\n", startAddress, - // endAddress); - std::memcpy(target.data(), ptr, target.size()); - } - - VkShaderCreateInfoEXT createInfo{ - .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, - .flags = 0, - .stage = shaderStageToVk(stage), - .nextStage = 0, - .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, - .codeSize = info.spirv.size() * sizeof(info.spirv[0]), - .pCode = info.spirv.data(), - .pName = "main", - .setLayoutCount = 1, - .pSetLayouts = &descriptorSetLayout, - }; - - VkShaderEXT shader; - Verify() << _vkCreateShadersEXT(vk::g_vkDevice, 1, &createInfo, - vk::g_vkAllocator, &shader); - entry->info = std::move(info); - entry->shader = shader; - })); - - return *entry; - } - - Ref - getImage(std::uint64_t tag, TaskChain &initTaskChain, std::uint64_t address, - SurfaceFormat dataFormat, TextureChannelType channelType, - TileMode tileMode, std::uint32_t width, std::uint32_t height, - std::uint32_t depth, std::uint32_t pitch, shader::AccessOp access, - bool isColor = true, bool isStorage = false) { - auto &line = getLine(address, pitch * height * depth); - return line.getImage(tag, initTaskChain, address, dataFormat, channelType, - tileMode, width, height, depth, pitch, access, isColor, - isStorage); - } - - Ref - getBuffer(std::uint64_t tag, TaskChain &initTaskChain, std::uint64_t address, - std::uint32_t elementCount, std::uint32_t stride, - std::uint32_t elementSize, shader::AccessOp access) { - auto &line = getLine(address, stride != 0 ? stride * elementCount - : elementSize * elementCount); - return line.getBuffer(tag, initTaskChain, address, elementCount, stride, - elementSize, access); - } +struct Cache +{ + // TODO: use descriptor buffer instead + VkDescriptorPool graphicsDescriptorPool{}; + VkDescriptorPool computeDescriptorPool{}; + std::vector graphicsDecsriptorSets; + std::vector computeDecsriptorSets; + + struct DetachedImageKey + { + SurfaceFormat dataFormat; + TextureChannelType channelType; + std::uint32_t width; + std::uint32_t height; + std::uint32_t depth; + + auto operator<=>(const DetachedImageKey& other) const = default; + }; + + // TODO: read S# + VkSampler sampler{}; + std::map> datachedImages; + std::map> cacheLines; + std::atomic nextTag{2}; + std::map> shaders; + + std::mutex mtx; + + Cache() + { + getCpuScheduler().enqueue([this] { + auto page = g_bridge->gpuCacheCommand.load(std::memory_order::relaxed); + if (page == 0) + { + return TaskResult::Reschedule; + } + + g_bridge->gpuCacheCommand.store(0, std::memory_order::relaxed); + auto address = static_cast(page) * bridge::kHostPageSize; + + auto& line = getLine(address, bridge::kHostPageSize); + line.lazyMemoryUpdate(createTag(), address); + return TaskResult::Reschedule; + }); + } + + void clear() + { + vkDestroyDescriptorPool(vk::g_vkDevice, graphicsDescriptorPool, + vk::g_vkAllocator); + vkDestroyDescriptorPool(vk::g_vkDevice, computeDescriptorPool, + vk::g_vkAllocator); + vkDestroySampler(vk::g_vkDevice, sampler, vk::g_vkAllocator); + graphicsDescriptorPool = VK_NULL_HANDLE; + computeDescriptorPool = VK_NULL_HANDLE; + sampler = VK_NULL_HANDLE; + + graphicsDecsriptorSets.clear(); + computeDecsriptorSets.clear(); + datachedImages.clear(); + cacheLines.clear(); + nextTag = 2; + } + + void syncLines() + { + std::lock_guard lock(mtx); + + auto areas = std::exchange(memoryAreaTable.invalidated, {}); + auto it = cacheLines.begin(); + + if (it == cacheLines.end()) + { + return; + } + + for (auto area : areas) + { + while (it->first > area) + { + if (++it == cacheLines.end()) + { + return; + } + } + + if (it->first == area) + { + it = cacheLines.erase(it); + + if (it == cacheLines.end()) + { + return; + } + } + } + } + + VkDescriptorSet getComputeDescriptorSet() + { + { + std::lock_guard lock(mtx); + if (computeDescriptorPool == nullptr) + { + VkDescriptorPoolSize poolSizes[]{ + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = shader::UniformBindings::kBufferSlots, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = shader::UniformBindings::kImageSlots, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = shader::UniformBindings::kSamplerSlots, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = shader::UniformBindings::kStorageImageSlots, + }, + }; + + VkDescriptorPoolCreateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 32, + .poolSizeCount = static_cast(std::size(poolSizes)), + .pPoolSizes = poolSizes, + }; + + Verify() << vkCreateDescriptorPool( + vk::g_vkDevice, &info, vk::g_vkAllocator, &computeDescriptorPool); + } + + if (!computeDecsriptorSets.empty()) + { + auto result = computeDecsriptorSets.back(); + computeDecsriptorSets.pop_back(); + return result; + } + } + + auto layout = getComputeLayout().first; + + VkDescriptorSetAllocateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = computeDescriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &layout, + }; + + VkDescriptorSet result; + Verify() << vkAllocateDescriptorSets(vk::g_vkDevice, &info, &result); + return result; + } + + std::uint64_t createTag() { return nextTag.fetch_add(2); } + + VkSampler getSampler() + { + if (sampler != VK_NULL_HANDLE) + { + return sampler; + } + + std::lock_guard lock(mtx); + VkSamplerCreateInfo samplerInfo{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_LINEAR, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + .mipLodBias = 0.0f, + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 1.0, + .compareOp = VK_COMPARE_OP_NEVER, + .minLod = 0.0f, + .maxLod = 0.0f, + .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, + }; + + Verify() << vkCreateSampler(vk::g_vkDevice, &samplerInfo, nullptr, + &sampler); + return sampler; + } + + VkDescriptorSet getGraphicsDescriptorSet() + { + { + std::lock_guard lock(mtx); + if (graphicsDescriptorPool == nullptr) + { + VkDescriptorPoolSize poolSizes[]{ + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = shader::UniformBindings::kBufferSlots * 2, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = shader::UniformBindings::kImageSlots * 2, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = shader::UniformBindings::kSamplerSlots * 2, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = + shader::UniformBindings::kStorageImageSlots * 2, + }, + }; + + VkDescriptorPoolCreateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 32, + .poolSizeCount = static_cast(std::size(poolSizes)), + .pPoolSizes = poolSizes, + }; + + Verify() << vkCreateDescriptorPool( + vk::g_vkDevice, &info, vk::g_vkAllocator, &graphicsDescriptorPool); + } + + if (!graphicsDecsriptorSets.empty()) + { + auto result = graphicsDecsriptorSets.back(); + graphicsDecsriptorSets.pop_back(); + return result; + } + } + + auto layout = getGraphicsLayout().first; + + VkDescriptorSetAllocateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = graphicsDescriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &layout, + }; + + VkDescriptorSet result; + Verify() << vkAllocateDescriptorSets(vk::g_vkDevice, &info, &result); + return result; + } + + void releaseGraphicsDescriptorSet(VkDescriptorSet descSet) + { + std::lock_guard lock(mtx); + graphicsDecsriptorSets.push_back(descSet); + } + + void releaseComputeDescriptorSet(VkDescriptorSet descSet) + { + std::lock_guard lock(mtx); + computeDecsriptorSets.push_back(descSet); + } + + const CachedShader& getShader(TaskSet& taskSet, + VkDescriptorSetLayout descriptorSetLayout, + shader::Stage stage, std::uint64_t address, + std::uint32_t* userSgprs, + std::uint8_t userSgprsCount, + std::uint16_t dimX = 1, std::uint16_t dimY = 1, + std::uint16_t dimZ = 1) + { + ShaderKey key{.address = address, + .dimX = dimX, + .dimY = dimY, + .dimZ = dimZ, + .stage = stage, + .userSgprCount = userSgprsCount}; + + std::memcpy(key.userSgprs, userSgprs, + userSgprsCount * sizeof(std::uint32_t)); + + decltype(shaders)::iterator it; + CachedShader* entry; + { + std::lock_guard lock(mtx); + + auto [emplacedIt, inserted] = + shaders.try_emplace(key, std::forward_list{}); + + if (!inserted) + { + for (auto& shader : emplacedIt->second) + { + bool isAllSame = true; + for (auto& [startAddress, bytes] : shader.cachedData) + { + if (std::memcmp(g_hostMemory.getPointer(startAddress), bytes.data(), + bytes.size()) != 0) + { + isAllSame = false; + break; + } + } + + if (isAllSame) + { + return shader; + } + } + + std::printf("cache: found shader with different data, recompiling\n"); + } + + it = emplacedIt; + entry = &it->second.emplace_front(); + } + + taskSet.append( + getCpuScheduler(), createCpuTask([=](const AsyncTaskCtl&) { + util::MemoryAreaTable<> dependencies; + flockfile(stdout); + auto info = shader::convert( + g_hostMemory, stage, address, + std::span(userSgprs, userSgprsCount), dimX, + dimY, dimZ, dependencies); + + if (!validateSpirv(info.spirv)) + { + printSpirv(info.spirv); + dumpShader(g_hostMemory.getPointer(address)); + util::unreachable(); + } + + // if (auto opt = optimizeSpirv(info.spirv)) { + // info.spirv = std::move(*opt); + // } + + printSpirv(info.spirv); + funlockfile(stdout); + + for (auto [startAddress, endAddress] : dependencies) + { + auto ptr = g_hostMemory.getPointer(startAddress); + auto& target = entry->cachedData[startAddress]; + target.resize(endAddress - startAddress); + + // std::printf("shader dependency %lx-%lx\n", startAddress, + // endAddress); + std::memcpy(target.data(), ptr, target.size()); + } + + VkShaderCreateInfoEXT createInfo{ + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, + .flags = 0, + .stage = shaderStageToVk(stage), + .nextStage = 0, + .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, + .codeSize = info.spirv.size() * sizeof(info.spirv[0]), + .pCode = info.spirv.data(), + .pName = "main", + .setLayoutCount = 1, + .pSetLayouts = &descriptorSetLayout, + }; + + VkShaderEXT shader; + Verify() << _vkCreateShadersEXT(vk::g_vkDevice, 1, &createInfo, + vk::g_vkAllocator, &shader); + entry->info = std::move(info); + entry->shader = shader; + })); + + return *entry; + } + + Ref + getImage(std::uint64_t tag, TaskChain& initTaskChain, std::uint64_t address, + SurfaceFormat dataFormat, TextureChannelType channelType, + TileMode tileMode, std::uint32_t width, std::uint32_t height, + std::uint32_t depth, std::uint32_t pitch, shader::AccessOp access, + bool isColor = true, bool isStorage = false) + { + auto& line = getLine(address, pitch * height * depth); + return line.getImage(tag, initTaskChain, address, dataFormat, channelType, + tileMode, width, height, depth, pitch, access, isColor, + isStorage); + } + + Ref + getBuffer(std::uint64_t tag, TaskChain& initTaskChain, std::uint64_t address, + std::uint32_t elementCount, std::uint32_t stride, + std::uint32_t elementSize, shader::AccessOp access) + { + auto& line = getLine(address, stride != 0 ? stride * elementCount : elementSize * elementCount); + return line.getBuffer(tag, initTaskChain, address, elementCount, stride, + elementSize, access); + } private: - CacheLine &getLine(std::uint64_t address, std::size_t size) { - std::lock_guard lock(mtx); - auto it = cacheLines.lower_bound(address); - - if (it == cacheLines.end() || - address >= it->second.areaAddress + it->second.areaSize || - it->second.areaAddress >= address + size) { - auto area = memoryAreaTable.queryArea(address / kPageSize); - area.beginAddress *= kPageSize; - area.endAddress *= kPageSize; - - assert(address >= area.beginAddress && address + size < area.endAddress); - it = cacheLines.emplace_hint( - it, std::piecewise_construct, std::tuple{area.beginAddress}, - std::tuple{area.beginAddress, area.endAddress}); - } - - return it->second; - } + CacheLine& getLine(std::uint64_t address, std::size_t size) + { + std::lock_guard lock(mtx); + auto it = cacheLines.lower_bound(address); + + if (it == cacheLines.end() || + address >= it->second.areaAddress + it->second.areaSize || + it->second.areaAddress >= address + size) + { + auto area = memoryAreaTable.queryArea(address / kPageSize); + area.beginAddress *= kPageSize; + area.endAddress *= kPageSize; + + assert(address >= area.beginAddress && address + size < area.endAddress); + it = cacheLines.emplace_hint( + it, std::piecewise_construct, std::tuple{area.beginAddress}, + std::tuple{area.beginAddress, area.endAddress}); + } + + return it->second; + } }; -static Cache &getCache() { - static Cache result; - return result; +static Cache& getCache() +{ + static Cache result; + return result; } -static VkShaderEXT getPrimTypeRectGeomShader() { - static VkShaderEXT shader = VK_NULL_HANDLE; - if (shader != VK_NULL_HANDLE) { - return shader; - } - - auto layout = getGraphicsLayout().first; - VkShaderCreateInfoEXT createInfo{ - .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, - .flags = 0, - .stage = VK_SHADER_STAGE_GEOMETRY_BIT, - .nextStage = 0, - .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, - .codeSize = sizeof(spirv_rect_list_geom), - .pCode = spirv_rect_list_geom, - .pName = "main", - .setLayoutCount = 1, - .pSetLayouts = &layout, - }; - - Verify() << _vkCreateShadersEXT(vk::g_vkDevice, 1, &createInfo, - vk::g_vkAllocator, &shader); - return shader; +static VkShaderEXT getPrimTypeRectGeomShader() +{ + static VkShaderEXT shader = VK_NULL_HANDLE; + if (shader != VK_NULL_HANDLE) + { + return shader; + } + + auto layout = getGraphicsLayout().first; + VkShaderCreateInfoEXT createInfo{ + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, + .flags = 0, + .stage = VK_SHADER_STAGE_GEOMETRY_BIT, + .nextStage = 0, + .codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT, + .codeSize = sizeof(spirv_rect_list_geom), + .pCode = spirv_rect_list_geom, + .pName = "main", + .setLayoutCount = 1, + .pSetLayouts = &layout, + }; + + Verify() << _vkCreateShadersEXT(vk::g_vkDevice, 1, &createInfo, + vk::g_vkAllocator, &shader); + return shader; } -struct GpuActionResources { - std::atomic refs{0}; - // GpuTaskHandle taskHandle; - // QueueRegisters ®s; - std::uint64_t tag = getCache().createTag(); - std::vector> usedImages; - std::vector> usedBuffers; - - void release() { - for (auto image : usedImages) { - image->unlock(tag); - } - - for (auto buffer : usedBuffers) { - buffer->unlock(tag); - } - } - - void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } - - void decRef() { - if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) { - delete this; - } - } - - void loadShaderBindings(TaskChain &initTaskChain, VkDescriptorSet descSet, - const shader::Shader &shader) { - for (auto &uniform : shader.uniforms) { - switch (uniform.kind) { - case shader::Shader::UniformKind::Buffer: { - auto &vbuffer = *reinterpret_cast(uniform.buffer); - - auto bufferRef = getCache().getBuffer( - tag, initTaskChain, vbuffer.getAddress(), vbuffer.getNumRecords(), - vbuffer.getStride(), vbuffer.getElementSize(), uniform.accessOp); - - VkDescriptorBufferInfo bufferInfo{ - .buffer = bufferRef->buffer.getHandle(), - .offset = vbuffer.getAddress() - bufferRef->bufferAddress, - .range = vbuffer.getSize(), - }; - - VkWriteDescriptorSet writeDescSet{ - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = descSet, - .dstBinding = uniform.binding, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .pBufferInfo = &bufferInfo, - }; - - usedBuffers.push_back(std::move(bufferRef)); - - vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); - break; - } - - case shader::Shader::UniformKind::StorageImage: - case shader::Shader::UniformKind::Image: { - auto &tbuffer = *reinterpret_cast(uniform.buffer); - auto dataFormat = tbuffer.dfmt; - auto channelType = tbuffer.nfmt; - - // assert(tbuffer->width == tbuffer->pitch); - std::size_t width = tbuffer.width + 1; - std::size_t height = tbuffer.height + 1; - std::size_t depth = tbuffer.depth + 1; - std::size_t pitch = tbuffer.pitch + 1; - auto tileMode = (TileMode)tbuffer.tiling_idx; - - auto image = getCache().getImage( - tag, initTaskChain, tbuffer.getAddress(), dataFormat, channelType, - tileMode, width, height, depth, pitch, uniform.accessOp, true, - uniform.kind == shader::Shader::UniformKind::StorageImage); - - VkDescriptorImageInfo imageInfo{ - .imageView = image->view, - .imageLayout = VK_IMAGE_LAYOUT_GENERAL, - }; - - usedImages.push_back(std::move(image)); - - VkWriteDescriptorSet writeDescSet{ - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = descSet, - .dstBinding = uniform.binding, - .descriptorCount = 1, - .descriptorType = - uniform.kind == shader::Shader::UniformKind::StorageImage - ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE - : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .pImageInfo = &imageInfo, - }; - - vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); - break; - } - - case shader::Shader::UniformKind::Sampler: { - // TODO: load S# sampler - auto sampler = getCache().getSampler(); - - VkDescriptorImageInfo imageInfo{ - .sampler = sampler, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - }; - - VkWriteDescriptorSet writeDescSet{ - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = descSet, - .dstBinding = uniform.binding, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .pImageInfo = &imageInfo, - }; - - vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); - break; - } - } - } - } +struct GpuActionResources +{ + std::atomic refs{0}; + // GpuTaskHandle taskHandle; + // QueueRegisters ®s; + std::uint64_t tag = getCache().createTag(); + std::vector> usedImages; + std::vector> usedBuffers; + + void release() + { + for (auto image : usedImages) + { + image->unlock(tag); + } + + for (auto buffer : usedBuffers) + { + buffer->unlock(tag); + } + } + + void incRef() { refs.fetch_add(1, std::memory_order::relaxed); } + + void decRef() + { + if (refs.fetch_sub(1, std::memory_order::relaxed) == 1) + { + delete this; + } + } + + void loadShaderBindings(TaskChain& initTaskChain, VkDescriptorSet descSet, + const shader::Shader& shader) + { + for (auto& uniform : shader.uniforms) + { + switch (uniform.kind) + { + case shader::Shader::UniformKind::Buffer: + { + auto& vbuffer = *reinterpret_cast(uniform.buffer); + + auto bufferRef = getCache().getBuffer( + tag, initTaskChain, vbuffer.getAddress(), vbuffer.getNumRecords(), + vbuffer.getStride(), vbuffer.getElementSize(), uniform.accessOp); + + VkDescriptorBufferInfo bufferInfo{ + .buffer = bufferRef->buffer.getHandle(), + .offset = vbuffer.getAddress() - bufferRef->bufferAddress, + .range = vbuffer.getSize(), + }; + + VkWriteDescriptorSet writeDescSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descSet, + .dstBinding = uniform.binding, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .pBufferInfo = &bufferInfo, + }; + + usedBuffers.push_back(std::move(bufferRef)); + + vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); + break; + } + + case shader::Shader::UniformKind::StorageImage: + case shader::Shader::UniformKind::Image: + { + auto& tbuffer = *reinterpret_cast(uniform.buffer); + auto dataFormat = tbuffer.dfmt; + auto channelType = tbuffer.nfmt; + + // assert(tbuffer->width == tbuffer->pitch); + std::size_t width = tbuffer.width + 1; + std::size_t height = tbuffer.height + 1; + std::size_t depth = tbuffer.depth + 1; + std::size_t pitch = tbuffer.pitch + 1; + auto tileMode = (TileMode)tbuffer.tiling_idx; + + auto image = getCache().getImage( + tag, initTaskChain, tbuffer.getAddress(), dataFormat, channelType, + tileMode, width, height, depth, pitch, uniform.accessOp, true, + uniform.kind == shader::Shader::UniformKind::StorageImage); + + VkDescriptorImageInfo imageInfo{ + .imageView = image->view, + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }; + + usedImages.push_back(std::move(image)); + + VkWriteDescriptorSet writeDescSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descSet, + .dstBinding = uniform.binding, + .descriptorCount = 1, + .descriptorType = + uniform.kind == shader::Shader::UniformKind::StorageImage ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = &imageInfo, + }; + + vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); + break; + } + + case shader::Shader::UniformKind::Sampler: + { + // TODO: load S# sampler + auto sampler = getCache().getSampler(); + + VkDescriptorImageInfo imageInfo{ + .sampler = sampler, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + + VkWriteDescriptorSet writeDescSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descSet, + .dstBinding = uniform.binding, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .pImageInfo = &imageInfo, + }; + + vkUpdateDescriptorSets(vk::g_vkDevice, 1, &writeDescSet, 0, nullptr); + break; + } + } + } + } }; -static void eliminateFastClear() { - // TODO - // util::unreachable(); +static void eliminateFastClear() +{ + // TODO + // util::unreachable(); } -static void resolve() { - // TODO: when texture cache will be implemented it MSAA should be done by - // GPU - util::unreachable(); - // auto srcBuffer = regs.colorBuffers[0]; - // auto dstBuffer = regs.colorBuffers[1]; +static void resolve() +{ + // TODO: when texture cache will be implemented it MSAA should be done by + // GPU + util::unreachable(); + // auto srcBuffer = regs.colorBuffers[0]; + // auto dstBuffer = regs.colorBuffers[1]; - // const auto src = g_hostMemory.getPointer(srcBuffer.base); - // auto dst = g_hostMemory.getPointer(dstBuffer.base); + // const auto src = g_hostMemory.getPointer(srcBuffer.base); + // auto dst = g_hostMemory.getPointer(dstBuffer.base); - // if (src == nullptr || dst == nullptr) { - // return; - // } + // if (src == nullptr || dst == nullptr) { + // return; + // } - // std::memcpy(dst, src, regs.screenScissorH * regs.screenScissorW * 4); + // std::memcpy(dst, src, regs.screenScissorH * regs.screenScissorW * 4); } -static void draw(TaskChain &taskSet, QueueRegisters ®s, std::uint32_t count, - std::uint64_t indeciesAddress, std::uint32_t indexCount) { - if (regs.cbColorFormat == CbColorFormat::Disable) { - return; - } - - if (regs.cbColorFormat == CbColorFormat::EliminateFastClear) { - eliminateFastClear(); - return; - } - - if (regs.cbColorFormat == CbColorFormat::Resolve) { - resolve(); - return; - } - - if (regs.pgmVsAddress == 0 || regs.pgmPsAddress == 0) { - return; - } - - if (regs.cbRenderTargetMask == 0 || regs.colorBuffers[0].base == 0) { - return; - } - - regs.depthClearEnable = true; - - auto resources = Ref(new GpuActionResources()); - - // std::printf("draw action, tag %lu\n", resources->tag); - - TaskSet shaderLoadTaskSet; - auto [desriptorSetLayout, pipelineLayout] = getGraphicsLayout(); - auto &vertexShader = getCache().getShader( - shaderLoadTaskSet, desriptorSetLayout, shader::Stage::Vertex, - regs.pgmVsAddress, regs.userVsData, regs.vsUserSpgrs); - - auto &fragmentShader = getCache().getShader( - shaderLoadTaskSet, desriptorSetLayout, shader::Stage::Fragment, - regs.pgmPsAddress, regs.userPsData, regs.psUserSpgrs); - - shaderLoadTaskSet.schedule(); - shaderLoadTaskSet.wait(); - - auto primType = static_cast(regs.vgtPrimitiveType); - - std::vector colorAttachments; - - std::vector colorBlendEnable; - std::vector colorBlendEquation; - std::vector colorWriteMask; - for (auto targetMask = regs.cbRenderTargetMask; - auto &colorBuffer : regs.colorBuffers) { - if (targetMask == 0 || colorBuffer.base == 0) { - break; - } - - auto mask = targetMask & 0xf; - - if (mask == 0) { - targetMask >>= 4; - continue; - } - targetMask >>= 4; - - shader::AccessOp access = shader::AccessOp::Load | shader::AccessOp::Store; - - auto dataFormat = (SurfaceFormat)colorBuffer.format; - auto channelType = kTextureChannelTypeSrgb; // TODO - - auto colorImage = getCache().getImage( - resources->tag, taskSet, colorBuffer.base, dataFormat, channelType, - (TileMode)colorBuffer.tileModeIndex, - regs.screenScissorW + regs.screenScissorX, - regs.screenScissorH + regs.screenScissorY, 1, - regs.screenScissorW + regs.screenScissorX, access); - - colorAttachments.push_back({ - .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .imageView = colorImage->view, - .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - }); - - resources->usedImages.push_back(std::move(colorImage)); - - colorBlendEnable.push_back(regs.blendEnable ? VK_TRUE : VK_FALSE); - colorBlendEquation.push_back(VkColorBlendEquationEXT{ - .srcColorBlendFactor = - blendMultiplierToVkBlendFactor(regs.blendColorSrc), - .dstColorBlendFactor = - blendMultiplierToVkBlendFactor(regs.blendColorDst), - .colorBlendOp = blendFuncToVkBlendOp(regs.blendColorFn), - .srcAlphaBlendFactor = - regs.blendSeparateAlpha - ? blendMultiplierToVkBlendFactor(regs.blendAlphaSrc) - : blendMultiplierToVkBlendFactor(regs.blendColorSrc), - .dstAlphaBlendFactor = - regs.blendSeparateAlpha - ? blendMultiplierToVkBlendFactor(regs.blendAlphaDst) - : blendMultiplierToVkBlendFactor(regs.blendColorDst), - .alphaBlendOp = blendFuncToVkBlendOp(regs.blendAlphaFn), - }); - - colorWriteMask.push_back(((mask & 1) ? VK_COLOR_COMPONENT_R_BIT : 0) | - ((mask & 2) ? VK_COLOR_COMPONENT_G_BIT : 0) | - ((mask & 4) ? VK_COLOR_COMPONENT_B_BIT : 0) | - ((mask & 8) ? VK_COLOR_COMPONENT_A_BIT : 0)); - } - - auto descSet = getCache().getGraphicsDescriptorSet(); - - resources->loadShaderBindings(taskSet, descSet, vertexShader.info); - resources->loadShaderBindings(taskSet, descSet, fragmentShader.info); - - shader::AccessOp depthAccess = shader::AccessOp::None; - - if (!regs.depthClearEnable && regs.zReadBase != 0) { - depthAccess |= shader::AccessOp::Load; - } - - if (regs.depthWriteEnable && regs.zWriteBase != 0) { - depthAccess |= shader::AccessOp::Store; - } - - if (regs.zReadBase != regs.zWriteBase) { - util::unreachable(); - } - - Ref depthImage; - VkRenderingAttachmentInfo depthAttachment; - - if (regs.depthEnable) { - depthImage = getCache().getImage( - resources->tag, taskSet, regs.zReadBase, kSurfaceFormat24_8, - kTextureChannelTypeUNorm, kTileModeDisplay_LinearAligned, - regs.screenScissorW + regs.screenScissorX, - regs.screenScissorH + regs.screenScissorY, 1, - regs.screenScissorW + regs.screenScissorX, depthAccess, false); - - depthAttachment = { - .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - .imageView = depthImage->view, - .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .loadOp = !regs.depthClearEnable && regs.zReadBase - ? VK_ATTACHMENT_LOAD_OP_LOAD - : VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = regs.depthWriteEnable && regs.zWriteBase - ? VK_ATTACHMENT_STORE_OP_STORE - : VK_ATTACHMENT_STORE_OP_DONT_CARE, - .clearValue = {.depthStencil = {.depth = regs.depthClear}}, - }; - - resources->usedImages.push_back(depthImage); - } - - vk::Buffer indexBufferStorage; - BufferRef indexBuffer; - auto needConversion = isPrimRequiresConversion(primType); - VkIndexType vkIndexType = (regs.indexType & 0x1f) == 0 ? VK_INDEX_TYPE_UINT16 - : VK_INDEX_TYPE_UINT32; - - if (needConversion) { - auto indecies = g_hostMemory.getPointer(indeciesAddress); - if (indecies == nullptr) { - indexCount = count; - } - - unsigned origIndexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 16 : 32; - auto converterFn = getPrimConverterFn(primType, &indexCount); - - if (indecies == nullptr) { - if (indexCount < 0x10000) { - vkIndexType = VK_INDEX_TYPE_UINT16; - } else if (indecies) { - vkIndexType = VK_INDEX_TYPE_UINT32; - } - } - - unsigned indexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 16 : 32; - auto indexBufferSize = indexSize * indexCount; - - indexBufferStorage = vk::Buffer::Allocate( - getHostVisibleMemory(), indexBufferSize, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - - void *data = indexBufferStorage.getData(); - - if (indecies == nullptr) { - if (indexSize == 16) { - for (std::uint32_t i = 0; i < indexCount; ++i) { - auto [dstIndex, srcIndex] = converterFn(i); - ((std::uint16_t *)data)[dstIndex] = srcIndex; - } - } else { - for (std::uint32_t i = 0; i < indexCount; ++i) { - auto [dstIndex, srcIndex] = converterFn(i); - ((std::uint32_t *)data)[dstIndex] = srcIndex; - } - } - } else { - if (indexSize == 16) { - for (std::uint32_t i = 0; i < indexCount; ++i) { - auto [dstIndex, srcIndex] = converterFn(i); - std::uint32_t origIndex = origIndexSize == 16 - ? ((std::uint16_t *)indecies)[srcIndex] - : ((std::uint32_t *)indecies)[srcIndex]; - ((std::uint16_t *)data)[dstIndex] = origIndex; - } - - } else { - for (std::uint32_t i = 0; i < indexCount; ++i) { - auto [dstIndex, srcIndex] = converterFn(i); - std::uint32_t origIndex = origIndexSize == 16 - ? ((std::uint16_t *)indecies)[srcIndex] - : ((std::uint32_t *)indecies)[srcIndex]; - ((std::uint32_t *)data)[dstIndex] = origIndex; - } - } - } - - indexBuffer = {indexBufferStorage.getHandle(), 0, indexBufferSize}; - } else if (indeciesAddress != 0) { - unsigned indexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 2 : 4; - - auto bufferRef = - getCache().getBuffer(resources->tag, taskSet, indeciesAddress, - indexCount, 0, indexSize, shader::AccessOp::Load); - indexBuffer = { - .buffer = bufferRef->buffer.getHandle(), - .offset = indeciesAddress - bufferRef->bufferAddress, - .size = static_cast(indexCount) * indexSize, - }; - - resources->usedBuffers.push_back(std::move(bufferRef)); - } - - auto drawTaskFn = [colorAttachments = std::move(colorAttachments), - colorBlendEnable = std::move(colorBlendEnable), - colorBlendEquation = std::move(colorBlendEquation), - pipelineLayout, colorWriteMask = std::move(colorWriteMask), - vertexShader = vertexShader.shader, - fragmentShader = fragmentShader.shader, depthAttachment, - loadTaskSet = std::move(shaderLoadTaskSet), primType, - vkIndexType, indexBuffer, count, indexCount, descSet, - ®s](VkCommandBuffer drawCommandBuffer) { - VkRenderingInfo renderInfo{ - .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, - .renderArea = - { - .offset = {.x = static_cast(regs.screenScissorX), - .y = static_cast(regs.screenScissorY)}, - .extent = - { - .width = regs.screenScissorW, - .height = regs.screenScissorH, - }, - }, - .layerCount = 1, - .colorAttachmentCount = static_cast(colorAttachments.size()), - .pColorAttachments = colorAttachments.data(), - .pDepthAttachment = regs.depthEnable ? &depthAttachment : nullptr, - .pStencilAttachment = regs.depthEnable ? &depthAttachment : nullptr, - }; - - vkCmdBeginRendering(drawCommandBuffer, &renderInfo); - - // std::printf("viewport: %ux%u, %ux%u\n", regs.screenScissorX, - // regs.screenScissorY, regs.screenScissorW, - // regs.screenScissorH); - VkViewport viewport{}; - viewport.x = regs.screenScissorX; - viewport.y = (float)regs.screenScissorH - regs.screenScissorY; - viewport.width = regs.screenScissorW; - viewport.height = -(float)regs.screenScissorH; - viewport.minDepth = -1.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(drawCommandBuffer, 0, 1, &viewport); - - VkRect2D scissor{}; - scissor.extent.width = regs.screenScissorW; - scissor.extent.height = regs.screenScissorH; - scissor.offset.x = regs.screenScissorX; - scissor.offset.y = regs.screenScissorY; - vkCmdSetScissor(drawCommandBuffer, 0, 1, &scissor); - - _vkCmdSetColorBlendEnableEXT(drawCommandBuffer, 0, colorBlendEnable.size(), - colorBlendEnable.data()); - _vkCmdSetColorBlendEquationEXT(drawCommandBuffer, 0, - colorBlendEquation.size(), - colorBlendEquation.data()); - - _vkCmdSetDepthClampEnableEXT(drawCommandBuffer, VK_TRUE); - vkCmdSetDepthCompareOp(drawCommandBuffer, (VkCompareOp)regs.zFunc); - vkCmdSetDepthTestEnable(drawCommandBuffer, - regs.depthEnable ? VK_TRUE : VK_FALSE); - vkCmdSetDepthWriteEnable(drawCommandBuffer, - regs.depthWriteEnable ? VK_TRUE : VK_FALSE); - vkCmdSetDepthBounds(drawCommandBuffer, -1.f, 1.f); - vkCmdSetDepthBoundsTestEnable(drawCommandBuffer, - regs.depthBoundsEnable ? VK_TRUE : VK_FALSE); - vkCmdSetStencilOp(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, - VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS); - - // VkDeviceSize strides = 0; - // vkCmdBindVertexBuffers2EXT(drawCommandBuffer, 0, 0, nullptr, nullptr, - // nullptr, &strides); - vkCmdSetRasterizerDiscardEnable(drawCommandBuffer, VK_FALSE); - vkCmdSetDepthBiasEnable(drawCommandBuffer, VK_TRUE); - vkCmdSetDepthBias(drawCommandBuffer, 0, 1, 1); - vkCmdSetPrimitiveRestartEnable(drawCommandBuffer, VK_FALSE); - - _vkCmdSetLogicOpEnableEXT(drawCommandBuffer, VK_FALSE); - _vkCmdSetLogicOpEXT(drawCommandBuffer, VK_LOGIC_OP_AND); - _vkCmdSetPolygonModeEXT(drawCommandBuffer, VK_POLYGON_MODE_FILL); - _vkCmdSetRasterizationSamplesEXT(drawCommandBuffer, VK_SAMPLE_COUNT_1_BIT); - VkSampleMask sampleMask = ~0; - _vkCmdSetSampleMaskEXT(drawCommandBuffer, VK_SAMPLE_COUNT_1_BIT, - &sampleMask); - _vkCmdSetTessellationDomainOriginEXT( - drawCommandBuffer, VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT); - _vkCmdSetAlphaToCoverageEnableEXT(drawCommandBuffer, VK_FALSE); - _vkCmdSetVertexInputEXT(drawCommandBuffer, 0, nullptr, 0, nullptr); - _vkCmdSetColorWriteMaskEXT(drawCommandBuffer, 0, colorWriteMask.size(), - colorWriteMask.data()); - - vkCmdSetStencilCompareMask(drawCommandBuffer, - VK_STENCIL_FACE_FRONT_AND_BACK, 0); - vkCmdSetStencilWriteMask(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, - 0); - vkCmdSetStencilReference(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, - 0); - - vkCmdSetCullMode( - drawCommandBuffer, - (regs.cullBack ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE) | - (regs.cullFront ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_NONE)); - vkCmdSetFrontFace(drawCommandBuffer, regs.face - ? VK_FRONT_FACE_CLOCKWISE - : VK_FRONT_FACE_COUNTER_CLOCKWISE); - - vkCmdSetPrimitiveTopology(drawCommandBuffer, getVkPrimitiveType(primType)); - vkCmdSetStencilTestEnable(drawCommandBuffer, VK_FALSE); - - vkCmdBindDescriptorSets(drawCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - pipelineLayout, 0, 1, &descSet, 0, nullptr); - - VkShaderStageFlagBits stages[]{VK_SHADER_STAGE_VERTEX_BIT, - VK_SHADER_STAGE_FRAGMENT_BIT}; - _vkCmdBindShadersEXT(drawCommandBuffer, 1, stages + 0, &vertexShader); - _vkCmdBindShadersEXT(drawCommandBuffer, 1, stages + 1, &fragmentShader); - - if (primType == kPrimitiveTypeRectList) { - VkShaderStageFlagBits stage = VK_SHADER_STAGE_GEOMETRY_BIT; - auto shader = getPrimTypeRectGeomShader(); - _vkCmdBindShadersEXT(drawCommandBuffer, 1, &stage, &shader); - } - - if (indexBuffer.buffer == nullptr) { - vkCmdDraw(drawCommandBuffer, count, 1, 0, 0); - } else { - vkCmdBindIndexBuffer(drawCommandBuffer, indexBuffer.buffer, - indexBuffer.offset, vkIndexType); - vkCmdDrawIndexed(drawCommandBuffer, indexCount, 1, 0, 0, 0); - } - - vkCmdEndRendering(drawCommandBuffer); - }; - - auto drawTaskId = taskSet.add(ProcessQueue::Graphics, taskSet.getLastTaskId(), - std::move(drawTaskFn)); - - taskSet.add(drawTaskId, [=] { - // std::printf("releasing draw action, tag %lu\n", resources->tag); - getCache().releaseGraphicsDescriptorSet(descSet); - resources->release(); - }); - - taskSet.wait(); +static void draw(TaskChain& taskSet, QueueRegisters& regs, std::uint32_t count, + std::uint64_t indeciesAddress, std::uint32_t indexCount) +{ + if (regs.cbColorFormat == CbColorFormat::Disable) + { + return; + } + + if (regs.cbColorFormat == CbColorFormat::EliminateFastClear) + { + eliminateFastClear(); + return; + } + + if (regs.cbColorFormat == CbColorFormat::Resolve) + { + resolve(); + return; + } + + if (regs.pgmVsAddress == 0 || regs.pgmPsAddress == 0) + { + return; + } + + if (regs.cbRenderTargetMask == 0 || regs.colorBuffers[0].base == 0) + { + return; + } + + regs.depthClearEnable = true; + + auto resources = Ref(new GpuActionResources()); + + // std::printf("draw action, tag %lu\n", resources->tag); + + TaskSet shaderLoadTaskSet; + auto [desriptorSetLayout, pipelineLayout] = getGraphicsLayout(); + auto& vertexShader = getCache().getShader( + shaderLoadTaskSet, desriptorSetLayout, shader::Stage::Vertex, + regs.pgmVsAddress, regs.userVsData, regs.vsUserSpgrs); + + auto& fragmentShader = getCache().getShader( + shaderLoadTaskSet, desriptorSetLayout, shader::Stage::Fragment, + regs.pgmPsAddress, regs.userPsData, regs.psUserSpgrs); + + shaderLoadTaskSet.schedule(); + shaderLoadTaskSet.wait(); + + auto primType = static_cast(regs.vgtPrimitiveType); + + std::vector colorAttachments; + + std::vector colorBlendEnable; + std::vector colorBlendEquation; + std::vector colorWriteMask; + for (auto targetMask = regs.cbRenderTargetMask; + auto& colorBuffer : regs.colorBuffers) + { + if (targetMask == 0 || colorBuffer.base == 0) + { + break; + } + + auto mask = targetMask & 0xf; + + if (mask == 0) + { + targetMask >>= 4; + continue; + } + targetMask >>= 4; + + shader::AccessOp access = shader::AccessOp::Load | shader::AccessOp::Store; + + auto dataFormat = (SurfaceFormat)colorBuffer.format; + auto channelType = kTextureChannelTypeSrgb; // TODO + + auto colorImage = getCache().getImage( + resources->tag, taskSet, colorBuffer.base, dataFormat, channelType, + (TileMode)colorBuffer.tileModeIndex, + regs.screenScissorW + regs.screenScissorX, + regs.screenScissorH + regs.screenScissorY, 1, + regs.screenScissorW + regs.screenScissorX, access); + + colorAttachments.push_back({ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = colorImage->view, + .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }); + + resources->usedImages.push_back(std::move(colorImage)); + + colorBlendEnable.push_back(regs.blendEnable ? VK_TRUE : VK_FALSE); + colorBlendEquation.push_back(VkColorBlendEquationEXT{ + .srcColorBlendFactor = + blendMultiplierToVkBlendFactor(regs.blendColorSrc), + .dstColorBlendFactor = + blendMultiplierToVkBlendFactor(regs.blendColorDst), + .colorBlendOp = blendFuncToVkBlendOp(regs.blendColorFn), + .srcAlphaBlendFactor = + regs.blendSeparateAlpha ? blendMultiplierToVkBlendFactor(regs.blendAlphaSrc) : blendMultiplierToVkBlendFactor(regs.blendColorSrc), + .dstAlphaBlendFactor = + regs.blendSeparateAlpha ? blendMultiplierToVkBlendFactor(regs.blendAlphaDst) : blendMultiplierToVkBlendFactor(regs.blendColorDst), + .alphaBlendOp = blendFuncToVkBlendOp(regs.blendAlphaFn), + }); + + colorWriteMask.push_back(((mask & 1) ? VK_COLOR_COMPONENT_R_BIT : 0) | + ((mask & 2) ? VK_COLOR_COMPONENT_G_BIT : 0) | + ((mask & 4) ? VK_COLOR_COMPONENT_B_BIT : 0) | + ((mask & 8) ? VK_COLOR_COMPONENT_A_BIT : 0)); + } + + auto descSet = getCache().getGraphicsDescriptorSet(); + + resources->loadShaderBindings(taskSet, descSet, vertexShader.info); + resources->loadShaderBindings(taskSet, descSet, fragmentShader.info); + + shader::AccessOp depthAccess = shader::AccessOp::None; + + if (!regs.depthClearEnable && regs.zReadBase != 0) + { + depthAccess |= shader::AccessOp::Load; + } + + if (regs.depthWriteEnable && regs.zWriteBase != 0) + { + depthAccess |= shader::AccessOp::Store; + } + + if (regs.zReadBase != regs.zWriteBase) + { + util::unreachable(); + } + + Ref depthImage; + VkRenderingAttachmentInfo depthAttachment; + + if (regs.depthEnable) + { + depthImage = getCache().getImage( + resources->tag, taskSet, regs.zReadBase, kSurfaceFormat24_8, + kTextureChannelTypeUNorm, kTileModeDisplay_LinearAligned, + regs.screenScissorW + regs.screenScissorX, + regs.screenScissorH + regs.screenScissorY, 1, + regs.screenScissorW + regs.screenScissorX, depthAccess, false); + + depthAttachment = { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = depthImage->view, + .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .loadOp = !regs.depthClearEnable && regs.zReadBase ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = regs.depthWriteEnable && regs.zWriteBase ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE, + .clearValue = {.depthStencil = {.depth = regs.depthClear}}, + }; + + resources->usedImages.push_back(depthImage); + } + + vk::Buffer indexBufferStorage; + BufferRef indexBuffer; + auto needConversion = isPrimRequiresConversion(primType); + VkIndexType vkIndexType = (regs.indexType & 0x1f) == 0 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; + + if (needConversion) + { + auto indecies = g_hostMemory.getPointer(indeciesAddress); + if (indecies == nullptr) + { + indexCount = count; + } + + unsigned origIndexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 16 : 32; + auto converterFn = getPrimConverterFn(primType, &indexCount); + + if (indecies == nullptr) + { + if (indexCount < 0x10000) + { + vkIndexType = VK_INDEX_TYPE_UINT16; + } + else if (indecies) + { + vkIndexType = VK_INDEX_TYPE_UINT32; + } + } + + unsigned indexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 16 : 32; + auto indexBufferSize = indexSize * indexCount; + + indexBufferStorage = vk::Buffer::Allocate( + getHostVisibleMemory(), indexBufferSize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + + void* data = indexBufferStorage.getData(); + + if (indecies == nullptr) + { + if (indexSize == 16) + { + for (std::uint32_t i = 0; i < indexCount; ++i) + { + auto [dstIndex, srcIndex] = converterFn(i); + ((std::uint16_t*)data)[dstIndex] = srcIndex; + } + } + else + { + for (std::uint32_t i = 0; i < indexCount; ++i) + { + auto [dstIndex, srcIndex] = converterFn(i); + ((std::uint32_t*)data)[dstIndex] = srcIndex; + } + } + } + else + { + if (indexSize == 16) + { + for (std::uint32_t i = 0; i < indexCount; ++i) + { + auto [dstIndex, srcIndex] = converterFn(i); + std::uint32_t origIndex = origIndexSize == 16 ? ((std::uint16_t*)indecies)[srcIndex] : ((std::uint32_t*)indecies)[srcIndex]; + ((std::uint16_t*)data)[dstIndex] = origIndex; + } + } + else + { + for (std::uint32_t i = 0; i < indexCount; ++i) + { + auto [dstIndex, srcIndex] = converterFn(i); + std::uint32_t origIndex = origIndexSize == 16 ? ((std::uint16_t*)indecies)[srcIndex] : ((std::uint32_t*)indecies)[srcIndex]; + ((std::uint32_t*)data)[dstIndex] = origIndex; + } + } + } + + indexBuffer = {indexBufferStorage.getHandle(), 0, indexBufferSize}; + } + else if (indeciesAddress != 0) + { + unsigned indexSize = vkIndexType == VK_INDEX_TYPE_UINT16 ? 2 : 4; + + auto bufferRef = + getCache().getBuffer(resources->tag, taskSet, indeciesAddress, + indexCount, 0, indexSize, shader::AccessOp::Load); + indexBuffer = { + .buffer = bufferRef->buffer.getHandle(), + .offset = indeciesAddress - bufferRef->bufferAddress, + .size = static_cast(indexCount) * indexSize, + }; + + resources->usedBuffers.push_back(std::move(bufferRef)); + } + + auto drawTaskFn = [colorAttachments = std::move(colorAttachments), + colorBlendEnable = std::move(colorBlendEnable), + colorBlendEquation = std::move(colorBlendEquation), + pipelineLayout, colorWriteMask = std::move(colorWriteMask), + vertexShader = vertexShader.shader, + fragmentShader = fragmentShader.shader, depthAttachment, + loadTaskSet = std::move(shaderLoadTaskSet), primType, + vkIndexType, indexBuffer, count, indexCount, descSet, + ®s](VkCommandBuffer drawCommandBuffer) { + VkRenderingInfo renderInfo{ + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea = + { + .offset = {.x = static_cast(regs.screenScissorX), + .y = static_cast(regs.screenScissorY)}, + .extent = + { + .width = regs.screenScissorW, + .height = regs.screenScissorH, + }, + }, + .layerCount = 1, + .colorAttachmentCount = static_cast(colorAttachments.size()), + .pColorAttachments = colorAttachments.data(), + .pDepthAttachment = regs.depthEnable ? &depthAttachment : nullptr, + .pStencilAttachment = regs.depthEnable ? &depthAttachment : nullptr, + }; + + vkCmdBeginRendering(drawCommandBuffer, &renderInfo); + + // std::printf("viewport: %ux%u, %ux%u\n", regs.screenScissorX, + // regs.screenScissorY, regs.screenScissorW, + // regs.screenScissorH); + VkViewport viewport{}; + viewport.x = regs.screenScissorX; + viewport.y = (float)regs.screenScissorH - regs.screenScissorY; + viewport.width = regs.screenScissorW; + viewport.height = -(float)regs.screenScissorH; + viewport.minDepth = -1.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(drawCommandBuffer, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.extent.width = regs.screenScissorW; + scissor.extent.height = regs.screenScissorH; + scissor.offset.x = regs.screenScissorX; + scissor.offset.y = regs.screenScissorY; + vkCmdSetScissor(drawCommandBuffer, 0, 1, &scissor); + + _vkCmdSetColorBlendEnableEXT(drawCommandBuffer, 0, colorBlendEnable.size(), + colorBlendEnable.data()); + _vkCmdSetColorBlendEquationEXT(drawCommandBuffer, 0, + colorBlendEquation.size(), + colorBlendEquation.data()); + + _vkCmdSetDepthClampEnableEXT(drawCommandBuffer, VK_TRUE); + vkCmdSetDepthCompareOp(drawCommandBuffer, (VkCompareOp)regs.zFunc); + vkCmdSetDepthTestEnable(drawCommandBuffer, + regs.depthEnable ? VK_TRUE : VK_FALSE); + vkCmdSetDepthWriteEnable(drawCommandBuffer, + regs.depthWriteEnable ? VK_TRUE : VK_FALSE); + vkCmdSetDepthBounds(drawCommandBuffer, -1.f, 1.f); + vkCmdSetDepthBoundsTestEnable(drawCommandBuffer, + regs.depthBoundsEnable ? VK_TRUE : VK_FALSE); + vkCmdSetStencilOp(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS); + + // VkDeviceSize strides = 0; + // vkCmdBindVertexBuffers2EXT(drawCommandBuffer, 0, 0, nullptr, nullptr, + // nullptr, &strides); + vkCmdSetRasterizerDiscardEnable(drawCommandBuffer, VK_FALSE); + vkCmdSetDepthBiasEnable(drawCommandBuffer, VK_TRUE); + vkCmdSetDepthBias(drawCommandBuffer, 0, 1, 1); + vkCmdSetPrimitiveRestartEnable(drawCommandBuffer, VK_FALSE); + + _vkCmdSetLogicOpEnableEXT(drawCommandBuffer, VK_FALSE); + _vkCmdSetLogicOpEXT(drawCommandBuffer, VK_LOGIC_OP_AND); + _vkCmdSetPolygonModeEXT(drawCommandBuffer, VK_POLYGON_MODE_FILL); + _vkCmdSetRasterizationSamplesEXT(drawCommandBuffer, VK_SAMPLE_COUNT_1_BIT); + VkSampleMask sampleMask = ~0; + _vkCmdSetSampleMaskEXT(drawCommandBuffer, VK_SAMPLE_COUNT_1_BIT, + &sampleMask); + _vkCmdSetTessellationDomainOriginEXT( + drawCommandBuffer, VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT); + _vkCmdSetAlphaToCoverageEnableEXT(drawCommandBuffer, VK_FALSE); + _vkCmdSetVertexInputEXT(drawCommandBuffer, 0, nullptr, 0, nullptr); + _vkCmdSetColorWriteMaskEXT(drawCommandBuffer, 0, colorWriteMask.size(), + colorWriteMask.data()); + + vkCmdSetStencilCompareMask(drawCommandBuffer, + VK_STENCIL_FACE_FRONT_AND_BACK, 0); + vkCmdSetStencilWriteMask(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, + 0); + vkCmdSetStencilReference(drawCommandBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, + 0); + + vkCmdSetCullMode( + drawCommandBuffer, + (regs.cullBack ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE) | + (regs.cullFront ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_NONE)); + vkCmdSetFrontFace(drawCommandBuffer, regs.face ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); + + vkCmdSetPrimitiveTopology(drawCommandBuffer, getVkPrimitiveType(primType)); + vkCmdSetStencilTestEnable(drawCommandBuffer, VK_FALSE); + + vkCmdBindDescriptorSets(drawCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout, 0, 1, &descSet, 0, nullptr); + + VkShaderStageFlagBits stages[]{VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT}; + _vkCmdBindShadersEXT(drawCommandBuffer, 1, stages + 0, &vertexShader); + _vkCmdBindShadersEXT(drawCommandBuffer, 1, stages + 1, &fragmentShader); + + if (primType == kPrimitiveTypeRectList) + { + VkShaderStageFlagBits stage = VK_SHADER_STAGE_GEOMETRY_BIT; + auto shader = getPrimTypeRectGeomShader(); + _vkCmdBindShadersEXT(drawCommandBuffer, 1, &stage, &shader); + } + + if (indexBuffer.buffer == nullptr) + { + vkCmdDraw(drawCommandBuffer, count, 1, 0, 0); + } + else + { + vkCmdBindIndexBuffer(drawCommandBuffer, indexBuffer.buffer, + indexBuffer.offset, vkIndexType); + vkCmdDrawIndexed(drawCommandBuffer, indexCount, 1, 0, 0, 0); + } + + vkCmdEndRendering(drawCommandBuffer); + }; + + auto drawTaskId = taskSet.add(ProcessQueue::Graphics, taskSet.getLastTaskId(), + std::move(drawTaskFn)); + + taskSet.add(drawTaskId, [=] { + // std::printf("releasing draw action, tag %lu\n", resources->tag); + getCache().releaseGraphicsDescriptorSet(descSet); + resources->release(); + }); + + taskSet.wait(); } -static void dispatch(TaskChain &taskSet, QueueRegisters ®s, std::size_t dimX, - std::size_t dimY, std::size_t dimZ) { - if (regs.pgmComputeAddress == 0) { - std::fprintf(stderr, "attempt to invoke dispatch without compute shader\n"); - return; - } +static void dispatch(TaskChain& taskSet, QueueRegisters& regs, std::size_t dimX, + std::size_t dimY, std::size_t dimZ) +{ + if (regs.pgmComputeAddress == 0) + { + std::fprintf(stderr, "attempt to invoke dispatch without compute shader\n"); + return; + } - auto resources = Ref(new GpuActionResources()); - auto descSet = getCache().getComputeDescriptorSet(); + auto resources = Ref(new GpuActionResources()); + auto descSet = getCache().getComputeDescriptorSet(); - // std::printf("dispatch action, tag %lu\n", resources->tag); + // std::printf("dispatch action, tag %lu\n", resources->tag); - auto [desriptorSetLayout, pipelineLayout] = getComputeLayout(); + auto [desriptorSetLayout, pipelineLayout] = getComputeLayout(); - TaskSet loadShaderTaskSet; + TaskSet loadShaderTaskSet; - auto &computeShader = getCache().getShader( - loadShaderTaskSet, desriptorSetLayout, shader::Stage::Compute, - regs.pgmComputeAddress, regs.userComputeData, regs.computeUserSpgrs, - regs.computeNumThreadX, regs.computeNumThreadY, regs.computeNumThreadZ); + auto& computeShader = getCache().getShader( + loadShaderTaskSet, desriptorSetLayout, shader::Stage::Compute, + regs.pgmComputeAddress, regs.userComputeData, regs.computeUserSpgrs, + regs.computeNumThreadX, regs.computeNumThreadY, regs.computeNumThreadZ); - loadShaderTaskSet.schedule(); - loadShaderTaskSet.wait(); + loadShaderTaskSet.schedule(); + loadShaderTaskSet.wait(); - resources->loadShaderBindings(taskSet, descSet, computeShader.info); + resources->loadShaderBindings(taskSet, descSet, computeShader.info); - auto dispatchTaskFn = - [=, shader = computeShader.shader](VkCommandBuffer commandBuffer) { - VkShaderStageFlagBits stages[]{VK_SHADER_STAGE_COMPUTE_BIT}; - _vkCmdBindShadersEXT(commandBuffer, 1, stages, &shader); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, - pipelineLayout, 0, 1, &descSet, 0, nullptr); + auto dispatchTaskFn = + [=, shader = computeShader.shader](VkCommandBuffer commandBuffer) { + VkShaderStageFlagBits stages[]{VK_SHADER_STAGE_COMPUTE_BIT}; + _vkCmdBindShadersEXT(commandBuffer, 1, stages, &shader); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, + pipelineLayout, 0, 1, &descSet, 0, nullptr); - vkCmdDispatch(commandBuffer, dimX, dimY, dimZ); - }; + vkCmdDispatch(commandBuffer, dimX, dimY, dimZ); + }; - auto computeTaskId = - taskSet.add(ProcessQueue::Compute, taskSet.getLastTaskId(), - std::move(dispatchTaskFn)); + auto computeTaskId = + taskSet.add(ProcessQueue::Compute, taskSet.getLastTaskId(), + std::move(dispatchTaskFn)); - taskSet.add(computeTaskId, [=] { - // std::printf("releasing dispatch action, tag %lu\n", resources->tag); - getCache().releaseComputeDescriptorSet(descSet); - resources->release(); - }); + taskSet.add(computeTaskId, [=] { + // std::printf("releasing dispatch action, tag %lu\n", resources->tag); + getCache().releaseComputeDescriptorSet(descSet); + resources->release(); + }); } -enum class EventWriteSource : std::uint8_t { - Immediate32 = 0x1, - Immediate64 = 0x2, - GlobalClockCounter = 0x3, - GpuCoreClockCounter = 0x4, +enum class EventWriteSource : std::uint8_t +{ + Immediate32 = 0x1, + Immediate64 = 0x2, + GlobalClockCounter = 0x3, + GpuCoreClockCounter = 0x4, }; -struct EopData { - std::uint32_t eventType; - std::uint32_t eventIndex; - std::uint64_t address; - std::uint64_t value; - std::uint8_t dstSel; - std::uint8_t intSel; - EventWriteSource eventSource; +struct EopData +{ + std::uint32_t eventType; + std::uint32_t eventIndex; + std::uint64_t address; + std::uint64_t value; + std::uint8_t dstSel; + std::uint8_t intSel; + EventWriteSource eventSource; }; -static std::uint64_t globalClock() { - // TODO - return 0x0; +static std::uint64_t globalClock() +{ + // TODO + return 0x0; } -static std::uint64_t gpuCoreClock() { - // TODO - return 0x0; +static std::uint64_t gpuCoreClock() +{ + // TODO + return 0x0; } -static void writeEop(EopData data) { - // std::printf("write eop: dstSel=%x, intSel=%x,eventIndex=%x, address = - // %#lx, - // " - // "value = %#lx, %x\n", - // data.dstSel, data.intSel, data.eventIndex, data.address, - // data.value, (unsigned)data.eventSource); - switch (data.eventSource) { - case EventWriteSource::Immediate32: { - *g_hostMemory.getPointer(data.address) = data.value; - break; - } - case EventWriteSource::Immediate64: { - *g_hostMemory.getPointer(data.address) = data.value; - break; - } - case EventWriteSource::GlobalClockCounter: { - *g_hostMemory.getPointer(data.address) = globalClock(); - break; - } - case EventWriteSource::GpuCoreClockCounter: { - *g_hostMemory.getPointer(data.address) = gpuCoreClock(); - break; - } - } +static void writeEop(EopData data) +{ + // std::printf("write eop: dstSel=%x, intSel=%x,eventIndex=%x, address = + // %#lx, + // " + // "value = %#lx, %x\n", + // data.dstSel, data.intSel, data.eventIndex, data.address, + // data.value, (unsigned)data.eventSource); + switch (data.eventSource) + { + case EventWriteSource::Immediate32: + { + *g_hostMemory.getPointer(data.address) = data.value; + break; + } + case EventWriteSource::Immediate64: + { + *g_hostMemory.getPointer(data.address) = data.value; + break; + } + case EventWriteSource::GlobalClockCounter: + { + *g_hostMemory.getPointer(data.address) = globalClock(); + break; + } + case EventWriteSource::GpuCoreClockCounter: + { + *g_hostMemory.getPointer(data.address) = gpuCoreClock(); + break; + } + } } -static void drawIndexAuto(TaskChain &waitTaskSet, QueueRegisters ®s, - std::uint32_t count) { - draw(waitTaskSet, regs, count, 0, 0); +static void drawIndexAuto(TaskChain& waitTaskSet, QueueRegisters& regs, + std::uint32_t count) +{ + draw(waitTaskSet, regs, count, 0, 0); } -static void drawIndex2(TaskChain &waitTaskSet, QueueRegisters ®s, - std::uint32_t maxSize, std::uint64_t address, - std::uint32_t count) { - draw(waitTaskSet, regs, count, address, maxSize); +static void drawIndex2(TaskChain& waitTaskSet, QueueRegisters& regs, + std::uint32_t maxSize, std::uint64_t address, + std::uint32_t count) +{ + draw(waitTaskSet, regs, count, address, maxSize); } -struct Queue { - Scheduler sched{1}; - QueueRegisters regs; - std::mutex mtx; +struct Queue +{ + Scheduler sched{1}; + QueueRegisters regs; + std::mutex mtx; - struct CommandBuffer { - std::span commands; - }; + struct CommandBuffer + { + std::span commands; + }; - std::deque commandBuffers; + std::deque commandBuffers; }; -static void handleCommandBuffer(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span &packets); -static void handleLoadConstRam(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - std::uint64_t addressLo = packet[1]; - std::uint64_t addressHi = packet[2]; - std::uint32_t numDw = getBits(packet[3], 14, 0); - std::uint32_t offset = getBits(packet[4], 15, 0); - auto address = addressLo | (addressHi << 32); +static void handleCommandBuffer(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span& packets); +static void handleLoadConstRam(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + std::uint64_t addressLo = packet[1]; + std::uint64_t addressHi = packet[2]; + std::uint32_t numDw = getBits(packet[3], 14, 0); + std::uint32_t offset = getBits(packet[4], 15, 0); + auto address = addressLo | (addressHi << 32); } -static void handleSET_UCONFIG_REG(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { +static void handleSET_UCONFIG_REG(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ - std::uint32_t regId = 0xc000 + packet[1]; + std::uint32_t regId = 0xc000 + packet[1]; - for (auto value : packet.subspan(2)) { - regs.setRegister(regId++, value); - } + for (auto value : packet.subspan(2)) + { + regs.setRegister(regId++, value); + } } -static void handleSET_CONTEXT_REG(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - std::uint32_t regId = 0xa000 + packet[1]; +static void handleSET_CONTEXT_REG(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + std::uint32_t regId = 0xa000 + packet[1]; - for (auto value : packet.subspan(2)) { - regs.setRegister(regId++, value); - } + for (auto value : packet.subspan(2)) + { + regs.setRegister(regId++, value); + } } -static void handleSET_SH_REG(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { +static void handleSET_SH_REG(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ - std::uint32_t regId = 0x2c00 + packet[1]; + std::uint32_t regId = 0x2c00 + packet[1]; - for (auto value : packet.subspan(2)) { - regs.setRegister(regId++, value); - } + for (auto value : packet.subspan(2)) + { + regs.setRegister(regId++, value); + } } -static void handleDMA_DATA(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto srcAddrLo = packet[2]; - auto srcAddrHi = packet[3]; - auto dstAddrLo = packet[4]; - auto dstAddrHi = packet[5]; +static void handleDMA_DATA(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto srcAddrLo = packet[2]; + auto srcAddrHi = packet[3]; + auto dstAddrLo = packet[4]; + auto dstAddrHi = packet[5]; - auto srcAddr = srcAddrLo | (static_cast(srcAddrHi) << 32); - auto dstAddr = dstAddrLo | (static_cast(dstAddrHi) << 32); + auto srcAddr = srcAddrLo | (static_cast(srcAddrHi) << 32); + auto dstAddr = dstAddrLo | (static_cast(dstAddrHi) << 32); - // std::printf("dma data: src address %lx, dst address %lx\n", srcAddr, - // dstAddr); + // std::printf("dma data: src address %lx, dst address %lx\n", srcAddr, + // dstAddr); } -static void handleAQUIRE_MEM(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - // std::printf("aquire mem\n"); +static void handleAQUIRE_MEM(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + // std::printf("aquire mem\n"); } -static void handleWRITE_DATA(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto control = packet[1]; - auto destAddrLo = packet[2]; - auto destAddrHi = packet[3]; - auto data = packet.subspan(4); - auto size = data.size(); - - // 0 - Micro Engine - ME - // 1 - Prefetch parser - PFP - // 2 - Constant engine - CE - // 3 - Dispatch engine - DE - auto engineSel = getBits(control, 31, 30); - - // wait for confirmation that write complete - auto wrConfirm = getBit(control, 20); - - // do not increment address - auto wrOneAddr = getBit(control, 16); - - // 0 - mem-mapped register - // 1 - memory sync - // 2 - tc/l2 - // 3 - gds - // 4 - reserved - // 5 - memory async - auto dstSel = getBits(control, 11, 8); - - auto memMappedRegisterAddress = getBits(destAddrLo, 15, 0); - auto memory32bit = getBits(destAddrLo, 31, 2); - auto memory64bit = getBits(destAddrLo, 31, 3); - auto gdsOffset = getBits(destAddrLo, 15, 0); - - auto address = destAddrLo | (static_cast(destAddrHi) << 32); - auto dest = g_hostMemory.getPointer(address); - // std::printf("write data: address=%lx\n", address); - for (unsigned i = 0; i < size; ++i) { - dest[i] = data[i]; - } +static void handleWRITE_DATA(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto control = packet[1]; + auto destAddrLo = packet[2]; + auto destAddrHi = packet[3]; + auto data = packet.subspan(4); + auto size = data.size(); + + // 0 - Micro Engine - ME + // 1 - Prefetch parser - PFP + // 2 - Constant engine - CE + // 3 - Dispatch engine - DE + auto engineSel = getBits(control, 31, 30); + + // wait for confirmation that write complete + auto wrConfirm = getBit(control, 20); + + // do not increment address + auto wrOneAddr = getBit(control, 16); + + // 0 - mem-mapped register + // 1 - memory sync + // 2 - tc/l2 + // 3 - gds + // 4 - reserved + // 5 - memory async + auto dstSel = getBits(control, 11, 8); + + auto memMappedRegisterAddress = getBits(destAddrLo, 15, 0); + auto memory32bit = getBits(destAddrLo, 31, 2); + auto memory64bit = getBits(destAddrLo, 31, 3); + auto gdsOffset = getBits(destAddrLo, 15, 0); + + auto address = destAddrLo | (static_cast(destAddrHi) << 32); + auto dest = g_hostMemory.getPointer(address); + // std::printf("write data: address=%lx\n", address); + for (unsigned i = 0; i < size; ++i) + { + dest[i] = data[i]; + } } -static void handleINDEX_TYPE(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - regs.indexType = packet[1]; +static void handleINDEX_TYPE(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + regs.indexType = packet[1]; } -static void handleINDEX_BASE(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - // std::printf("INDEX_BASE:\n"); - // for (auto cmd : packet) { - // std::printf(" %x\n", cmd); - // } +static void handleINDEX_BASE(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + // std::printf("INDEX_BASE:\n"); + // for (auto cmd : packet) { + // std::printf(" %x\n", cmd); + // } - std::uint64_t addressLo = packet[1] << 1; - std::uint64_t addressHi = getBits(packet[2], 15, 0); + std::uint64_t addressLo = packet[1] << 1; + std::uint64_t addressHi = getBits(packet[2], 15, 0); - regs.indexBase = (addressHi << 32) | addressLo; + regs.indexBase = (addressHi << 32) | addressLo; } -static void handleDRAW_INDEX_AUTO(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - drawIndexAuto(waitTaskSet, regs, packet[1]); +static void handleDRAW_INDEX_AUTO(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + drawIndexAuto(waitTaskSet, regs, packet[1]); } -static void handleDRAW_INDEX_OFFSET_2(TaskChain &waitTaskSet, - QueueRegisters ®s, - std::span packet) { - auto maxSize = packet[1]; - auto offset = packet[2]; - auto count = packet[3]; - auto drawInitiator = packet[4]; +static void handleDRAW_INDEX_OFFSET_2(TaskChain& waitTaskSet, + QueueRegisters& regs, + std::span packet) +{ + auto maxSize = packet[1]; + auto offset = packet[2]; + auto count = packet[3]; + auto drawInitiator = packet[4]; - drawIndex2(waitTaskSet, regs, maxSize, regs.indexBase + offset, count); + drawIndex2(waitTaskSet, regs, maxSize, regs.indexBase + offset, count); } -static void handleDRAW_INDEX_2(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto maxSize = packet[1]; - auto address = packet[2] | (static_cast(packet[3]) << 32); - auto count = packet[4]; +static void handleDRAW_INDEX_2(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto maxSize = packet[1]; + auto address = packet[2] | (static_cast(packet[3]) << 32); + auto count = packet[4]; - drawIndex2(waitTaskSet, regs, maxSize, address, count); + drawIndex2(waitTaskSet, regs, maxSize, address, count); } -static void handleDISPATCH_DIRECT(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto dimX = packet[1]; - auto dimY = packet[2]; - auto dimZ = packet[3]; +static void handleDISPATCH_DIRECT(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto dimX = packet[1]; + auto dimY = packet[2]; + auto dimZ = packet[3]; - dispatch(waitTaskSet, regs, dimX, dimY, dimZ); + dispatch(waitTaskSet, regs, dimX, dimY, dimZ); } -static void handleCONTEXT_CONTROL(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - // std::printf("context control\n"); +static void handleCONTEXT_CONTROL(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + // std::printf("context control\n"); } -static void handleCLEAR_STATE(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - // std::printf("clear state\n"); +static void handleCLEAR_STATE(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + // std::printf("clear state\n"); } -static void handleRELEASE_MEM(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto writeSource = static_cast(getBits(packet[2], 32, 29)); - auto addressLo = packet[3]; - auto addressHi = packet[4]; - auto dataLo = packet[5]; - auto dataHi = packet[6]; - - auto address = addressLo | (static_cast(addressHi) << 32); - auto data = dataLo | (static_cast(dataHi) << 32); - - // std::printf("release memory: address %lx, data %lx, source %x\n", - // address, - // data, (unsigned)writeSource); - - switch (writeSource) { - case EventWriteSource::Immediate32: { - *g_hostMemory.getPointer(address) = data; - break; - } - case EventWriteSource::Immediate64: { - *g_hostMemory.getPointer(address) = data; - break; - } - case EventWriteSource::GlobalClockCounter: { - *g_hostMemory.getPointer(address) = globalClock(); - break; - } - case EventWriteSource::GpuCoreClockCounter: { - *g_hostMemory.getPointer(address) = gpuCoreClock(); - break; - } - } +static void handleRELEASE_MEM(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto writeSource = static_cast(getBits(packet[2], 32, 29)); + auto addressLo = packet[3]; + auto addressHi = packet[4]; + auto dataLo = packet[5]; + auto dataHi = packet[6]; + + auto address = addressLo | (static_cast(addressHi) << 32); + auto data = dataLo | (static_cast(dataHi) << 32); + + // std::printf("release memory: address %lx, data %lx, source %x\n", + // address, + // data, (unsigned)writeSource); + + switch (writeSource) + { + case EventWriteSource::Immediate32: + { + *g_hostMemory.getPointer(address) = data; + break; + } + case EventWriteSource::Immediate64: + { + *g_hostMemory.getPointer(address) = data; + break; + } + case EventWriteSource::GlobalClockCounter: + { + *g_hostMemory.getPointer(address) = globalClock(); + break; + } + case EventWriteSource::GpuCoreClockCounter: + { + *g_hostMemory.getPointer(address) = gpuCoreClock(); + break; + } + } } -static void handleEVENT_WRITE(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) {} - -static void handleINDIRECT_BUFFER_3F(TaskChain &waitTaskSet, - QueueRegisters ®s, - std::span packet) { - auto swapFn = getBits(packet[1], 1, 0); - auto addressLo = getBits(packet[1], 31, 2) << 2; - auto addressHi = packet[2]; - auto count = getBits(packet[3], 19, 0); - auto vmid = getBits(packet[3], 31, 24); - auto address = addressLo | (static_cast(addressHi) << 32); - std::printf("indirect buffer: address=%lx, size = %x, vmid=%x\n", address, - count, vmid); - - auto commands = - std::span(g_hostMemory.getPointer(address), count); - - waitTaskSet.add([=, waitTaskSet = TaskChain::Create()] mutable { - while (!commands.empty()) { - handleCommandBuffer(*waitTaskSet.get(), regs, commands); - waitTaskSet->wait(); - } - std::printf("indirect buffer end\n"); - std::fflush(stdout); - }); +static void handleEVENT_WRITE(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) {} + +static void handleINDIRECT_BUFFER_3F(TaskChain& waitTaskSet, + QueueRegisters& regs, + std::span packet) +{ + auto swapFn = getBits(packet[1], 1, 0); + auto addressLo = getBits(packet[1], 31, 2) << 2; + auto addressHi = packet[2]; + auto count = getBits(packet[3], 19, 0); + auto vmid = getBits(packet[3], 31, 24); + auto address = addressLo | (static_cast(addressHi) << 32); + std::printf("indirect buffer: address=%lx, size = %x, vmid=%x\n", address, + count, vmid); + + auto commands = + std::span(g_hostMemory.getPointer(address), count); + + waitTaskSet.add([=, waitTaskSet = TaskChain::Create()] mutable { + while (!commands.empty()) + { + handleCommandBuffer(*waitTaskSet.get(), regs, commands); + waitTaskSet->wait(); + } + std::printf("indirect buffer end\n"); + std::fflush(stdout); + }); } -static void handleEVENT_WRITE_EOP(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - EopData eopData{}; - eopData.eventType = getBits(packet[1], 6, 0); - eopData.eventIndex = getBits(packet[1], 12, 8); - eopData.address = - packet[2] | (static_cast(getBits(packet[3], 16, 0)) << 32); - eopData.value = packet[4] | (static_cast(packet[5]) << 32); - eopData.dstSel = getBit(packet[3], 16); - eopData.intSel = getBits(packet[3], 26, 24); - eopData.eventSource = - static_cast(getBits(packet[3], 32, 29)); - writeEop(eopData); +static void handleEVENT_WRITE_EOP(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + EopData eopData{}; + eopData.eventType = getBits(packet[1], 6, 0); + eopData.eventIndex = getBits(packet[1], 12, 8); + eopData.address = + packet[2] | (static_cast(getBits(packet[3], 16, 0)) << 32); + eopData.value = packet[4] | (static_cast(packet[5]) << 32); + eopData.dstSel = getBit(packet[3], 16); + eopData.intSel = getBits(packet[3], 26, 24); + eopData.eventSource = + static_cast(getBits(packet[3], 32, 29)); + writeEop(eopData); } -static void handleEVENT_WRITE_EOS(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - std::uint32_t eventType = getBits(packet[1], 6, 0); - std::uint32_t eventIndex = getBits(packet[1], 12, 8); - std::uint64_t address = - packet[2] | (static_cast(getBits(packet[3], 16, 0)) << 32); - std::uint32_t command = getBits(packet[3], 32, 16); - // std::printf("write eos: eventType=%x, eventIndex=%x, " - // "address = %#lx, command = %#x\n", - // eventType, eventIndex, address, command); - if (command == 0x4000) { // store 32bit data - *g_hostMemory.getPointer(address) = packet[4]; - } else { - util::unreachable(); - } +static void handleEVENT_WRITE_EOS(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + std::uint32_t eventType = getBits(packet[1], 6, 0); + std::uint32_t eventIndex = getBits(packet[1], 12, 8); + std::uint64_t address = + packet[2] | (static_cast(getBits(packet[3], 16, 0)) << 32); + std::uint32_t command = getBits(packet[3], 32, 16); + // std::printf("write eos: eventType=%x, eventIndex=%x, " + // "address = %#lx, command = %#x\n", + // eventType, eventIndex, address, command); + if (command == 0x4000) + { // store 32bit data + *g_hostMemory.getPointer(address) = packet[4]; + } + else + { + util::unreachable(); + } } -static void handleWAIT_REG_MEM(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto function = packet[1] & 7; - auto pollAddressLo = packet[2]; - auto pollAddressHi = packet[3]; - auto reference = packet[4]; - auto mask = packet[5]; - auto pollInterval = packet[6]; - - auto pollAddress = - pollAddressLo | (static_cast(pollAddressHi) << 32); - auto pointer = g_hostMemory.getPointer(pollAddress); - - auto compare = [&](std::uint32_t value, std::uint32_t reference, - int function) { - switch (function) { - case 0: - return true; - case 1: - return value < reference; - case 2: - return value <= reference; - case 3: - return value == reference; - case 4: - return value != reference; - case 5: - return value >= reference; - case 6: - return value > reference; - } - - util::unreachable(); - }; - - // std::printf(" polling address %lx, reference = %x, mask = %x, " - // "function = %u, " - // "interval = %x, value = %x\n", - // pollAddress, reference, mask, function, pollInterval, - // *pointer & mask); - // std::fflush(stdout); - - reference &= mask; - - waitTaskSet.add([=] { - while (true) { - auto value = *pointer & mask; - if (compare(value, reference, function)) { - return; - } - } - }); +static void handleWAIT_REG_MEM(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto function = packet[1] & 7; + auto pollAddressLo = packet[2]; + auto pollAddressHi = packet[3]; + auto reference = packet[4]; + auto mask = packet[5]; + auto pollInterval = packet[6]; + + auto pollAddress = + pollAddressLo | (static_cast(pollAddressHi) << 32); + auto pointer = g_hostMemory.getPointer(pollAddress); + + auto compare = [&](std::uint32_t value, std::uint32_t reference, + int function) { + switch (function) + { + case 0: + return true; + case 1: + return value < reference; + case 2: + return value <= reference; + case 3: + return value == reference; + case 4: + return value != reference; + case 5: + return value >= reference; + case 6: + return value > reference; + } + + util::unreachable(); + }; + + // std::printf(" polling address %lx, reference = %x, mask = %x, " + // "function = %u, " + // "interval = %x, value = %x\n", + // pollAddress, reference, mask, function, pollInterval, + // *pointer & mask); + // std::fflush(stdout); + + reference &= mask; + + waitTaskSet.add([=] { + while (true) + { + auto value = *pointer & mask; + if (compare(value, reference, function)) + { + return; + } + } + }); } -static void handleNOP(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) {} +static void handleNOP(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) {} -static void handleUnknownCommand(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet) { - auto op = getBits(packet[0], 15, 8); - auto len = getBits(packet[0], 29, 16) + 1; - // std::printf("unimplemented packet: op=%s, len=%x\n", - // opcodeToString(op).c_str(), len); +static void handleUnknownCommand(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet) +{ + auto op = getBits(packet[0], 15, 8); + auto len = getBits(packet[0], 29, 16) + 1; + // std::printf("unimplemented packet: op=%s, len=%x\n", + // opcodeToString(op).c_str(), len); } -using CommandHandler = void (*)(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span packet); +using CommandHandler = void (*)(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span packet); static auto g_commandHandlers = [] { - std::array handlers; - handlers.fill(handleUnknownCommand); - handlers[kOpcodeNOP] = handleNOP; - - handlers[kOpcodeCLEAR_STATE] = handleCLEAR_STATE; - handlers[kOpcodeDISPATCH_DIRECT] = handleDISPATCH_DIRECT; - handlers[kOpcodeINDEX_BASE] = handleINDEX_BASE; - handlers[kOpcodeDRAW_INDEX_2] = handleDRAW_INDEX_2; - handlers[kOpcodeCONTEXT_CONTROL] = handleCONTEXT_CONTROL; - handlers[kOpcodeINDEX_TYPE] = handleINDEX_TYPE; - handlers[kOpcodeDRAW_INDEX_AUTO] = handleDRAW_INDEX_AUTO; - handlers[kOpcodeDRAW_INDEX_OFFSET_2] = handleDRAW_INDEX_OFFSET_2; - - handlers[kOpcodeWRITE_DATA] = handleWRITE_DATA; - handlers[kOpcodeWAIT_REG_MEM] = handleWAIT_REG_MEM; - handlers[kOpcodeINDIRECT_BUFFER_3F] = handleINDIRECT_BUFFER_3F; - - handlers[kOpcodeEVENT_WRITE] = handleEVENT_WRITE; - handlers[kOpcodeEVENT_WRITE_EOP] = handleEVENT_WRITE_EOP; - handlers[kOpcodeEVENT_WRITE_EOS] = handleEVENT_WRITE_EOS; - handlers[kOpcodeRELEASE_MEM] = handleRELEASE_MEM; - handlers[kOpcodeDMA_DATA] = handleDMA_DATA; - handlers[kOpcodeAQUIRE_MEM] = handleAQUIRE_MEM; - - handlers[kOpcodeSET_CONTEXT_REG] = handleSET_CONTEXT_REG; - handlers[kOpcodeSET_SH_REG] = handleSET_SH_REG; - handlers[kOpcodeSET_UCONFIG_REG] = handleSET_UCONFIG_REG; - - handlers[kOpcodeLOAD_CONST_RAM] = handleLoadConstRam; - return handlers; + std::array handlers; + handlers.fill(handleUnknownCommand); + handlers[kOpcodeNOP] = handleNOP; + + handlers[kOpcodeCLEAR_STATE] = handleCLEAR_STATE; + handlers[kOpcodeDISPATCH_DIRECT] = handleDISPATCH_DIRECT; + handlers[kOpcodeINDEX_BASE] = handleINDEX_BASE; + handlers[kOpcodeDRAW_INDEX_2] = handleDRAW_INDEX_2; + handlers[kOpcodeCONTEXT_CONTROL] = handleCONTEXT_CONTROL; + handlers[kOpcodeINDEX_TYPE] = handleINDEX_TYPE; + handlers[kOpcodeDRAW_INDEX_AUTO] = handleDRAW_INDEX_AUTO; + handlers[kOpcodeDRAW_INDEX_OFFSET_2] = handleDRAW_INDEX_OFFSET_2; + + handlers[kOpcodeWRITE_DATA] = handleWRITE_DATA; + handlers[kOpcodeWAIT_REG_MEM] = handleWAIT_REG_MEM; + handlers[kOpcodeINDIRECT_BUFFER_3F] = handleINDIRECT_BUFFER_3F; + + handlers[kOpcodeEVENT_WRITE] = handleEVENT_WRITE; + handlers[kOpcodeEVENT_WRITE_EOP] = handleEVENT_WRITE_EOP; + handlers[kOpcodeEVENT_WRITE_EOS] = handleEVENT_WRITE_EOS; + handlers[kOpcodeRELEASE_MEM] = handleRELEASE_MEM; + handlers[kOpcodeDMA_DATA] = handleDMA_DATA; + handlers[kOpcodeAQUIRE_MEM] = handleAQUIRE_MEM; + + handlers[kOpcodeSET_CONTEXT_REG] = handleSET_CONTEXT_REG; + handlers[kOpcodeSET_SH_REG] = handleSET_SH_REG; + handlers[kOpcodeSET_UCONFIG_REG] = handleSET_UCONFIG_REG; + + handlers[kOpcodeLOAD_CONST_RAM] = handleLoadConstRam; + return handlers; }(); -static void handleCommandBuffer(TaskChain &waitTaskSet, QueueRegisters ®s, - std::span &packets) { - while (!packets.empty()) { - auto cmd = packets[0]; - auto type = getBits(cmd, 31, 30); - - if (type == 3) { - // auto predicate = getBit(cmd, 0); - // auto shaderType = getBit(cmd, 1); - auto op = getBits(cmd, 15, 8); - auto len = getBits(cmd, 29, 16) + 2; - - g_commandHandlers[op](waitTaskSet, regs, packets.subspan(0, len)); - packets = packets.subspan(len); - - if (!waitTaskSet.empty()) { - return; - } - - continue; - } - - if (type == 0) { - std::printf("!packet type 0!\n"); - auto baseIndex = getBits(cmd, 15, 0); - auto count = getBits(cmd, 29, 16); - std::printf("-- baseIndex=%x, count=%d\n", baseIndex, count); - packets = {}; // HACK - packets = packets.subspan(count); - continue; - } - - if (type == 2) { - std::printf("!packet type 2!\n"); - } - - if (type == 1) { - util::unreachable("Unexpected packet type 1!\n"); - } - } +static void handleCommandBuffer(TaskChain& waitTaskSet, QueueRegisters& regs, + std::span& packets) +{ + while (!packets.empty()) + { + auto cmd = packets[0]; + auto type = getBits(cmd, 31, 30); + + if (type == 3) + { + // auto predicate = getBit(cmd, 0); + // auto shaderType = getBit(cmd, 1); + auto op = getBits(cmd, 15, 8); + auto len = getBits(cmd, 29, 16) + 2; + + g_commandHandlers[op](waitTaskSet, regs, packets.subspan(0, len)); + packets = packets.subspan(len); + + if (!waitTaskSet.empty()) + { + return; + } + + continue; + } + + if (type == 0) + { + std::printf("!packet type 0!\n"); + auto baseIndex = getBits(cmd, 15, 0); + auto count = getBits(cmd, 29, 16); + std::printf("-- baseIndex=%x, count=%d\n", baseIndex, count); + packets = {}; // HACK + packets = packets.subspan(count); + continue; + } + + if (type == 2) + { + std::printf("!packet type 2!\n"); + } + + if (type == 1) + { + util::unreachable("Unexpected packet type 1!\n"); + } + } } void amdgpu::device::AmdgpuDevice::handleProtectMemory(std::uint64_t address, - std::uint64_t size, - std::uint32_t prot) { - auto beginPage = address / kPageSize; - auto endPage = (address + size + kPageSize - 1) / kPageSize; - - ::mprotect(g_hostMemory.getPointer(address), size, prot >> 4); - - if (prot >> 4) { - memoryAreaTable.map(beginPage, endPage); - const char *protStr; - switch (prot >> 4) { - case PROT_READ: - protStr = "R"; - break; - - case PROT_WRITE: - protStr = "W"; - break; - - case PROT_WRITE | PROT_READ: - protStr = "W"; - break; - - default: - protStr = "unknown"; - break; - } - std::printf("Allocated area at %zx, size %lx, prot %s\n", address, size, - protStr); - } else { - memoryAreaTable.unmap(beginPage, endPage); - std::printf("Unmapped area at %zx, size %lx\n", address, size); - } - - std::size_t index = 0; - for (auto area : memoryAreaTable) { - if (index >= std::size(g_bridge->memoryAreas)) { - util::unreachable("too many memory areas"); - } - - // std::printf("area %lx-%lx\n", area.beginAddress * kPageSize, - // area.endAddress * kPageSize); - - g_bridge->memoryAreas[index++] = { - .address = area.beginAddress * kPageSize, - .size = (area.endAddress - area.beginAddress) * kPageSize, - .prot = (PROT_READ | PROT_WRITE) << 4 // TODO - }; - } - - g_bridge->memoryAreaCount = index; + std::uint64_t size, + std::uint32_t prot) +{ + auto beginPage = address / kPageSize; + auto endPage = (address + size + kPageSize - 1) / kPageSize; + + ::mprotect(g_hostMemory.getPointer(address), size, prot >> 4); + + if (prot >> 4) + { + memoryAreaTable.map(beginPage, endPage); + const char* protStr; + switch (prot >> 4) + { + case PROT_READ: + protStr = "R"; + break; + + case PROT_WRITE: + protStr = "W"; + break; + + case PROT_WRITE | PROT_READ: + protStr = "W"; + break; + + default: + protStr = "unknown"; + break; + } + std::printf("Allocated area at %zx, size %lx, prot %s\n", address, size, + protStr); + } + else + { + memoryAreaTable.unmap(beginPage, endPage); + std::printf("Unmapped area at %zx, size %lx\n", address, size); + } + + std::size_t index = 0; + for (auto area : memoryAreaTable) + { + if (index >= std::size(g_bridge->memoryAreas)) + { + util::unreachable("too many memory areas"); + } + + // std::printf("area %lx-%lx\n", area.beginAddress * kPageSize, + // area.endAddress * kPageSize); + + g_bridge->memoryAreas[index++] = { + .address = area.beginAddress * kPageSize, + .size = (area.endAddress - area.beginAddress) * kPageSize, + .prot = (PROT_READ | PROT_WRITE) << 4 // TODO + }; + } + + g_bridge->memoryAreaCount = index; } static std::map queues; void amdgpu::device::AmdgpuDevice::handleCommandBuffer(std::uint64_t queueId, - std::uint64_t address, - std::uint64_t size) { - auto count = size / sizeof(std::uint32_t); - - if (queueId == 0xc0023300) { - queueId = 0xc0023f00; - } - - auto [it, inserted] = queues.try_emplace(queueId); - - if (inserted) { - std::printf("creation queue %lx\n", queueId); - it->second.sched.enqueue([=, queue = &it->second] { - if (queueId == 0xc0023f00) { - setThreadName("Graphics queue"); - } else { - setThreadName(("Compute queue" + std::to_string(queueId)).c_str()); - } - - Queue::CommandBuffer *commandBuffer; - { - std::lock_guard lock(queue->mtx); - if (queue->commandBuffers.empty()) { - return TaskResult::Reschedule; - } - commandBuffer = &queue->commandBuffers.front(); - } - - if (commandBuffer->commands.empty()) { - std::lock_guard lock(queue->mtx); - queue->commandBuffers.pop_front(); - return TaskResult::Reschedule; - } - - auto taskChain = TaskChain::Create(); - ::handleCommandBuffer(*taskChain.get(), queue->regs, - commandBuffer->commands); - taskChain->wait(); - return TaskResult::Reschedule; - }); - } - - // std::printf("address = %lx, count = %lx\n", address, count); - - std::lock_guard lock(it->second.mtx); - it->second.commandBuffers.push_back( - {.commands = - std::span(g_hostMemory.getPointer(address), count)}); + std::uint64_t address, + std::uint64_t size) +{ + auto count = size / sizeof(std::uint32_t); + + if (queueId == 0xc0023300) + { + queueId = 0xc0023f00; + } + + auto [it, inserted] = queues.try_emplace(queueId); + + if (inserted) + { + std::printf("creation queue %lx\n", queueId); + it->second.sched.enqueue([=, queue = &it->second] { + if (queueId == 0xc0023f00) + { + setThreadName("Graphics queue"); + } + else + { + setThreadName(("Compute queue" + std::to_string(queueId)).c_str()); + } + + Queue::CommandBuffer* commandBuffer; + { + std::lock_guard lock(queue->mtx); + if (queue->commandBuffers.empty()) + { + return TaskResult::Reschedule; + } + commandBuffer = &queue->commandBuffers.front(); + } + + if (commandBuffer->commands.empty()) + { + std::lock_guard lock(queue->mtx); + queue->commandBuffers.pop_front(); + return TaskResult::Reschedule; + } + + auto taskChain = TaskChain::Create(); + ::handleCommandBuffer(*taskChain.get(), queue->regs, + commandBuffer->commands); + taskChain->wait(); + return TaskResult::Reschedule; + }); + } + + // std::printf("address = %lx, count = %lx\n", address, count); + + std::lock_guard lock(it->second.mtx); + it->second.commandBuffers.push_back( + {.commands = + std::span(g_hostMemory.getPointer(address), count)}); } bool amdgpu::device::AmdgpuDevice::handleFlip( - VkQueue queue, VkCommandBuffer cmdBuffer, TaskChain &taskChain, - std::uint32_t bufferIndex, std::uint64_t arg, VkImage targetImage, - VkExtent2D targetExtent, VkSemaphore waitSemaphore, - VkSemaphore signalSemaphore, VkFence fence) { - // std::printf("requested flip %d\n", bufferIndex); - - if (bufferIndex == ~static_cast(0)) { - g_bridge->flipBuffer = bufferIndex; - g_bridge->flipArg = arg; - g_bridge->flipCount = g_bridge->flipCount + 1; - - // black surface, ignore for now - return false; - } - - // std::fprintf(stderr, "device local memory: "); - // getDeviceLocalMemory().dump(); - // std::fprintf(stderr, "host visible memory: "); - // getHostVisibleMemory().dump(); - - auto buffer = g_bridge->buffers[bufferIndex]; - - if (buffer.pitch == 0 || buffer.height == 0 || buffer.address == 0) { - std::printf("Attempt to flip unallocated buffer\n"); - return false; - } - - // std::fprintf(stderr, - // "flip: address=%lx, buffer=%ux%u, target=%ux%u, format = - // %x\n - // ", buffer.address, buffer.width, buffer.height, - // targetExtent.width, targetExtent.height, - // buffer.pixelFormat); - - TaskSet readTask; - TaskSet writeTask; - Ref imageRef; - - SurfaceFormat surfFormat; - TextureChannelType channelType; - - switch (buffer.pixelFormat) { - case 0x80000000: - // bgra - surfFormat = kSurfaceFormat8_8_8_8; - channelType = kTextureChannelTypeSrgb; - break; - - case 0x80002200: - // rgba - surfFormat = kSurfaceFormat8_8_8_8; - channelType = kTextureChannelTypeSrgb; - break; - - case 0x88060000: - // bgra - surfFormat = kSurfaceFormat2_10_10_10; - channelType = kTextureChannelTypeSrgb; - break; - - default: - util::unreachable("unimplemented color buffer format %x", - buffer.pixelFormat); - } - - auto tag = getCache().createTag(); - - imageRef = getCache().getImage( - tag, taskChain, buffer.address, surfFormat, channelType, - buffer.tilingMode == 1 ? kTileModeDisplay_2dThin - : kTileModeDisplay_LinearAligned, - buffer.width, buffer.height, 1, buffer.pitch, shader::AccessOp::Load); - - auto initTask = taskChain.getLastTaskId(); - - auto presentTaskFn = [=](VkCommandBuffer cmdBuffer) { - transitionImageLayout(cmdBuffer, targetImage, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkImageBlit region{ - .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1}, - .srcOffsets = {{}, - {static_cast(buffer.width), - static_cast(buffer.height), 1}}, - .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1}, - .dstOffsets = {{}, - {static_cast(targetExtent.width), - static_cast(targetExtent.height), 1}}, - }; - - vkCmdBlitImage(cmdBuffer, imageRef->image.getHandle(), - VK_IMAGE_LAYOUT_GENERAL, targetImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, - VK_FILTER_LINEAR); - - transitionImageLayout(cmdBuffer, targetImage, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - }; - - auto submitCompleteTask = taskChain.createExternalTask(); - - auto submit = [=, &taskChain](VkQueue queue, VkCommandBuffer cmdBuffer) { - VkSemaphoreSubmitInfo signalSemSubmitInfos[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = signalSemaphore, - .value = 1, - .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, - }, - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = taskChain.semaphore.getHandle(), - .value = submitCompleteTask, - .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, - }, - }; - - VkSemaphoreSubmitInfo waitSemSubmitInfos[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = waitSemaphore, - .value = 1, - .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - }, - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = taskChain.semaphore.getHandle(), - .value = initTask, - .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - }, - }; - - VkCommandBufferSubmitInfo cmdBufferSubmitInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = cmdBuffer, - }; - - VkSubmitInfo2 submitInfo{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .waitSemaphoreInfoCount = static_cast(initTask ? 2 : 1), - .pWaitSemaphoreInfos = waitSemSubmitInfos, - .commandBufferInfoCount = 1, - .pCommandBufferInfos = &cmdBufferSubmitInfo, - .signalSemaphoreInfoCount = 2, - .pSignalSemaphoreInfos = signalSemSubmitInfos, - }; - - // vkQueueWaitIdle(queue); - Verify() << vkQueueSubmit2(queue, 1, &submitInfo, fence); - - // if (initTaskChain.semaphore.wait( - // submitCompleteTask, - // std::chrono::duration_cast( - // std::chrono::seconds(10)) - // .count())) { - // util::unreachable("gpu operation takes too long time. wait id = %lu\n", - // initTask); - // } - }; - - getGraphicsQueueScheduler().enqueue({ - .chain = Ref(&taskChain), - .waitId = initTask, - .invoke = std::move(presentTaskFn), - .submit = std::move(submit), - }); - - taskChain.add(submitCompleteTask, [=] { - imageRef->unlock(tag); - - g_bridge->flipBuffer = bufferIndex; - g_bridge->flipArg = arg; - g_bridge->flipCount = g_bridge->flipCount + 1; - auto bufferInUse = - g_hostMemory.getPointer(g_bridge->bufferInUseAddress); - if (bufferInUse != nullptr) { - bufferInUse[bufferIndex] = 0; - } - }); - - taskChain.wait(); - - return true; + VkQueue queue, VkCommandBuffer cmdBuffer, TaskChain& taskChain, + std::uint32_t bufferIndex, std::uint64_t arg, VkImage targetImage, + VkExtent2D targetExtent, VkSemaphore waitSemaphore, + VkSemaphore signalSemaphore, VkFence fence) +{ + // std::printf("requested flip %d\n", bufferIndex); + + if (bufferIndex == ~static_cast(0)) + { + g_bridge->flipBuffer = bufferIndex; + g_bridge->flipArg = arg; + g_bridge->flipCount = g_bridge->flipCount + 1; + + // black surface, ignore for now + return false; + } + + // std::fprintf(stderr, "device local memory: "); + // getDeviceLocalMemory().dump(); + // std::fprintf(stderr, "host visible memory: "); + // getHostVisibleMemory().dump(); + + auto buffer = g_bridge->buffers[bufferIndex]; + + if (buffer.pitch == 0 || buffer.height == 0 || buffer.address == 0) + { + std::printf("Attempt to flip unallocated buffer\n"); + return false; + } + + // std::fprintf(stderr, + // "flip: address=%lx, buffer=%ux%u, target=%ux%u, format = + // %x\n + // ", buffer.address, buffer.width, buffer.height, + // targetExtent.width, targetExtent.height, + // buffer.pixelFormat); + + TaskSet readTask; + TaskSet writeTask; + Ref imageRef; + + SurfaceFormat surfFormat; + TextureChannelType channelType; + + switch (buffer.pixelFormat) + { + case 0x80000000: + // bgra + surfFormat = kSurfaceFormat8_8_8_8; + channelType = kTextureChannelTypeSrgb; + break; + + case 0x80002200: + // rgba + surfFormat = kSurfaceFormat8_8_8_8; + channelType = kTextureChannelTypeSrgb; + break; + + case 0x88060000: + // bgra + surfFormat = kSurfaceFormat2_10_10_10; + channelType = kTextureChannelTypeSrgb; + break; + + default: + util::unreachable("unimplemented color buffer format %x", + buffer.pixelFormat); + } + + auto tag = getCache().createTag(); + + imageRef = getCache().getImage( + tag, taskChain, buffer.address, surfFormat, channelType, + buffer.tilingMode == 1 ? kTileModeDisplay_2dThin : kTileModeDisplay_LinearAligned, + buffer.width, buffer.height, 1, buffer.pitch, shader::AccessOp::Load); + + auto initTask = taskChain.getLastTaskId(); + + auto presentTaskFn = [=](VkCommandBuffer cmdBuffer) { + transitionImageLayout(cmdBuffer, targetImage, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkImageBlit region{ + .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1}, + .srcOffsets = {{}, + {static_cast(buffer.width), + static_cast(buffer.height), 1}}, + .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1}, + .dstOffsets = {{}, + {static_cast(targetExtent.width), + static_cast(targetExtent.height), 1}}, + }; + + vkCmdBlitImage(cmdBuffer, imageRef->image.getHandle(), + VK_IMAGE_LAYOUT_GENERAL, targetImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, + VK_FILTER_LINEAR); + + transitionImageLayout(cmdBuffer, targetImage, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + }; + + auto submitCompleteTask = taskChain.createExternalTask(); + + auto submit = [=, &taskChain](VkQueue queue, VkCommandBuffer cmdBuffer) { + VkSemaphoreSubmitInfo signalSemSubmitInfos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = signalSemaphore, + .value = 1, + .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = taskChain.semaphore.getHandle(), + .value = submitCompleteTask, + .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, + }, + }; + + VkSemaphoreSubmitInfo waitSemSubmitInfos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = waitSemaphore, + .value = 1, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = taskChain.semaphore.getHandle(), + .value = initTask, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + }, + }; + + VkCommandBufferSubmitInfo cmdBufferSubmitInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + .commandBuffer = cmdBuffer, + }; + + VkSubmitInfo2 submitInfo{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .waitSemaphoreInfoCount = static_cast(initTask ? 2 : 1), + .pWaitSemaphoreInfos = waitSemSubmitInfos, + .commandBufferInfoCount = 1, + .pCommandBufferInfos = &cmdBufferSubmitInfo, + .signalSemaphoreInfoCount = 2, + .pSignalSemaphoreInfos = signalSemSubmitInfos, + }; + + // vkQueueWaitIdle(queue); + Verify() << vkQueueSubmit2(queue, 1, &submitInfo, fence); + + // if (initTaskChain.semaphore.wait( + // submitCompleteTask, + // std::chrono::duration_cast( + // std::chrono::seconds(10)) + // .count())) { + // util::unreachable("gpu operation takes too long time. wait id = %lu\n", + // initTask); + // } + }; + + getGraphicsQueueScheduler().enqueue({ + .chain = Ref(&taskChain), + .waitId = initTask, + .invoke = std::move(presentTaskFn), + .submit = std::move(submit), + }); + + taskChain.add(submitCompleteTask, [=] { + imageRef->unlock(tag); + + g_bridge->flipBuffer = bufferIndex; + g_bridge->flipArg = arg; + g_bridge->flipCount = g_bridge->flipCount + 1; + auto bufferInUse = + g_hostMemory.getPointer(g_bridge->bufferInUseAddress); + if (bufferInUse != nullptr) + { + bufferInUse[bufferIndex] = 0; + } + }); + + taskChain.wait(); + + return true; } -AmdgpuDevice::AmdgpuDevice(amdgpu::bridge::BridgeHeader *bridge) { - g_bridge = bridge; +AmdgpuDevice::AmdgpuDevice(amdgpu::bridge::BridgeHeader* bridge) +{ + g_bridge = bridge; } -AmdgpuDevice::~AmdgpuDevice() { - getCache().clear(); +AmdgpuDevice::~AmdgpuDevice() +{ + getCache().clear(); - auto [gSetLayout, gPipelineLayout] = getGraphicsLayout(); - auto [cSetLayout, cPipelineLayout] = getComputeLayout(); + auto [gSetLayout, gPipelineLayout] = getGraphicsLayout(); + auto [cSetLayout, cPipelineLayout] = getComputeLayout(); - vkDestroyDescriptorSetLayout(vk::g_vkDevice, gSetLayout, vk::g_vkAllocator); - vkDestroyDescriptorSetLayout(vk::g_vkDevice, cSetLayout, vk::g_vkAllocator); + vkDestroyDescriptorSetLayout(vk::g_vkDevice, gSetLayout, vk::g_vkAllocator); + vkDestroyDescriptorSetLayout(vk::g_vkDevice, cSetLayout, vk::g_vkAllocator); - vkDestroyPipelineLayout(vk::g_vkDevice, gPipelineLayout, vk::g_vkAllocator); - vkDestroyPipelineLayout(vk::g_vkDevice, cPipelineLayout, vk::g_vkAllocator); + vkDestroyPipelineLayout(vk::g_vkDevice, gPipelineLayout, vk::g_vkAllocator); + vkDestroyPipelineLayout(vk::g_vkDevice, cPipelineLayout, vk::g_vkAllocator); } diff --git a/hw/amdgpu/include/amdgpu/RemoteMemory.hpp b/hw/amdgpu/include/amdgpu/RemoteMemory.hpp index e292bc51..e334c969 100644 --- a/hw/amdgpu/include/amdgpu/RemoteMemory.hpp +++ b/hw/amdgpu/include/amdgpu/RemoteMemory.hpp @@ -1,13 +1,16 @@ #pragma once #include -namespace amdgpu { -struct RemoteMemory { - char *shmPointer; +namespace amdgpu +{ + struct RemoteMemory + { + char* shmPointer; - template T *getPointer(std::uint64_t address) const { - return address ? reinterpret_cast(shmPointer + address - 0x40000) - : nullptr; - } -}; + template + T* getPointer(std::uint64_t address) const + { + return address ? reinterpret_cast(shmPointer + address - 0x40000) : nullptr; + } + }; } // namespace amdgpu diff --git a/hw/amdgpu/include/util/SourceLocation.hpp b/hw/amdgpu/include/util/SourceLocation.hpp index 1275fbfd..c1a20b48 100644 --- a/hw/amdgpu/include/util/SourceLocation.hpp +++ b/hw/amdgpu/include/util/SourceLocation.hpp @@ -1,31 +1,36 @@ #pragma once -namespace util { -class SourceLocation { -public: - const char *mFileName = {}; - const char *mFunctionName = {}; - unsigned mLine = 0; - unsigned mColumn = 0; +namespace util +{ + class SourceLocation + { + public: + const char* mFileName = {}; + const char* mFunctionName = {}; + unsigned mLine = 0; + unsigned mColumn = 0; -public: - constexpr SourceLocation(const char *fileName = __builtin_FILE(), - const char *functionName = __builtin_FUNCTION(), - unsigned line = __builtin_LINE(), - unsigned column = + public: + constexpr SourceLocation(const char* fileName = __builtin_FILE(), + const char* functionName = __builtin_FUNCTION(), + unsigned line = __builtin_LINE(), + unsigned column = #if __has_builtin(__builtin_COLUMN) - __builtin_COLUMN() + __builtin_COLUMN() #else - 0 + 0 #endif - ) noexcept - : mFileName(fileName), mFunctionName(functionName), mLine(line), - mColumn(column) { - } + ) noexcept + : mFileName(fileName) + , mFunctionName(functionName) + , mLine(line) + , mColumn(column) + { + } - constexpr unsigned line() const noexcept { return mLine; } - constexpr unsigned column() const noexcept { return mColumn; } - constexpr const char *file_name() const noexcept { return mFileName; } - constexpr const char *function_name() const noexcept { return mFunctionName; } -}; + constexpr unsigned line() const noexcept { return mLine; } + constexpr unsigned column() const noexcept { return mColumn; } + constexpr const char* file_name() const noexcept { return mFileName; } + constexpr const char* function_name() const noexcept { return mFunctionName; } + }; } // namespace util diff --git a/hw/amdgpu/include/util/Verify.hpp b/hw/amdgpu/include/util/Verify.hpp index ba40e823..9f375e37 100644 --- a/hw/amdgpu/include/util/Verify.hpp +++ b/hw/amdgpu/include/util/Verify.hpp @@ -3,22 +3,27 @@ #include "SourceLocation.hpp" #include "unreachable.hpp" -class Verify { - util::SourceLocation mLocation; +class Verify +{ + util::SourceLocation mLocation; public: - util::SourceLocation location() const { return mLocation; } + util::SourceLocation location() const { return mLocation; } - Verify(util::SourceLocation location = util::SourceLocation()) - : mLocation(location) {} + Verify(util::SourceLocation location = util::SourceLocation()) + : mLocation(location) + { + } - Verify &operator<<(bool result) { - if (!result) { - util::unreachable("Verification failed at %s: %s:%u:%u", - mLocation.function_name(), mLocation.file_name(), - mLocation.line(), mLocation.column()); - } + Verify& operator<<(bool result) + { + if (!result) + { + util::unreachable("Verification failed at %s: %s:%u:%u", + mLocation.function_name(), mLocation.file_name(), + mLocation.line(), mLocation.column()); + } - return *this; - } + return *this; + } }; diff --git a/hw/amdgpu/include/util/VerifyVulkan.hpp b/hw/amdgpu/include/util/VerifyVulkan.hpp index 4665990a..85214c3a 100644 --- a/hw/amdgpu/include/util/VerifyVulkan.hpp +++ b/hw/amdgpu/include/util/VerifyVulkan.hpp @@ -2,13 +2,15 @@ #include "Verify.hpp" #include -inline Verify operator<<(Verify lhs, VkResult result) { - if (result < VK_SUCCESS) { - auto location = lhs.location(); - util::unreachable("Verification failed at %s: %s:%u:%u(res = %d)", - location.function_name(), location.file_name(), - location.line(), location.column(), result); - } +inline Verify operator<<(Verify lhs, VkResult result) +{ + if (result < VK_SUCCESS) + { + auto location = lhs.location(); + util::unreachable("Verification failed at %s: %s:%u:%u(res = %d)", + location.function_name(), location.file_name(), + location.line(), location.column(), result); + } - return lhs; + return lhs; } diff --git a/hw/amdgpu/include/util/area.hpp b/hw/amdgpu/include/util/area.hpp index 898870da..65918fb5 100644 --- a/hw/amdgpu/include/util/area.hpp +++ b/hw/amdgpu/include/util/area.hpp @@ -2,6 +2,7 @@ #include -namespace util { -using namespace rx; +namespace util +{ + using namespace rx; } // namespace util diff --git a/hw/amdgpu/include/util/unreachable.hpp b/hw/amdgpu/include/util/unreachable.hpp index 64e8396d..a204a02f 100644 --- a/hw/amdgpu/include/util/unreachable.hpp +++ b/hw/amdgpu/include/util/unreachable.hpp @@ -4,29 +4,33 @@ #include #include -namespace util { -[[noreturn]] inline void unreachable_impl() { - std::fflush(stdout); - __builtin_trap(); -} +namespace util +{ + [[noreturn]] inline void unreachable_impl() + { + std::fflush(stdout); + __builtin_trap(); + } -[[noreturn]] inline void unreachable(SourceLocation location = {}) { - std::printf("\n"); - std::fflush(stdout); - std::fprintf(stderr, "Unreachable at %s:%u:%u %s\n", location.file_name(), - location.line(), location.column(), location.function_name()); - unreachable_impl(); -} + [[noreturn]] inline void unreachable(SourceLocation location = {}) + { + std::printf("\n"); + std::fflush(stdout); + std::fprintf(stderr, "Unreachable at %s:%u:%u %s\n", location.file_name(), + location.line(), location.column(), location.function_name()); + unreachable_impl(); + } -[[noreturn]] inline void unreachable(const char *fmt, ...) { - std::printf("\n"); - std::fflush(stdout); - va_list list; - va_start(list, fmt); - std::vfprintf(stderr, fmt, list); - va_end(list); - std::fprintf(stderr, "\n"); + [[noreturn]] inline void unreachable(const char* fmt, ...) + { + std::printf("\n"); + std::fflush(stdout); + va_list list; + va_start(list, fmt); + std::vfprintf(stderr, fmt, list); + va_end(list); + std::fprintf(stderr, "\n"); - unreachable_impl(); -} + unreachable_impl(); + } } // namespace util diff --git a/hw/amdgpu/lib/libspirv/include/spirv/spirv-builder.hpp b/hw/amdgpu/lib/libspirv/include/spirv/spirv-builder.hpp index 9d682009..db090299 100644 --- a/hw/amdgpu/lib/libspirv/include/spirv/spirv-builder.hpp +++ b/hw/amdgpu/lib/libspirv/include/spirv/spirv-builder.hpp @@ -12,2237 +12,2643 @@ #include #include -namespace spirv { -struct Id { - unsigned id{}; - - Id() = default; - explicit Id(unsigned value) : id(value) {} - - explicit operator unsigned() const { - assert(id != 0); - return id; - } - explicit operator bool() const { return id != 0; } - - bool operator==(Id other) const { return id == other.id; } - bool operator!=(Id other) const { return id != other.id; } - bool operator<(Id other) const { return id < other.id; } - bool operator>(Id other) const { return id > other.id; } - bool operator<=(Id other) const { return id <= other.id; } - bool operator>=(Id other) const { return id >= other.id; } -}; - -struct Type : Id {}; -struct ScalarType : Type {}; -struct VoidType : Type {}; -struct BoolType : ScalarType {}; -struct IntType : ScalarType {}; -struct SIntType : IntType {}; -struct UIntType : IntType {}; -struct FloatType : ScalarType {}; -struct VectorType : Type {}; -struct MatrixType : Type {}; -struct SamplerType : Type {}; -struct ImageType : Type {}; -struct SampledImageType : Type {}; -struct ArrayType : Type {}; -struct RuntimeArrayType : Type {}; -struct StructType : Type {}; -struct PointerType : Type {}; -struct FunctionType : Type {}; - -struct ExtInstSet : Id {}; -struct Function : Id {}; -struct Block : Id {}; -struct Value : Id {}; - -struct BoolValue : Value {}; -struct IntValue : Value {}; -struct SIntValue : IntValue {}; -struct UIntValue : IntValue {}; -struct FloatValue : Value {}; -struct StructValue : Value {}; -struct PointerValue : Value {}; -struct VectorValue : Value {}; -struct ArrayValue : Value {}; -struct SamplerValue : Value {}; -struct ImageValue : Value {}; -struct SampledImageValue : Value {}; - -template - requires(std::is_base_of_v) -struct ConstantValue : T {}; - -struct AnyConstantValue : Value { - AnyConstantValue() = default; - - template AnyConstantValue(ConstantValue specialization) { - id = specialization.id; - } - - template - AnyConstantValue &operator=(ConstantValue specialization) { - id = specialization.id; - return *this; - } - - template explicit operator ConstantValue() { - ConstantValue result; - result.id = id; - return result; - } -}; - -template - requires(std::is_base_of_v) -struct VectorOfType : VectorType {}; - -template - requires(std::is_base_of_v) -struct ArrayOfType : ArrayType {}; - -template - requires(std::is_base_of_v) -struct VectorOfValue : VectorValue {}; - -template - requires(std::is_base_of_v) -struct ArrayOfValue : ArrayValue {}; - -template - requires(std::is_base_of_v) -struct PointerToType : PointerType {}; - -template - requires(std::is_base_of_v) -struct PointerToValue : PointerValue {}; - -struct StructPointerValue : Value {}; - -struct VariableValue : PointerValue {}; - -namespace detail { -template struct TypeToValueImpl; - -template <> struct TypeToValueImpl { - using type = Value; -}; -template <> struct TypeToValueImpl { - using type = BoolValue; -}; -template <> struct TypeToValueImpl { - using type = IntValue; -}; -template <> struct TypeToValueImpl { - using type = SIntValue; -}; -template <> struct TypeToValueImpl { - using type = UIntValue; -}; -template <> struct TypeToValueImpl { - using type = FloatValue; -}; -template <> struct TypeToValueImpl { - using type = StructValue; -}; -template <> struct TypeToValueImpl { - using type = PointerValue; -}; -template <> struct TypeToValueImpl { - using type = PointerValue; -}; -template <> struct TypeToValueImpl { - using type = VectorValue; -}; -template <> struct TypeToValueImpl { - using type = ArrayValue; -}; -template <> struct TypeToValueImpl { - using type = SamplerValue; -}; -template <> struct TypeToValueImpl { - using type = ImageValue; -}; -template <> struct TypeToValueImpl { - using type = SampledImageValue; -}; - -template struct TypeToValueImpl> { - using type = PointerToValue; -}; -template struct TypeToValueImpl> { - using type = VectorOfValue; -}; - -template struct TypeToValueImpl> { - using type = ArrayOfValue; -}; -} // namespace detail - -template -using TypeToValue = typename detail::TypeToValueImpl::type; - -template - requires(std::is_base_of_v) -struct ScalarOrVectorOfValue : Value { - ScalarOrVectorOfValue() = default; - - ScalarOrVectorOfValue(TypeToValue scalar) { id = scalar.id; } - ScalarOrVectorOfValue(VectorOfValue vector) { id = vector.id; } -}; - -using ConstantBool = ConstantValue; -using ConstantSInt = ConstantValue; -using ConstantUInt = ConstantValue; -using ConstantInt = ConstantValue; -using ConstantFloat = ConstantValue; - -template - requires(std::is_base_of_v && std::is_base_of_v) -ToT cast(FromT from) { - ToT result; - result.id = from.id; - return result; -} - -inline unsigned calcStringWordCount(std::string_view string) { - return (string.length() + 1 + (sizeof(std::uint32_t) - 1)) / - sizeof(std::uint32_t); -} - -using IdUsesTackerType = - std::unordered_map>; -using IdDefTackerType = std::unordered_map; - -class RegionPusher { - IdUsesTackerType *mIdUses = nullptr; - IdDefTackerType *mIdDefs = nullptr; - std::uint32_t *mBeginPtr = nullptr; - std::uint32_t *mPtr = nullptr; - std::size_t mCount = 0; - - RegionPusher &operator=(const RegionPusher &) = default; - -public: - RegionPusher() = default; - RegionPusher(const RegionPusher &) = delete; - RegionPusher(std::uint32_t *beginPtr, std::uint32_t *ptr, std::size_t count, - IdUsesTackerType *idUses, IdDefTackerType *idDefs) - : mIdUses(idUses), mIdDefs(idDefs), mBeginPtr(beginPtr), mPtr(ptr), - mCount(count) {} - RegionPusher(RegionPusher &&other) { *this = std::move(other); } - - RegionPusher &operator=(RegionPusher &&other) { - *this = other; - other.mCount = 0; - return *this; - } - - ~RegionPusher() { assert(mCount == 0); } - - void pushWord(unsigned word) { - assert(mCount > 0); - *mPtr++ = word; - --mCount; - } - - void pushIdDef(Id id) { - assert(id); - (*mIdDefs)[id.id] = mPtr - mBeginPtr; - pushWord(id.id); - } - - void pushIdUse(Id id) { - assert(id); - (*mIdUses)[id.id].push_back(mPtr - mBeginPtr); - - pushWord(id.id); - } - - void pushString(std::string_view string) { - auto nwords = calcStringWordCount(string); - assert(mCount >= nwords); - - auto dst = reinterpret_cast(mPtr); - std::memcpy(dst, string.data(), string.length()); - std::memset(dst + string.length(), 0, - nwords * sizeof(std::uint32_t) - string.length()); - mPtr += nwords; - mCount -= nwords; - } -}; - -struct IdGenerator { - std::uint32_t bounds = 1; - - template - requires(std::is_base_of_v) - T newId() { - T result; - result.id = bounds++; - return result; - } - - Id newId() { - Id result; - result.id = bounds++; - return result; - } - - void reset() { bounds = 1; } -}; - -class RegionPoint { - const std::vector *mData = nullptr; - std::size_t mOffset = 0; - -public: - RegionPoint() = default; - RegionPoint(const std::vector *data, std::size_t offset) - : mData(data), mOffset(offset) {} - - std::span operator-(RegionPoint other) const { - assert(mData == other.mData); - assert(mOffset >= other.mOffset); - - return {other.mData->data() + other.mOffset, mData->data() + mOffset}; - } -}; - -class Region { - std::vector mData; - IdUsesTackerType mIdUses; - IdDefTackerType mIdDefs; - -public: - Region() = default; - Region(std::size_t expInstCount) { mData.reserve(expInstCount); } - - bool isIdDefined(Id id) const { return mIdDefs.contains(id.id); } - bool isIdUsed(Id id) const { return mIdUses.contains(id.id); } - - void clear() { mData.clear(); } - - const std::uint32_t *data() const { return mData.data(); } - std::size_t size() const { return mData.size(); } - - RegionPoint getCurrentPosition() const { return {&mData, mData.size()}; } - - RegionPusher pushOp(spv::Op op, unsigned wordCount) { - assert(wordCount >= 1); - auto offset = mData.size(); - mData.resize(mData.size() + wordCount); - RegionPusher pusher(mData.data(), mData.data() + offset, wordCount, - &mIdUses, &mIdDefs); - pusher.pushWord((static_cast(op) & spv::OpCodeMask) | - (wordCount << spv::WordCountShift)); - - return pusher; - } - - void pushRegion(const Region &other) { - auto offset = mData.size(); - mData.resize(mData.size() + other.size()); - std::memcpy(mData.data() + offset, other.data(), - other.size() * sizeof(std::uint32_t)); - - for (auto &[id, def] : other.mIdDefs) { - mIdDefs[id] = offset + def; - } - - for (auto &[id, uses] : other.mIdUses) { - auto &idUses = mIdUses[id]; - idUses.reserve(idUses.size() + uses.size()); - - for (auto use : uses) { - idUses.push_back(offset + use); - } - } - } - - void recreateDefs(std::unordered_map &remap, - IdGenerator &generator) { - auto prevDefs = std::move(mIdDefs); - mIdDefs = {}; - - for (auto [id, def] : prevDefs) { - auto newId = generator.newId().id; - - remap[id] = newId; - mData[def] = newId; - mIdDefs[newId] = def; - } - } - - void - remapUses(const std::unordered_map &remap) { - auto prevUses = std::move(mIdUses); - mIdUses = {}; - - for (auto &[id, uses] : prevUses) { - auto it = remap.find(id); - assert(it != remap.end()); - auto newId = it->second; - - for (auto &use : uses) { - mData[use] = newId; - } - - mIdUses[newId] = std::move(uses); - } - } -}; - -class BlockBuilder { - IdGenerator *mIdGenerator = nullptr; - - template auto newId() -> decltype(mIdGenerator->newId()) { - return mIdGenerator->newId(); - } - -public: - Block id; - Region prefix; - Region phiRegion; - Region variablesRegion; - Region bodyRegion; - Region terminatorRegion; - - BlockBuilder() = default; - BlockBuilder(IdGenerator &idGenerator, Block id, - std::size_t expInstructionsCount) - : mIdGenerator(&idGenerator), id(id), bodyRegion{expInstructionsCount}, - terminatorRegion{1} {} - - void moveBlock(BlockBuilder &&other) { - prefix.pushRegion(other.prefix); - { - auto region = prefix.pushOp(spv::Op::OpLabel, 2); - region.pushIdDef(id); - } - prefix.pushRegion(phiRegion); - prefix.pushRegion(bodyRegion); - prefix.pushRegion(terminatorRegion); - - id = other.id; - phiRegion = std::move(other.phiRegion); - variablesRegion.pushRegion(other.variablesRegion); - bodyRegion = std::move(other.bodyRegion); - terminatorRegion = std::move(other.terminatorRegion); - } - - Value createExtInst(Type resultType, ExtInstSet set, - std::uint32_t instruction, - std::span operands) { - auto region = bodyRegion.pushOp(spv::Op::OpExtInst, 5 + operands.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(set); - region.pushWord(instruction); - for (auto operand : operands) { - region.pushIdUse(operand); - } - return id; - } - - VariableValue createVariable(Type type, spv::StorageClass storageClass, - std::optional initializer = {}) { - auto region = variablesRegion.pushOp(spv::Op::OpVariable, - 4 + (initializer.has_value() ? 1 : 0)); - auto id = newId(); - region.pushIdUse(type); - region.pushIdDef(id); - region.pushWord(static_cast(storageClass)); - if (initializer.has_value()) { - region.pushIdUse(initializer.value()); - } - return id; - } - - Value createFunctionCall(Type resultType, Function function, - std::span arguments) { - auto region = - bodyRegion.pushOp(spv::Op::OpFunctionCall, 4 + arguments.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(function); - for (auto argument : arguments) { - region.pushIdUse(argument); - } - return id; - } - - // composite - Value createVectorExtractDynamic(Type resultType, Value vector, - IntValue index) { - auto region = bodyRegion.pushOp(spv::Op::OpVectorExtractDynamic, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(vector); - region.pushIdUse(index); - return id; - } - - Value createVectorInsertDynamic(Type resultType, Value vector, - Value component, IntValue index) { - auto region = bodyRegion.pushOp(spv::Op::OpVectorInsertDynamic, 6); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(vector); - region.pushIdUse(component); - region.pushIdUse(index); - return id; - } - - Value createVectorShuffle(Type resultType, Value vector1, Value vector2, - std::span components) { - auto region = - bodyRegion.pushOp(spv::Op::OpVectorShuffle, 5 + components.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(vector1); - region.pushIdUse(vector2); - - for (auto component : components) { - region.pushWord(component); - } - return id; - } - - template - TypeToValue createCompositeConstruct(T resultType, - std::span constituents) { - auto region = bodyRegion.pushOp(spv::Op::OpCompositeConstruct, - 3 + constituents.size()); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - - for (auto constituent : constituents) { - region.pushIdUse(constituent); - } - return id; - } - - Value createCompositeExtract(Type resultType, Value composite, - std::span indexes) { - auto region = - bodyRegion.pushOp(spv::Op::OpCompositeExtract, 4 + indexes.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(composite); - - for (auto index : indexes) { - region.pushWord(index); - } - return id; - } - - // arithmetic - template - requires(std::is_base_of_v) - TypeToValue createInst(spv::Op op, T resultType, - std::span> operands) { - auto region = bodyRegion.pushOp(op, 3 + operands.size()); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - for (auto operand : operands) { - region.pushIdUse(operand); - } - return id; - } - - Value createInst(spv::Op op, Type resultType, - std::span operands) { - auto region = bodyRegion.pushOp(op, 3 + operands.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - for (auto operand : operands) { - region.pushIdUse(operand); - } - return id; - } - - template - VectorOfValue createInst(spv::Op op, VectorOfType resultType, - std::span> operands) { - auto region = bodyRegion.pushOp(op, 3 + operands.size()); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - for (auto operand : operands) { - region.pushIdUse(operand); - } - return id; - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createSNegate(T resultType, TypeToValue operand) { - return createInst(spv::Op::OpSNegate, resultType, std::array{operand}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFNegate(T resultType, TypeToValue operand) { - return createInst(spv::Op::OpFNegate, resultType, std::array{operand}); - } - - template - requires(std::is_same_v || std::is_base_of_v || - std::is_same_v, T> || - std::is_same_v, T> || - std::is_same_v, T>) - TypeToValue createIAdd(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpIAdd, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFAdd(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFAdd, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || std::is_base_of_v || - std::is_same_v, T> || - std::is_same_v, T> || - std::is_same_v, T>) - TypeToValue createISub(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpISub, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFSub(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFSub, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || std::is_base_of_v || - std::is_same_v, T> || - std::is_same_v, T> || - std::is_same_v, T>) - TypeToValue createIMul(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpIMul, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFMul(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFMul, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createUDiv(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpUDiv, resultType, - std::array{operand1, operand2}); - } - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createSDiv(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpSDiv, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFDiv(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFDiv, resultType, - std::array{operand1, operand2}); - } - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createUMod(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpUMod, resultType, - std::array{operand1, operand2}); - } - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createSRem(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpSRem, resultType, - std::array{operand1, operand2}); - } - - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createSMod(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpSMod, resultType, - std::array{operand1, operand2}); - } - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFRem(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFRem, resultType, - std::array{operand1, operand2}); - } - template - requires(std::is_same_v || - std::is_same_v, T>) - TypeToValue createFMod(T resultType, TypeToValue operand1, - TypeToValue operand2) { - return createInst(spv::Op::OpFMod, resultType, - std::array{operand1, operand2}); - } - - Value createIAddCarry(Type resultType, Value operand1, Value operand2) { - return createInst(spv::Op::OpIAddCarry, resultType, - std::array{operand1, operand2}); - } - - Value createISubBorrow(Type resultType, Value operand1, Value operand2) { - return createInst(spv::Op::OpISubBorrow, resultType, - std::array{operand1, operand2}); - } - - Value createUMulExtended(Type resultType, Value operand1, Value operand2) { - return createInst(spv::Op::OpUMulExtended, resultType, - std::array{operand1, operand2}); - } - - Value createSMulExtended(Type resultType, Value operand1, Value operand2) { - return createInst(spv::Op::OpSMulExtended, resultType, - std::array{operand1, operand2}); - } - - Value createPhi(Type resultType, - std::span> values) { - auto region = phiRegion.pushOp(spv::Op::OpPhi, 3 + values.size() * 2); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - for (auto [variable, block] : values) { - region.pushIdUse(variable); - region.pushIdUse(block); - } - return id; - } - - void addBlockToPhis(spirv::Block block, - std::span values) { - auto phi = phiRegion.data(); - spirv::Region newPhi(phiRegion.size() * 2); - - assert(block); - - for (std::size_t i = 0, end = phiRegion.size(), index = 0; i < end; - index++) { - auto opWordCount = phi[i]; - - assert(static_cast(static_cast(opWordCount) & - spv::OpCodeMask) == spv::Op::OpPhi); - auto wordCount = - static_cast(opWordCount) >> spv::WordCountShift; - auto newOp = newPhi.pushOp(spv::Op::OpPhi, wordCount + 2); - - for (std::size_t j = 1; j < wordCount; ++j) { - newOp.pushWord(phi[i + j]); - } - - i += wordCount; - - assert(index < values.size()); - assert(values[index]); - - newOp.pushIdUse(values[index]); - newOp.pushIdUse(block); - } - - phiRegion = std::move(newPhi); - } - - void moveVariablesFrom(BlockBuilder &otherBlock) { - variablesRegion.pushRegion(otherBlock.variablesRegion); - otherBlock.variablesRegion.clear(); - } - - template - requires(std::is_base_of_v) - TypeToValue createPhi(T resultType, - std::span> values) { - return cast>( - createPhi(static_cast(resultType), values)); - } - - void createLoopMerge(Block mergeBlock, Block continueTarget, - spv::LoopControlMask loopControl, - std::span loopControlParameters) { - auto region = terminatorRegion.pushOp(spv::Op::OpLoopMerge, - 4 + loopControlParameters.size()); - region.pushIdUse(mergeBlock); - region.pushIdUse(continueTarget); - region.pushWord(static_cast(loopControl)); - - for (auto loopControlParameter : loopControlParameters) { - region.pushWord(static_cast(loopControlParameter)); - } - } - - void createSelectionMerge(Block mergeBlock, - spv::SelectionControlMask selectionControl) { - auto region = terminatorRegion.pushOp(spv::Op::OpSelectionMerge, 3); - region.pushIdUse(mergeBlock); - region.pushWord(static_cast(selectionControl)); - } - - void createBranch(Block label) { - auto region = terminatorRegion.pushOp(spv::Op::OpBranch, 2); - region.pushIdUse(label); - } - - void createBranchConditional( - BoolValue condition, Block trueLabel, Block falseLabel, - std::optional> weights = {}) { - auto region = terminatorRegion.pushOp(spv::Op::OpBranchConditional, - 4 + (weights.has_value() ? 1 : 0)); - region.pushIdUse(condition); - region.pushIdUse(trueLabel); - region.pushIdUse(falseLabel); - - if (weights.has_value()) { - region.pushWord(weights->first); - region.pushWord(weights->second); - } - } - - void createKill() { - assert(terminatorRegion.size() == 0); - terminatorRegion.pushOp(spv::Op::OpKill, 1); - } - - void createReturn() { - assert(terminatorRegion.size() == 0); - terminatorRegion.pushOp(spv::Op::OpReturn, 1); - } - - void createReturnValue(Value value) { - assert(terminatorRegion.size() == 0); - auto region = terminatorRegion.pushOp(spv::Op::OpReturnValue, 2); - region.pushIdUse(value); - } - - void createUnreachable() { - assert(terminatorRegion.size() == 0); - terminatorRegion.pushOp(spv::Op::OpUnreachable, 1); - } - - Value createLoad(Type resultType, PointerValue pointer, - spv::MemoryAccessMask memoryAccess, - std::span memoryAccessOperands) { - auto region = - bodyRegion.pushOp(spv::Op::OpLoad, 5 + memoryAccessOperands.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(pointer); - region.pushWord(static_cast(memoryAccess)); - - for (auto memoryAccessOperand : memoryAccessOperands) { - region.pushWord(static_cast(memoryAccessOperand)); - } - - return id; - } - - template - requires(std::is_base_of_v) - TypeToValue createLoad(T resultType, PointerValue pointer) { - auto region = bodyRegion.pushOp(spv::Op::OpLoad, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(pointer); - return id; - } - - void createStore(PointerValue pointer, Value object) { - auto region = bodyRegion.pushOp(spv::Op::OpStore, 3); - region.pushIdUse(pointer); - region.pushIdUse(object); - } - - void createStore(PointerValue pointer, Value object, - spv::MemoryAccessMask memoryAccess, - std::span memoryAccessOperands) { - auto region = - bodyRegion.pushOp(spv::Op::OpStore, 4 + memoryAccessOperands.size()); - region.pushIdUse(pointer); - region.pushIdUse(object); - region.pushWord(static_cast(memoryAccess)); - - for (auto memoryAccessOperand : memoryAccessOperands) { - region.pushWord(memoryAccessOperand); - } - } - - void createCopyMemory(PointerValue targetPointer, - PointerValue sourcePointer) { - auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, 3); - region.pushIdUse(targetPointer); - region.pushIdUse(sourcePointer); - } - - void createCopyMemory(PointerValue targetPointer, PointerValue sourcePointer, - spv::MemoryAccessMask memoryAccess, - std::span memoryAccessOperands) { - auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, - 4 + memoryAccessOperands.size()); - region.pushIdUse(targetPointer); - region.pushIdUse(sourcePointer); - region.pushWord(static_cast(memoryAccess)); - for (auto memoryAccessOperand : memoryAccessOperands) { - region.pushWord(memoryAccessOperand); - } - } - - void - createCopyMemory(PointerValue targetPointer, PointerValue sourcePointer, - spv::MemoryAccessMask targetMemoryAccess, - std::span targetMemoryAccessOperands, - spv::MemoryAccessMask sourceMemoryAccess, - std::span sourceMemoryAccessOperands) { - auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, - 5 + targetMemoryAccessOperands.size() + - sourceMemoryAccessOperands.size()); - region.pushIdUse(targetPointer); - region.pushIdUse(sourcePointer); - region.pushWord(static_cast(targetMemoryAccess)); - for (auto memoryAccessOperand : targetMemoryAccessOperands) { - region.pushWord(static_cast(memoryAccessOperand)); - } - region.pushWord(static_cast(sourceMemoryAccess)); - for (auto memoryAccessOperand : sourceMemoryAccessOperands) { - region.pushWord(static_cast(memoryAccessOperand)); - } - } - - UIntValue createArrayLength(UIntType resultType, - PointerToValue structure, - std::uint32_t member) { - auto region = bodyRegion.pushOp(spv::Op::OpArrayLength, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(structure); - region.pushWord(member); - return id; - } - - BoolValue createPtrEqual(BoolType resultType, PointerValue operand1, - PointerValue operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpPtrEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - BoolValue createPtrNotEqual(BoolType resultType, PointerValue operand1, - PointerValue operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpPtrNotEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - PointerValue createAccessChain(PointerType resultType, PointerValue base, - std::span indices) { - auto region = bodyRegion.pushOp(spv::Op::OpAccessChain, 4 + indices.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(base); - - for (auto index : indices) { - region.pushIdUse(index); - } - return id; - } - - PointerValue createInBoundsAccessChain(PointerType resultType, - PointerValue base, - std::span indices) { - auto region = - bodyRegion.pushOp(spv::Op::OpInBoundsAccessChain, 4 + indices.size()); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(base); - - for (auto index : indices) { - region.pushIdUse(index); - } - return id; - } - - // conversion - Value createConvertFToU(Type resultType, Value operand) { - auto region = bodyRegion.pushOp(spv::Op::OpConvertFToU, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - Value createConvertFToS(Type resultType, Value operand) { - auto region = bodyRegion.pushOp(spv::Op::OpConvertFToS, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - template - TypeToValue createConvertSToF(T resultType, SIntValue operand) { - auto region = bodyRegion.pushOp(spv::Op::OpConvertSToF, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - template - TypeToValue createConvertUToF(T resultType, UIntValue operand) { - auto region = bodyRegion.pushOp(spv::Op::OpConvertUToF, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - template - TypeToValue createUConvert(T resultType, UIntValue operand) { - auto region = bodyRegion.pushOp(spv::Op::OpUConvert, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - template - TypeToValue createSConvert(T resultType, SIntValue operand) { - auto region = bodyRegion.pushOp(spv::Op::OpSConvert, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - Value createFConvert(Type resultType, Value operand) { - auto region = bodyRegion.pushOp(spv::Op::OpFConvert, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - template - TypeToValue createBitcast(T resultType, Value operand) { - auto region = bodyRegion.pushOp(spv::Op::OpBitcast, 4); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - - // bit - template - TypeToValue createShiftRightLogical(T resultType, TypeToValue base, - IntValue shift) { - auto region = bodyRegion.pushOp(spv::Op::OpShiftRightLogical, 5); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(base); - region.pushIdUse(shift); - return id; - } - - template - TypeToValue createShiftRightArithmetic(T resultType, TypeToValue base, - IntValue shift) { - auto region = bodyRegion.pushOp(spv::Op::OpShiftRightArithmetic, 5); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(base); - region.pushIdUse(shift); - return id; - } - - template - TypeToValue createShiftLeftLogical(T resultType, TypeToValue base, - IntValue shift) { - auto region = bodyRegion.pushOp(spv::Op::OpShiftLeftLogical, 5); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(base); - region.pushIdUse(shift); - return id; - } - - Value createBitwiseOr(Type resultType, Value operand1, Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpBitwiseOr, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - Value createBitwiseXor(Type resultType, Value operand1, Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpBitwiseXor, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - Value createBitwiseAnd(Type resultType, Value operand1, Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpBitwiseAnd, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - Value createNot(Type resultType, Value operand) { - auto region = bodyRegion.pushOp(spv::Op::OpNot, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - - // relational - BoolValue createIsNan(BoolType resultType, Value operand1) { - auto region = bodyRegion.pushOp(spv::Op::OpIsNan, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - return id; - } - - BoolValue createIsInf(BoolType resultType, Value operand1) { - auto region = bodyRegion.pushOp(spv::Op::OpIsInf, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - return id; - } - - // logic - BoolValue createLogicalEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpLogicalEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createLogicalNotEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpLogicalNotEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - BoolValue createLogicalOr(BoolType resultType, BoolValue operand1, - BoolValue operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpLogicalOr, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - BoolValue createLogicalAnd(BoolType resultType, BoolValue operand1, - BoolValue operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpLogicalAnd, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - BoolValue createLogicalNot(BoolType resultType, BoolValue operand) { - auto region = bodyRegion.pushOp(spv::Op::OpLogicalNot, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand); - return id; - } - - template - TypeToValue createSelect(T resultType, BoolValue condition, Value object1, - Value object2) { - auto region = bodyRegion.pushOp(spv::Op::OpSelect, 6); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(condition); - region.pushIdUse(object1); - region.pushIdUse(object2); - return id; - } - - BoolValue createIEqual(BoolType resultType, Value operand1, Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpIEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createINotEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpINotEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createUGreaterThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpUGreaterThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createSGreaterThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpSGreaterThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createUGreaterThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpUGreaterThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createSGreaterThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpSGreaterThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createULessThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpULessThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createSLessThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpSLessThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createULessThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpULessThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createSLessThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpSLessThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - BoolValue createFOrdEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFOrdNotEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdNotEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordNotEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordNotEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFOrdLessThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdLessThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordLessThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordLessThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFOrdLessThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdLessThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordLessThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordLessThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFOrdGreaterThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdGreaterThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordGreaterThan(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordGreaterThan, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFOrdGreaterThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFOrdGreaterThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - BoolValue createFUnordGreaterThanEqual(BoolType resultType, Value operand1, - Value operand2) { - auto region = bodyRegion.pushOp(spv::Op::OpFUnordGreaterThanEqual, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(operand1); - region.pushIdUse(operand2); - return id; - } - - // image - SampledImageValue createSampledImage(SampledImageType resultType, - ImageValue image, SamplerValue sampler) { - auto region = bodyRegion.pushOp(spv::Op::OpSampledImage, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(image); - region.pushIdUse(sampler); - return id; - } - VectorOfValue createImageSampleImplicitLod( - VectorOfType resultType, SampledImageValue sampledImage, - ScalarOrVectorOfValue coords, - spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, - std::span args = {}) { - auto region = bodyRegion.pushOp( - spv::Op::OpImageSampleImplicitLod, - 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 - : 1 + args.size())); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(sampledImage); - region.pushIdUse(coords); - - if (operands != spv::ImageOperandsMask::MaskNone) { - region.pushWord(static_cast(operands)); - - for (auto arg : args) { - region.pushIdUse(arg); - } - } - - return id; - } - - VectorOfValue createImageSampleExplicitLod( - VectorOfType resultType, SampledImageValue sampledImage, - ScalarOrVectorOfValue coords, - spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, - std::span args = {}) { - auto region = bodyRegion.pushOp( - spv::Op::OpImageSampleExplicitLod, - 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 - : 1 + args.size())); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(sampledImage); - region.pushIdUse(coords); - - if (operands != spv::ImageOperandsMask::MaskNone) { - region.pushWord(static_cast(operands)); - - for (auto arg : args) { - region.pushIdUse(arg); - } - } - - return id; - } - - VectorOfValue createImageRead( - VectorOfType resultType, ImageValue image, - ScalarOrVectorOfValue coords, - spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, - std::span args = {}) { - auto region = bodyRegion.pushOp( - spv::Op::OpImageRead, - 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 - : 1 + args.size())); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(image); - region.pushIdUse(coords); - - if (operands != spv::ImageOperandsMask::MaskNone) { - region.pushWord(static_cast(operands)); - - for (auto arg : args) { - region.pushIdUse(arg); - } - } - - return id; - } - - void createImageWrite( - ImageValue image, ScalarOrVectorOfValue coords, Value texel, - spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, - std::span args = {}) { - auto region = bodyRegion.pushOp( - spv::Op::OpImageWrite, - 4 + (operands == spv::ImageOperandsMask::MaskNone ? 0 - : 1 + args.size())); - region.pushIdUse(image); - region.pushIdUse(coords); - region.pushIdUse(texel); - - if (operands != spv::ImageOperandsMask::MaskNone) { - region.pushWord(static_cast(operands)); - - for (auto arg : args) { - region.pushIdUse(arg); - } - } - } - - Value createImageQuerySizeLod(Type resultType, ImageValue image, Value lod) { - auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySizeLod, 5); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(image); - region.pushIdUse(lod); - return id; - } - - Value createImageQuerySize(Type resultType, ImageValue image) { - auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySize, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(image); - return id; - } - - VectorOfValue - createImageQueryLod(VectorOfType resultType, - SampledImageValue sampledImage, - ScalarOrVectorOfValue coords) { - auto region = bodyRegion.pushOp(spv::Op::OpImageQueryLod, 5); - auto id = newId>(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(sampledImage); - region.pushIdUse(coords); - return id; - } - - IntValue createImageQueryLevels(IntType resultType, ImageValue sampledImage) { - auto region = bodyRegion.pushOp(spv::Op::OpImageQueryLevels, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(sampledImage); - return id; - } - - IntValue createImageQuerySamples(IntType resultType, - ImageValue sampledImage) { - auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySamples, 4); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushIdUse(sampledImage); - return id; - } -}; - -class FunctionBuilder { - IdGenerator *mIdGenerator = nullptr; - - template auto newId() -> decltype(mIdGenerator->newId()) { - return mIdGenerator->newId(); - } - -public: - Region paramsRegion; - Region bodyRegion; - Function id; - - FunctionBuilder() = default; - FunctionBuilder(IdGenerator &idGenerator, Function id, - std::size_t expInstructionsCount) - : mIdGenerator(&idGenerator), bodyRegion{expInstructionsCount}, id(id) {} - - Value createFunctionParameter(Type resultType) { - auto region = paramsRegion.pushOp(spv::Op::OpFunctionParameter, 3); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - return id; - } - - BlockBuilder createBlockBuilder(std::size_t expInstructionsCount) { - auto id = newId(); - - return BlockBuilder(*mIdGenerator, id, expInstructionsCount); - } - - void insertBlock(const BlockBuilder &builder) { - bodyRegion.pushRegion(builder.prefix); - - auto region = bodyRegion.pushOp(spv::Op::OpLabel, 2); - region.pushIdDef(builder.id); - - bodyRegion.pushRegion(builder.variablesRegion); - bodyRegion.pushRegion(builder.phiRegion); - bodyRegion.pushRegion(builder.bodyRegion); - bodyRegion.pushRegion(builder.terminatorRegion); - } -}; - -class SpirvBuilder { - IdGenerator *mIdGenerator = nullptr; - - Region capabilityRegion; - Region extensionRegion; - Region extInstRegion; - Region memoryModelRegion; - Region entryPointRegion; - Region executionModeRegion; - Region debugRegion; - Region annotationRegion; - Region globalRegion; - Region functionDeclRegion; - Region functionRegion; - - template auto newId() -> decltype(mIdGenerator->newId()) { - return mIdGenerator->newId(); - } - -private: - SpirvBuilder(const SpirvBuilder &) = default; - SpirvBuilder(SpirvBuilder &&) = default; - SpirvBuilder &operator=(SpirvBuilder &&) = default; - -public: - bool isIdDefined(Id id) const { - std::array regions = { - // &capabilityRegion, &extensionRegion, &extInstRegion, - // &memoryModelRegion, &entryPointRegion, &executionModeRegion, - // &debugRegion, &annotationRegion, &globalRegion, - &functionRegion, - }; - - for (auto reg : regions) { - if (reg->isIdDefined(id)) { - return true; - } - } - - return false; - } - bool isIdUsed(Id id) const { - std::array regions = { - &capabilityRegion, &extensionRegion, &extInstRegion, - &memoryModelRegion, &entryPointRegion, &executionModeRegion, - &debugRegion, &annotationRegion, &globalRegion, - &functionDeclRegion, &functionRegion, - }; - - for (auto reg : regions) { - if (reg->isIdUsed(id)) { - return true; - } - } - - return false; - } - SpirvBuilder() = default; - - SpirvBuilder(IdGenerator &idGenerator, std::size_t expInstructionsCount) - : mIdGenerator(&idGenerator), capabilityRegion{1}, extensionRegion{1}, - extInstRegion{4}, memoryModelRegion{3}, entryPointRegion{1}, - executionModeRegion{1}, debugRegion{0}, annotationRegion{1}, - globalRegion{1}, functionDeclRegion{1}, - functionRegion{expInstructionsCount} {} - - SpirvBuilder clone() const { return *this; } - - void swap(SpirvBuilder &other) { - std::swap(mIdGenerator, other.mIdGenerator); - std::swap(capabilityRegion, other.capabilityRegion); - std::swap(extensionRegion, other.extensionRegion); - std::swap(extInstRegion, other.extInstRegion); - std::swap(memoryModelRegion, other.memoryModelRegion); - std::swap(entryPointRegion, other.entryPointRegion); - std::swap(executionModeRegion, other.executionModeRegion); - std::swap(debugRegion, other.debugRegion); - std::swap(annotationRegion, other.annotationRegion); - std::swap(globalRegion, other.globalRegion); - std::swap(functionDeclRegion, other.functionDeclRegion); - std::swap(functionRegion, other.functionRegion); - } - - void reset() { - mIdGenerator->reset(); - capabilityRegion.clear(); - extensionRegion.clear(); - extInstRegion.clear(); - memoryModelRegion.clear(); - entryPointRegion.clear(); - executionModeRegion.clear(); - debugRegion.clear(); - annotationRegion.clear(); - globalRegion.clear(); - functionDeclRegion.clear(); - functionRegion.clear(); - } - - IdGenerator *getIdGenerator() const { return mIdGenerator; } - - std::vector build(std::uint32_t spirvVersion, - std::uint32_t generatorMagic) { - const std::size_t headerSize = 5; - std::size_t finalSize = headerSize; - - std::array regions = { - &capabilityRegion, &extensionRegion, &extInstRegion, - &memoryModelRegion, &entryPointRegion, &executionModeRegion, - &debugRegion, &annotationRegion, &globalRegion, - &functionDeclRegion, &functionRegion, - }; - - for (auto region : regions) { - finalSize += region->size(); - } - - std::vector result; - result.resize(finalSize); - - result[0] = spv::MagicNumber; - result[1] = spirvVersion; - result[2] = generatorMagic; - result[3] = mIdGenerator->bounds; - result[4] = 0; // instruction schema - - std::size_t currentOffset = headerSize; - - for (auto region : regions) { - std::memcpy(result.data() + currentOffset, region->data(), - region->size() * sizeof(std::uint32_t)); - currentOffset += region->size(); - } - - return result; - } - - // misc - Value createUndef(Type resultType) { - auto region = globalRegion.pushOp(spv::Op::OpUndef, 3); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - return id; - } - - template - requires(std::is_base_of_v) - TypeToValue createUndef(T resultType) { - return cast>(createUndef(resultType)); - } - - // annotation - void createDecorate(Id target, spv::Decoration decoration, - std::span decorationOperands) { - auto region = annotationRegion.pushOp(spv::Op::OpDecorate, - 3 + decorationOperands.size()); - region.pushIdUse(target); - region.pushWord(static_cast(decoration)); - - for (auto decorationOperand : decorationOperands) { - region.pushWord(decorationOperand); - } - } - - void createMemberDecorate(StructType structureType, std::uint32_t member, - spv::Decoration decoration, - std::span decorationOperands) { - auto region = annotationRegion.pushOp(spv::Op::OpMemberDecorate, - 4 + decorationOperands.size()); - region.pushIdUse(structureType); - region.pushWord(member); - region.pushWord(static_cast(decoration)); - - for (auto decorationOperand : decorationOperands) { - region.pushWord(decorationOperand); - } - } - - void createDecorateId(Id target, spv::Decoration decoration, - std::span decorationOperands) { - auto region = annotationRegion.pushOp(spv::Op::OpDecorateId, - 3 + decorationOperands.size()); - region.pushIdUse(target); - region.pushWord(static_cast(decoration)); - - for (auto decorationOperand : decorationOperands) { - region.pushIdUse(decorationOperand); - } - } - - void createDecorateString( - Id target, spv::Decoration decoration, - std::string_view firstDecorationOperand, - std::span decorationOperands = {}) { - std::size_t decorationOperandsLen = - calcStringWordCount(firstDecorationOperand); - - for (auto decorationOperand : decorationOperands) { - decorationOperandsLen += calcStringWordCount(decorationOperand); - } - - auto region = annotationRegion.pushOp(spv::Op::OpDecorateString, - 3 + decorationOperandsLen); - region.pushIdUse(target); - region.pushWord(static_cast(decoration)); - region.pushString(firstDecorationOperand); - - for (auto decorationOperand : decorationOperands) { - region.pushString(decorationOperand); - } - } - - void createMemberDecorateString( - StructType structType, std::uint32_t member, spv::Decoration decoration, - std::string_view firstDecorationOperand, - std::span decorationOperands = {}) { - std::size_t decorationOperandsLen = - calcStringWordCount(firstDecorationOperand); - - for (auto decorationOperand : decorationOperands) { - decorationOperandsLen += calcStringWordCount(decorationOperand); - } - - auto region = annotationRegion.pushOp(spv::Op::OpMemberDecorateString, - 4 + decorationOperandsLen); - region.pushIdUse(structType); - region.pushWord(member); - region.pushWord(static_cast(decoration)); - region.pushString(firstDecorationOperand); - - for (auto decorationOperand : decorationOperands) { - region.pushString(decorationOperand); - } - } - - // extension - void createExtension(std::string_view name) { - auto region = extensionRegion.pushOp(spv::Op::OpExtension, - 1 + calcStringWordCount(name)); - region.pushString(name); - } - - ExtInstSet createExtInstImport(std::string_view name) { - auto region = extInstRegion.pushOp(spv::Op::OpExtInstImport, - 2 + calcStringWordCount(name)); - auto id = newId(); - region.pushIdDef(id); - region.pushString(name); - return id; - } - - // mode set - void createCapability(spv::Capability cap) { - auto region = capabilityRegion.pushOp(spv::Op::OpCapability, 2); - region.pushWord(static_cast(cap)); - } - - void setMemoryModel(spv::AddressingModel addressingModel, - spv::MemoryModel memoryModel) { - memoryModelRegion.clear(); - auto region = memoryModelRegion.pushOp(spv::Op::OpMemoryModel, 3); - region.pushWord(static_cast(addressingModel)); - region.pushWord(static_cast(memoryModel)); - } - - void createEntryPoint(spv::ExecutionModel executionModel, Function entryPoint, - std::string_view name, - std::span interfaces) { - auto region = entryPointRegion.pushOp(spv::Op::OpEntryPoint, - 3 + calcStringWordCount(name) + - interfaces.size()); - region.pushWord(static_cast(executionModel)); - region.pushIdUse(entryPoint); - region.pushString(name); - for (auto iface : interfaces) { - region.pushIdUse(iface); - } - } - void createExecutionMode(Function entryPoint, spv::ExecutionMode mode, - std::span args) { - auto region = - executionModeRegion.pushOp(spv::Op::OpExecutionMode, 3 + args.size()); - region.pushIdUse(entryPoint); - region.pushWord(static_cast(mode)); - for (auto arg : args) { - region.pushWord(arg); - } - } - - void createExecutionModeId(Function entryPoint, spv::ExecutionMode mode, - std::span args) { - auto region = - executionModeRegion.pushOp(spv::Op::OpExecutionModeId, 3 + args.size()); - region.pushIdUse(entryPoint); - region.pushWord(static_cast(mode)); - for (auto arg : args) { - region.pushIdUse(arg); - } - } - - // type - VoidType createTypeVoid() { - auto region = globalRegion.pushOp(spv::Op::OpTypeVoid, 2); - auto id = newId(); - region.pushIdDef(id); - return id; - } - BoolType createTypeBool() { - auto region = globalRegion.pushOp(spv::Op::OpTypeBool, 2); - auto id = newId(); - region.pushIdDef(id); - return id; - } - IntType createTypeInt(std::uint32_t width, bool signedness) { - auto region = globalRegion.pushOp(spv::Op::OpTypeInt, 4); - auto id = newId(); - region.pushIdDef(id); - region.pushWord(width); - region.pushWord(static_cast(signedness)); - return id; - } - SIntType createTypeSInt(std::uint32_t width) { - return cast(createTypeInt(width, true)); - } - UIntType createTypeUInt(std::uint32_t width) { - return cast(createTypeInt(width, false)); - } - FloatType createTypeFloat(std::uint32_t width) { - auto region = globalRegion.pushOp(spv::Op::OpTypeFloat, 3); - auto id = newId(); - region.pushIdDef(id); - region.pushWord(width); - return id; - } - template - VectorOfType createTypeVector(T componentType, - std::uint32_t componentCount) { - auto region = globalRegion.pushOp(spv::Op::OpTypeVector, 4); - auto id = newId>(); - region.pushIdDef(id); - region.pushIdUse(componentType); - region.pushWord(componentCount); - return id; - } - MatrixType createTypeMatrix(VectorType columnType, - std::uint32_t coulumnCount) { - auto region = globalRegion.pushOp(spv::Op::OpTypeMatrix, 4); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(columnType); - region.pushWord(coulumnCount); - return id; - } - - ImageType createTypeImage(Type sampledType, spv::Dim dim, std::uint32_t depth, - std::uint32_t arrayed, std::uint32_t ms, - std::uint32_t sampled, spv::ImageFormat imageFormat, - std::optional access = {}) { - auto region = globalRegion.pushOp(spv::Op::OpTypeImage, - 9 + (access.has_value() ? 1 : 0)); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(sampledType); - region.pushWord(static_cast(dim)); - region.pushWord(depth); - region.pushWord(arrayed); - region.pushWord(ms); - region.pushWord(sampled); - region.pushWord(static_cast(imageFormat)); - - if (access.has_value()) { - region.pushWord(static_cast(*access)); - } - - return id; - } - - SamplerType createTypeSampler() { - auto region = globalRegion.pushOp(spv::Op::OpTypeSampler, 2); - auto id = newId(); - region.pushIdDef(id); - return id; - } - - SampledImageType createTypeSampledImage(ImageType imageType) { - auto region = globalRegion.pushOp(spv::Op::OpTypeSampledImage, 3); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(imageType); - return id; - } - - ArrayType createTypeArray(Type elementType, AnyConstantValue count) { - auto region = globalRegion.pushOp(spv::Op::OpTypeArray, 4); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(elementType); - region.pushIdUse(count); - return id; - } - - RuntimeArrayType createTypeRuntimeArray(Type elementType) { - auto region = globalRegion.pushOp(spv::Op::OpTypeRuntimeArray, 3); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(elementType); - - return id; - } - - StructType createTypeStruct(std::span members) { - auto region = - globalRegion.pushOp(spv::Op::OpTypeStruct, 2 + members.size()); - auto id = newId(); - region.pushIdDef(id); - - for (auto member : members) { - region.pushIdUse(member); - } - - return id; - } - - PointerType createTypePointer(spv::StorageClass storageClass, Type type) { - auto region = globalRegion.pushOp(spv::Op::OpTypePointer, 4); - auto id = newId(); - region.pushIdDef(id); - region.pushWord(static_cast(storageClass)); - region.pushIdUse(type); - return id; - } - - template - requires(std::is_base_of_v) - PointerToType createTypePointer(spv::StorageClass storageClass, T type) { - return cast>( - createTypePointer(storageClass, static_cast(type))); - } - - FunctionType createTypeFunction(Type returnType, - std::span parameters) { - auto region = - globalRegion.pushOp(spv::Op::OpTypeFunction, 3 + parameters.size()); - auto id = newId(); - region.pushIdDef(id); - region.pushIdUse(returnType); - - for (auto param : parameters) { - region.pushIdUse(param); - } - - return id; - } - - // constant - ConstantBool createConstantTrue(BoolType type) { - auto region = globalRegion.pushOp(spv::Op::OpConstantTrue, 3); - auto id = newId(); - region.pushIdUse(type); - region.pushIdDef(id); - return id; - } - - ConstantBool createConstantFalse(BoolType type) { - auto region = globalRegion.pushOp(spv::Op::OpConstantFalse, 3); - auto id = newId(); - region.pushIdUse(type); - region.pushIdDef(id); - return id; - } - - template - requires(std::is_base_of_v) - ConstantValue> - createConstant(T type, std::span values) { - auto region = globalRegion.pushOp(spv::Op::OpConstant, 3 + values.size()); - auto id = newId>>(); - region.pushIdUse(type); - region.pushIdDef(id); - for (auto value : values) { - region.pushWord(value); - } - return id; - } - - template - requires(std::is_base_of_v) - ConstantValue> createConstant32(T type, std::uint32_t value) { - return createConstant(type, std::array{value}); - } - - template - requires(std::is_base_of_v) - ConstantValue> createConstant64(T type, std::uint64_t value) { - return createConstant(type, - std::array{static_cast(value), - static_cast(value >> 32)}); - } - - // memory - VariableValue createVariable(Type type, spv::StorageClass storageClass, - std::optional initializer = {}) { - auto region = globalRegion.pushOp(spv::Op::OpVariable, - 4 + (initializer.has_value() ? 1 : 0)); - auto id = newId(); - region.pushIdUse(type); - region.pushIdDef(id); - region.pushWord(static_cast(storageClass)); - if (initializer.has_value()) { - region.pushIdUse(initializer.value()); - } - return id; - } - -private: - void createFunction(Function id, Type resultType, - spv::FunctionControlMask functionControl, - Type functionType) { - auto region = functionRegion.pushOp(spv::Op::OpFunction, 5); - region.pushIdUse(resultType); - region.pushIdDef(id); - region.pushWord(static_cast(functionControl)); - region.pushIdUse(functionType); - } - - Value createFunctionParameter(Type resultType) { - auto region = functionRegion.pushOp(spv::Op::OpFunctionParameter, 3); - auto id = newId(); - region.pushIdUse(resultType); - region.pushIdDef(id); - return id; - } - - void createFunctionEnd() { functionRegion.pushOp(spv::Op::OpFunctionEnd, 1); } - -public: - FunctionBuilder createFunctionBuilder(std::size_t expInstructionsCount) { - auto id = newId(); - return FunctionBuilder(*mIdGenerator, id, expInstructionsCount); - } - - void insertFunctionDeclaration(const FunctionBuilder &function, - Type resultType, - spv::FunctionControlMask functionControl, - Type functionType) { - createFunction(function.id, resultType, functionControl, functionType); - functionRegion.pushRegion(function.paramsRegion); - createFunctionEnd(); - } - - void insertFunction(const FunctionBuilder &function, Type resultType, - spv::FunctionControlMask functionControl, - Type functionType) { - createFunction(function.id, resultType, functionControl, functionType); - functionRegion.pushRegion(function.paramsRegion); - functionRegion.pushRegion(function.bodyRegion); - createFunctionEnd(); - } - - BlockBuilder createBlockBuilder(std::size_t expInstructionsCount) { - auto id = newId(); - - return BlockBuilder(*mIdGenerator, id, expInstructionsCount); - } -}; +namespace spirv +{ + struct Id + { + unsigned id{}; + + Id() = default; + explicit Id(unsigned value) + : id(value) + { + } + + explicit operator unsigned() const + { + assert(id != 0); + return id; + } + explicit operator bool() const { return id != 0; } + + bool operator==(Id other) const { return id == other.id; } + bool operator!=(Id other) const { return id != other.id; } + bool operator<(Id other) const { return id < other.id; } + bool operator>(Id other) const { return id > other.id; } + bool operator<=(Id other) const { return id <= other.id; } + bool operator>=(Id other) const { return id >= other.id; } + }; + + struct Type : Id + { + }; + struct ScalarType : Type + { + }; + struct VoidType : Type + { + }; + struct BoolType : ScalarType + { + }; + struct IntType : ScalarType + { + }; + struct SIntType : IntType + { + }; + struct UIntType : IntType + { + }; + struct FloatType : ScalarType + { + }; + struct VectorType : Type + { + }; + struct MatrixType : Type + { + }; + struct SamplerType : Type + { + }; + struct ImageType : Type + { + }; + struct SampledImageType : Type + { + }; + struct ArrayType : Type + { + }; + struct RuntimeArrayType : Type + { + }; + struct StructType : Type + { + }; + struct PointerType : Type + { + }; + struct FunctionType : Type + { + }; + + struct ExtInstSet : Id + { + }; + struct Function : Id + { + }; + struct Block : Id + { + }; + struct Value : Id + { + }; + + struct BoolValue : Value + { + }; + struct IntValue : Value + { + }; + struct SIntValue : IntValue + { + }; + struct UIntValue : IntValue + { + }; + struct FloatValue : Value + { + }; + struct StructValue : Value + { + }; + struct PointerValue : Value + { + }; + struct VectorValue : Value + { + }; + struct ArrayValue : Value + { + }; + struct SamplerValue : Value + { + }; + struct ImageValue : Value + { + }; + struct SampledImageValue : Value + { + }; + + template + requires(std::is_base_of_v) struct ConstantValue : T + { + }; + + struct AnyConstantValue : Value + { + AnyConstantValue() = default; + + template + AnyConstantValue(ConstantValue specialization) + { + id = specialization.id; + } + + template + AnyConstantValue& operator=(ConstantValue specialization) + { + id = specialization.id; + return *this; + } + + template + explicit operator ConstantValue() + { + ConstantValue result; + result.id = id; + return result; + } + }; + + template + requires(std::is_base_of_v) struct VectorOfType : VectorType + { + }; + + template + requires(std::is_base_of_v) struct ArrayOfType : ArrayType + { + }; + + template + requires(std::is_base_of_v) struct VectorOfValue : VectorValue + { + }; + + template + requires(std::is_base_of_v) struct ArrayOfValue : ArrayValue + { + }; + + template + requires(std::is_base_of_v) struct PointerToType : PointerType + { + }; + + template + requires(std::is_base_of_v) struct PointerToValue : PointerValue + { + }; + + struct StructPointerValue : Value + { + }; + + struct VariableValue : PointerValue + { + }; + + namespace detail + { + template + struct TypeToValueImpl; + + template <> + struct TypeToValueImpl + { + using type = Value; + }; + template <> + struct TypeToValueImpl + { + using type = BoolValue; + }; + template <> + struct TypeToValueImpl + { + using type = IntValue; + }; + template <> + struct TypeToValueImpl + { + using type = SIntValue; + }; + template <> + struct TypeToValueImpl + { + using type = UIntValue; + }; + template <> + struct TypeToValueImpl + { + using type = FloatValue; + }; + template <> + struct TypeToValueImpl + { + using type = StructValue; + }; + template <> + struct TypeToValueImpl + { + using type = PointerValue; + }; + template <> + struct TypeToValueImpl + { + using type = PointerValue; + }; + template <> + struct TypeToValueImpl + { + using type = VectorValue; + }; + template <> + struct TypeToValueImpl + { + using type = ArrayValue; + }; + template <> + struct TypeToValueImpl + { + using type = SamplerValue; + }; + template <> + struct TypeToValueImpl + { + using type = ImageValue; + }; + template <> + struct TypeToValueImpl + { + using type = SampledImageValue; + }; + + template + struct TypeToValueImpl> + { + using type = PointerToValue; + }; + template + struct TypeToValueImpl> + { + using type = VectorOfValue; + }; + + template + struct TypeToValueImpl> + { + using type = ArrayOfValue; + }; + } // namespace detail + + template + using TypeToValue = typename detail::TypeToValueImpl::type; + + template + requires(std::is_base_of_v) struct ScalarOrVectorOfValue : Value + { + ScalarOrVectorOfValue() = default; + + ScalarOrVectorOfValue(TypeToValue scalar) { id = scalar.id; } + ScalarOrVectorOfValue(VectorOfValue vector) { id = vector.id; } + }; + + using ConstantBool = ConstantValue; + using ConstantSInt = ConstantValue; + using ConstantUInt = ConstantValue; + using ConstantInt = ConstantValue; + using ConstantFloat = ConstantValue; + + template + requires(std::is_base_of_v&& std::is_base_of_v) + ToT cast(FromT from) + { + ToT result; + result.id = from.id; + return result; + } + + inline unsigned calcStringWordCount(std::string_view string) + { + return (string.length() + 1 + (sizeof(std::uint32_t) - 1)) / + sizeof(std::uint32_t); + } + + using IdUsesTackerType = + std::unordered_map>; + using IdDefTackerType = std::unordered_map; + + class RegionPusher + { + IdUsesTackerType* mIdUses = nullptr; + IdDefTackerType* mIdDefs = nullptr; + std::uint32_t* mBeginPtr = nullptr; + std::uint32_t* mPtr = nullptr; + std::size_t mCount = 0; + + RegionPusher& operator=(const RegionPusher&) = default; + + public: + RegionPusher() = default; + RegionPusher(const RegionPusher&) = delete; + RegionPusher(std::uint32_t* beginPtr, std::uint32_t* ptr, std::size_t count, + IdUsesTackerType* idUses, IdDefTackerType* idDefs) + : mIdUses(idUses) + , mIdDefs(idDefs) + , mBeginPtr(beginPtr) + , mPtr(ptr) + , mCount(count) + { + } + RegionPusher(RegionPusher&& other) { *this = std::move(other); } + + RegionPusher& operator=(RegionPusher&& other) + { + *this = other; + other.mCount = 0; + return *this; + } + + ~RegionPusher() { assert(mCount == 0); } + + void pushWord(unsigned word) + { + assert(mCount > 0); + *mPtr++ = word; + --mCount; + } + + void pushIdDef(Id id) + { + assert(id); + (*mIdDefs)[id.id] = mPtr - mBeginPtr; + pushWord(id.id); + } + + void pushIdUse(Id id) + { + assert(id); + (*mIdUses)[id.id].push_back(mPtr - mBeginPtr); + + pushWord(id.id); + } + + void pushString(std::string_view string) + { + auto nwords = calcStringWordCount(string); + assert(mCount >= nwords); + + auto dst = reinterpret_cast(mPtr); + std::memcpy(dst, string.data(), string.length()); + std::memset(dst + string.length(), 0, + nwords * sizeof(std::uint32_t) - string.length()); + mPtr += nwords; + mCount -= nwords; + } + }; + + struct IdGenerator + { + std::uint32_t bounds = 1; + + template + requires(std::is_base_of_v) + T newId() + { + T result; + result.id = bounds++; + return result; + } + + Id newId() + { + Id result; + result.id = bounds++; + return result; + } + + void reset() { bounds = 1; } + }; + + class RegionPoint + { + const std::vector* mData = nullptr; + std::size_t mOffset = 0; + + public: + RegionPoint() = default; + RegionPoint(const std::vector* data, std::size_t offset) + : mData(data) + , mOffset(offset) + { + } + + std::span operator-(RegionPoint other) const + { + assert(mData == other.mData); + assert(mOffset >= other.mOffset); + + return {other.mData->data() + other.mOffset, mData->data() + mOffset}; + } + }; + + class Region + { + std::vector mData; + IdUsesTackerType mIdUses; + IdDefTackerType mIdDefs; + + public: + Region() = default; + Region(std::size_t expInstCount) { mData.reserve(expInstCount); } + + bool isIdDefined(Id id) const { return mIdDefs.contains(id.id); } + bool isIdUsed(Id id) const { return mIdUses.contains(id.id); } + + void clear() { mData.clear(); } + + const std::uint32_t* data() const { return mData.data(); } + std::size_t size() const { return mData.size(); } + + RegionPoint getCurrentPosition() const { return {&mData, mData.size()}; } + + RegionPusher pushOp(spv::Op op, unsigned wordCount) + { + assert(wordCount >= 1); + auto offset = mData.size(); + mData.resize(mData.size() + wordCount); + RegionPusher pusher(mData.data(), mData.data() + offset, wordCount, + &mIdUses, &mIdDefs); + pusher.pushWord((static_cast(op) & spv::OpCodeMask) | + (wordCount << spv::WordCountShift)); + + return pusher; + } + + void pushRegion(const Region& other) + { + auto offset = mData.size(); + mData.resize(mData.size() + other.size()); + std::memcpy(mData.data() + offset, other.data(), + other.size() * sizeof(std::uint32_t)); + + for (auto& [id, def] : other.mIdDefs) + { + mIdDefs[id] = offset + def; + } + + for (auto& [id, uses] : other.mIdUses) + { + auto& idUses = mIdUses[id]; + idUses.reserve(idUses.size() + uses.size()); + + for (auto use : uses) + { + idUses.push_back(offset + use); + } + } + } + + void recreateDefs(std::unordered_map& remap, + IdGenerator& generator) + { + auto prevDefs = std::move(mIdDefs); + mIdDefs = {}; + + for (auto [id, def] : prevDefs) + { + auto newId = generator.newId().id; + + remap[id] = newId; + mData[def] = newId; + mIdDefs[newId] = def; + } + } + + void + remapUses(const std::unordered_map& remap) + { + auto prevUses = std::move(mIdUses); + mIdUses = {}; + + for (auto& [id, uses] : prevUses) + { + auto it = remap.find(id); + assert(it != remap.end()); + auto newId = it->second; + + for (auto& use : uses) + { + mData[use] = newId; + } + + mIdUses[newId] = std::move(uses); + } + } + }; + + class BlockBuilder + { + IdGenerator* mIdGenerator = nullptr; + + template + auto newId() -> decltype(mIdGenerator->newId()) + { + return mIdGenerator->newId(); + } + + public: + Block id; + Region prefix; + Region phiRegion; + Region variablesRegion; + Region bodyRegion; + Region terminatorRegion; + + BlockBuilder() = default; + BlockBuilder(IdGenerator& idGenerator, Block id, + std::size_t expInstructionsCount) + : mIdGenerator(&idGenerator) + , id(id) + , bodyRegion{expInstructionsCount} + , terminatorRegion{1} + { + } + + void moveBlock(BlockBuilder&& other) + { + prefix.pushRegion(other.prefix); + { + auto region = prefix.pushOp(spv::Op::OpLabel, 2); + region.pushIdDef(id); + } + prefix.pushRegion(phiRegion); + prefix.pushRegion(bodyRegion); + prefix.pushRegion(terminatorRegion); + + id = other.id; + phiRegion = std::move(other.phiRegion); + variablesRegion.pushRegion(other.variablesRegion); + bodyRegion = std::move(other.bodyRegion); + terminatorRegion = std::move(other.terminatorRegion); + } + + Value createExtInst(Type resultType, ExtInstSet set, + std::uint32_t instruction, + std::span operands) + { + auto region = bodyRegion.pushOp(spv::Op::OpExtInst, 5 + operands.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(set); + region.pushWord(instruction); + for (auto operand : operands) + { + region.pushIdUse(operand); + } + return id; + } + + VariableValue createVariable(Type type, spv::StorageClass storageClass, + std::optional initializer = {}) + { + auto region = variablesRegion.pushOp(spv::Op::OpVariable, + 4 + (initializer.has_value() ? 1 : 0)); + auto id = newId(); + region.pushIdUse(type); + region.pushIdDef(id); + region.pushWord(static_cast(storageClass)); + if (initializer.has_value()) + { + region.pushIdUse(initializer.value()); + } + return id; + } + + Value createFunctionCall(Type resultType, Function function, + std::span arguments) + { + auto region = + bodyRegion.pushOp(spv::Op::OpFunctionCall, 4 + arguments.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(function); + for (auto argument : arguments) + { + region.pushIdUse(argument); + } + return id; + } + + // composite + Value createVectorExtractDynamic(Type resultType, Value vector, + IntValue index) + { + auto region = bodyRegion.pushOp(spv::Op::OpVectorExtractDynamic, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(vector); + region.pushIdUse(index); + return id; + } + + Value createVectorInsertDynamic(Type resultType, Value vector, + Value component, IntValue index) + { + auto region = bodyRegion.pushOp(spv::Op::OpVectorInsertDynamic, 6); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(vector); + region.pushIdUse(component); + region.pushIdUse(index); + return id; + } + + Value createVectorShuffle(Type resultType, Value vector1, Value vector2, + std::span components) + { + auto region = + bodyRegion.pushOp(spv::Op::OpVectorShuffle, 5 + components.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(vector1); + region.pushIdUse(vector2); + + for (auto component : components) + { + region.pushWord(component); + } + return id; + } + + template + TypeToValue createCompositeConstruct(T resultType, + std::span constituents) + { + auto region = bodyRegion.pushOp(spv::Op::OpCompositeConstruct, + 3 + constituents.size()); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + + for (auto constituent : constituents) + { + region.pushIdUse(constituent); + } + return id; + } + + Value createCompositeExtract(Type resultType, Value composite, + std::span indexes) + { + auto region = + bodyRegion.pushOp(spv::Op::OpCompositeExtract, 4 + indexes.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(composite); + + for (auto index : indexes) + { + region.pushWord(index); + } + return id; + } + + // arithmetic + template + requires(std::is_base_of_v) + TypeToValue createInst(spv::Op op, T resultType, + std::span> operands) + { + auto region = bodyRegion.pushOp(op, 3 + operands.size()); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + for (auto operand : operands) + { + region.pushIdUse(operand); + } + return id; + } + + Value createInst(spv::Op op, Type resultType, + std::span operands) + { + auto region = bodyRegion.pushOp(op, 3 + operands.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + for (auto operand : operands) + { + region.pushIdUse(operand); + } + return id; + } + + template + VectorOfValue createInst(spv::Op op, VectorOfType resultType, + std::span> operands) + { + auto region = bodyRegion.pushOp(op, 3 + operands.size()); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + for (auto operand : operands) + { + region.pushIdUse(operand); + } + return id; + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createSNegate(T resultType, TypeToValue operand) + { + return createInst(spv::Op::OpSNegate, resultType, std::array{operand}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFNegate(T resultType, TypeToValue operand) + { + return createInst(spv::Op::OpFNegate, resultType, std::array{operand}); + } + + template + requires(std::is_same_v || std::is_base_of_v || + std::is_same_v, T> || + std::is_same_v, T> || + std::is_same_v, T>) + TypeToValue createIAdd(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpIAdd, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFAdd(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFAdd, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || std::is_base_of_v || + std::is_same_v, T> || + std::is_same_v, T> || + std::is_same_v, T>) + TypeToValue createISub(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpISub, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFSub(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFSub, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || std::is_base_of_v || + std::is_same_v, T> || + std::is_same_v, T> || + std::is_same_v, T>) + TypeToValue createIMul(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpIMul, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFMul(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFMul, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createUDiv(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpUDiv, resultType, + std::array{operand1, operand2}); + } + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createSDiv(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpSDiv, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFDiv(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFDiv, resultType, + std::array{operand1, operand2}); + } + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createUMod(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpUMod, resultType, + std::array{operand1, operand2}); + } + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createSRem(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpSRem, resultType, + std::array{operand1, operand2}); + } + + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createSMod(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpSMod, resultType, + std::array{operand1, operand2}); + } + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFRem(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFRem, resultType, + std::array{operand1, operand2}); + } + template + requires(std::is_same_v || + std::is_same_v, T>) + TypeToValue createFMod(T resultType, TypeToValue operand1, + TypeToValue operand2) + { + return createInst(spv::Op::OpFMod, resultType, + std::array{operand1, operand2}); + } + + Value createIAddCarry(Type resultType, Value operand1, Value operand2) + { + return createInst(spv::Op::OpIAddCarry, resultType, + std::array{operand1, operand2}); + } + + Value createISubBorrow(Type resultType, Value operand1, Value operand2) + { + return createInst(spv::Op::OpISubBorrow, resultType, + std::array{operand1, operand2}); + } + + Value createUMulExtended(Type resultType, Value operand1, Value operand2) + { + return createInst(spv::Op::OpUMulExtended, resultType, + std::array{operand1, operand2}); + } + + Value createSMulExtended(Type resultType, Value operand1, Value operand2) + { + return createInst(spv::Op::OpSMulExtended, resultType, + std::array{operand1, operand2}); + } + + Value createPhi(Type resultType, + std::span> values) + { + auto region = phiRegion.pushOp(spv::Op::OpPhi, 3 + values.size() * 2); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + for (auto [variable, block] : values) + { + region.pushIdUse(variable); + region.pushIdUse(block); + } + return id; + } + + void addBlockToPhis(spirv::Block block, + std::span values) + { + auto phi = phiRegion.data(); + spirv::Region newPhi(phiRegion.size() * 2); + + assert(block); + + for (std::size_t i = 0, end = phiRegion.size(), index = 0; i < end; + index++) + { + auto opWordCount = phi[i]; + + assert(static_cast(static_cast(opWordCount) & + spv::OpCodeMask) == spv::Op::OpPhi); + auto wordCount = + static_cast(opWordCount) >> spv::WordCountShift; + auto newOp = newPhi.pushOp(spv::Op::OpPhi, wordCount + 2); + + for (std::size_t j = 1; j < wordCount; ++j) + { + newOp.pushWord(phi[i + j]); + } + + i += wordCount; + + assert(index < values.size()); + assert(values[index]); + + newOp.pushIdUse(values[index]); + newOp.pushIdUse(block); + } + + phiRegion = std::move(newPhi); + } + + void moveVariablesFrom(BlockBuilder& otherBlock) + { + variablesRegion.pushRegion(otherBlock.variablesRegion); + otherBlock.variablesRegion.clear(); + } + + template + requires(std::is_base_of_v) + TypeToValue createPhi(T resultType, + std::span> values) + { + return cast>( + createPhi(static_cast(resultType), values)); + } + + void createLoopMerge(Block mergeBlock, Block continueTarget, + spv::LoopControlMask loopControl, + std::span loopControlParameters) + { + auto region = terminatorRegion.pushOp(spv::Op::OpLoopMerge, + 4 + loopControlParameters.size()); + region.pushIdUse(mergeBlock); + region.pushIdUse(continueTarget); + region.pushWord(static_cast(loopControl)); + + for (auto loopControlParameter : loopControlParameters) + { + region.pushWord(static_cast(loopControlParameter)); + } + } + + void createSelectionMerge(Block mergeBlock, + spv::SelectionControlMask selectionControl) + { + auto region = terminatorRegion.pushOp(spv::Op::OpSelectionMerge, 3); + region.pushIdUse(mergeBlock); + region.pushWord(static_cast(selectionControl)); + } + + void createBranch(Block label) + { + auto region = terminatorRegion.pushOp(spv::Op::OpBranch, 2); + region.pushIdUse(label); + } + + void createBranchConditional( + BoolValue condition, Block trueLabel, Block falseLabel, + std::optional> weights = {}) + { + auto region = terminatorRegion.pushOp(spv::Op::OpBranchConditional, + 4 + (weights.has_value() ? 1 : 0)); + region.pushIdUse(condition); + region.pushIdUse(trueLabel); + region.pushIdUse(falseLabel); + + if (weights.has_value()) + { + region.pushWord(weights->first); + region.pushWord(weights->second); + } + } + + void createKill() + { + assert(terminatorRegion.size() == 0); + terminatorRegion.pushOp(spv::Op::OpKill, 1); + } + + void createReturn() + { + assert(terminatorRegion.size() == 0); + terminatorRegion.pushOp(spv::Op::OpReturn, 1); + } + + void createReturnValue(Value value) + { + assert(terminatorRegion.size() == 0); + auto region = terminatorRegion.pushOp(spv::Op::OpReturnValue, 2); + region.pushIdUse(value); + } + + void createUnreachable() + { + assert(terminatorRegion.size() == 0); + terminatorRegion.pushOp(spv::Op::OpUnreachable, 1); + } + + Value createLoad(Type resultType, PointerValue pointer, + spv::MemoryAccessMask memoryAccess, + std::span memoryAccessOperands) + { + auto region = + bodyRegion.pushOp(spv::Op::OpLoad, 5 + memoryAccessOperands.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(pointer); + region.pushWord(static_cast(memoryAccess)); + + for (auto memoryAccessOperand : memoryAccessOperands) + { + region.pushWord(static_cast(memoryAccessOperand)); + } + + return id; + } + + template + requires(std::is_base_of_v) + TypeToValue createLoad(T resultType, PointerValue pointer) + { + auto region = bodyRegion.pushOp(spv::Op::OpLoad, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(pointer); + return id; + } + + void createStore(PointerValue pointer, Value object) + { + auto region = bodyRegion.pushOp(spv::Op::OpStore, 3); + region.pushIdUse(pointer); + region.pushIdUse(object); + } + + void createStore(PointerValue pointer, Value object, + spv::MemoryAccessMask memoryAccess, + std::span memoryAccessOperands) + { + auto region = + bodyRegion.pushOp(spv::Op::OpStore, 4 + memoryAccessOperands.size()); + region.pushIdUse(pointer); + region.pushIdUse(object); + region.pushWord(static_cast(memoryAccess)); + + for (auto memoryAccessOperand : memoryAccessOperands) + { + region.pushWord(memoryAccessOperand); + } + } + + void createCopyMemory(PointerValue targetPointer, + PointerValue sourcePointer) + { + auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, 3); + region.pushIdUse(targetPointer); + region.pushIdUse(sourcePointer); + } + + void createCopyMemory(PointerValue targetPointer, PointerValue sourcePointer, + spv::MemoryAccessMask memoryAccess, + std::span memoryAccessOperands) + { + auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, + 4 + memoryAccessOperands.size()); + region.pushIdUse(targetPointer); + region.pushIdUse(sourcePointer); + region.pushWord(static_cast(memoryAccess)); + for (auto memoryAccessOperand : memoryAccessOperands) + { + region.pushWord(memoryAccessOperand); + } + } + + void + createCopyMemory(PointerValue targetPointer, PointerValue sourcePointer, + spv::MemoryAccessMask targetMemoryAccess, + std::span targetMemoryAccessOperands, + spv::MemoryAccessMask sourceMemoryAccess, + std::span sourceMemoryAccessOperands) + { + auto region = bodyRegion.pushOp(spv::Op::OpCopyMemory, + 5 + targetMemoryAccessOperands.size() + + sourceMemoryAccessOperands.size()); + region.pushIdUse(targetPointer); + region.pushIdUse(sourcePointer); + region.pushWord(static_cast(targetMemoryAccess)); + for (auto memoryAccessOperand : targetMemoryAccessOperands) + { + region.pushWord(static_cast(memoryAccessOperand)); + } + region.pushWord(static_cast(sourceMemoryAccess)); + for (auto memoryAccessOperand : sourceMemoryAccessOperands) + { + region.pushWord(static_cast(memoryAccessOperand)); + } + } + + UIntValue createArrayLength(UIntType resultType, + PointerToValue structure, + std::uint32_t member) + { + auto region = bodyRegion.pushOp(spv::Op::OpArrayLength, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(structure); + region.pushWord(member); + return id; + } + + BoolValue createPtrEqual(BoolType resultType, PointerValue operand1, + PointerValue operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpPtrEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + BoolValue createPtrNotEqual(BoolType resultType, PointerValue operand1, + PointerValue operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpPtrNotEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + PointerValue createAccessChain(PointerType resultType, PointerValue base, + std::span indices) + { + auto region = bodyRegion.pushOp(spv::Op::OpAccessChain, 4 + indices.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(base); + + for (auto index : indices) + { + region.pushIdUse(index); + } + return id; + } + + PointerValue createInBoundsAccessChain(PointerType resultType, + PointerValue base, + std::span indices) + { + auto region = + bodyRegion.pushOp(spv::Op::OpInBoundsAccessChain, 4 + indices.size()); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(base); + + for (auto index : indices) + { + region.pushIdUse(index); + } + return id; + } + + // conversion + Value createConvertFToU(Type resultType, Value operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpConvertFToU, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + Value createConvertFToS(Type resultType, Value operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpConvertFToS, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + template + TypeToValue createConvertSToF(T resultType, SIntValue operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpConvertSToF, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + template + TypeToValue createConvertUToF(T resultType, UIntValue operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpConvertUToF, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + template + TypeToValue createUConvert(T resultType, UIntValue operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpUConvert, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + template + TypeToValue createSConvert(T resultType, SIntValue operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpSConvert, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + Value createFConvert(Type resultType, Value operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpFConvert, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + template + TypeToValue createBitcast(T resultType, Value operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpBitcast, 4); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + + // bit + template + TypeToValue createShiftRightLogical(T resultType, TypeToValue base, + IntValue shift) + { + auto region = bodyRegion.pushOp(spv::Op::OpShiftRightLogical, 5); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(base); + region.pushIdUse(shift); + return id; + } + + template + TypeToValue createShiftRightArithmetic(T resultType, TypeToValue base, + IntValue shift) + { + auto region = bodyRegion.pushOp(spv::Op::OpShiftRightArithmetic, 5); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(base); + region.pushIdUse(shift); + return id; + } + + template + TypeToValue createShiftLeftLogical(T resultType, TypeToValue base, + IntValue shift) + { + auto region = bodyRegion.pushOp(spv::Op::OpShiftLeftLogical, 5); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(base); + region.pushIdUse(shift); + return id; + } + + Value createBitwiseOr(Type resultType, Value operand1, Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpBitwiseOr, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + Value createBitwiseXor(Type resultType, Value operand1, Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpBitwiseXor, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + Value createBitwiseAnd(Type resultType, Value operand1, Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpBitwiseAnd, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + Value createNot(Type resultType, Value operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpNot, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + + // relational + BoolValue createIsNan(BoolType resultType, Value operand1) + { + auto region = bodyRegion.pushOp(spv::Op::OpIsNan, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + return id; + } + + BoolValue createIsInf(BoolType resultType, Value operand1) + { + auto region = bodyRegion.pushOp(spv::Op::OpIsInf, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + return id; + } + + // logic + BoolValue createLogicalEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpLogicalEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createLogicalNotEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpLogicalNotEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + BoolValue createLogicalOr(BoolType resultType, BoolValue operand1, + BoolValue operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpLogicalOr, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + BoolValue createLogicalAnd(BoolType resultType, BoolValue operand1, + BoolValue operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpLogicalAnd, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + BoolValue createLogicalNot(BoolType resultType, BoolValue operand) + { + auto region = bodyRegion.pushOp(spv::Op::OpLogicalNot, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand); + return id; + } + + template + TypeToValue createSelect(T resultType, BoolValue condition, Value object1, + Value object2) + { + auto region = bodyRegion.pushOp(spv::Op::OpSelect, 6); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(condition); + region.pushIdUse(object1); + region.pushIdUse(object2); + return id; + } + + BoolValue createIEqual(BoolType resultType, Value operand1, Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpIEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createINotEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpINotEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createUGreaterThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpUGreaterThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createSGreaterThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpSGreaterThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createUGreaterThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpUGreaterThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createSGreaterThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpSGreaterThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createULessThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpULessThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createSLessThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpSLessThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createULessThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpULessThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createSLessThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpSLessThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + BoolValue createFOrdEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFOrdNotEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdNotEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordNotEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordNotEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFOrdLessThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdLessThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordLessThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordLessThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFOrdLessThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdLessThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordLessThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordLessThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFOrdGreaterThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdGreaterThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordGreaterThan(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordGreaterThan, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFOrdGreaterThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFOrdGreaterThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + BoolValue createFUnordGreaterThanEqual(BoolType resultType, Value operand1, + Value operand2) + { + auto region = bodyRegion.pushOp(spv::Op::OpFUnordGreaterThanEqual, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(operand1); + region.pushIdUse(operand2); + return id; + } + + // image + SampledImageValue createSampledImage(SampledImageType resultType, + ImageValue image, SamplerValue sampler) + { + auto region = bodyRegion.pushOp(spv::Op::OpSampledImage, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(image); + region.pushIdUse(sampler); + return id; + } + VectorOfValue createImageSampleImplicitLod( + VectorOfType resultType, SampledImageValue sampledImage, + ScalarOrVectorOfValue coords, + spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, + std::span args = {}) + { + auto region = bodyRegion.pushOp( + spv::Op::OpImageSampleImplicitLod, + 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 : 1 + args.size())); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(sampledImage); + region.pushIdUse(coords); + + if (operands != spv::ImageOperandsMask::MaskNone) + { + region.pushWord(static_cast(operands)); + + for (auto arg : args) + { + region.pushIdUse(arg); + } + } + + return id; + } + + VectorOfValue createImageSampleExplicitLod( + VectorOfType resultType, SampledImageValue sampledImage, + ScalarOrVectorOfValue coords, + spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, + std::span args = {}) + { + auto region = bodyRegion.pushOp( + spv::Op::OpImageSampleExplicitLod, + 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 : 1 + args.size())); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(sampledImage); + region.pushIdUse(coords); + + if (operands != spv::ImageOperandsMask::MaskNone) + { + region.pushWord(static_cast(operands)); + + for (auto arg : args) + { + region.pushIdUse(arg); + } + } + + return id; + } + + VectorOfValue createImageRead( + VectorOfType resultType, ImageValue image, + ScalarOrVectorOfValue coords, + spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, + std::span args = {}) + { + auto region = bodyRegion.pushOp( + spv::Op::OpImageRead, + 5 + (operands == spv::ImageOperandsMask::MaskNone ? 0 : 1 + args.size())); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(image); + region.pushIdUse(coords); + + if (operands != spv::ImageOperandsMask::MaskNone) + { + region.pushWord(static_cast(operands)); + + for (auto arg : args) + { + region.pushIdUse(arg); + } + } + + return id; + } + + void createImageWrite( + ImageValue image, ScalarOrVectorOfValue coords, Value texel, + spv::ImageOperandsMask operands = spv::ImageOperandsMask::MaskNone, + std::span args = {}) + { + auto region = bodyRegion.pushOp( + spv::Op::OpImageWrite, + 4 + (operands == spv::ImageOperandsMask::MaskNone ? 0 : 1 + args.size())); + region.pushIdUse(image); + region.pushIdUse(coords); + region.pushIdUse(texel); + + if (operands != spv::ImageOperandsMask::MaskNone) + { + region.pushWord(static_cast(operands)); + + for (auto arg : args) + { + region.pushIdUse(arg); + } + } + } + + Value createImageQuerySizeLod(Type resultType, ImageValue image, Value lod) + { + auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySizeLod, 5); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(image); + region.pushIdUse(lod); + return id; + } + + Value createImageQuerySize(Type resultType, ImageValue image) + { + auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySize, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(image); + return id; + } + + VectorOfValue + createImageQueryLod(VectorOfType resultType, + SampledImageValue sampledImage, + ScalarOrVectorOfValue coords) + { + auto region = bodyRegion.pushOp(spv::Op::OpImageQueryLod, 5); + auto id = newId>(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(sampledImage); + region.pushIdUse(coords); + return id; + } + + IntValue createImageQueryLevels(IntType resultType, ImageValue sampledImage) + { + auto region = bodyRegion.pushOp(spv::Op::OpImageQueryLevels, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(sampledImage); + return id; + } + + IntValue createImageQuerySamples(IntType resultType, + ImageValue sampledImage) + { + auto region = bodyRegion.pushOp(spv::Op::OpImageQuerySamples, 4); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushIdUse(sampledImage); + return id; + } + }; + + class FunctionBuilder + { + IdGenerator* mIdGenerator = nullptr; + + template + auto newId() -> decltype(mIdGenerator->newId()) + { + return mIdGenerator->newId(); + } + + public: + Region paramsRegion; + Region bodyRegion; + Function id; + + FunctionBuilder() = default; + FunctionBuilder(IdGenerator& idGenerator, Function id, + std::size_t expInstructionsCount) + : mIdGenerator(&idGenerator) + , bodyRegion{expInstructionsCount} + , id(id) + { + } + + Value createFunctionParameter(Type resultType) + { + auto region = paramsRegion.pushOp(spv::Op::OpFunctionParameter, 3); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + return id; + } + + BlockBuilder createBlockBuilder(std::size_t expInstructionsCount) + { + auto id = newId(); + + return BlockBuilder(*mIdGenerator, id, expInstructionsCount); + } + + void insertBlock(const BlockBuilder& builder) + { + bodyRegion.pushRegion(builder.prefix); + + auto region = bodyRegion.pushOp(spv::Op::OpLabel, 2); + region.pushIdDef(builder.id); + + bodyRegion.pushRegion(builder.variablesRegion); + bodyRegion.pushRegion(builder.phiRegion); + bodyRegion.pushRegion(builder.bodyRegion); + bodyRegion.pushRegion(builder.terminatorRegion); + } + }; + + class SpirvBuilder + { + IdGenerator* mIdGenerator = nullptr; + + Region capabilityRegion; + Region extensionRegion; + Region extInstRegion; + Region memoryModelRegion; + Region entryPointRegion; + Region executionModeRegion; + Region debugRegion; + Region annotationRegion; + Region globalRegion; + Region functionDeclRegion; + Region functionRegion; + + template + auto newId() -> decltype(mIdGenerator->newId()) + { + return mIdGenerator->newId(); + } + + private: + SpirvBuilder(const SpirvBuilder&) = default; + SpirvBuilder(SpirvBuilder&&) = default; + SpirvBuilder& operator=(SpirvBuilder&&) = default; + + public: + bool isIdDefined(Id id) const + { + std::array regions = { + // &capabilityRegion, &extensionRegion, &extInstRegion, + // &memoryModelRegion, &entryPointRegion, &executionModeRegion, + // &debugRegion, &annotationRegion, &globalRegion, + &functionRegion, + }; + + for (auto reg : regions) + { + if (reg->isIdDefined(id)) + { + return true; + } + } + + return false; + } + bool isIdUsed(Id id) const + { + std::array regions = { + &capabilityRegion, + &extensionRegion, + &extInstRegion, + &memoryModelRegion, + &entryPointRegion, + &executionModeRegion, + &debugRegion, + &annotationRegion, + &globalRegion, + &functionDeclRegion, + &functionRegion, + }; + + for (auto reg : regions) + { + if (reg->isIdUsed(id)) + { + return true; + } + } + + return false; + } + SpirvBuilder() = default; + + SpirvBuilder(IdGenerator& idGenerator, std::size_t expInstructionsCount) + : mIdGenerator(&idGenerator) + , capabilityRegion{1} + , extensionRegion{1} + , extInstRegion{4} + , memoryModelRegion{3} + , entryPointRegion{1} + , executionModeRegion{1} + , debugRegion{0} + , annotationRegion{1} + , globalRegion{1} + , functionDeclRegion{1} + , functionRegion{expInstructionsCount} + { + } + + SpirvBuilder clone() const { return *this; } + + void swap(SpirvBuilder& other) + { + std::swap(mIdGenerator, other.mIdGenerator); + std::swap(capabilityRegion, other.capabilityRegion); + std::swap(extensionRegion, other.extensionRegion); + std::swap(extInstRegion, other.extInstRegion); + std::swap(memoryModelRegion, other.memoryModelRegion); + std::swap(entryPointRegion, other.entryPointRegion); + std::swap(executionModeRegion, other.executionModeRegion); + std::swap(debugRegion, other.debugRegion); + std::swap(annotationRegion, other.annotationRegion); + std::swap(globalRegion, other.globalRegion); + std::swap(functionDeclRegion, other.functionDeclRegion); + std::swap(functionRegion, other.functionRegion); + } + + void reset() + { + mIdGenerator->reset(); + capabilityRegion.clear(); + extensionRegion.clear(); + extInstRegion.clear(); + memoryModelRegion.clear(); + entryPointRegion.clear(); + executionModeRegion.clear(); + debugRegion.clear(); + annotationRegion.clear(); + globalRegion.clear(); + functionDeclRegion.clear(); + functionRegion.clear(); + } + + IdGenerator* getIdGenerator() const { return mIdGenerator; } + + std::vector build(std::uint32_t spirvVersion, + std::uint32_t generatorMagic) + { + const std::size_t headerSize = 5; + std::size_t finalSize = headerSize; + + std::array regions = { + &capabilityRegion, + &extensionRegion, + &extInstRegion, + &memoryModelRegion, + &entryPointRegion, + &executionModeRegion, + &debugRegion, + &annotationRegion, + &globalRegion, + &functionDeclRegion, + &functionRegion, + }; + + for (auto region : regions) + { + finalSize += region->size(); + } + + std::vector result; + result.resize(finalSize); + + result[0] = spv::MagicNumber; + result[1] = spirvVersion; + result[2] = generatorMagic; + result[3] = mIdGenerator->bounds; + result[4] = 0; // instruction schema + + std::size_t currentOffset = headerSize; + + for (auto region : regions) + { + std::memcpy(result.data() + currentOffset, region->data(), + region->size() * sizeof(std::uint32_t)); + currentOffset += region->size(); + } + + return result; + } + + // misc + Value createUndef(Type resultType) + { + auto region = globalRegion.pushOp(spv::Op::OpUndef, 3); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + return id; + } + + template + requires(std::is_base_of_v) + TypeToValue createUndef(T resultType) + { + return cast>(createUndef(resultType)); + } + + // annotation + void createDecorate(Id target, spv::Decoration decoration, + std::span decorationOperands) + { + auto region = annotationRegion.pushOp(spv::Op::OpDecorate, + 3 + decorationOperands.size()); + region.pushIdUse(target); + region.pushWord(static_cast(decoration)); + + for (auto decorationOperand : decorationOperands) + { + region.pushWord(decorationOperand); + } + } + + void createMemberDecorate(StructType structureType, std::uint32_t member, + spv::Decoration decoration, + std::span decorationOperands) + { + auto region = annotationRegion.pushOp(spv::Op::OpMemberDecorate, + 4 + decorationOperands.size()); + region.pushIdUse(structureType); + region.pushWord(member); + region.pushWord(static_cast(decoration)); + + for (auto decorationOperand : decorationOperands) + { + region.pushWord(decorationOperand); + } + } + + void createDecorateId(Id target, spv::Decoration decoration, + std::span decorationOperands) + { + auto region = annotationRegion.pushOp(spv::Op::OpDecorateId, + 3 + decorationOperands.size()); + region.pushIdUse(target); + region.pushWord(static_cast(decoration)); + + for (auto decorationOperand : decorationOperands) + { + region.pushIdUse(decorationOperand); + } + } + + void createDecorateString( + Id target, spv::Decoration decoration, + std::string_view firstDecorationOperand, + std::span decorationOperands = {}) + { + std::size_t decorationOperandsLen = + calcStringWordCount(firstDecorationOperand); + + for (auto decorationOperand : decorationOperands) + { + decorationOperandsLen += calcStringWordCount(decorationOperand); + } + + auto region = annotationRegion.pushOp(spv::Op::OpDecorateString, + 3 + decorationOperandsLen); + region.pushIdUse(target); + region.pushWord(static_cast(decoration)); + region.pushString(firstDecorationOperand); + + for (auto decorationOperand : decorationOperands) + { + region.pushString(decorationOperand); + } + } + + void createMemberDecorateString( + StructType structType, std::uint32_t member, spv::Decoration decoration, + std::string_view firstDecorationOperand, + std::span decorationOperands = {}) + { + std::size_t decorationOperandsLen = + calcStringWordCount(firstDecorationOperand); + + for (auto decorationOperand : decorationOperands) + { + decorationOperandsLen += calcStringWordCount(decorationOperand); + } + + auto region = annotationRegion.pushOp(spv::Op::OpMemberDecorateString, + 4 + decorationOperandsLen); + region.pushIdUse(structType); + region.pushWord(member); + region.pushWord(static_cast(decoration)); + region.pushString(firstDecorationOperand); + + for (auto decorationOperand : decorationOperands) + { + region.pushString(decorationOperand); + } + } + + // extension + void createExtension(std::string_view name) + { + auto region = extensionRegion.pushOp(spv::Op::OpExtension, + 1 + calcStringWordCount(name)); + region.pushString(name); + } + + ExtInstSet createExtInstImport(std::string_view name) + { + auto region = extInstRegion.pushOp(spv::Op::OpExtInstImport, + 2 + calcStringWordCount(name)); + auto id = newId(); + region.pushIdDef(id); + region.pushString(name); + return id; + } + + // mode set + void createCapability(spv::Capability cap) + { + auto region = capabilityRegion.pushOp(spv::Op::OpCapability, 2); + region.pushWord(static_cast(cap)); + } + + void setMemoryModel(spv::AddressingModel addressingModel, + spv::MemoryModel memoryModel) + { + memoryModelRegion.clear(); + auto region = memoryModelRegion.pushOp(spv::Op::OpMemoryModel, 3); + region.pushWord(static_cast(addressingModel)); + region.pushWord(static_cast(memoryModel)); + } + + void createEntryPoint(spv::ExecutionModel executionModel, Function entryPoint, + std::string_view name, + std::span interfaces) + { + auto region = entryPointRegion.pushOp(spv::Op::OpEntryPoint, + 3 + calcStringWordCount(name) + + interfaces.size()); + region.pushWord(static_cast(executionModel)); + region.pushIdUse(entryPoint); + region.pushString(name); + for (auto iface : interfaces) + { + region.pushIdUse(iface); + } + } + void createExecutionMode(Function entryPoint, spv::ExecutionMode mode, + std::span args) + { + auto region = + executionModeRegion.pushOp(spv::Op::OpExecutionMode, 3 + args.size()); + region.pushIdUse(entryPoint); + region.pushWord(static_cast(mode)); + for (auto arg : args) + { + region.pushWord(arg); + } + } + + void createExecutionModeId(Function entryPoint, spv::ExecutionMode mode, + std::span args) + { + auto region = + executionModeRegion.pushOp(spv::Op::OpExecutionModeId, 3 + args.size()); + region.pushIdUse(entryPoint); + region.pushWord(static_cast(mode)); + for (auto arg : args) + { + region.pushIdUse(arg); + } + } + + // type + VoidType createTypeVoid() + { + auto region = globalRegion.pushOp(spv::Op::OpTypeVoid, 2); + auto id = newId(); + region.pushIdDef(id); + return id; + } + BoolType createTypeBool() + { + auto region = globalRegion.pushOp(spv::Op::OpTypeBool, 2); + auto id = newId(); + region.pushIdDef(id); + return id; + } + IntType createTypeInt(std::uint32_t width, bool signedness) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeInt, 4); + auto id = newId(); + region.pushIdDef(id); + region.pushWord(width); + region.pushWord(static_cast(signedness)); + return id; + } + SIntType createTypeSInt(std::uint32_t width) + { + return cast(createTypeInt(width, true)); + } + UIntType createTypeUInt(std::uint32_t width) + { + return cast(createTypeInt(width, false)); + } + FloatType createTypeFloat(std::uint32_t width) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeFloat, 3); + auto id = newId(); + region.pushIdDef(id); + region.pushWord(width); + return id; + } + template + VectorOfType createTypeVector(T componentType, + std::uint32_t componentCount) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeVector, 4); + auto id = newId>(); + region.pushIdDef(id); + region.pushIdUse(componentType); + region.pushWord(componentCount); + return id; + } + MatrixType createTypeMatrix(VectorType columnType, + std::uint32_t coulumnCount) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeMatrix, 4); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(columnType); + region.pushWord(coulumnCount); + return id; + } + + ImageType createTypeImage(Type sampledType, spv::Dim dim, std::uint32_t depth, + std::uint32_t arrayed, std::uint32_t ms, + std::uint32_t sampled, spv::ImageFormat imageFormat, + std::optional access = {}) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeImage, + 9 + (access.has_value() ? 1 : 0)); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(sampledType); + region.pushWord(static_cast(dim)); + region.pushWord(depth); + region.pushWord(arrayed); + region.pushWord(ms); + region.pushWord(sampled); + region.pushWord(static_cast(imageFormat)); + + if (access.has_value()) + { + region.pushWord(static_cast(*access)); + } + + return id; + } + + SamplerType createTypeSampler() + { + auto region = globalRegion.pushOp(spv::Op::OpTypeSampler, 2); + auto id = newId(); + region.pushIdDef(id); + return id; + } + + SampledImageType createTypeSampledImage(ImageType imageType) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeSampledImage, 3); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(imageType); + return id; + } + + ArrayType createTypeArray(Type elementType, AnyConstantValue count) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeArray, 4); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(elementType); + region.pushIdUse(count); + return id; + } + + RuntimeArrayType createTypeRuntimeArray(Type elementType) + { + auto region = globalRegion.pushOp(spv::Op::OpTypeRuntimeArray, 3); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(elementType); + + return id; + } + + StructType createTypeStruct(std::span members) + { + auto region = + globalRegion.pushOp(spv::Op::OpTypeStruct, 2 + members.size()); + auto id = newId(); + region.pushIdDef(id); + + for (auto member : members) + { + region.pushIdUse(member); + } + + return id; + } + + PointerType createTypePointer(spv::StorageClass storageClass, Type type) + { + auto region = globalRegion.pushOp(spv::Op::OpTypePointer, 4); + auto id = newId(); + region.pushIdDef(id); + region.pushWord(static_cast(storageClass)); + region.pushIdUse(type); + return id; + } + + template + requires(std::is_base_of_v) + PointerToType createTypePointer(spv::StorageClass storageClass, T type) + { + return cast>( + createTypePointer(storageClass, static_cast(type))); + } + + FunctionType createTypeFunction(Type returnType, + std::span parameters) + { + auto region = + globalRegion.pushOp(spv::Op::OpTypeFunction, 3 + parameters.size()); + auto id = newId(); + region.pushIdDef(id); + region.pushIdUse(returnType); + + for (auto param : parameters) + { + region.pushIdUse(param); + } + + return id; + } + + // constant + ConstantBool createConstantTrue(BoolType type) + { + auto region = globalRegion.pushOp(spv::Op::OpConstantTrue, 3); + auto id = newId(); + region.pushIdUse(type); + region.pushIdDef(id); + return id; + } + + ConstantBool createConstantFalse(BoolType type) + { + auto region = globalRegion.pushOp(spv::Op::OpConstantFalse, 3); + auto id = newId(); + region.pushIdUse(type); + region.pushIdDef(id); + return id; + } + + template + requires(std::is_base_of_v) + ConstantValue> createConstant(T type, std::span values) + { + auto region = globalRegion.pushOp(spv::Op::OpConstant, 3 + values.size()); + auto id = newId>>(); + region.pushIdUse(type); + region.pushIdDef(id); + for (auto value : values) + { + region.pushWord(value); + } + return id; + } + + template + requires(std::is_base_of_v) + ConstantValue> createConstant32(T type, std::uint32_t value) + { + return createConstant(type, std::array{value}); + } + + template + requires(std::is_base_of_v) + ConstantValue> createConstant64(T type, std::uint64_t value) + { + return createConstant(type, + std::array{static_cast(value), + static_cast(value >> 32)}); + } + + // memory + VariableValue createVariable(Type type, spv::StorageClass storageClass, + std::optional initializer = {}) + { + auto region = globalRegion.pushOp(spv::Op::OpVariable, + 4 + (initializer.has_value() ? 1 : 0)); + auto id = newId(); + region.pushIdUse(type); + region.pushIdDef(id); + region.pushWord(static_cast(storageClass)); + if (initializer.has_value()) + { + region.pushIdUse(initializer.value()); + } + return id; + } + + private: + void createFunction(Function id, Type resultType, + spv::FunctionControlMask functionControl, + Type functionType) + { + auto region = functionRegion.pushOp(spv::Op::OpFunction, 5); + region.pushIdUse(resultType); + region.pushIdDef(id); + region.pushWord(static_cast(functionControl)); + region.pushIdUse(functionType); + } + + Value createFunctionParameter(Type resultType) + { + auto region = functionRegion.pushOp(spv::Op::OpFunctionParameter, 3); + auto id = newId(); + region.pushIdUse(resultType); + region.pushIdDef(id); + return id; + } + + void createFunctionEnd() { functionRegion.pushOp(spv::Op::OpFunctionEnd, 1); } + + public: + FunctionBuilder createFunctionBuilder(std::size_t expInstructionsCount) + { + auto id = newId(); + return FunctionBuilder(*mIdGenerator, id, expInstructionsCount); + } + + void insertFunctionDeclaration(const FunctionBuilder& function, + Type resultType, + spv::FunctionControlMask functionControl, + Type functionType) + { + createFunction(function.id, resultType, functionControl, functionType); + functionRegion.pushRegion(function.paramsRegion); + createFunctionEnd(); + } + + void insertFunction(const FunctionBuilder& function, Type resultType, + spv::FunctionControlMask functionControl, + Type functionType) + { + createFunction(function.id, resultType, functionControl, functionType); + functionRegion.pushRegion(function.paramsRegion); + functionRegion.pushRegion(function.bodyRegion); + createFunctionEnd(); + } + + BlockBuilder createBlockBuilder(std::size_t expInstructionsCount) + { + auto id = newId(); + + return BlockBuilder(*mIdGenerator, id, expInstructionsCount); + } + }; } // namespace spirv diff --git a/hw/amdgpu/lib/libspirv/include/spirv/spirv-instruction.hpp b/hw/amdgpu/lib/libspirv/include/spirv/spirv-instruction.hpp index 36dc2710..2e567112 100644 --- a/hw/amdgpu/lib/libspirv/include/spirv/spirv-instruction.hpp +++ b/hw/amdgpu/lib/libspirv/include/spirv/spirv-instruction.hpp @@ -4,2411 +4,2798 @@ #include #include -namespace spirv { -enum class OperandKind { - Invalid, - ValueId, - TypeId, - Word, - String, - VariadicId, - VariadicWord, -}; +namespace spirv +{ + enum class OperandKind + { + Invalid, + ValueId, + TypeId, + Word, + String, + VariadicId, + VariadicWord, + }; -enum class OperandDirection { - In, - Out, -}; + enum class OperandDirection + { + In, + Out, + }; -enum class InstructionFlags { - None = 0, - HasResult = 1 << 0, - HasResultType = 1 << 1, -}; + enum class InstructionFlags + { + None = 0, + HasResult = 1 << 0, + HasResultType = 1 << 1, + }; -inline InstructionFlags operator|(InstructionFlags lhs, InstructionFlags rhs) { - return static_cast(static_cast(lhs) | - static_cast(rhs)); -} -inline InstructionFlags operator&(InstructionFlags lhs, InstructionFlags rhs) { - return static_cast(static_cast(lhs) & - static_cast(rhs)); -} + inline InstructionFlags operator|(InstructionFlags lhs, InstructionFlags rhs) + { + return static_cast(static_cast(lhs) | + static_cast(rhs)); + } + inline InstructionFlags operator&(InstructionFlags lhs, InstructionFlags rhs) + { + return static_cast(static_cast(lhs) & + static_cast(rhs)); + } -struct InstructionInfo { - const char *name; - InstructionFlags flags; - OperandKind operands[16]; -}; + struct InstructionInfo + { + const char* name; + InstructionFlags flags; + OperandKind operands[16]; + }; -inline const InstructionInfo *getInstructionInfo(spv::Op opcode) { - switch (opcode) { - default: /* unknown opcode */ - break; - case spv::Op::OpNop: { - static InstructionInfo result = {"OpNop", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpUndef: { - static InstructionInfo result = {"OpUndef", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSourceContinued: { - static InstructionInfo result = { - "OpSourceContinued", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpSource: { - static InstructionInfo result = {"OpSource", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpSourceExtension: { - static InstructionInfo result = { - "OpSourceExtension", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpName: { - static InstructionInfo result = {"OpName", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpMemberName: { - static InstructionInfo result = { - "OpMemberName", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpString: { - static InstructionInfo result = { - "OpString", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpLine: { - static InstructionInfo result = {"OpLine", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpExtension: { - static InstructionInfo result = {"OpExtension", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpExtInstImport: { - static InstructionInfo result = { - "OpExtInstImport", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpExtInst: { - static InstructionInfo result = {"OpExtInst", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpMemoryModel: { - static InstructionInfo result = { - "OpMemoryModel", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpEntryPoint: { - static InstructionInfo result = { - "OpEntryPoint", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpExecutionMode: { - static InstructionInfo result = { - "OpExecutionMode", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCapability: { - static InstructionInfo result = { - "OpCapability", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpTypeVoid: { - static InstructionInfo result = { - "OpTypeVoid", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeBool: { - static InstructionInfo result = { - "OpTypeBool", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeInt: { - static InstructionInfo result = { - "OpTypeInt", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeFloat: { - static InstructionInfo result = { - "OpTypeFloat", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeVector: { - static InstructionInfo result = { - "OpTypeVector", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeMatrix: { - static InstructionInfo result = { - "OpTypeMatrix", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeImage: { - static InstructionInfo result = { - "OpTypeImage", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeSampler: { - static InstructionInfo result = { - "OpTypeSampler", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeSampledImage: { - static InstructionInfo result = { - "OpTypeSampledImage", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeArray: { - static InstructionInfo result = { - "OpTypeArray", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeRuntimeArray: { - static InstructionInfo result = { - "OpTypeRuntimeArray", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeStruct: { - static InstructionInfo result = { - "OpTypeStruct", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeOpaque: { - static InstructionInfo result = { - "OpTypeOpaque", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypePointer: { - static InstructionInfo result = { - "OpTypePointer", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeFunction: { - static InstructionInfo result = { - "OpTypeFunction", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeEvent: { - static InstructionInfo result = { - "OpTypeEvent", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeDeviceEvent: { - static InstructionInfo result = { - "OpTypeDeviceEvent", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeReserveId: { - static InstructionInfo result = { - "OpTypeReserveId", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeQueue: { - static InstructionInfo result = { - "OpTypeQueue", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypePipe: { - static InstructionInfo result = { - "OpTypePipe", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpTypeForwardPointer: { - static InstructionInfo result = { - "OpTypeForwardPointer", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpConstantTrue: { - static InstructionInfo result = {"OpConstantTrue", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConstantFalse: { - static InstructionInfo result = {"OpConstantFalse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConstant: { - static InstructionInfo result = {"OpConstant", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConstantComposite: { - static InstructionInfo result = {"OpConstantComposite", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConstantSampler: { - static InstructionInfo result = {"OpConstantSampler", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConstantNull: { - static InstructionInfo result = {"OpConstantNull", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSpecConstantTrue: { - static InstructionInfo result = {"OpSpecConstantTrue", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSpecConstantFalse: { - static InstructionInfo result = {"OpSpecConstantFalse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSpecConstant: { - static InstructionInfo result = {"OpSpecConstant", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSpecConstantComposite: { - static InstructionInfo result = {"OpSpecConstantComposite", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSpecConstantOp: { - static InstructionInfo result = {"OpSpecConstantOp", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFunction: { - static InstructionInfo result = {"OpFunction", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFunctionParameter: { - static InstructionInfo result = {"OpFunctionParameter", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFunctionEnd: { - static InstructionInfo result = { - "OpFunctionEnd", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpFunctionCall: { - static InstructionInfo result = {"OpFunctionCall", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpVariable: { - static InstructionInfo result = {"OpVariable", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageTexelPointer: { - static InstructionInfo result = {"OpImageTexelPointer", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLoad: { - static InstructionInfo result = {"OpLoad", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpStore: { - static InstructionInfo result = {"OpStore", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCopyMemory: { - static InstructionInfo result = { - "OpCopyMemory", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCopyMemorySized: { - static InstructionInfo result = { - "OpCopyMemorySized", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpAccessChain: { - static InstructionInfo result = {"OpAccessChain", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpInBoundsAccessChain: { - static InstructionInfo result = {"OpInBoundsAccessChain", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPtrAccessChain: { - static InstructionInfo result = {"OpPtrAccessChain", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpArrayLength: { - static InstructionInfo result = {"OpArrayLength", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGenericPtrMemSemantics: { - static InstructionInfo result = {"OpGenericPtrMemSemantics", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpInBoundsPtrAccessChain: { - static InstructionInfo result = {"OpInBoundsPtrAccessChain", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDecorate: { - static InstructionInfo result = {"OpDecorate", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpMemberDecorate: { - static InstructionInfo result = { - "OpMemberDecorate", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpDecorationGroup: { - static InstructionInfo result = { - "OpDecorationGroup", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpGroupDecorate: { - static InstructionInfo result = { - "OpGroupDecorate", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGroupMemberDecorate: { - static InstructionInfo result = { - "OpGroupMemberDecorate", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpVectorExtractDynamic: { - static InstructionInfo result = {"OpVectorExtractDynamic", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpVectorInsertDynamic: { - static InstructionInfo result = {"OpVectorInsertDynamic", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpVectorShuffle: { - static InstructionInfo result = {"OpVectorShuffle", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCompositeConstruct: { - static InstructionInfo result = {"OpCompositeConstruct", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCompositeExtract: { - static InstructionInfo result = {"OpCompositeExtract", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCompositeInsert: { - static InstructionInfo result = {"OpCompositeInsert", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCopyObject: { - static InstructionInfo result = {"OpCopyObject", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpTranspose: { - static InstructionInfo result = {"OpTranspose", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSampledImage: { - static InstructionInfo result = {"OpSampledImage", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleImplicitLod: { - static InstructionInfo result = {"OpImageSampleImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleExplicitLod: { - static InstructionInfo result = {"OpImageSampleExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleDrefImplicitLod: { - static InstructionInfo result = {"OpImageSampleDrefImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleDrefExplicitLod: { - static InstructionInfo result = {"OpImageSampleDrefExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleProjImplicitLod: { - static InstructionInfo result = {"OpImageSampleProjImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleProjExplicitLod: { - static InstructionInfo result = {"OpImageSampleProjExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleProjDrefImplicitLod: { - static InstructionInfo result = {"OpImageSampleProjDrefImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSampleProjDrefExplicitLod: { - static InstructionInfo result = {"OpImageSampleProjDrefExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageFetch: { - static InstructionInfo result = {"OpImageFetch", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageGather: { - static InstructionInfo result = {"OpImageGather", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageDrefGather: { - static InstructionInfo result = {"OpImageDrefGather", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageRead: { - static InstructionInfo result = {"OpImageRead", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageWrite: { - static InstructionInfo result = { - "OpImageWrite", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpImage: { - static InstructionInfo result = {"OpImage", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQueryFormat: { - static InstructionInfo result = {"OpImageQueryFormat", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQueryOrder: { - static InstructionInfo result = {"OpImageQueryOrder", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQuerySizeLod: { - static InstructionInfo result = {"OpImageQuerySizeLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQuerySize: { - static InstructionInfo result = {"OpImageQuerySize", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQueryLod: { - static InstructionInfo result = {"OpImageQueryLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQueryLevels: { - static InstructionInfo result = {"OpImageQueryLevels", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageQuerySamples: { - static InstructionInfo result = {"OpImageQuerySamples", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertFToU: { - static InstructionInfo result = {"OpConvertFToU", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertFToS: { - static InstructionInfo result = {"OpConvertFToS", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertSToF: { - static InstructionInfo result = {"OpConvertSToF", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertUToF: { - static InstructionInfo result = {"OpConvertUToF", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUConvert: { - static InstructionInfo result = {"OpUConvert", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSConvert: { - static InstructionInfo result = {"OpSConvert", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFConvert: { - static InstructionInfo result = {"OpFConvert", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpQuantizeToF16: { - static InstructionInfo result = {"OpQuantizeToF16", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertPtrToU: { - static InstructionInfo result = {"OpConvertPtrToU", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSatConvertSToU: { - static InstructionInfo result = {"OpSatConvertSToU", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSatConvertUToS: { - static InstructionInfo result = {"OpSatConvertUToS", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpConvertUToPtr: { - static InstructionInfo result = {"OpConvertUToPtr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPtrCastToGeneric: { - static InstructionInfo result = {"OpPtrCastToGeneric", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGenericCastToPtr: { - static InstructionInfo result = {"OpGenericCastToPtr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGenericCastToPtrExplicit: { - static InstructionInfo result = {"OpGenericCastToPtrExplicit", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitcast: { - static InstructionInfo result = {"OpBitcast", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSNegate: { - static InstructionInfo result = {"OpSNegate", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFNegate: { - static InstructionInfo result = {"OpFNegate", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIAdd: { - static InstructionInfo result = {"OpIAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFAdd: { - static InstructionInfo result = {"OpFAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpISub: { - static InstructionInfo result = {"OpISub", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFSub: { - static InstructionInfo result = {"OpFSub", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIMul: { - static InstructionInfo result = {"OpIMul", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFMul: { - static InstructionInfo result = {"OpFMul", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUDiv: { - static InstructionInfo result = {"OpUDiv", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSDiv: { - static InstructionInfo result = {"OpSDiv", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFDiv: { - static InstructionInfo result = {"OpFDiv", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUMod: { - static InstructionInfo result = {"OpUMod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSRem: { - static InstructionInfo result = {"OpSRem", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSMod: { - static InstructionInfo result = {"OpSMod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFRem: { - static InstructionInfo result = {"OpFRem", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFMod: { - static InstructionInfo result = {"OpFMod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpVectorTimesScalar: { - static InstructionInfo result = {"OpVectorTimesScalar", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpMatrixTimesScalar: { - static InstructionInfo result = {"OpMatrixTimesScalar", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpVectorTimesMatrix: { - static InstructionInfo result = {"OpVectorTimesMatrix", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpMatrixTimesVector: { - static InstructionInfo result = {"OpMatrixTimesVector", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpMatrixTimesMatrix: { - static InstructionInfo result = {"OpMatrixTimesMatrix", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpOuterProduct: { - static InstructionInfo result = {"OpOuterProduct", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDot: { - static InstructionInfo result = {"OpDot", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIAddCarry: { - static InstructionInfo result = {"OpIAddCarry", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpISubBorrow: { - static InstructionInfo result = {"OpISubBorrow", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUMulExtended: { - static InstructionInfo result = {"OpUMulExtended", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSMulExtended: { - static InstructionInfo result = {"OpSMulExtended", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAny: { - static InstructionInfo result = {"OpAny", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAll: { - static InstructionInfo result = {"OpAll", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIsNan: { - static InstructionInfo result = {"OpIsNan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIsInf: { - static InstructionInfo result = {"OpIsInf", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIsFinite: { - static InstructionInfo result = {"OpIsFinite", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIsNormal: { - static InstructionInfo result = {"OpIsNormal", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSignBitSet: { - static InstructionInfo result = {"OpSignBitSet", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLessOrGreater: { - static InstructionInfo result = {"OpLessOrGreater", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpOrdered: { - static InstructionInfo result = {"OpOrdered", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUnordered: { - static InstructionInfo result = {"OpUnordered", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLogicalEqual: { - static InstructionInfo result = {"OpLogicalEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLogicalNotEqual: { - static InstructionInfo result = {"OpLogicalNotEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLogicalOr: { - static InstructionInfo result = {"OpLogicalOr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLogicalAnd: { - static InstructionInfo result = {"OpLogicalAnd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLogicalNot: { - static InstructionInfo result = {"OpLogicalNot", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSelect: { - static InstructionInfo result = {"OpSelect", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIEqual: { - static InstructionInfo result = {"OpIEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpINotEqual: { - static InstructionInfo result = {"OpINotEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUGreaterThan: { - static InstructionInfo result = {"OpUGreaterThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSGreaterThan: { - static InstructionInfo result = {"OpSGreaterThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpUGreaterThanEqual: { - static InstructionInfo result = {"OpUGreaterThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSGreaterThanEqual: { - static InstructionInfo result = {"OpSGreaterThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpULessThan: { - static InstructionInfo result = {"OpULessThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSLessThan: { - static InstructionInfo result = {"OpSLessThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpULessThanEqual: { - static InstructionInfo result = {"OpULessThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSLessThanEqual: { - static InstructionInfo result = {"OpSLessThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdEqual: { - static InstructionInfo result = {"OpFOrdEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordEqual: { - static InstructionInfo result = {"OpFUnordEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdNotEqual: { - static InstructionInfo result = {"OpFOrdNotEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordNotEqual: { - static InstructionInfo result = {"OpFUnordNotEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdLessThan: { - static InstructionInfo result = {"OpFOrdLessThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordLessThan: { - static InstructionInfo result = {"OpFUnordLessThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdGreaterThan: { - static InstructionInfo result = {"OpFOrdGreaterThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordGreaterThan: { - static InstructionInfo result = {"OpFUnordGreaterThan", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdLessThanEqual: { - static InstructionInfo result = {"OpFOrdLessThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordLessThanEqual: { - static InstructionInfo result = {"OpFUnordLessThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFOrdGreaterThanEqual: { - static InstructionInfo result = {"OpFOrdGreaterThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFUnordGreaterThanEqual: { - static InstructionInfo result = {"OpFUnordGreaterThanEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpShiftRightLogical: { - static InstructionInfo result = {"OpShiftRightLogical", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpShiftRightArithmetic: { - static InstructionInfo result = {"OpShiftRightArithmetic", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpShiftLeftLogical: { - static InstructionInfo result = {"OpShiftLeftLogical", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitwiseOr: { - static InstructionInfo result = {"OpBitwiseOr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitwiseXor: { - static InstructionInfo result = {"OpBitwiseXor", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitwiseAnd: { - static InstructionInfo result = {"OpBitwiseAnd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpNot: { - static InstructionInfo result = {"OpNot", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitFieldInsert: { - static InstructionInfo result = {"OpBitFieldInsert", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitFieldSExtract: { - static InstructionInfo result = {"OpBitFieldSExtract", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitFieldUExtract: { - static InstructionInfo result = {"OpBitFieldUExtract", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitReverse: { - static InstructionInfo result = {"OpBitReverse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBitCount: { - static InstructionInfo result = {"OpBitCount", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdx: { - static InstructionInfo result = {"OpDPdx", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdy: { - static InstructionInfo result = {"OpDPdy", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFwidth: { - static InstructionInfo result = {"OpFwidth", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdxFine: { - static InstructionInfo result = {"OpDPdxFine", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdyFine: { - static InstructionInfo result = {"OpDPdyFine", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFwidthFine: { - static InstructionInfo result = {"OpFwidthFine", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdxCoarse: { - static InstructionInfo result = {"OpDPdxCoarse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpDPdyCoarse: { - static InstructionInfo result = {"OpDPdyCoarse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpFwidthCoarse: { - static InstructionInfo result = {"OpFwidthCoarse", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpEmitVertex: { - static InstructionInfo result = { - "OpEmitVertex", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpEndPrimitive: { - static InstructionInfo result = { - "OpEndPrimitive", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpEmitStreamVertex: { - static InstructionInfo result = { - "OpEmitStreamVertex", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpEndStreamPrimitive: { - static InstructionInfo result = { - "OpEndStreamPrimitive", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpControlBarrier: { - static InstructionInfo result = { - "OpControlBarrier", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpMemoryBarrier: { - static InstructionInfo result = { - "OpMemoryBarrier", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpAtomicLoad: { - static InstructionInfo result = {"OpAtomicLoad", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicStore: { - static InstructionInfo result = { - "OpAtomicStore", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpAtomicExchange: { - static InstructionInfo result = {"OpAtomicExchange", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicCompareExchange: { - static InstructionInfo result = {"OpAtomicCompareExchange", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicCompareExchangeWeak: { - static InstructionInfo result = {"OpAtomicCompareExchangeWeak", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicIIncrement: { - static InstructionInfo result = {"OpAtomicIIncrement", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicIDecrement: { - static InstructionInfo result = {"OpAtomicIDecrement", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicIAdd: { - static InstructionInfo result = {"OpAtomicIAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicISub: { - static InstructionInfo result = {"OpAtomicISub", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicSMin: { - static InstructionInfo result = {"OpAtomicSMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicUMin: { - static InstructionInfo result = {"OpAtomicUMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicSMax: { - static InstructionInfo result = {"OpAtomicSMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicUMax: { - static InstructionInfo result = {"OpAtomicUMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicAnd: { - static InstructionInfo result = {"OpAtomicAnd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicOr: { - static InstructionInfo result = {"OpAtomicOr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicXor: { - static InstructionInfo result = {"OpAtomicXor", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPhi: { - static InstructionInfo result = {"OpPhi", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpLoopMerge: { - static InstructionInfo result = {"OpLoopMerge", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpSelectionMerge: { - static InstructionInfo result = { - "OpSelectionMerge", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpLabel: { - static InstructionInfo result = { - "OpLabel", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpBranch: { - static InstructionInfo result = {"OpBranch", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpBranchConditional: { - static InstructionInfo result = { - "OpBranchConditional", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpSwitch: { - static InstructionInfo result = {"OpSwitch", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpKill: { - static InstructionInfo result = {"OpKill", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpReturn: { - static InstructionInfo result = {"OpReturn", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpReturnValue: { - static InstructionInfo result = { - "OpReturnValue", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpUnreachable: { - static InstructionInfo result = { - "OpUnreachable", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpLifetimeStart: { - static InstructionInfo result = { - "OpLifetimeStart", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpLifetimeStop: { - static InstructionInfo result = { - "OpLifetimeStop", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGroupAsyncCopy: { - static InstructionInfo result = {"OpGroupAsyncCopy", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupWaitEvents: { - static InstructionInfo result = { - "OpGroupWaitEvents", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGroupAll: { - static InstructionInfo result = {"OpGroupAll", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupAny: { - static InstructionInfo result = {"OpGroupAny", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupBroadcast: { - static InstructionInfo result = {"OpGroupBroadcast", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupIAdd: { - static InstructionInfo result = {"OpGroupIAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupFAdd: { - static InstructionInfo result = {"OpGroupFAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupFMin: { - static InstructionInfo result = {"OpGroupFMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupUMin: { - static InstructionInfo result = {"OpGroupUMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupSMin: { - static InstructionInfo result = {"OpGroupSMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupFMax: { - static InstructionInfo result = {"OpGroupFMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupUMax: { - static InstructionInfo result = {"OpGroupUMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupSMax: { - static InstructionInfo result = {"OpGroupSMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpReadPipe: { - static InstructionInfo result = {"OpReadPipe", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpWritePipe: { - static InstructionInfo result = {"OpWritePipe", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpReservedReadPipe: { - static InstructionInfo result = {"OpReservedReadPipe", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpReservedWritePipe: { - static InstructionInfo result = {"OpReservedWritePipe", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpReserveReadPipePackets: { - static InstructionInfo result = {"OpReserveReadPipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpReserveWritePipePackets: { - static InstructionInfo result = {"OpReserveWritePipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCommitReadPipe: { - static InstructionInfo result = { - "OpCommitReadPipe", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCommitWritePipe: { - static InstructionInfo result = { - "OpCommitWritePipe", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpIsValidReserveId: { - static InstructionInfo result = {"OpIsValidReserveId", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetNumPipePackets: { - static InstructionInfo result = {"OpGetNumPipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetMaxPipePackets: { - static InstructionInfo result = {"OpGetMaxPipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupReserveReadPipePackets: { - static InstructionInfo result = {"OpGroupReserveReadPipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupReserveWritePipePackets: { - static InstructionInfo result = {"OpGroupReserveWritePipePackets", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupCommitReadPipe: { - static InstructionInfo result = { - "OpGroupCommitReadPipe", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGroupCommitWritePipe: { - static InstructionInfo result = { - "OpGroupCommitWritePipe", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpEnqueueMarker: { - static InstructionInfo result = {"OpEnqueueMarker", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpEnqueueKernel: { - static InstructionInfo result = {"OpEnqueueKernel", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelNDrangeSubGroupCount: { - static InstructionInfo result = {"OpGetKernelNDrangeSubGroupCount", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelNDrangeMaxSubGroupSize: { - static InstructionInfo result = {"OpGetKernelNDrangeMaxSubGroupSize", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelWorkGroupSize: { - static InstructionInfo result = {"OpGetKernelWorkGroupSize", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple: { - static InstructionInfo result = { - "OpGetKernelPreferredWorkGroupSizeMultiple", - InstructionFlags::HasResult | InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpRetainEvent: { - static InstructionInfo result = { - "OpRetainEvent", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpReleaseEvent: { - static InstructionInfo result = { - "OpReleaseEvent", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCreateUserEvent: { - static InstructionInfo result = {"OpCreateUserEvent", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpIsValidEvent: { - static InstructionInfo result = {"OpIsValidEvent", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSetUserEventStatus: { - static InstructionInfo result = { - "OpSetUserEventStatus", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpCaptureEventProfilingInfo: { - static InstructionInfo result = { - "OpCaptureEventProfilingInfo", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGetDefaultQueue: { - static InstructionInfo result = {"OpGetDefaultQueue", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpBuildNDRange: { - static InstructionInfo result = {"OpBuildNDRange", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleImplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleExplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleDrefImplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleDrefImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleDrefExplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleDrefExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleProjImplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleProjImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleProjExplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleProjExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleProjDrefImplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleProjDrefImplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseSampleProjDrefExplicitLod: { - static InstructionInfo result = {"OpImageSparseSampleProjDrefExplicitLod", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseFetch: { - static InstructionInfo result = {"OpImageSparseFetch", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseGather: { - static InstructionInfo result = {"OpImageSparseGather", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseDrefGather: { - static InstructionInfo result = {"OpImageSparseDrefGather", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpImageSparseTexelsResident: { - static InstructionInfo result = {"OpImageSparseTexelsResident", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpNoLine: { - static InstructionInfo result = {"OpNoLine", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpAtomicFlagTestAndSet: { - static InstructionInfo result = {"OpAtomicFlagTestAndSet", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpAtomicFlagClear: { - static InstructionInfo result = { - "OpAtomicFlagClear", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpImageSparseRead: { - static InstructionInfo result = {"OpImageSparseRead", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpSizeOf: { - static InstructionInfo result = {"OpSizeOf", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpTypePipeStorage: { - static InstructionInfo result = { - "OpTypePipeStorage", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpConstantPipeStorage: { - static InstructionInfo result = {"OpConstantPipeStorage", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCreatePipeFromPipeStorage: { - static InstructionInfo result = {"OpCreatePipeFromPipeStorage", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelLocalSizeForSubgroupCount: { - static InstructionInfo result = {"OpGetKernelLocalSizeForSubgroupCount", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGetKernelMaxNumSubgroups: { - static InstructionInfo result = {"OpGetKernelMaxNumSubgroups", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpTypeNamedBarrier: { - static InstructionInfo result = { - "OpTypeNamedBarrier", InstructionFlags::HasResult, {}}; - return &result; - } - case spv::Op::OpNamedBarrierInitialize: { - static InstructionInfo result = {"OpNamedBarrierInitialize", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpMemoryNamedBarrier: { - static InstructionInfo result = { - "OpMemoryNamedBarrier", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpModuleProcessed: { - static InstructionInfo result = { - "OpModuleProcessed", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpExecutionModeId: { - static InstructionInfo result = { - "OpExecutionModeId", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpDecorateId: { - static InstructionInfo result = { - "OpDecorateId", InstructionFlags::None, {}}; - return &result; - } - case spv::Op::OpGroupNonUniformElect: { - static InstructionInfo result = {"OpGroupNonUniformElect", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformAll: { - static InstructionInfo result = {"OpGroupNonUniformAll", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformAny: { - static InstructionInfo result = {"OpGroupNonUniformAny", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformAllEqual: { - static InstructionInfo result = {"OpGroupNonUniformAllEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBroadcast: { - static InstructionInfo result = {"OpGroupNonUniformBroadcast", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBroadcastFirst: { - static InstructionInfo result = {"OpGroupNonUniformBroadcastFirst", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBallot: { - static InstructionInfo result = {"OpGroupNonUniformBallot", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformInverseBallot: { - static InstructionInfo result = {"OpGroupNonUniformInverseBallot", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBallotBitExtract: { - static InstructionInfo result = {"OpGroupNonUniformBallotBitExtract", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBallotBitCount: { - static InstructionInfo result = {"OpGroupNonUniformBallotBitCount", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBallotFindLSB: { - static InstructionInfo result = {"OpGroupNonUniformBallotFindLSB", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBallotFindMSB: { - static InstructionInfo result = {"OpGroupNonUniformBallotFindMSB", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformShuffle: { - static InstructionInfo result = {"OpGroupNonUniformShuffle", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformShuffleXor: { - static InstructionInfo result = {"OpGroupNonUniformShuffleXor", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformShuffleUp: { - static InstructionInfo result = {"OpGroupNonUniformShuffleUp", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformShuffleDown: { - static InstructionInfo result = {"OpGroupNonUniformShuffleDown", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformIAdd: { - static InstructionInfo result = {"OpGroupNonUniformIAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformFAdd: { - static InstructionInfo result = {"OpGroupNonUniformFAdd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformIMul: { - static InstructionInfo result = {"OpGroupNonUniformIMul", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformFMul: { - static InstructionInfo result = {"OpGroupNonUniformFMul", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformSMin: { - static InstructionInfo result = {"OpGroupNonUniformSMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformUMin: { - static InstructionInfo result = {"OpGroupNonUniformUMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformFMin: { - static InstructionInfo result = {"OpGroupNonUniformFMin", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformSMax: { - static InstructionInfo result = {"OpGroupNonUniformSMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformUMax: { - static InstructionInfo result = {"OpGroupNonUniformUMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformFMax: { - static InstructionInfo result = {"OpGroupNonUniformFMax", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBitwiseAnd: { - static InstructionInfo result = {"OpGroupNonUniformBitwiseAnd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBitwiseOr: { - static InstructionInfo result = {"OpGroupNonUniformBitwiseOr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformBitwiseXor: { - static InstructionInfo result = {"OpGroupNonUniformBitwiseXor", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformLogicalAnd: { - static InstructionInfo result = {"OpGroupNonUniformLogicalAnd", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformLogicalOr: { - static InstructionInfo result = {"OpGroupNonUniformLogicalOr", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformLogicalXor: { - static InstructionInfo result = {"OpGroupNonUniformLogicalXor", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformQuadBroadcast: { - static InstructionInfo result = {"OpGroupNonUniformQuadBroadcast", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpGroupNonUniformQuadSwap: { - static InstructionInfo result = {"OpGroupNonUniformQuadSwap", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpCopyLogical: { - static InstructionInfo result = {"OpCopyLogical", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPtrEqual: { - static InstructionInfo result = {"OpPtrEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPtrNotEqual: { - static InstructionInfo result = {"OpPtrNotEqual", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - case spv::Op::OpPtrDiff: { - static InstructionInfo result = {"OpPtrDiff", - InstructionFlags::HasResult | - InstructionFlags::HasResultType, - {}}; - return &result; - } - } + inline const InstructionInfo* getInstructionInfo(spv::Op opcode) + { + switch (opcode) + { + default: /* unknown opcode */ + break; + case spv::Op::OpNop: + { + static InstructionInfo result = {"OpNop", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpUndef: + { + static InstructionInfo result = {"OpUndef", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSourceContinued: + { + static InstructionInfo result = { + "OpSourceContinued", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpSource: + { + static InstructionInfo result = {"OpSource", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpSourceExtension: + { + static InstructionInfo result = { + "OpSourceExtension", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpName: + { + static InstructionInfo result = {"OpName", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpMemberName: + { + static InstructionInfo result = { + "OpMemberName", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpString: + { + static InstructionInfo result = { + "OpString", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpLine: + { + static InstructionInfo result = {"OpLine", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpExtension: + { + static InstructionInfo result = {"OpExtension", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpExtInstImport: + { + static InstructionInfo result = { + "OpExtInstImport", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpExtInst: + { + static InstructionInfo result = {"OpExtInst", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpMemoryModel: + { + static InstructionInfo result = { + "OpMemoryModel", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpEntryPoint: + { + static InstructionInfo result = { + "OpEntryPoint", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpExecutionMode: + { + static InstructionInfo result = { + "OpExecutionMode", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCapability: + { + static InstructionInfo result = { + "OpCapability", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpTypeVoid: + { + static InstructionInfo result = { + "OpTypeVoid", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeBool: + { + static InstructionInfo result = { + "OpTypeBool", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeInt: + { + static InstructionInfo result = { + "OpTypeInt", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeFloat: + { + static InstructionInfo result = { + "OpTypeFloat", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeVector: + { + static InstructionInfo result = { + "OpTypeVector", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeMatrix: + { + static InstructionInfo result = { + "OpTypeMatrix", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeImage: + { + static InstructionInfo result = { + "OpTypeImage", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeSampler: + { + static InstructionInfo result = { + "OpTypeSampler", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeSampledImage: + { + static InstructionInfo result = { + "OpTypeSampledImage", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeArray: + { + static InstructionInfo result = { + "OpTypeArray", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeRuntimeArray: + { + static InstructionInfo result = { + "OpTypeRuntimeArray", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeStruct: + { + static InstructionInfo result = { + "OpTypeStruct", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeOpaque: + { + static InstructionInfo result = { + "OpTypeOpaque", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypePointer: + { + static InstructionInfo result = { + "OpTypePointer", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeFunction: + { + static InstructionInfo result = { + "OpTypeFunction", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeEvent: + { + static InstructionInfo result = { + "OpTypeEvent", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeDeviceEvent: + { + static InstructionInfo result = { + "OpTypeDeviceEvent", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeReserveId: + { + static InstructionInfo result = { + "OpTypeReserveId", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeQueue: + { + static InstructionInfo result = { + "OpTypeQueue", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypePipe: + { + static InstructionInfo result = { + "OpTypePipe", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpTypeForwardPointer: + { + static InstructionInfo result = { + "OpTypeForwardPointer", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpConstantTrue: + { + static InstructionInfo result = {"OpConstantTrue", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConstantFalse: + { + static InstructionInfo result = {"OpConstantFalse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConstant: + { + static InstructionInfo result = {"OpConstant", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConstantComposite: + { + static InstructionInfo result = {"OpConstantComposite", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConstantSampler: + { + static InstructionInfo result = {"OpConstantSampler", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConstantNull: + { + static InstructionInfo result = {"OpConstantNull", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSpecConstantTrue: + { + static InstructionInfo result = {"OpSpecConstantTrue", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSpecConstantFalse: + { + static InstructionInfo result = {"OpSpecConstantFalse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSpecConstant: + { + static InstructionInfo result = {"OpSpecConstant", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSpecConstantComposite: + { + static InstructionInfo result = {"OpSpecConstantComposite", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSpecConstantOp: + { + static InstructionInfo result = {"OpSpecConstantOp", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFunction: + { + static InstructionInfo result = {"OpFunction", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFunctionParameter: + { + static InstructionInfo result = {"OpFunctionParameter", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFunctionEnd: + { + static InstructionInfo result = { + "OpFunctionEnd", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpFunctionCall: + { + static InstructionInfo result = {"OpFunctionCall", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpVariable: + { + static InstructionInfo result = {"OpVariable", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageTexelPointer: + { + static InstructionInfo result = {"OpImageTexelPointer", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLoad: + { + static InstructionInfo result = {"OpLoad", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpStore: + { + static InstructionInfo result = {"OpStore", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCopyMemory: + { + static InstructionInfo result = { + "OpCopyMemory", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCopyMemorySized: + { + static InstructionInfo result = { + "OpCopyMemorySized", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpAccessChain: + { + static InstructionInfo result = {"OpAccessChain", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpInBoundsAccessChain: + { + static InstructionInfo result = {"OpInBoundsAccessChain", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPtrAccessChain: + { + static InstructionInfo result = {"OpPtrAccessChain", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpArrayLength: + { + static InstructionInfo result = {"OpArrayLength", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGenericPtrMemSemantics: + { + static InstructionInfo result = {"OpGenericPtrMemSemantics", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpInBoundsPtrAccessChain: + { + static InstructionInfo result = {"OpInBoundsPtrAccessChain", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDecorate: + { + static InstructionInfo result = {"OpDecorate", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpMemberDecorate: + { + static InstructionInfo result = { + "OpMemberDecorate", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpDecorationGroup: + { + static InstructionInfo result = { + "OpDecorationGroup", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpGroupDecorate: + { + static InstructionInfo result = { + "OpGroupDecorate", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGroupMemberDecorate: + { + static InstructionInfo result = { + "OpGroupMemberDecorate", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpVectorExtractDynamic: + { + static InstructionInfo result = {"OpVectorExtractDynamic", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpVectorInsertDynamic: + { + static InstructionInfo result = {"OpVectorInsertDynamic", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpVectorShuffle: + { + static InstructionInfo result = {"OpVectorShuffle", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCompositeConstruct: + { + static InstructionInfo result = {"OpCompositeConstruct", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCompositeExtract: + { + static InstructionInfo result = {"OpCompositeExtract", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCompositeInsert: + { + static InstructionInfo result = {"OpCompositeInsert", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCopyObject: + { + static InstructionInfo result = {"OpCopyObject", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpTranspose: + { + static InstructionInfo result = {"OpTranspose", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSampledImage: + { + static InstructionInfo result = {"OpSampledImage", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleImplicitLod: + { + static InstructionInfo result = {"OpImageSampleImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleExplicitLod: + { + static InstructionInfo result = {"OpImageSampleExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleDrefImplicitLod: + { + static InstructionInfo result = {"OpImageSampleDrefImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleDrefExplicitLod: + { + static InstructionInfo result = {"OpImageSampleDrefExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleProjImplicitLod: + { + static InstructionInfo result = {"OpImageSampleProjImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleProjExplicitLod: + { + static InstructionInfo result = {"OpImageSampleProjExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleProjDrefImplicitLod: + { + static InstructionInfo result = {"OpImageSampleProjDrefImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSampleProjDrefExplicitLod: + { + static InstructionInfo result = {"OpImageSampleProjDrefExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageFetch: + { + static InstructionInfo result = {"OpImageFetch", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageGather: + { + static InstructionInfo result = {"OpImageGather", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageDrefGather: + { + static InstructionInfo result = {"OpImageDrefGather", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageRead: + { + static InstructionInfo result = {"OpImageRead", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageWrite: + { + static InstructionInfo result = { + "OpImageWrite", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpImage: + { + static InstructionInfo result = {"OpImage", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQueryFormat: + { + static InstructionInfo result = {"OpImageQueryFormat", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQueryOrder: + { + static InstructionInfo result = {"OpImageQueryOrder", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQuerySizeLod: + { + static InstructionInfo result = {"OpImageQuerySizeLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQuerySize: + { + static InstructionInfo result = {"OpImageQuerySize", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQueryLod: + { + static InstructionInfo result = {"OpImageQueryLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQueryLevels: + { + static InstructionInfo result = {"OpImageQueryLevels", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageQuerySamples: + { + static InstructionInfo result = {"OpImageQuerySamples", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertFToU: + { + static InstructionInfo result = {"OpConvertFToU", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertFToS: + { + static InstructionInfo result = {"OpConvertFToS", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertSToF: + { + static InstructionInfo result = {"OpConvertSToF", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertUToF: + { + static InstructionInfo result = {"OpConvertUToF", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUConvert: + { + static InstructionInfo result = {"OpUConvert", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSConvert: + { + static InstructionInfo result = {"OpSConvert", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFConvert: + { + static InstructionInfo result = {"OpFConvert", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpQuantizeToF16: + { + static InstructionInfo result = {"OpQuantizeToF16", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertPtrToU: + { + static InstructionInfo result = {"OpConvertPtrToU", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSatConvertSToU: + { + static InstructionInfo result = {"OpSatConvertSToU", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSatConvertUToS: + { + static InstructionInfo result = {"OpSatConvertUToS", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpConvertUToPtr: + { + static InstructionInfo result = {"OpConvertUToPtr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPtrCastToGeneric: + { + static InstructionInfo result = {"OpPtrCastToGeneric", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGenericCastToPtr: + { + static InstructionInfo result = {"OpGenericCastToPtr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGenericCastToPtrExplicit: + { + static InstructionInfo result = {"OpGenericCastToPtrExplicit", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitcast: + { + static InstructionInfo result = {"OpBitcast", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSNegate: + { + static InstructionInfo result = {"OpSNegate", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFNegate: + { + static InstructionInfo result = {"OpFNegate", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIAdd: + { + static InstructionInfo result = {"OpIAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFAdd: + { + static InstructionInfo result = {"OpFAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpISub: + { + static InstructionInfo result = {"OpISub", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFSub: + { + static InstructionInfo result = {"OpFSub", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIMul: + { + static InstructionInfo result = {"OpIMul", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFMul: + { + static InstructionInfo result = {"OpFMul", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUDiv: + { + static InstructionInfo result = {"OpUDiv", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSDiv: + { + static InstructionInfo result = {"OpSDiv", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFDiv: + { + static InstructionInfo result = {"OpFDiv", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUMod: + { + static InstructionInfo result = {"OpUMod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSRem: + { + static InstructionInfo result = {"OpSRem", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSMod: + { + static InstructionInfo result = {"OpSMod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFRem: + { + static InstructionInfo result = {"OpFRem", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFMod: + { + static InstructionInfo result = {"OpFMod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpVectorTimesScalar: + { + static InstructionInfo result = {"OpVectorTimesScalar", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpMatrixTimesScalar: + { + static InstructionInfo result = {"OpMatrixTimesScalar", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpVectorTimesMatrix: + { + static InstructionInfo result = {"OpVectorTimesMatrix", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpMatrixTimesVector: + { + static InstructionInfo result = {"OpMatrixTimesVector", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpMatrixTimesMatrix: + { + static InstructionInfo result = {"OpMatrixTimesMatrix", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpOuterProduct: + { + static InstructionInfo result = {"OpOuterProduct", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDot: + { + static InstructionInfo result = {"OpDot", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIAddCarry: + { + static InstructionInfo result = {"OpIAddCarry", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpISubBorrow: + { + static InstructionInfo result = {"OpISubBorrow", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUMulExtended: + { + static InstructionInfo result = {"OpUMulExtended", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSMulExtended: + { + static InstructionInfo result = {"OpSMulExtended", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAny: + { + static InstructionInfo result = {"OpAny", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAll: + { + static InstructionInfo result = {"OpAll", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIsNan: + { + static InstructionInfo result = {"OpIsNan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIsInf: + { + static InstructionInfo result = {"OpIsInf", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIsFinite: + { + static InstructionInfo result = {"OpIsFinite", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIsNormal: + { + static InstructionInfo result = {"OpIsNormal", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSignBitSet: + { + static InstructionInfo result = {"OpSignBitSet", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLessOrGreater: + { + static InstructionInfo result = {"OpLessOrGreater", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpOrdered: + { + static InstructionInfo result = {"OpOrdered", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUnordered: + { + static InstructionInfo result = {"OpUnordered", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLogicalEqual: + { + static InstructionInfo result = {"OpLogicalEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLogicalNotEqual: + { + static InstructionInfo result = {"OpLogicalNotEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLogicalOr: + { + static InstructionInfo result = {"OpLogicalOr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLogicalAnd: + { + static InstructionInfo result = {"OpLogicalAnd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLogicalNot: + { + static InstructionInfo result = {"OpLogicalNot", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSelect: + { + static InstructionInfo result = {"OpSelect", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIEqual: + { + static InstructionInfo result = {"OpIEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpINotEqual: + { + static InstructionInfo result = {"OpINotEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUGreaterThan: + { + static InstructionInfo result = {"OpUGreaterThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSGreaterThan: + { + static InstructionInfo result = {"OpSGreaterThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpUGreaterThanEqual: + { + static InstructionInfo result = {"OpUGreaterThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSGreaterThanEqual: + { + static InstructionInfo result = {"OpSGreaterThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpULessThan: + { + static InstructionInfo result = {"OpULessThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSLessThan: + { + static InstructionInfo result = {"OpSLessThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpULessThanEqual: + { + static InstructionInfo result = {"OpULessThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSLessThanEqual: + { + static InstructionInfo result = {"OpSLessThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdEqual: + { + static InstructionInfo result = {"OpFOrdEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordEqual: + { + static InstructionInfo result = {"OpFUnordEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdNotEqual: + { + static InstructionInfo result = {"OpFOrdNotEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordNotEqual: + { + static InstructionInfo result = {"OpFUnordNotEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdLessThan: + { + static InstructionInfo result = {"OpFOrdLessThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordLessThan: + { + static InstructionInfo result = {"OpFUnordLessThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdGreaterThan: + { + static InstructionInfo result = {"OpFOrdGreaterThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordGreaterThan: + { + static InstructionInfo result = {"OpFUnordGreaterThan", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdLessThanEqual: + { + static InstructionInfo result = {"OpFOrdLessThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordLessThanEqual: + { + static InstructionInfo result = {"OpFUnordLessThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFOrdGreaterThanEqual: + { + static InstructionInfo result = {"OpFOrdGreaterThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFUnordGreaterThanEqual: + { + static InstructionInfo result = {"OpFUnordGreaterThanEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpShiftRightLogical: + { + static InstructionInfo result = {"OpShiftRightLogical", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpShiftRightArithmetic: + { + static InstructionInfo result = {"OpShiftRightArithmetic", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpShiftLeftLogical: + { + static InstructionInfo result = {"OpShiftLeftLogical", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitwiseOr: + { + static InstructionInfo result = {"OpBitwiseOr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitwiseXor: + { + static InstructionInfo result = {"OpBitwiseXor", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitwiseAnd: + { + static InstructionInfo result = {"OpBitwiseAnd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpNot: + { + static InstructionInfo result = {"OpNot", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitFieldInsert: + { + static InstructionInfo result = {"OpBitFieldInsert", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitFieldSExtract: + { + static InstructionInfo result = {"OpBitFieldSExtract", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitFieldUExtract: + { + static InstructionInfo result = {"OpBitFieldUExtract", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitReverse: + { + static InstructionInfo result = {"OpBitReverse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBitCount: + { + static InstructionInfo result = {"OpBitCount", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdx: + { + static InstructionInfo result = {"OpDPdx", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdy: + { + static InstructionInfo result = {"OpDPdy", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFwidth: + { + static InstructionInfo result = {"OpFwidth", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdxFine: + { + static InstructionInfo result = {"OpDPdxFine", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdyFine: + { + static InstructionInfo result = {"OpDPdyFine", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFwidthFine: + { + static InstructionInfo result = {"OpFwidthFine", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdxCoarse: + { + static InstructionInfo result = {"OpDPdxCoarse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpDPdyCoarse: + { + static InstructionInfo result = {"OpDPdyCoarse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpFwidthCoarse: + { + static InstructionInfo result = {"OpFwidthCoarse", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpEmitVertex: + { + static InstructionInfo result = { + "OpEmitVertex", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpEndPrimitive: + { + static InstructionInfo result = { + "OpEndPrimitive", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpEmitStreamVertex: + { + static InstructionInfo result = { + "OpEmitStreamVertex", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpEndStreamPrimitive: + { + static InstructionInfo result = { + "OpEndStreamPrimitive", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpControlBarrier: + { + static InstructionInfo result = { + "OpControlBarrier", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpMemoryBarrier: + { + static InstructionInfo result = { + "OpMemoryBarrier", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpAtomicLoad: + { + static InstructionInfo result = {"OpAtomicLoad", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicStore: + { + static InstructionInfo result = { + "OpAtomicStore", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpAtomicExchange: + { + static InstructionInfo result = {"OpAtomicExchange", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicCompareExchange: + { + static InstructionInfo result = {"OpAtomicCompareExchange", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicCompareExchangeWeak: + { + static InstructionInfo result = {"OpAtomicCompareExchangeWeak", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicIIncrement: + { + static InstructionInfo result = {"OpAtomicIIncrement", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicIDecrement: + { + static InstructionInfo result = {"OpAtomicIDecrement", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicIAdd: + { + static InstructionInfo result = {"OpAtomicIAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicISub: + { + static InstructionInfo result = {"OpAtomicISub", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicSMin: + { + static InstructionInfo result = {"OpAtomicSMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicUMin: + { + static InstructionInfo result = {"OpAtomicUMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicSMax: + { + static InstructionInfo result = {"OpAtomicSMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicUMax: + { + static InstructionInfo result = {"OpAtomicUMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicAnd: + { + static InstructionInfo result = {"OpAtomicAnd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicOr: + { + static InstructionInfo result = {"OpAtomicOr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicXor: + { + static InstructionInfo result = {"OpAtomicXor", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPhi: + { + static InstructionInfo result = {"OpPhi", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpLoopMerge: + { + static InstructionInfo result = {"OpLoopMerge", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpSelectionMerge: + { + static InstructionInfo result = { + "OpSelectionMerge", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpLabel: + { + static InstructionInfo result = { + "OpLabel", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpBranch: + { + static InstructionInfo result = {"OpBranch", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpBranchConditional: + { + static InstructionInfo result = { + "OpBranchConditional", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpSwitch: + { + static InstructionInfo result = {"OpSwitch", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpKill: + { + static InstructionInfo result = {"OpKill", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpReturn: + { + static InstructionInfo result = {"OpReturn", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpReturnValue: + { + static InstructionInfo result = { + "OpReturnValue", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpUnreachable: + { + static InstructionInfo result = { + "OpUnreachable", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpLifetimeStart: + { + static InstructionInfo result = { + "OpLifetimeStart", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpLifetimeStop: + { + static InstructionInfo result = { + "OpLifetimeStop", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGroupAsyncCopy: + { + static InstructionInfo result = {"OpGroupAsyncCopy", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupWaitEvents: + { + static InstructionInfo result = { + "OpGroupWaitEvents", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGroupAll: + { + static InstructionInfo result = {"OpGroupAll", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupAny: + { + static InstructionInfo result = {"OpGroupAny", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupBroadcast: + { + static InstructionInfo result = {"OpGroupBroadcast", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupIAdd: + { + static InstructionInfo result = {"OpGroupIAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupFAdd: + { + static InstructionInfo result = {"OpGroupFAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupFMin: + { + static InstructionInfo result = {"OpGroupFMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupUMin: + { + static InstructionInfo result = {"OpGroupUMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupSMin: + { + static InstructionInfo result = {"OpGroupSMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupFMax: + { + static InstructionInfo result = {"OpGroupFMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupUMax: + { + static InstructionInfo result = {"OpGroupUMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupSMax: + { + static InstructionInfo result = {"OpGroupSMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpReadPipe: + { + static InstructionInfo result = {"OpReadPipe", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpWritePipe: + { + static InstructionInfo result = {"OpWritePipe", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpReservedReadPipe: + { + static InstructionInfo result = {"OpReservedReadPipe", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpReservedWritePipe: + { + static InstructionInfo result = {"OpReservedWritePipe", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpReserveReadPipePackets: + { + static InstructionInfo result = {"OpReserveReadPipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpReserveWritePipePackets: + { + static InstructionInfo result = {"OpReserveWritePipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCommitReadPipe: + { + static InstructionInfo result = { + "OpCommitReadPipe", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCommitWritePipe: + { + static InstructionInfo result = { + "OpCommitWritePipe", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpIsValidReserveId: + { + static InstructionInfo result = {"OpIsValidReserveId", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetNumPipePackets: + { + static InstructionInfo result = {"OpGetNumPipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetMaxPipePackets: + { + static InstructionInfo result = {"OpGetMaxPipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupReserveReadPipePackets: + { + static InstructionInfo result = {"OpGroupReserveReadPipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupReserveWritePipePackets: + { + static InstructionInfo result = {"OpGroupReserveWritePipePackets", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupCommitReadPipe: + { + static InstructionInfo result = { + "OpGroupCommitReadPipe", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGroupCommitWritePipe: + { + static InstructionInfo result = { + "OpGroupCommitWritePipe", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpEnqueueMarker: + { + static InstructionInfo result = {"OpEnqueueMarker", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpEnqueueKernel: + { + static InstructionInfo result = {"OpEnqueueKernel", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelNDrangeSubGroupCount: + { + static InstructionInfo result = {"OpGetKernelNDrangeSubGroupCount", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelNDrangeMaxSubGroupSize: + { + static InstructionInfo result = {"OpGetKernelNDrangeMaxSubGroupSize", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelWorkGroupSize: + { + static InstructionInfo result = {"OpGetKernelWorkGroupSize", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple: + { + static InstructionInfo result = { + "OpGetKernelPreferredWorkGroupSizeMultiple", + InstructionFlags::HasResult | InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpRetainEvent: + { + static InstructionInfo result = { + "OpRetainEvent", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpReleaseEvent: + { + static InstructionInfo result = { + "OpReleaseEvent", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCreateUserEvent: + { + static InstructionInfo result = {"OpCreateUserEvent", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpIsValidEvent: + { + static InstructionInfo result = {"OpIsValidEvent", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSetUserEventStatus: + { + static InstructionInfo result = { + "OpSetUserEventStatus", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpCaptureEventProfilingInfo: + { + static InstructionInfo result = { + "OpCaptureEventProfilingInfo", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGetDefaultQueue: + { + static InstructionInfo result = {"OpGetDefaultQueue", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpBuildNDRange: + { + static InstructionInfo result = {"OpBuildNDRange", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleImplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleExplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleDrefImplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleDrefImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleDrefExplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleDrefExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleProjImplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleProjImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleProjExplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleProjExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleProjDrefImplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleProjDrefImplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseSampleProjDrefExplicitLod: + { + static InstructionInfo result = {"OpImageSparseSampleProjDrefExplicitLod", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseFetch: + { + static InstructionInfo result = {"OpImageSparseFetch", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseGather: + { + static InstructionInfo result = {"OpImageSparseGather", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseDrefGather: + { + static InstructionInfo result = {"OpImageSparseDrefGather", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpImageSparseTexelsResident: + { + static InstructionInfo result = {"OpImageSparseTexelsResident", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpNoLine: + { + static InstructionInfo result = {"OpNoLine", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpAtomicFlagTestAndSet: + { + static InstructionInfo result = {"OpAtomicFlagTestAndSet", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpAtomicFlagClear: + { + static InstructionInfo result = { + "OpAtomicFlagClear", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpImageSparseRead: + { + static InstructionInfo result = {"OpImageSparseRead", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpSizeOf: + { + static InstructionInfo result = {"OpSizeOf", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpTypePipeStorage: + { + static InstructionInfo result = { + "OpTypePipeStorage", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpConstantPipeStorage: + { + static InstructionInfo result = {"OpConstantPipeStorage", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCreatePipeFromPipeStorage: + { + static InstructionInfo result = {"OpCreatePipeFromPipeStorage", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelLocalSizeForSubgroupCount: + { + static InstructionInfo result = {"OpGetKernelLocalSizeForSubgroupCount", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGetKernelMaxNumSubgroups: + { + static InstructionInfo result = {"OpGetKernelMaxNumSubgroups", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpTypeNamedBarrier: + { + static InstructionInfo result = { + "OpTypeNamedBarrier", InstructionFlags::HasResult, {}}; + return &result; + } + case spv::Op::OpNamedBarrierInitialize: + { + static InstructionInfo result = {"OpNamedBarrierInitialize", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpMemoryNamedBarrier: + { + static InstructionInfo result = { + "OpMemoryNamedBarrier", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpModuleProcessed: + { + static InstructionInfo result = { + "OpModuleProcessed", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpExecutionModeId: + { + static InstructionInfo result = { + "OpExecutionModeId", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpDecorateId: + { + static InstructionInfo result = { + "OpDecorateId", InstructionFlags::None, {}}; + return &result; + } + case spv::Op::OpGroupNonUniformElect: + { + static InstructionInfo result = {"OpGroupNonUniformElect", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformAll: + { + static InstructionInfo result = {"OpGroupNonUniformAll", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformAny: + { + static InstructionInfo result = {"OpGroupNonUniformAny", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformAllEqual: + { + static InstructionInfo result = {"OpGroupNonUniformAllEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBroadcast: + { + static InstructionInfo result = {"OpGroupNonUniformBroadcast", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBroadcastFirst: + { + static InstructionInfo result = {"OpGroupNonUniformBroadcastFirst", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBallot: + { + static InstructionInfo result = {"OpGroupNonUniformBallot", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformInverseBallot: + { + static InstructionInfo result = {"OpGroupNonUniformInverseBallot", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBallotBitExtract: + { + static InstructionInfo result = {"OpGroupNonUniformBallotBitExtract", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBallotBitCount: + { + static InstructionInfo result = {"OpGroupNonUniformBallotBitCount", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBallotFindLSB: + { + static InstructionInfo result = {"OpGroupNonUniformBallotFindLSB", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBallotFindMSB: + { + static InstructionInfo result = {"OpGroupNonUniformBallotFindMSB", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformShuffle: + { + static InstructionInfo result = {"OpGroupNonUniformShuffle", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformShuffleXor: + { + static InstructionInfo result = {"OpGroupNonUniformShuffleXor", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformShuffleUp: + { + static InstructionInfo result = {"OpGroupNonUniformShuffleUp", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformShuffleDown: + { + static InstructionInfo result = {"OpGroupNonUniformShuffleDown", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformIAdd: + { + static InstructionInfo result = {"OpGroupNonUniformIAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformFAdd: + { + static InstructionInfo result = {"OpGroupNonUniformFAdd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformIMul: + { + static InstructionInfo result = {"OpGroupNonUniformIMul", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformFMul: + { + static InstructionInfo result = {"OpGroupNonUniformFMul", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformSMin: + { + static InstructionInfo result = {"OpGroupNonUniformSMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformUMin: + { + static InstructionInfo result = {"OpGroupNonUniformUMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformFMin: + { + static InstructionInfo result = {"OpGroupNonUniformFMin", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformSMax: + { + static InstructionInfo result = {"OpGroupNonUniformSMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformUMax: + { + static InstructionInfo result = {"OpGroupNonUniformUMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformFMax: + { + static InstructionInfo result = {"OpGroupNonUniformFMax", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBitwiseAnd: + { + static InstructionInfo result = {"OpGroupNonUniformBitwiseAnd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBitwiseOr: + { + static InstructionInfo result = {"OpGroupNonUniformBitwiseOr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformBitwiseXor: + { + static InstructionInfo result = {"OpGroupNonUniformBitwiseXor", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformLogicalAnd: + { + static InstructionInfo result = {"OpGroupNonUniformLogicalAnd", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformLogicalOr: + { + static InstructionInfo result = {"OpGroupNonUniformLogicalOr", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformLogicalXor: + { + static InstructionInfo result = {"OpGroupNonUniformLogicalXor", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformQuadBroadcast: + { + static InstructionInfo result = {"OpGroupNonUniformQuadBroadcast", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpGroupNonUniformQuadSwap: + { + static InstructionInfo result = {"OpGroupNonUniformQuadSwap", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpCopyLogical: + { + static InstructionInfo result = {"OpCopyLogical", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPtrEqual: + { + static InstructionInfo result = {"OpPtrEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPtrNotEqual: + { + static InstructionInfo result = {"OpPtrNotEqual", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + case spv::Op::OpPtrDiff: + { + static InstructionInfo result = {"OpPtrDiff", + InstructionFlags::HasResult | + InstructionFlags::HasResultType, + {}}; + return &result; + } + } - return nullptr; -} + return nullptr; + } -inline void dump(std::span range, - void (*printId)(std::uint32_t id) = nullptr) { - if (printId == nullptr) { - printId = [](uint32_t id) { std::printf("%%%u", id); }; - } + inline void dump(std::span range, + void (*printId)(std::uint32_t id) = nullptr) + { + if (printId == nullptr) + { + printId = [](uint32_t id) { std::printf("%%%u", id); }; + } - while (!range.empty()) { - auto opWordCount = range[0]; - auto op = static_cast(opWordCount & spv::OpCodeMask); - auto wordCount = opWordCount >> spv::WordCountShift; + while (!range.empty()) + { + auto opWordCount = range[0]; + auto op = static_cast(opWordCount & spv::OpCodeMask); + auto wordCount = opWordCount >> spv::WordCountShift; - if (range.size() < wordCount || wordCount == 0) { - std::printf("\n"); + if (range.size() < wordCount || wordCount == 0) + { + std::printf("\n"); - for (auto word : range) { - std::printf("%08x ", (unsigned)word); - } + for (auto word : range) + { + std::printf("%08x ", (unsigned)word); + } - std::printf("\n"); + std::printf("\n"); - break; - } + break; + } - auto info = getInstructionInfo(op); + auto info = getInstructionInfo(op); - if (info == nullptr) { - std::printf("unknown instruction\n"); - range = range.subspan(wordCount); - continue; - } + if (info == nullptr) + { + std::printf("unknown instruction\n"); + range = range.subspan(wordCount); + continue; + } - auto word = range.data() + 1; - auto wordEnd = range.data() + wordCount; - bool isFirst = true; + auto word = range.data() + 1; + auto wordEnd = range.data() + wordCount; + bool isFirst = true; - if ((info->flags & InstructionFlags::HasResult) == - InstructionFlags::HasResult) { - std::uint32_t outputTypeId = 0; + if ((info->flags & InstructionFlags::HasResult) == + InstructionFlags::HasResult) + { + std::uint32_t outputTypeId = 0; - if ((info->flags & InstructionFlags::HasResultType) == - InstructionFlags::HasResultType) { - if (word < wordEnd) { - outputTypeId = *word++; - } - } + if ((info->flags & InstructionFlags::HasResultType) == + InstructionFlags::HasResultType) + { + if (word < wordEnd) + { + outputTypeId = *word++; + } + } - std::uint32_t outputId = word < wordEnd ? *word++ : 0; + std::uint32_t outputId = word < wordEnd ? *word++ : 0; - printId(outputId); - if ((info->flags & InstructionFlags::HasResultType) == - InstructionFlags::HasResultType) { - std::printf(": "); - printId(outputTypeId); - } + printId(outputId); + if ((info->flags & InstructionFlags::HasResultType) == + InstructionFlags::HasResultType) + { + std::printf(": "); + printId(outputTypeId); + } - std::printf(" = "); - } + std::printf(" = "); + } - std::printf("%s(", info->name); + std::printf("%s(", info->name); - for (auto &op : std::span(info->operands)) { - if (op == OperandKind::Invalid) { - break; - } + for (auto& op : std::span(info->operands)) + { + if (op == OperandKind::Invalid) + { + break; + } - if (word >= wordEnd) { - if (op == OperandKind::VariadicWord || op == OperandKind::VariadicId) { - break; - } + if (word >= wordEnd) + { + if (op == OperandKind::VariadicWord || op == OperandKind::VariadicId) + { + break; + } - std::printf("\n"); - break; - } + std::printf("\n"); + break; + } - auto currentWord = *word++; + auto currentWord = *word++; - if (isFirst) { - isFirst = false; - } else { - std::printf(", "); - } + if (isFirst) + { + isFirst = false; + } + else + { + std::printf(", "); + } - if (op == OperandKind::VariadicId || op == OperandKind::TypeId || - op == OperandKind::ValueId) { - printId(currentWord); - } else if (op == OperandKind::Word || op == OperandKind::VariadicWord) { - std::printf("%u", currentWord); - } else if (op == OperandKind::String) { - bool foundEnd = false; - while (true) { - if (reinterpret_cast(currentWord)[3] == '\0') { - foundEnd = true; - break; - } + if (op == OperandKind::VariadicId || op == OperandKind::TypeId || + op == OperandKind::ValueId) + { + printId(currentWord); + } + else if (op == OperandKind::Word || op == OperandKind::VariadicWord) + { + std::printf("%u", currentWord); + } + else if (op == OperandKind::String) + { + bool foundEnd = false; + while (true) + { + if (reinterpret_cast(currentWord)[3] == '\0') + { + foundEnd = true; + break; + } - if (word >= wordEnd) { - break; - } + if (word >= wordEnd) + { + break; + } - currentWord = *word++; - } + currentWord = *word++; + } - if (foundEnd) { - std::printf("'%s'", reinterpret_cast(word - 1)); - } else { - std::printf(""); - } - } else { - std::printf(""); - } - } + if (foundEnd) + { + std::printf("'%s'", reinterpret_cast(word - 1)); + } + else + { + std::printf(""); + } + } + else + { + std::printf(""); + } + } - while (word < wordEnd) { - if (isFirst) { - isFirst = false; - } else { - std::printf(", "); - } + while (word < wordEnd) + { + if (isFirst) + { + isFirst = false; + } + else + { + std::printf(", "); + } - auto currentWord = *word++; + auto currentWord = *word++; - std::printf("%u", currentWord); - } + std::printf("%u", currentWord); + } - std::printf(")\n"); - range = range.subspan(wordCount); - } -} + std::printf(")\n"); + range = range.subspan(wordCount); + } + } } // namespace spirv \ No newline at end of file diff --git a/hw/amdgpu/lib/libspirv/include/spirv/spirv.hpp b/hw/amdgpu/lib/libspirv/include/spirv/spirv.hpp index 242b2e09..2d23fbc5 100644 --- a/hw/amdgpu/lib/libspirv/include/spirv/spirv.hpp +++ b/hw/amdgpu/lib/libspirv/include/spirv/spirv.hpp @@ -50,4918 +50,5012 @@ #ifndef spirv_HPP #define spirv_HPP -namespace spv { +namespace spv +{ -typedef unsigned int Id; + typedef unsigned int Id; #define SPV_VERSION 0x10600 #define SPV_REVISION 1 -static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010600; -static const unsigned int Revision = 1; -static const unsigned int OpCodeMask = 0xffff; -static const unsigned int WordCountShift = 16; + static const unsigned int MagicNumber = 0x07230203; + static const unsigned int Version = 0x00010600; + static const unsigned int Revision = 1; + static const unsigned int OpCodeMask = 0xffff; + static const unsigned int WordCountShift = 16; -enum class SourceLanguage : unsigned { - Unknown = 0, - ESSL = 1, - GLSL = 2, - OpenCL_C = 3, - OpenCL_CPP = 4, - HLSL = 5, - CPP_for_OpenCL = 6, - SYCL = 7, - HERO_C = 8, - Max = 0x7fffffff, -}; + enum class SourceLanguage : unsigned + { + Unknown = 0, + ESSL = 1, + GLSL = 2, + OpenCL_C = 3, + OpenCL_CPP = 4, + HLSL = 5, + CPP_for_OpenCL = 6, + SYCL = 7, + HERO_C = 8, + Max = 0x7fffffff, + }; -enum class ExecutionModel : unsigned { - Vertex = 0, - TessellationControl = 1, - TessellationEvaluation = 2, - Geometry = 3, - Fragment = 4, - GLCompute = 5, - Kernel = 6, - TaskNV = 5267, - MeshNV = 5268, - RayGenerationKHR = 5313, - RayGenerationNV = 5313, - IntersectionKHR = 5314, - IntersectionNV = 5314, - AnyHitKHR = 5315, - AnyHitNV = 5315, - ClosestHitKHR = 5316, - ClosestHitNV = 5316, - MissKHR = 5317, - MissNV = 5317, - CallableKHR = 5318, - CallableNV = 5318, - TaskEXT = 5364, - MeshEXT = 5365, - Max = 0x7fffffff, -}; + enum class ExecutionModel : unsigned + { + Vertex = 0, + TessellationControl = 1, + TessellationEvaluation = 2, + Geometry = 3, + Fragment = 4, + GLCompute = 5, + Kernel = 6, + TaskNV = 5267, + MeshNV = 5268, + RayGenerationKHR = 5313, + RayGenerationNV = 5313, + IntersectionKHR = 5314, + IntersectionNV = 5314, + AnyHitKHR = 5315, + AnyHitNV = 5315, + ClosestHitKHR = 5316, + ClosestHitNV = 5316, + MissKHR = 5317, + MissNV = 5317, + CallableKHR = 5318, + CallableNV = 5318, + TaskEXT = 5364, + MeshEXT = 5365, + Max = 0x7fffffff, + }; -enum class AddressingModel : unsigned { - Logical = 0, - Physical32 = 1, - Physical64 = 2, - PhysicalStorageBuffer64 = 5348, - PhysicalStorageBuffer64EXT = 5348, - Max = 0x7fffffff, -}; + enum class AddressingModel : unsigned + { + Logical = 0, + Physical32 = 1, + Physical64 = 2, + PhysicalStorageBuffer64 = 5348, + PhysicalStorageBuffer64EXT = 5348, + Max = 0x7fffffff, + }; -enum class MemoryModel : unsigned { - Simple = 0, - GLSL450 = 1, - OpenCL = 2, - Vulkan = 3, - VulkanKHR = 3, - Max = 0x7fffffff, -}; + enum class MemoryModel : unsigned + { + Simple = 0, + GLSL450 = 1, + OpenCL = 2, + Vulkan = 3, + VulkanKHR = 3, + Max = 0x7fffffff, + }; -enum class ExecutionMode : unsigned { - Invocations = 0, - SpacingEqual = 1, - SpacingFractionalEven = 2, - SpacingFractionalOdd = 3, - VertexOrderCw = 4, - VertexOrderCcw = 5, - PixelCenterInteger = 6, - OriginUpperLeft = 7, - OriginLowerLeft = 8, - EarlyFragmentTests = 9, - PointMode = 10, - Xfb = 11, - DepthReplacing = 12, - DepthGreater = 14, - DepthLess = 15, - DepthUnchanged = 16, - LocalSize = 17, - LocalSizeHint = 18, - InputPoints = 19, - InputLines = 20, - InputLinesAdjacency = 21, - Triangles = 22, - InputTrianglesAdjacency = 23, - Quads = 24, - Isolines = 25, - OutputVertices = 26, - OutputPoints = 27, - OutputLineStrip = 28, - OutputTriangleStrip = 29, - VecTypeHint = 30, - ContractionOff = 31, - Initializer = 33, - Finalizer = 34, - SubgroupSize = 35, - SubgroupsPerWorkgroup = 36, - SubgroupsPerWorkgroupId = 37, - LocalSizeId = 38, - LocalSizeHintId = 39, - NonCoherentColorAttachmentReadEXT = 4169, - NonCoherentDepthAttachmentReadEXT = 4170, - NonCoherentStencilAttachmentReadEXT = 4171, - SubgroupUniformControlFlowKHR = 4421, - PostDepthCoverage = 4446, - DenormPreserve = 4459, - DenormFlushToZero = 4460, - SignedZeroInfNanPreserve = 4461, - RoundingModeRTE = 4462, - RoundingModeRTZ = 4463, - EarlyAndLateFragmentTestsAMD = 5017, - StencilRefReplacingEXT = 5027, - StencilRefUnchangedFrontAMD = 5079, - StencilRefGreaterFrontAMD = 5080, - StencilRefLessFrontAMD = 5081, - StencilRefUnchangedBackAMD = 5082, - StencilRefGreaterBackAMD = 5083, - StencilRefLessBackAMD = 5084, - OutputLinesEXT = 5269, - OutputLinesNV = 5269, - OutputPrimitivesEXT = 5270, - OutputPrimitivesNV = 5270, - DerivativeGroupQuadsNV = 5289, - DerivativeGroupLinearNV = 5290, - OutputTrianglesEXT = 5298, - OutputTrianglesNV = 5298, - PixelInterlockOrderedEXT = 5366, - PixelInterlockUnorderedEXT = 5367, - SampleInterlockOrderedEXT = 5368, - SampleInterlockUnorderedEXT = 5369, - ShadingRateInterlockOrderedEXT = 5370, - ShadingRateInterlockUnorderedEXT = 5371, - SharedLocalMemorySizeINTEL = 5618, - RoundingModeRTPINTEL = 5620, - RoundingModeRTNINTEL = 5621, - FloatingPointModeALTINTEL = 5622, - FloatingPointModeIEEEINTEL = 5623, - MaxWorkgroupSizeINTEL = 5893, - MaxWorkDimINTEL = 5894, - NoGlobalOffsetINTEL = 5895, - NumSIMDWorkitemsINTEL = 5896, - SchedulerTargetFmaxMhzINTEL = 5903, - StreamingInterfaceINTEL = 6154, - RegisterMapInterfaceINTEL = 6160, - NamedBarrierCountINTEL = 6417, - Max = 0x7fffffff, -}; + enum class ExecutionMode : unsigned + { + Invocations = 0, + SpacingEqual = 1, + SpacingFractionalEven = 2, + SpacingFractionalOdd = 3, + VertexOrderCw = 4, + VertexOrderCcw = 5, + PixelCenterInteger = 6, + OriginUpperLeft = 7, + OriginLowerLeft = 8, + EarlyFragmentTests = 9, + PointMode = 10, + Xfb = 11, + DepthReplacing = 12, + DepthGreater = 14, + DepthLess = 15, + DepthUnchanged = 16, + LocalSize = 17, + LocalSizeHint = 18, + InputPoints = 19, + InputLines = 20, + InputLinesAdjacency = 21, + Triangles = 22, + InputTrianglesAdjacency = 23, + Quads = 24, + Isolines = 25, + OutputVertices = 26, + OutputPoints = 27, + OutputLineStrip = 28, + OutputTriangleStrip = 29, + VecTypeHint = 30, + ContractionOff = 31, + Initializer = 33, + Finalizer = 34, + SubgroupSize = 35, + SubgroupsPerWorkgroup = 36, + SubgroupsPerWorkgroupId = 37, + LocalSizeId = 38, + LocalSizeHintId = 39, + NonCoherentColorAttachmentReadEXT = 4169, + NonCoherentDepthAttachmentReadEXT = 4170, + NonCoherentStencilAttachmentReadEXT = 4171, + SubgroupUniformControlFlowKHR = 4421, + PostDepthCoverage = 4446, + DenormPreserve = 4459, + DenormFlushToZero = 4460, + SignedZeroInfNanPreserve = 4461, + RoundingModeRTE = 4462, + RoundingModeRTZ = 4463, + EarlyAndLateFragmentTestsAMD = 5017, + StencilRefReplacingEXT = 5027, + StencilRefUnchangedFrontAMD = 5079, + StencilRefGreaterFrontAMD = 5080, + StencilRefLessFrontAMD = 5081, + StencilRefUnchangedBackAMD = 5082, + StencilRefGreaterBackAMD = 5083, + StencilRefLessBackAMD = 5084, + OutputLinesEXT = 5269, + OutputLinesNV = 5269, + OutputPrimitivesEXT = 5270, + OutputPrimitivesNV = 5270, + DerivativeGroupQuadsNV = 5289, + DerivativeGroupLinearNV = 5290, + OutputTrianglesEXT = 5298, + OutputTrianglesNV = 5298, + PixelInterlockOrderedEXT = 5366, + PixelInterlockUnorderedEXT = 5367, + SampleInterlockOrderedEXT = 5368, + SampleInterlockUnorderedEXT = 5369, + ShadingRateInterlockOrderedEXT = 5370, + ShadingRateInterlockUnorderedEXT = 5371, + SharedLocalMemorySizeINTEL = 5618, + RoundingModeRTPINTEL = 5620, + RoundingModeRTNINTEL = 5621, + FloatingPointModeALTINTEL = 5622, + FloatingPointModeIEEEINTEL = 5623, + MaxWorkgroupSizeINTEL = 5893, + MaxWorkDimINTEL = 5894, + NoGlobalOffsetINTEL = 5895, + NumSIMDWorkitemsINTEL = 5896, + SchedulerTargetFmaxMhzINTEL = 5903, + StreamingInterfaceINTEL = 6154, + RegisterMapInterfaceINTEL = 6160, + NamedBarrierCountINTEL = 6417, + Max = 0x7fffffff, + }; -enum class StorageClass : unsigned { - UniformConstant = 0, - Input = 1, - Uniform = 2, - Output = 3, - Workgroup = 4, - CrossWorkgroup = 5, - Private = 6, - Function = 7, - Generic = 8, - PushConstant = 9, - AtomicCounter = 10, - Image = 11, - StorageBuffer = 12, - TileImageEXT = 4172, - CallableDataKHR = 5328, - CallableDataNV = 5328, - IncomingCallableDataKHR = 5329, - IncomingCallableDataNV = 5329, - RayPayloadKHR = 5338, - RayPayloadNV = 5338, - HitAttributeKHR = 5339, - HitAttributeNV = 5339, - IncomingRayPayloadKHR = 5342, - IncomingRayPayloadNV = 5342, - ShaderRecordBufferKHR = 5343, - ShaderRecordBufferNV = 5343, - PhysicalStorageBuffer = 5349, - PhysicalStorageBufferEXT = 5349, - HitObjectAttributeNV = 5385, - TaskPayloadWorkgroupEXT = 5402, - CodeSectionINTEL = 5605, - DeviceOnlyINTEL = 5936, - HostOnlyINTEL = 5937, - Max = 0x7fffffff, -}; + enum class StorageClass : unsigned + { + UniformConstant = 0, + Input = 1, + Uniform = 2, + Output = 3, + Workgroup = 4, + CrossWorkgroup = 5, + Private = 6, + Function = 7, + Generic = 8, + PushConstant = 9, + AtomicCounter = 10, + Image = 11, + StorageBuffer = 12, + TileImageEXT = 4172, + CallableDataKHR = 5328, + CallableDataNV = 5328, + IncomingCallableDataKHR = 5329, + IncomingCallableDataNV = 5329, + RayPayloadKHR = 5338, + RayPayloadNV = 5338, + HitAttributeKHR = 5339, + HitAttributeNV = 5339, + IncomingRayPayloadKHR = 5342, + IncomingRayPayloadNV = 5342, + ShaderRecordBufferKHR = 5343, + ShaderRecordBufferNV = 5343, + PhysicalStorageBuffer = 5349, + PhysicalStorageBufferEXT = 5349, + HitObjectAttributeNV = 5385, + TaskPayloadWorkgroupEXT = 5402, + CodeSectionINTEL = 5605, + DeviceOnlyINTEL = 5936, + HostOnlyINTEL = 5937, + Max = 0x7fffffff, + }; -enum class Dim : unsigned { - Dim1D = 0, - Dim2D = 1, - Dim3D = 2, - Cube = 3, - Rect = 4, - Buffer = 5, - SubpassData = 6, - TileImageDataEXT = 4173, - Max = 0x7fffffff, -}; + enum class Dim : unsigned + { + Dim1D = 0, + Dim2D = 1, + Dim3D = 2, + Cube = 3, + Rect = 4, + Buffer = 5, + SubpassData = 6, + TileImageDataEXT = 4173, + Max = 0x7fffffff, + }; -enum class SamplerAddressingMode : unsigned { - None = 0, - ClampToEdge = 1, - Clamp = 2, - Repeat = 3, - RepeatMirrored = 4, - Max = 0x7fffffff, -}; + enum class SamplerAddressingMode : unsigned + { + None = 0, + ClampToEdge = 1, + Clamp = 2, + Repeat = 3, + RepeatMirrored = 4, + Max = 0x7fffffff, + }; -enum class SamplerFilterMode : unsigned { - Nearest = 0, - Linear = 1, - Max = 0x7fffffff, -}; + enum class SamplerFilterMode : unsigned + { + Nearest = 0, + Linear = 1, + Max = 0x7fffffff, + }; -enum class ImageFormat : unsigned { - Unknown = 0, - Rgba32f = 1, - Rgba16f = 2, - R32f = 3, - Rgba8 = 4, - Rgba8Snorm = 5, - Rg32f = 6, - Rg16f = 7, - R11fG11fB10f = 8, - R16f = 9, - Rgba16 = 10, - Rgb10A2 = 11, - Rg16 = 12, - Rg8 = 13, - R16 = 14, - R8 = 15, - Rgba16Snorm = 16, - Rg16Snorm = 17, - Rg8Snorm = 18, - R16Snorm = 19, - R8Snorm = 20, - Rgba32i = 21, - Rgba16i = 22, - Rgba8i = 23, - R32i = 24, - Rg32i = 25, - Rg16i = 26, - Rg8i = 27, - R16i = 28, - R8i = 29, - Rgba32ui = 30, - Rgba16ui = 31, - Rgba8ui = 32, - R32ui = 33, - Rgb10a2ui = 34, - Rg32ui = 35, - Rg16ui = 36, - Rg8ui = 37, - R16ui = 38, - R8ui = 39, - R64ui = 40, - R64i = 41, - Max = 0x7fffffff, -}; + enum class ImageFormat : unsigned + { + Unknown = 0, + Rgba32f = 1, + Rgba16f = 2, + R32f = 3, + Rgba8 = 4, + Rgba8Snorm = 5, + Rg32f = 6, + Rg16f = 7, + R11fG11fB10f = 8, + R16f = 9, + Rgba16 = 10, + Rgb10A2 = 11, + Rg16 = 12, + Rg8 = 13, + R16 = 14, + R8 = 15, + Rgba16Snorm = 16, + Rg16Snorm = 17, + Rg8Snorm = 18, + R16Snorm = 19, + R8Snorm = 20, + Rgba32i = 21, + Rgba16i = 22, + Rgba8i = 23, + R32i = 24, + Rg32i = 25, + Rg16i = 26, + Rg8i = 27, + R16i = 28, + R8i = 29, + Rgba32ui = 30, + Rgba16ui = 31, + Rgba8ui = 32, + R32ui = 33, + Rgb10a2ui = 34, + Rg32ui = 35, + Rg16ui = 36, + Rg8ui = 37, + R16ui = 38, + R8ui = 39, + R64ui = 40, + R64i = 41, + Max = 0x7fffffff, + }; -enum class ImageChannelOrder : unsigned { - R = 0, - A = 1, - RG = 2, - RA = 3, - RGB = 4, - RGBA = 5, - BGRA = 6, - ARGB = 7, - Intensity = 8, - Luminance = 9, - Rx = 10, - RGx = 11, - RGBx = 12, - Depth = 13, - DepthStencil = 14, - sRGB = 15, - sRGBx = 16, - sRGBA = 17, - sBGRA = 18, - ABGR = 19, - Max = 0x7fffffff, -}; + enum class ImageChannelOrder : unsigned + { + R = 0, + A = 1, + RG = 2, + RA = 3, + RGB = 4, + RGBA = 5, + BGRA = 6, + ARGB = 7, + Intensity = 8, + Luminance = 9, + Rx = 10, + RGx = 11, + RGBx = 12, + Depth = 13, + DepthStencil = 14, + sRGB = 15, + sRGBx = 16, + sRGBA = 17, + sBGRA = 18, + ABGR = 19, + Max = 0x7fffffff, + }; -enum class ImageChannelDataType : unsigned { - SnormInt8 = 0, - SnormInt16 = 1, - UnormInt8 = 2, - UnormInt16 = 3, - UnormShort565 = 4, - UnormShort555 = 5, - UnormInt101010 = 6, - SignedInt8 = 7, - SignedInt16 = 8, - SignedInt32 = 9, - UnsignedInt8 = 10, - UnsignedInt16 = 11, - UnsignedInt32 = 12, - HalfFloat = 13, - Float = 14, - UnormInt24 = 15, - UnormInt101010_2 = 16, - Max = 0x7fffffff, -}; + enum class ImageChannelDataType : unsigned + { + SnormInt8 = 0, + SnormInt16 = 1, + UnormInt8 = 2, + UnormInt16 = 3, + UnormShort565 = 4, + UnormShort555 = 5, + UnormInt101010 = 6, + SignedInt8 = 7, + SignedInt16 = 8, + SignedInt32 = 9, + UnsignedInt8 = 10, + UnsignedInt16 = 11, + UnsignedInt32 = 12, + HalfFloat = 13, + Float = 14, + UnormInt24 = 15, + UnormInt101010_2 = 16, + Max = 0x7fffffff, + }; -enum class ImageOperandsShift : unsigned { - Bias = 0, - Lod = 1, - Grad = 2, - ConstOffset = 3, - Offset = 4, - ConstOffsets = 5, - Sample = 6, - MinLod = 7, - MakeTexelAvailable = 8, - MakeTexelAvailableKHR = 8, - MakeTexelVisible = 9, - MakeTexelVisibleKHR = 9, - NonPrivateTexel = 10, - NonPrivateTexelKHR = 10, - VolatileTexel = 11, - VolatileTexelKHR = 11, - SignExtend = 12, - ZeroExtend = 13, - Nontemporal = 14, - Offsets = 16, - Max = 0x7fffffff, -}; + enum class ImageOperandsShift : unsigned + { + Bias = 0, + Lod = 1, + Grad = 2, + ConstOffset = 3, + Offset = 4, + ConstOffsets = 5, + Sample = 6, + MinLod = 7, + MakeTexelAvailable = 8, + MakeTexelAvailableKHR = 8, + MakeTexelVisible = 9, + MakeTexelVisibleKHR = 9, + NonPrivateTexel = 10, + NonPrivateTexelKHR = 10, + VolatileTexel = 11, + VolatileTexelKHR = 11, + SignExtend = 12, + ZeroExtend = 13, + Nontemporal = 14, + Offsets = 16, + Max = 0x7fffffff, + }; -enum class ImageOperandsMask : unsigned { - MaskNone = 0, - Bias = 0x00000001, - Lod = 0x00000002, - Grad = 0x00000004, - ConstOffset = 0x00000008, - Offset = 0x00000010, - ConstOffsets = 0x00000020, - Sample = 0x00000040, - MinLod = 0x00000080, - MakeTexelAvailable = 0x00000100, - MakeTexelAvailableKHR = 0x00000100, - MakeTexelVisible = 0x00000200, - MakeTexelVisibleKHR = 0x00000200, - NonPrivateTexel = 0x00000400, - NonPrivateTexelKHR = 0x00000400, - VolatileTexel = 0x00000800, - VolatileTexelKHR = 0x00000800, - SignExtend = 0x00001000, - ZeroExtend = 0x00002000, - Nontemporal = 0x00004000, - Offsets = 0x00010000, -}; + enum class ImageOperandsMask : unsigned + { + MaskNone = 0, + Bias = 0x00000001, + Lod = 0x00000002, + Grad = 0x00000004, + ConstOffset = 0x00000008, + Offset = 0x00000010, + ConstOffsets = 0x00000020, + Sample = 0x00000040, + MinLod = 0x00000080, + MakeTexelAvailable = 0x00000100, + MakeTexelAvailableKHR = 0x00000100, + MakeTexelVisible = 0x00000200, + MakeTexelVisibleKHR = 0x00000200, + NonPrivateTexel = 0x00000400, + NonPrivateTexelKHR = 0x00000400, + VolatileTexel = 0x00000800, + VolatileTexelKHR = 0x00000800, + SignExtend = 0x00001000, + ZeroExtend = 0x00002000, + Nontemporal = 0x00004000, + Offsets = 0x00010000, + }; -enum class FPFastMathModeShift : unsigned { - NotNaN = 0, - NotInf = 1, - NSZ = 2, - AllowRecip = 3, - Fast = 4, - AllowContractFastINTEL = 16, - AllowReassocINTEL = 17, - Max = 0x7fffffff, -}; + enum class FPFastMathModeShift : unsigned + { + NotNaN = 0, + NotInf = 1, + NSZ = 2, + AllowRecip = 3, + Fast = 4, + AllowContractFastINTEL = 16, + AllowReassocINTEL = 17, + Max = 0x7fffffff, + }; -enum class FPFastMathModeMask : unsigned { - MaskNone = 0, - NotNaN = 0x00000001, - NotInf = 0x00000002, - NSZ = 0x00000004, - AllowRecip = 0x00000008, - Fast = 0x00000010, - AllowContractFastINTEL = 0x00010000, - AllowReassocINTEL = 0x00020000, -}; + enum class FPFastMathModeMask : unsigned + { + MaskNone = 0, + NotNaN = 0x00000001, + NotInf = 0x00000002, + NSZ = 0x00000004, + AllowRecip = 0x00000008, + Fast = 0x00000010, + AllowContractFastINTEL = 0x00010000, + AllowReassocINTEL = 0x00020000, + }; -enum class FPRoundingMode : unsigned { - RTE = 0, - RTZ = 1, - RTP = 2, - RTN = 3, - Max = 0x7fffffff, -}; + enum class FPRoundingMode : unsigned + { + RTE = 0, + RTZ = 1, + RTP = 2, + RTN = 3, + Max = 0x7fffffff, + }; -enum class LinkageType : unsigned { - Export = 0, - Import = 1, - LinkOnceODR = 2, - Max = 0x7fffffff, -}; + enum class LinkageType : unsigned + { + Export = 0, + Import = 1, + LinkOnceODR = 2, + Max = 0x7fffffff, + }; -enum class AccessQualifier : unsigned { - ReadOnly = 0, - WriteOnly = 1, - ReadWrite = 2, - Max = 0x7fffffff, -}; + enum class AccessQualifier : unsigned + { + ReadOnly = 0, + WriteOnly = 1, + ReadWrite = 2, + Max = 0x7fffffff, + }; -enum class FunctionParameterAttribute : unsigned { - Zext = 0, - Sext = 1, - ByVal = 2, - Sret = 3, - NoAlias = 4, - NoCapture = 5, - NoWrite = 6, - NoReadWrite = 7, - RuntimeAlignedINTEL = 5940, - Max = 0x7fffffff, -}; + enum class FunctionParameterAttribute : unsigned + { + Zext = 0, + Sext = 1, + ByVal = 2, + Sret = 3, + NoAlias = 4, + NoCapture = 5, + NoWrite = 6, + NoReadWrite = 7, + RuntimeAlignedINTEL = 5940, + Max = 0x7fffffff, + }; -enum class Decoration : unsigned { - RelaxedPrecision = 0, - SpecId = 1, - Block = 2, - BufferBlock = 3, - RowMajor = 4, - ColMajor = 5, - ArrayStride = 6, - MatrixStride = 7, - GLSLShared = 8, - GLSLPacked = 9, - CPacked = 10, - BuiltIn = 11, - NoPerspective = 13, - Flat = 14, - Patch = 15, - Centroid = 16, - Sample = 17, - Invariant = 18, - Restrict = 19, - Aliased = 20, - Volatile = 21, - Constant = 22, - Coherent = 23, - NonWritable = 24, - NonReadable = 25, - Uniform = 26, - UniformId = 27, - SaturatedConversion = 28, - Stream = 29, - Location = 30, - Component = 31, - Index = 32, - Binding = 33, - DescriptorSet = 34, - Offset = 35, - XfbBuffer = 36, - XfbStride = 37, - FuncParamAttr = 38, - FPRoundingMode = 39, - FPFastMathMode = 40, - LinkageAttributes = 41, - NoContraction = 42, - InputAttachmentIndex = 43, - Alignment = 44, - MaxByteOffset = 45, - AlignmentId = 46, - MaxByteOffsetId = 47, - NoSignedWrap = 4469, - NoUnsignedWrap = 4470, - WeightTextureQCOM = 4487, - BlockMatchTextureQCOM = 4488, - ExplicitInterpAMD = 4999, - OverrideCoverageNV = 5248, - PassthroughNV = 5250, - ViewportRelativeNV = 5252, - SecondaryViewportRelativeNV = 5256, - PerPrimitiveEXT = 5271, - PerPrimitiveNV = 5271, - PerViewNV = 5272, - PerTaskNV = 5273, - PerVertexKHR = 5285, - PerVertexNV = 5285, - NonUniform = 5300, - NonUniformEXT = 5300, - RestrictPointer = 5355, - RestrictPointerEXT = 5355, - AliasedPointer = 5356, - AliasedPointerEXT = 5356, - HitObjectShaderRecordBufferNV = 5386, - BindlessSamplerNV = 5398, - BindlessImageNV = 5399, - BoundSamplerNV = 5400, - BoundImageNV = 5401, - SIMTCallINTEL = 5599, - ReferencedIndirectlyINTEL = 5602, - ClobberINTEL = 5607, - SideEffectsINTEL = 5608, - VectorComputeVariableINTEL = 5624, - FuncParamIOKindINTEL = 5625, - VectorComputeFunctionINTEL = 5626, - StackCallINTEL = 5627, - GlobalVariableOffsetINTEL = 5628, - CounterBuffer = 5634, - HlslCounterBufferGOOGLE = 5634, - HlslSemanticGOOGLE = 5635, - UserSemantic = 5635, - UserTypeGOOGLE = 5636, - FunctionRoundingModeINTEL = 5822, - FunctionDenormModeINTEL = 5823, - RegisterINTEL = 5825, - MemoryINTEL = 5826, - NumbanksINTEL = 5827, - BankwidthINTEL = 5828, - MaxPrivateCopiesINTEL = 5829, - SinglepumpINTEL = 5830, - DoublepumpINTEL = 5831, - MaxReplicatesINTEL = 5832, - SimpleDualPortINTEL = 5833, - MergeINTEL = 5834, - BankBitsINTEL = 5835, - ForcePow2DepthINTEL = 5836, - BurstCoalesceINTEL = 5899, - CacheSizeINTEL = 5900, - DontStaticallyCoalesceINTEL = 5901, - PrefetchINTEL = 5902, - StallEnableINTEL = 5905, - FuseLoopsInFunctionINTEL = 5907, - MathOpDSPModeINTEL = 5909, - AliasScopeINTEL = 5914, - NoAliasINTEL = 5915, - InitiationIntervalINTEL = 5917, - MaxConcurrencyINTEL = 5918, - PipelineEnableINTEL = 5919, - BufferLocationINTEL = 5921, - IOPipeStorageINTEL = 5944, - FunctionFloatingPointModeINTEL = 6080, - SingleElementVectorINTEL = 6085, - VectorComputeCallableFunctionINTEL = 6087, - MediaBlockIOINTEL = 6140, - LatencyControlLabelINTEL = 6172, - LatencyControlConstraintINTEL = 6173, - ConduitKernelArgumentINTEL = 6175, - RegisterMapKernelArgumentINTEL = 6176, - MMHostInterfaceAddressWidthINTEL = 6177, - MMHostInterfaceDataWidthINTEL = 6178, - MMHostInterfaceLatencyINTEL = 6179, - MMHostInterfaceReadWriteModeINTEL = 6180, - MMHostInterfaceMaxBurstINTEL = 6181, - MMHostInterfaceWaitRequestINTEL = 6182, - StableKernelArgumentINTEL = 6183, - Max = 0x7fffffff, -}; + enum class Decoration : unsigned + { + RelaxedPrecision = 0, + SpecId = 1, + Block = 2, + BufferBlock = 3, + RowMajor = 4, + ColMajor = 5, + ArrayStride = 6, + MatrixStride = 7, + GLSLShared = 8, + GLSLPacked = 9, + CPacked = 10, + BuiltIn = 11, + NoPerspective = 13, + Flat = 14, + Patch = 15, + Centroid = 16, + Sample = 17, + Invariant = 18, + Restrict = 19, + Aliased = 20, + Volatile = 21, + Constant = 22, + Coherent = 23, + NonWritable = 24, + NonReadable = 25, + Uniform = 26, + UniformId = 27, + SaturatedConversion = 28, + Stream = 29, + Location = 30, + Component = 31, + Index = 32, + Binding = 33, + DescriptorSet = 34, + Offset = 35, + XfbBuffer = 36, + XfbStride = 37, + FuncParamAttr = 38, + FPRoundingMode = 39, + FPFastMathMode = 40, + LinkageAttributes = 41, + NoContraction = 42, + InputAttachmentIndex = 43, + Alignment = 44, + MaxByteOffset = 45, + AlignmentId = 46, + MaxByteOffsetId = 47, + NoSignedWrap = 4469, + NoUnsignedWrap = 4470, + WeightTextureQCOM = 4487, + BlockMatchTextureQCOM = 4488, + ExplicitInterpAMD = 4999, + OverrideCoverageNV = 5248, + PassthroughNV = 5250, + ViewportRelativeNV = 5252, + SecondaryViewportRelativeNV = 5256, + PerPrimitiveEXT = 5271, + PerPrimitiveNV = 5271, + PerViewNV = 5272, + PerTaskNV = 5273, + PerVertexKHR = 5285, + PerVertexNV = 5285, + NonUniform = 5300, + NonUniformEXT = 5300, + RestrictPointer = 5355, + RestrictPointerEXT = 5355, + AliasedPointer = 5356, + AliasedPointerEXT = 5356, + HitObjectShaderRecordBufferNV = 5386, + BindlessSamplerNV = 5398, + BindlessImageNV = 5399, + BoundSamplerNV = 5400, + BoundImageNV = 5401, + SIMTCallINTEL = 5599, + ReferencedIndirectlyINTEL = 5602, + ClobberINTEL = 5607, + SideEffectsINTEL = 5608, + VectorComputeVariableINTEL = 5624, + FuncParamIOKindINTEL = 5625, + VectorComputeFunctionINTEL = 5626, + StackCallINTEL = 5627, + GlobalVariableOffsetINTEL = 5628, + CounterBuffer = 5634, + HlslCounterBufferGOOGLE = 5634, + HlslSemanticGOOGLE = 5635, + UserSemantic = 5635, + UserTypeGOOGLE = 5636, + FunctionRoundingModeINTEL = 5822, + FunctionDenormModeINTEL = 5823, + RegisterINTEL = 5825, + MemoryINTEL = 5826, + NumbanksINTEL = 5827, + BankwidthINTEL = 5828, + MaxPrivateCopiesINTEL = 5829, + SinglepumpINTEL = 5830, + DoublepumpINTEL = 5831, + MaxReplicatesINTEL = 5832, + SimpleDualPortINTEL = 5833, + MergeINTEL = 5834, + BankBitsINTEL = 5835, + ForcePow2DepthINTEL = 5836, + BurstCoalesceINTEL = 5899, + CacheSizeINTEL = 5900, + DontStaticallyCoalesceINTEL = 5901, + PrefetchINTEL = 5902, + StallEnableINTEL = 5905, + FuseLoopsInFunctionINTEL = 5907, + MathOpDSPModeINTEL = 5909, + AliasScopeINTEL = 5914, + NoAliasINTEL = 5915, + InitiationIntervalINTEL = 5917, + MaxConcurrencyINTEL = 5918, + PipelineEnableINTEL = 5919, + BufferLocationINTEL = 5921, + IOPipeStorageINTEL = 5944, + FunctionFloatingPointModeINTEL = 6080, + SingleElementVectorINTEL = 6085, + VectorComputeCallableFunctionINTEL = 6087, + MediaBlockIOINTEL = 6140, + LatencyControlLabelINTEL = 6172, + LatencyControlConstraintINTEL = 6173, + ConduitKernelArgumentINTEL = 6175, + RegisterMapKernelArgumentINTEL = 6176, + MMHostInterfaceAddressWidthINTEL = 6177, + MMHostInterfaceDataWidthINTEL = 6178, + MMHostInterfaceLatencyINTEL = 6179, + MMHostInterfaceReadWriteModeINTEL = 6180, + MMHostInterfaceMaxBurstINTEL = 6181, + MMHostInterfaceWaitRequestINTEL = 6182, + StableKernelArgumentINTEL = 6183, + Max = 0x7fffffff, + }; -enum class BuiltIn : unsigned { - Position = 0, - PointSize = 1, - ClipDistance = 3, - CullDistance = 4, - VertexId = 5, - InstanceId = 6, - PrimitiveId = 7, - InvocationId = 8, - Layer = 9, - ViewportIndex = 10, - TessLevelOuter = 11, - TessLevelInner = 12, - TessCoord = 13, - PatchVertices = 14, - FragCoord = 15, - PointCoord = 16, - FrontFacing = 17, - SampleId = 18, - SamplePosition = 19, - SampleMask = 20, - FragDepth = 22, - HelperInvocation = 23, - NumWorkgroups = 24, - WorkgroupSize = 25, - WorkgroupId = 26, - LocalInvocationId = 27, - GlobalInvocationId = 28, - LocalInvocationIndex = 29, - WorkDim = 30, - GlobalSize = 31, - EnqueuedWorkgroupSize = 32, - GlobalOffset = 33, - GlobalLinearId = 34, - SubgroupSize = 36, - SubgroupMaxSize = 37, - NumSubgroups = 38, - NumEnqueuedSubgroups = 39, - SubgroupId = 40, - SubgroupLocalInvocationId = 41, - VertexIndex = 42, - InstanceIndex = 43, - CoreIDARM = 4160, - CoreCountARM = 4161, - CoreMaxIDARM = 4162, - WarpIDARM = 4163, - WarpMaxIDARM = 4164, - SubgroupEqMask = 4416, - SubgroupEqMaskKHR = 4416, - SubgroupGeMask = 4417, - SubgroupGeMaskKHR = 4417, - SubgroupGtMask = 4418, - SubgroupGtMaskKHR = 4418, - SubgroupLeMask = 4419, - SubgroupLeMaskKHR = 4419, - SubgroupLtMask = 4420, - SubgroupLtMaskKHR = 4420, - BaseVertex = 4424, - BaseInstance = 4425, - DrawIndex = 4426, - PrimitiveShadingRateKHR = 4432, - DeviceIndex = 4438, - ViewIndex = 4440, - ShadingRateKHR = 4444, - BaryCoordNoPerspAMD = 4992, - BaryCoordNoPerspCentroidAMD = 4993, - BaryCoordNoPerspSampleAMD = 4994, - BaryCoordSmoothAMD = 4995, - BaryCoordSmoothCentroidAMD = 4996, - BaryCoordSmoothSampleAMD = 4997, - BaryCoordPullModelAMD = 4998, - FragStencilRefEXT = 5014, - ViewportMaskNV = 5253, - SecondaryPositionNV = 5257, - SecondaryViewportMaskNV = 5258, - PositionPerViewNV = 5261, - ViewportMaskPerViewNV = 5262, - FullyCoveredEXT = 5264, - TaskCountNV = 5274, - PrimitiveCountNV = 5275, - PrimitiveIndicesNV = 5276, - ClipDistancePerViewNV = 5277, - CullDistancePerViewNV = 5278, - LayerPerViewNV = 5279, - MeshViewCountNV = 5280, - MeshViewIndicesNV = 5281, - BaryCoordKHR = 5286, - BaryCoordNV = 5286, - BaryCoordNoPerspKHR = 5287, - BaryCoordNoPerspNV = 5287, - FragSizeEXT = 5292, - FragmentSizeNV = 5292, - FragInvocationCountEXT = 5293, - InvocationsPerPixelNV = 5293, - PrimitivePointIndicesEXT = 5294, - PrimitiveLineIndicesEXT = 5295, - PrimitiveTriangleIndicesEXT = 5296, - CullPrimitiveEXT = 5299, - LaunchIdKHR = 5319, - LaunchIdNV = 5319, - LaunchSizeKHR = 5320, - LaunchSizeNV = 5320, - WorldRayOriginKHR = 5321, - WorldRayOriginNV = 5321, - WorldRayDirectionKHR = 5322, - WorldRayDirectionNV = 5322, - ObjectRayOriginKHR = 5323, - ObjectRayOriginNV = 5323, - ObjectRayDirectionKHR = 5324, - ObjectRayDirectionNV = 5324, - RayTminKHR = 5325, - RayTminNV = 5325, - RayTmaxKHR = 5326, - RayTmaxNV = 5326, - InstanceCustomIndexKHR = 5327, - InstanceCustomIndexNV = 5327, - ObjectToWorldKHR = 5330, - ObjectToWorldNV = 5330, - WorldToObjectKHR = 5331, - WorldToObjectNV = 5331, - HitTNV = 5332, - HitKindKHR = 5333, - HitKindNV = 5333, - CurrentRayTimeNV = 5334, - HitTriangleVertexPositionsKHR = 5335, - IncomingRayFlagsKHR = 5351, - IncomingRayFlagsNV = 5351, - RayGeometryIndexKHR = 5352, - WarpsPerSMNV = 5374, - SMCountNV = 5375, - WarpIDNV = 5376, - SMIDNV = 5377, - CullMaskKHR = 6021, - Max = 0x7fffffff, -}; + enum class BuiltIn : unsigned + { + Position = 0, + PointSize = 1, + ClipDistance = 3, + CullDistance = 4, + VertexId = 5, + InstanceId = 6, + PrimitiveId = 7, + InvocationId = 8, + Layer = 9, + ViewportIndex = 10, + TessLevelOuter = 11, + TessLevelInner = 12, + TessCoord = 13, + PatchVertices = 14, + FragCoord = 15, + PointCoord = 16, + FrontFacing = 17, + SampleId = 18, + SamplePosition = 19, + SampleMask = 20, + FragDepth = 22, + HelperInvocation = 23, + NumWorkgroups = 24, + WorkgroupSize = 25, + WorkgroupId = 26, + LocalInvocationId = 27, + GlobalInvocationId = 28, + LocalInvocationIndex = 29, + WorkDim = 30, + GlobalSize = 31, + EnqueuedWorkgroupSize = 32, + GlobalOffset = 33, + GlobalLinearId = 34, + SubgroupSize = 36, + SubgroupMaxSize = 37, + NumSubgroups = 38, + NumEnqueuedSubgroups = 39, + SubgroupId = 40, + SubgroupLocalInvocationId = 41, + VertexIndex = 42, + InstanceIndex = 43, + CoreIDARM = 4160, + CoreCountARM = 4161, + CoreMaxIDARM = 4162, + WarpIDARM = 4163, + WarpMaxIDARM = 4164, + SubgroupEqMask = 4416, + SubgroupEqMaskKHR = 4416, + SubgroupGeMask = 4417, + SubgroupGeMaskKHR = 4417, + SubgroupGtMask = 4418, + SubgroupGtMaskKHR = 4418, + SubgroupLeMask = 4419, + SubgroupLeMaskKHR = 4419, + SubgroupLtMask = 4420, + SubgroupLtMaskKHR = 4420, + BaseVertex = 4424, + BaseInstance = 4425, + DrawIndex = 4426, + PrimitiveShadingRateKHR = 4432, + DeviceIndex = 4438, + ViewIndex = 4440, + ShadingRateKHR = 4444, + BaryCoordNoPerspAMD = 4992, + BaryCoordNoPerspCentroidAMD = 4993, + BaryCoordNoPerspSampleAMD = 4994, + BaryCoordSmoothAMD = 4995, + BaryCoordSmoothCentroidAMD = 4996, + BaryCoordSmoothSampleAMD = 4997, + BaryCoordPullModelAMD = 4998, + FragStencilRefEXT = 5014, + ViewportMaskNV = 5253, + SecondaryPositionNV = 5257, + SecondaryViewportMaskNV = 5258, + PositionPerViewNV = 5261, + ViewportMaskPerViewNV = 5262, + FullyCoveredEXT = 5264, + TaskCountNV = 5274, + PrimitiveCountNV = 5275, + PrimitiveIndicesNV = 5276, + ClipDistancePerViewNV = 5277, + CullDistancePerViewNV = 5278, + LayerPerViewNV = 5279, + MeshViewCountNV = 5280, + MeshViewIndicesNV = 5281, + BaryCoordKHR = 5286, + BaryCoordNV = 5286, + BaryCoordNoPerspKHR = 5287, + BaryCoordNoPerspNV = 5287, + FragSizeEXT = 5292, + FragmentSizeNV = 5292, + FragInvocationCountEXT = 5293, + InvocationsPerPixelNV = 5293, + PrimitivePointIndicesEXT = 5294, + PrimitiveLineIndicesEXT = 5295, + PrimitiveTriangleIndicesEXT = 5296, + CullPrimitiveEXT = 5299, + LaunchIdKHR = 5319, + LaunchIdNV = 5319, + LaunchSizeKHR = 5320, + LaunchSizeNV = 5320, + WorldRayOriginKHR = 5321, + WorldRayOriginNV = 5321, + WorldRayDirectionKHR = 5322, + WorldRayDirectionNV = 5322, + ObjectRayOriginKHR = 5323, + ObjectRayOriginNV = 5323, + ObjectRayDirectionKHR = 5324, + ObjectRayDirectionNV = 5324, + RayTminKHR = 5325, + RayTminNV = 5325, + RayTmaxKHR = 5326, + RayTmaxNV = 5326, + InstanceCustomIndexKHR = 5327, + InstanceCustomIndexNV = 5327, + ObjectToWorldKHR = 5330, + ObjectToWorldNV = 5330, + WorldToObjectKHR = 5331, + WorldToObjectNV = 5331, + HitTNV = 5332, + HitKindKHR = 5333, + HitKindNV = 5333, + CurrentRayTimeNV = 5334, + HitTriangleVertexPositionsKHR = 5335, + IncomingRayFlagsKHR = 5351, + IncomingRayFlagsNV = 5351, + RayGeometryIndexKHR = 5352, + WarpsPerSMNV = 5374, + SMCountNV = 5375, + WarpIDNV = 5376, + SMIDNV = 5377, + CullMaskKHR = 6021, + Max = 0x7fffffff, + }; -enum class SelectionControlShift : unsigned { - Flatten = 0, - DontFlatten = 1, - Max = 0x7fffffff, -}; + enum class SelectionControlShift : unsigned + { + Flatten = 0, + DontFlatten = 1, + Max = 0x7fffffff, + }; -enum class SelectionControlMask : unsigned { - MaskNone = 0, - Flatten = 0x00000001, - DontFlatten = 0x00000002, -}; + enum class SelectionControlMask : unsigned + { + MaskNone = 0, + Flatten = 0x00000001, + DontFlatten = 0x00000002, + }; -enum class LoopControlShift : unsigned { - Unroll = 0, - DontUnroll = 1, - DependencyInfinite = 2, - DependencyLength = 3, - MinIterations = 4, - MaxIterations = 5, - IterationMultiple = 6, - PeelCount = 7, - PartialCount = 8, - InitiationIntervalINTEL = 16, - MaxConcurrencyINTEL = 17, - DependencyArrayINTEL = 18, - PipelineEnableINTEL = 19, - LoopCoalesceINTEL = 20, - MaxInterleavingINTEL = 21, - SpeculatedIterationsINTEL = 22, - NoFusionINTEL = 23, - LoopCountINTEL = 24, - MaxReinvocationDelayINTEL = 25, - Max = 0x7fffffff, -}; + enum class LoopControlShift : unsigned + { + Unroll = 0, + DontUnroll = 1, + DependencyInfinite = 2, + DependencyLength = 3, + MinIterations = 4, + MaxIterations = 5, + IterationMultiple = 6, + PeelCount = 7, + PartialCount = 8, + InitiationIntervalINTEL = 16, + MaxConcurrencyINTEL = 17, + DependencyArrayINTEL = 18, + PipelineEnableINTEL = 19, + LoopCoalesceINTEL = 20, + MaxInterleavingINTEL = 21, + SpeculatedIterationsINTEL = 22, + NoFusionINTEL = 23, + LoopCountINTEL = 24, + MaxReinvocationDelayINTEL = 25, + Max = 0x7fffffff, + }; -enum class LoopControlMask : unsigned { - MaskNone = 0, - Unroll = 0x00000001, - DontUnroll = 0x00000002, - DependencyInfinite = 0x00000004, - DependencyLength = 0x00000008, - MinIterations = 0x00000010, - MaxIterations = 0x00000020, - IterationMultiple = 0x00000040, - PeelCount = 0x00000080, - PartialCount = 0x00000100, - InitiationIntervalINTEL = 0x00010000, - MaxConcurrencyINTEL = 0x00020000, - DependencyArrayINTEL = 0x00040000, - PipelineEnableINTEL = 0x00080000, - LoopCoalesceINTEL = 0x00100000, - MaxInterleavingINTEL = 0x00200000, - SpeculatedIterationsINTEL = 0x00400000, - NoFusionINTEL = 0x00800000, - LoopCountINTEL = 0x01000000, - MaxReinvocationDelayINTEL = 0x02000000, -}; + enum class LoopControlMask : unsigned + { + MaskNone = 0, + Unroll = 0x00000001, + DontUnroll = 0x00000002, + DependencyInfinite = 0x00000004, + DependencyLength = 0x00000008, + MinIterations = 0x00000010, + MaxIterations = 0x00000020, + IterationMultiple = 0x00000040, + PeelCount = 0x00000080, + PartialCount = 0x00000100, + InitiationIntervalINTEL = 0x00010000, + MaxConcurrencyINTEL = 0x00020000, + DependencyArrayINTEL = 0x00040000, + PipelineEnableINTEL = 0x00080000, + LoopCoalesceINTEL = 0x00100000, + MaxInterleavingINTEL = 0x00200000, + SpeculatedIterationsINTEL = 0x00400000, + NoFusionINTEL = 0x00800000, + LoopCountINTEL = 0x01000000, + MaxReinvocationDelayINTEL = 0x02000000, + }; -enum class FunctionControlShift : unsigned { - Inline = 0, - DontInline = 1, - Pure = 2, - Const = 3, - OptNoneINTEL = 16, - Max = 0x7fffffff, -}; + enum class FunctionControlShift : unsigned + { + Inline = 0, + DontInline = 1, + Pure = 2, + Const = 3, + OptNoneINTEL = 16, + Max = 0x7fffffff, + }; -enum class FunctionControlMask : unsigned { - MaskNone = 0, - Inline = 0x00000001, - DontInline = 0x00000002, - Pure = 0x00000004, - Const = 0x00000008, - OptNoneINTEL = 0x00010000, -}; + enum class FunctionControlMask : unsigned + { + MaskNone = 0, + Inline = 0x00000001, + DontInline = 0x00000002, + Pure = 0x00000004, + Const = 0x00000008, + OptNoneINTEL = 0x00010000, + }; -enum class MemorySemanticsShift : unsigned { - Acquire = 1, - Release = 2, - AcquireRelease = 3, - SequentiallyConsistent = 4, - UniformMemory = 6, - SubgroupMemory = 7, - WorkgroupMemory = 8, - CrossWorkgroupMemory = 9, - AtomicCounterMemory = 10, - ImageMemory = 11, - OutputMemory = 12, - OutputMemoryKHR = 12, - MakeAvailable = 13, - MakeAvailableKHR = 13, - MakeVisible = 14, - MakeVisibleKHR = 14, - Volatile = 15, - Max = 0x7fffffff, -}; + enum class MemorySemanticsShift : unsigned + { + Acquire = 1, + Release = 2, + AcquireRelease = 3, + SequentiallyConsistent = 4, + UniformMemory = 6, + SubgroupMemory = 7, + WorkgroupMemory = 8, + CrossWorkgroupMemory = 9, + AtomicCounterMemory = 10, + ImageMemory = 11, + OutputMemory = 12, + OutputMemoryKHR = 12, + MakeAvailable = 13, + MakeAvailableKHR = 13, + MakeVisible = 14, + MakeVisibleKHR = 14, + Volatile = 15, + Max = 0x7fffffff, + }; -enum class MemorySemanticsMask : unsigned { - MaskNone = 0, - Acquire = 0x00000002, - Release = 0x00000004, - AcquireRelease = 0x00000008, - SequentiallyConsistent = 0x00000010, - UniformMemory = 0x00000040, - SubgroupMemory = 0x00000080, - WorkgroupMemory = 0x00000100, - CrossWorkgroupMemory = 0x00000200, - AtomicCounterMemory = 0x00000400, - ImageMemory = 0x00000800, - OutputMemory = 0x00001000, - OutputMemoryKHR = 0x00001000, - MakeAvailable = 0x00002000, - MakeAvailableKHR = 0x00002000, - MakeVisible = 0x00004000, - MakeVisibleKHR = 0x00004000, - Volatile = 0x00008000, -}; + enum class MemorySemanticsMask : unsigned + { + MaskNone = 0, + Acquire = 0x00000002, + Release = 0x00000004, + AcquireRelease = 0x00000008, + SequentiallyConsistent = 0x00000010, + UniformMemory = 0x00000040, + SubgroupMemory = 0x00000080, + WorkgroupMemory = 0x00000100, + CrossWorkgroupMemory = 0x00000200, + AtomicCounterMemory = 0x00000400, + ImageMemory = 0x00000800, + OutputMemory = 0x00001000, + OutputMemoryKHR = 0x00001000, + MakeAvailable = 0x00002000, + MakeAvailableKHR = 0x00002000, + MakeVisible = 0x00004000, + MakeVisibleKHR = 0x00004000, + Volatile = 0x00008000, + }; -enum class MemoryAccessShift : unsigned { - Volatile = 0, - Aligned = 1, - Nontemporal = 2, - MakePointerAvailable = 3, - MakePointerAvailableKHR = 3, - MakePointerVisible = 4, - MakePointerVisibleKHR = 4, - NonPrivatePointer = 5, - NonPrivatePointerKHR = 5, - AliasScopeINTELMask = 16, - NoAliasINTELMask = 17, - Max = 0x7fffffff, -}; + enum class MemoryAccessShift : unsigned + { + Volatile = 0, + Aligned = 1, + Nontemporal = 2, + MakePointerAvailable = 3, + MakePointerAvailableKHR = 3, + MakePointerVisible = 4, + MakePointerVisibleKHR = 4, + NonPrivatePointer = 5, + NonPrivatePointerKHR = 5, + AliasScopeINTELMask = 16, + NoAliasINTELMask = 17, + Max = 0x7fffffff, + }; -enum class MemoryAccessMask : unsigned { - MaskNone = 0, - Volatile = 0x00000001, - Aligned = 0x00000002, - Nontemporal = 0x00000004, - MakePointerAvailable = 0x00000008, - MakePointerAvailableKHR = 0x00000008, - MakePointerVisible = 0x00000010, - MakePointerVisibleKHR = 0x00000010, - NonPrivatePointer = 0x00000020, - NonPrivatePointerKHR = 0x00000020, - AliasScopeINTELMask = 0x00010000, - NoAliasINTELMask = 0x00020000, -}; + enum class MemoryAccessMask : unsigned + { + MaskNone = 0, + Volatile = 0x00000001, + Aligned = 0x00000002, + Nontemporal = 0x00000004, + MakePointerAvailable = 0x00000008, + MakePointerAvailableKHR = 0x00000008, + MakePointerVisible = 0x00000010, + MakePointerVisibleKHR = 0x00000010, + NonPrivatePointer = 0x00000020, + NonPrivatePointerKHR = 0x00000020, + AliasScopeINTELMask = 0x00010000, + NoAliasINTELMask = 0x00020000, + }; -enum class Scope : unsigned { - CrossDevice = 0, - Device = 1, - Workgroup = 2, - Subgroup = 3, - Invocation = 4, - QueueFamily = 5, - QueueFamilyKHR = 5, - ShaderCallKHR = 6, - Max = 0x7fffffff, -}; + enum class Scope : unsigned + { + CrossDevice = 0, + Device = 1, + Workgroup = 2, + Subgroup = 3, + Invocation = 4, + QueueFamily = 5, + QueueFamilyKHR = 5, + ShaderCallKHR = 6, + Max = 0x7fffffff, + }; -enum class GroupOperation : unsigned { - Reduce = 0, - InclusiveScan = 1, - ExclusiveScan = 2, - ClusteredReduce = 3, - PartitionedReduceNV = 6, - PartitionedInclusiveScanNV = 7, - PartitionedExclusiveScanNV = 8, - Max = 0x7fffffff, -}; + enum class GroupOperation : unsigned + { + Reduce = 0, + InclusiveScan = 1, + ExclusiveScan = 2, + ClusteredReduce = 3, + PartitionedReduceNV = 6, + PartitionedInclusiveScanNV = 7, + PartitionedExclusiveScanNV = 8, + Max = 0x7fffffff, + }; -enum class KernelEnqueueFlags : unsigned { - NoWait = 0, - WaitKernel = 1, - WaitWorkGroup = 2, - Max = 0x7fffffff, -}; + enum class KernelEnqueueFlags : unsigned + { + NoWait = 0, + WaitKernel = 1, + WaitWorkGroup = 2, + Max = 0x7fffffff, + }; -enum class KernelProfilingInfoShift : unsigned { - CmdExecTime = 0, - Max = 0x7fffffff, -}; + enum class KernelProfilingInfoShift : unsigned + { + CmdExecTime = 0, + Max = 0x7fffffff, + }; -enum class KernelProfilingInfoMask : unsigned { - MaskNone = 0, - CmdExecTime = 0x00000001, -}; + enum class KernelProfilingInfoMask : unsigned + { + MaskNone = 0, + CmdExecTime = 0x00000001, + }; -enum class Capability : unsigned { - Matrix = 0, - Shader = 1, - Geometry = 2, - Tessellation = 3, - Addresses = 4, - Linkage = 5, - Kernel = 6, - Vector16 = 7, - Float16Buffer = 8, - Float16 = 9, - Float64 = 10, - Int64 = 11, - Int64Atomics = 12, - ImageBasic = 13, - ImageReadWrite = 14, - ImageMipmap = 15, - Pipes = 17, - Groups = 18, - DeviceEnqueue = 19, - LiteralSampler = 20, - AtomicStorage = 21, - Int16 = 22, - TessellationPointSize = 23, - GeometryPointSize = 24, - ImageGatherExtended = 25, - StorageImageMultisample = 27, - UniformBufferArrayDynamicIndexing = 28, - SampledImageArrayDynamicIndexing = 29, - StorageBufferArrayDynamicIndexing = 30, - StorageImageArrayDynamicIndexing = 31, - ClipDistance = 32, - CullDistance = 33, - ImageCubeArray = 34, - SampleRateShading = 35, - ImageRect = 36, - SampledRect = 37, - GenericPointer = 38, - Int8 = 39, - InputAttachment = 40, - SparseResidency = 41, - MinLod = 42, - Sampled1D = 43, - Image1D = 44, - SampledCubeArray = 45, - SampledBuffer = 46, - ImageBuffer = 47, - ImageMSArray = 48, - StorageImageExtendedFormats = 49, - ImageQuery = 50, - DerivativeControl = 51, - InterpolationFunction = 52, - TransformFeedback = 53, - GeometryStreams = 54, - StorageImageReadWithoutFormat = 55, - StorageImageWriteWithoutFormat = 56, - MultiViewport = 57, - SubgroupDispatch = 58, - NamedBarrier = 59, - PipeStorage = 60, - GroupNonUniform = 61, - GroupNonUniformVote = 62, - GroupNonUniformArithmetic = 63, - GroupNonUniformBallot = 64, - GroupNonUniformShuffle = 65, - GroupNonUniformShuffleRelative = 66, - GroupNonUniformClustered = 67, - GroupNonUniformQuad = 68, - ShaderLayer = 69, - ShaderViewportIndex = 70, - UniformDecoration = 71, - CoreBuiltinsARM = 4165, - TileImageColorReadAccessEXT = 4166, - TileImageDepthReadAccessEXT = 4167, - TileImageStencilReadAccessEXT = 4168, - FragmentShadingRateKHR = 4422, - SubgroupBallotKHR = 4423, - DrawParameters = 4427, - WorkgroupMemoryExplicitLayoutKHR = 4428, - WorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, - WorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, - SubgroupVoteKHR = 4431, - StorageBuffer16BitAccess = 4433, - StorageUniformBufferBlock16 = 4433, - StorageUniform16 = 4434, - UniformAndStorageBuffer16BitAccess = 4434, - StoragePushConstant16 = 4435, - StorageInputOutput16 = 4436, - DeviceGroup = 4437, - MultiView = 4439, - VariablePointersStorageBuffer = 4441, - VariablePointers = 4442, - AtomicStorageOps = 4445, - SampleMaskPostDepthCoverage = 4447, - StorageBuffer8BitAccess = 4448, - UniformAndStorageBuffer8BitAccess = 4449, - StoragePushConstant8 = 4450, - DenormPreserve = 4464, - DenormFlushToZero = 4465, - SignedZeroInfNanPreserve = 4466, - RoundingModeRTE = 4467, - RoundingModeRTZ = 4468, - RayQueryProvisionalKHR = 4471, - RayQueryKHR = 4472, - RayTraversalPrimitiveCullingKHR = 4478, - RayTracingKHR = 4479, - TextureSampleWeightedQCOM = 4484, - TextureBoxFilterQCOM = 4485, - TextureBlockMatchQCOM = 4486, - Float16ImageAMD = 5008, - ImageGatherBiasLodAMD = 5009, - FragmentMaskAMD = 5010, - StencilExportEXT = 5013, - ImageReadWriteLodAMD = 5015, - Int64ImageEXT = 5016, - ShaderClockKHR = 5055, - SampleMaskOverrideCoverageNV = 5249, - GeometryShaderPassthroughNV = 5251, - ShaderViewportIndexLayerEXT = 5254, - ShaderViewportIndexLayerNV = 5254, - ShaderViewportMaskNV = 5255, - ShaderStereoViewNV = 5259, - PerViewAttributesNV = 5260, - FragmentFullyCoveredEXT = 5265, - MeshShadingNV = 5266, - ImageFootprintNV = 5282, - MeshShadingEXT = 5283, - FragmentBarycentricKHR = 5284, - FragmentBarycentricNV = 5284, - ComputeDerivativeGroupQuadsNV = 5288, - FragmentDensityEXT = 5291, - ShadingRateNV = 5291, - GroupNonUniformPartitionedNV = 5297, - ShaderNonUniform = 5301, - ShaderNonUniformEXT = 5301, - RuntimeDescriptorArray = 5302, - RuntimeDescriptorArrayEXT = 5302, - InputAttachmentArrayDynamicIndexing = 5303, - InputAttachmentArrayDynamicIndexingEXT = 5303, - UniformTexelBufferArrayDynamicIndexing = 5304, - UniformTexelBufferArrayDynamicIndexingEXT = 5304, - StorageTexelBufferArrayDynamicIndexing = 5305, - StorageTexelBufferArrayDynamicIndexingEXT = 5305, - UniformBufferArrayNonUniformIndexing = 5306, - UniformBufferArrayNonUniformIndexingEXT = 5306, - SampledImageArrayNonUniformIndexing = 5307, - SampledImageArrayNonUniformIndexingEXT = 5307, - StorageBufferArrayNonUniformIndexing = 5308, - StorageBufferArrayNonUniformIndexingEXT = 5308, - StorageImageArrayNonUniformIndexing = 5309, - StorageImageArrayNonUniformIndexingEXT = 5309, - InputAttachmentArrayNonUniformIndexing = 5310, - InputAttachmentArrayNonUniformIndexingEXT = 5310, - UniformTexelBufferArrayNonUniformIndexing = 5311, - UniformTexelBufferArrayNonUniformIndexingEXT = 5311, - StorageTexelBufferArrayNonUniformIndexing = 5312, - StorageTexelBufferArrayNonUniformIndexingEXT = 5312, - RayTracingPositionFetchKHR = 5336, - RayTracingNV = 5340, - RayTracingMotionBlurNV = 5341, - VulkanMemoryModel = 5345, - VulkanMemoryModelKHR = 5345, - VulkanMemoryModelDeviceScope = 5346, - VulkanMemoryModelDeviceScopeKHR = 5346, - PhysicalStorageBufferAddresses = 5347, - PhysicalStorageBufferAddressesEXT = 5347, - ComputeDerivativeGroupLinearNV = 5350, - RayTracingProvisionalKHR = 5353, - CooperativeMatrixNV = 5357, - FragmentShaderSampleInterlockEXT = 5363, - FragmentShaderShadingRateInterlockEXT = 5372, - ShaderSMBuiltinsNV = 5373, - FragmentShaderPixelInterlockEXT = 5378, - DemoteToHelperInvocation = 5379, - DemoteToHelperInvocationEXT = 5379, - RayTracingOpacityMicromapEXT = 5381, - ShaderInvocationReorderNV = 5383, - BindlessTextureNV = 5390, - RayQueryPositionFetchKHR = 5391, - SubgroupShuffleINTEL = 5568, - SubgroupBufferBlockIOINTEL = 5569, - SubgroupImageBlockIOINTEL = 5570, - SubgroupImageMediaBlockIOINTEL = 5579, - RoundToInfinityINTEL = 5582, - FloatingPointModeINTEL = 5583, - IntegerFunctions2INTEL = 5584, - FunctionPointersINTEL = 5603, - IndirectReferencesINTEL = 5604, - AsmINTEL = 5606, - AtomicFloat32MinMaxEXT = 5612, - AtomicFloat64MinMaxEXT = 5613, - AtomicFloat16MinMaxEXT = 5616, - VectorComputeINTEL = 5617, - VectorAnyINTEL = 5619, - ExpectAssumeKHR = 5629, - SubgroupAvcMotionEstimationINTEL = 5696, - SubgroupAvcMotionEstimationIntraINTEL = 5697, - SubgroupAvcMotionEstimationChromaINTEL = 5698, - VariableLengthArrayINTEL = 5817, - FunctionFloatControlINTEL = 5821, - FPGAMemoryAttributesINTEL = 5824, - FPFastMathModeINTEL = 5837, - ArbitraryPrecisionIntegersINTEL = 5844, - ArbitraryPrecisionFloatingPointINTEL = 5845, - UnstructuredLoopControlsINTEL = 5886, - FPGALoopControlsINTEL = 5888, - KernelAttributesINTEL = 5892, - FPGAKernelAttributesINTEL = 5897, - FPGAMemoryAccessesINTEL = 5898, - FPGAClusterAttributesINTEL = 5904, - LoopFuseINTEL = 5906, - FPGADSPControlINTEL = 5908, - MemoryAccessAliasingINTEL = 5910, - FPGAInvocationPipeliningAttributesINTEL = 5916, - FPGABufferLocationINTEL = 5920, - ArbitraryPrecisionFixedPointINTEL = 5922, - USMStorageClassesINTEL = 5935, - RuntimeAlignedAttributeINTEL = 5939, - IOPipesINTEL = 5943, - BlockingPipesINTEL = 5945, - FPGARegINTEL = 5948, - DotProductInputAll = 6016, - DotProductInputAllKHR = 6016, - DotProductInput4x8Bit = 6017, - DotProductInput4x8BitKHR = 6017, - DotProductInput4x8BitPacked = 6018, - DotProductInput4x8BitPackedKHR = 6018, - DotProduct = 6019, - DotProductKHR = 6019, - RayCullMaskKHR = 6020, - BitInstructions = 6025, - GroupNonUniformRotateKHR = 6026, - AtomicFloat32AddEXT = 6033, - AtomicFloat64AddEXT = 6034, - LongConstantCompositeINTEL = 6089, - OptNoneINTEL = 6094, - AtomicFloat16AddEXT = 6095, - DebugInfoModuleINTEL = 6114, - BFloat16ConversionINTEL = 6115, - SplitBarrierINTEL = 6141, - FPGAKernelAttributesv2INTEL = 6161, - FPGALatencyControlINTEL = 6171, - FPGAArgumentInterfacesINTEL = 6174, - GroupUniformArithmeticKHR = 6400, - Max = 0x7fffffff, -}; + enum class Capability : unsigned + { + Matrix = 0, + Shader = 1, + Geometry = 2, + Tessellation = 3, + Addresses = 4, + Linkage = 5, + Kernel = 6, + Vector16 = 7, + Float16Buffer = 8, + Float16 = 9, + Float64 = 10, + Int64 = 11, + Int64Atomics = 12, + ImageBasic = 13, + ImageReadWrite = 14, + ImageMipmap = 15, + Pipes = 17, + Groups = 18, + DeviceEnqueue = 19, + LiteralSampler = 20, + AtomicStorage = 21, + Int16 = 22, + TessellationPointSize = 23, + GeometryPointSize = 24, + ImageGatherExtended = 25, + StorageImageMultisample = 27, + UniformBufferArrayDynamicIndexing = 28, + SampledImageArrayDynamicIndexing = 29, + StorageBufferArrayDynamicIndexing = 30, + StorageImageArrayDynamicIndexing = 31, + ClipDistance = 32, + CullDistance = 33, + ImageCubeArray = 34, + SampleRateShading = 35, + ImageRect = 36, + SampledRect = 37, + GenericPointer = 38, + Int8 = 39, + InputAttachment = 40, + SparseResidency = 41, + MinLod = 42, + Sampled1D = 43, + Image1D = 44, + SampledCubeArray = 45, + SampledBuffer = 46, + ImageBuffer = 47, + ImageMSArray = 48, + StorageImageExtendedFormats = 49, + ImageQuery = 50, + DerivativeControl = 51, + InterpolationFunction = 52, + TransformFeedback = 53, + GeometryStreams = 54, + StorageImageReadWithoutFormat = 55, + StorageImageWriteWithoutFormat = 56, + MultiViewport = 57, + SubgroupDispatch = 58, + NamedBarrier = 59, + PipeStorage = 60, + GroupNonUniform = 61, + GroupNonUniformVote = 62, + GroupNonUniformArithmetic = 63, + GroupNonUniformBallot = 64, + GroupNonUniformShuffle = 65, + GroupNonUniformShuffleRelative = 66, + GroupNonUniformClustered = 67, + GroupNonUniformQuad = 68, + ShaderLayer = 69, + ShaderViewportIndex = 70, + UniformDecoration = 71, + CoreBuiltinsARM = 4165, + TileImageColorReadAccessEXT = 4166, + TileImageDepthReadAccessEXT = 4167, + TileImageStencilReadAccessEXT = 4168, + FragmentShadingRateKHR = 4422, + SubgroupBallotKHR = 4423, + DrawParameters = 4427, + WorkgroupMemoryExplicitLayoutKHR = 4428, + WorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, + WorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, + SubgroupVoteKHR = 4431, + StorageBuffer16BitAccess = 4433, + StorageUniformBufferBlock16 = 4433, + StorageUniform16 = 4434, + UniformAndStorageBuffer16BitAccess = 4434, + StoragePushConstant16 = 4435, + StorageInputOutput16 = 4436, + DeviceGroup = 4437, + MultiView = 4439, + VariablePointersStorageBuffer = 4441, + VariablePointers = 4442, + AtomicStorageOps = 4445, + SampleMaskPostDepthCoverage = 4447, + StorageBuffer8BitAccess = 4448, + UniformAndStorageBuffer8BitAccess = 4449, + StoragePushConstant8 = 4450, + DenormPreserve = 4464, + DenormFlushToZero = 4465, + SignedZeroInfNanPreserve = 4466, + RoundingModeRTE = 4467, + RoundingModeRTZ = 4468, + RayQueryProvisionalKHR = 4471, + RayQueryKHR = 4472, + RayTraversalPrimitiveCullingKHR = 4478, + RayTracingKHR = 4479, + TextureSampleWeightedQCOM = 4484, + TextureBoxFilterQCOM = 4485, + TextureBlockMatchQCOM = 4486, + Float16ImageAMD = 5008, + ImageGatherBiasLodAMD = 5009, + FragmentMaskAMD = 5010, + StencilExportEXT = 5013, + ImageReadWriteLodAMD = 5015, + Int64ImageEXT = 5016, + ShaderClockKHR = 5055, + SampleMaskOverrideCoverageNV = 5249, + GeometryShaderPassthroughNV = 5251, + ShaderViewportIndexLayerEXT = 5254, + ShaderViewportIndexLayerNV = 5254, + ShaderViewportMaskNV = 5255, + ShaderStereoViewNV = 5259, + PerViewAttributesNV = 5260, + FragmentFullyCoveredEXT = 5265, + MeshShadingNV = 5266, + ImageFootprintNV = 5282, + MeshShadingEXT = 5283, + FragmentBarycentricKHR = 5284, + FragmentBarycentricNV = 5284, + ComputeDerivativeGroupQuadsNV = 5288, + FragmentDensityEXT = 5291, + ShadingRateNV = 5291, + GroupNonUniformPartitionedNV = 5297, + ShaderNonUniform = 5301, + ShaderNonUniformEXT = 5301, + RuntimeDescriptorArray = 5302, + RuntimeDescriptorArrayEXT = 5302, + InputAttachmentArrayDynamicIndexing = 5303, + InputAttachmentArrayDynamicIndexingEXT = 5303, + UniformTexelBufferArrayDynamicIndexing = 5304, + UniformTexelBufferArrayDynamicIndexingEXT = 5304, + StorageTexelBufferArrayDynamicIndexing = 5305, + StorageTexelBufferArrayDynamicIndexingEXT = 5305, + UniformBufferArrayNonUniformIndexing = 5306, + UniformBufferArrayNonUniformIndexingEXT = 5306, + SampledImageArrayNonUniformIndexing = 5307, + SampledImageArrayNonUniformIndexingEXT = 5307, + StorageBufferArrayNonUniformIndexing = 5308, + StorageBufferArrayNonUniformIndexingEXT = 5308, + StorageImageArrayNonUniformIndexing = 5309, + StorageImageArrayNonUniformIndexingEXT = 5309, + InputAttachmentArrayNonUniformIndexing = 5310, + InputAttachmentArrayNonUniformIndexingEXT = 5310, + UniformTexelBufferArrayNonUniformIndexing = 5311, + UniformTexelBufferArrayNonUniformIndexingEXT = 5311, + StorageTexelBufferArrayNonUniformIndexing = 5312, + StorageTexelBufferArrayNonUniformIndexingEXT = 5312, + RayTracingPositionFetchKHR = 5336, + RayTracingNV = 5340, + RayTracingMotionBlurNV = 5341, + VulkanMemoryModel = 5345, + VulkanMemoryModelKHR = 5345, + VulkanMemoryModelDeviceScope = 5346, + VulkanMemoryModelDeviceScopeKHR = 5346, + PhysicalStorageBufferAddresses = 5347, + PhysicalStorageBufferAddressesEXT = 5347, + ComputeDerivativeGroupLinearNV = 5350, + RayTracingProvisionalKHR = 5353, + CooperativeMatrixNV = 5357, + FragmentShaderSampleInterlockEXT = 5363, + FragmentShaderShadingRateInterlockEXT = 5372, + ShaderSMBuiltinsNV = 5373, + FragmentShaderPixelInterlockEXT = 5378, + DemoteToHelperInvocation = 5379, + DemoteToHelperInvocationEXT = 5379, + RayTracingOpacityMicromapEXT = 5381, + ShaderInvocationReorderNV = 5383, + BindlessTextureNV = 5390, + RayQueryPositionFetchKHR = 5391, + SubgroupShuffleINTEL = 5568, + SubgroupBufferBlockIOINTEL = 5569, + SubgroupImageBlockIOINTEL = 5570, + SubgroupImageMediaBlockIOINTEL = 5579, + RoundToInfinityINTEL = 5582, + FloatingPointModeINTEL = 5583, + IntegerFunctions2INTEL = 5584, + FunctionPointersINTEL = 5603, + IndirectReferencesINTEL = 5604, + AsmINTEL = 5606, + AtomicFloat32MinMaxEXT = 5612, + AtomicFloat64MinMaxEXT = 5613, + AtomicFloat16MinMaxEXT = 5616, + VectorComputeINTEL = 5617, + VectorAnyINTEL = 5619, + ExpectAssumeKHR = 5629, + SubgroupAvcMotionEstimationINTEL = 5696, + SubgroupAvcMotionEstimationIntraINTEL = 5697, + SubgroupAvcMotionEstimationChromaINTEL = 5698, + VariableLengthArrayINTEL = 5817, + FunctionFloatControlINTEL = 5821, + FPGAMemoryAttributesINTEL = 5824, + FPFastMathModeINTEL = 5837, + ArbitraryPrecisionIntegersINTEL = 5844, + ArbitraryPrecisionFloatingPointINTEL = 5845, + UnstructuredLoopControlsINTEL = 5886, + FPGALoopControlsINTEL = 5888, + KernelAttributesINTEL = 5892, + FPGAKernelAttributesINTEL = 5897, + FPGAMemoryAccessesINTEL = 5898, + FPGAClusterAttributesINTEL = 5904, + LoopFuseINTEL = 5906, + FPGADSPControlINTEL = 5908, + MemoryAccessAliasingINTEL = 5910, + FPGAInvocationPipeliningAttributesINTEL = 5916, + FPGABufferLocationINTEL = 5920, + ArbitraryPrecisionFixedPointINTEL = 5922, + USMStorageClassesINTEL = 5935, + RuntimeAlignedAttributeINTEL = 5939, + IOPipesINTEL = 5943, + BlockingPipesINTEL = 5945, + FPGARegINTEL = 5948, + DotProductInputAll = 6016, + DotProductInputAllKHR = 6016, + DotProductInput4x8Bit = 6017, + DotProductInput4x8BitKHR = 6017, + DotProductInput4x8BitPacked = 6018, + DotProductInput4x8BitPackedKHR = 6018, + DotProduct = 6019, + DotProductKHR = 6019, + RayCullMaskKHR = 6020, + BitInstructions = 6025, + GroupNonUniformRotateKHR = 6026, + AtomicFloat32AddEXT = 6033, + AtomicFloat64AddEXT = 6034, + LongConstantCompositeINTEL = 6089, + OptNoneINTEL = 6094, + AtomicFloat16AddEXT = 6095, + DebugInfoModuleINTEL = 6114, + BFloat16ConversionINTEL = 6115, + SplitBarrierINTEL = 6141, + FPGAKernelAttributesv2INTEL = 6161, + FPGALatencyControlINTEL = 6171, + FPGAArgumentInterfacesINTEL = 6174, + GroupUniformArithmeticKHR = 6400, + Max = 0x7fffffff, + }; -enum class RayFlagsShift : unsigned { - OpaqueKHR = 0, - NoOpaqueKHR = 1, - TerminateOnFirstHitKHR = 2, - SkipClosestHitShaderKHR = 3, - CullBackFacingTrianglesKHR = 4, - CullFrontFacingTrianglesKHR = 5, - CullOpaqueKHR = 6, - CullNoOpaqueKHR = 7, - SkipTrianglesKHR = 8, - SkipAABBsKHR = 9, - ForceOpacityMicromap2StateEXT = 10, - Max = 0x7fffffff, -}; + enum class RayFlagsShift : unsigned + { + OpaqueKHR = 0, + NoOpaqueKHR = 1, + TerminateOnFirstHitKHR = 2, + SkipClosestHitShaderKHR = 3, + CullBackFacingTrianglesKHR = 4, + CullFrontFacingTrianglesKHR = 5, + CullOpaqueKHR = 6, + CullNoOpaqueKHR = 7, + SkipTrianglesKHR = 8, + SkipAABBsKHR = 9, + ForceOpacityMicromap2StateEXT = 10, + Max = 0x7fffffff, + }; -enum class RayFlagsMask : unsigned { - MaskNone = 0, - OpaqueKHR = 0x00000001, - NoOpaqueKHR = 0x00000002, - TerminateOnFirstHitKHR = 0x00000004, - SkipClosestHitShaderKHR = 0x00000008, - CullBackFacingTrianglesKHR = 0x00000010, - CullFrontFacingTrianglesKHR = 0x00000020, - CullOpaqueKHR = 0x00000040, - CullNoOpaqueKHR = 0x00000080, - SkipTrianglesKHR = 0x00000100, - SkipAABBsKHR = 0x00000200, - ForceOpacityMicromap2StateEXT = 0x00000400, -}; + enum class RayFlagsMask : unsigned + { + MaskNone = 0, + OpaqueKHR = 0x00000001, + NoOpaqueKHR = 0x00000002, + TerminateOnFirstHitKHR = 0x00000004, + SkipClosestHitShaderKHR = 0x00000008, + CullBackFacingTrianglesKHR = 0x00000010, + CullFrontFacingTrianglesKHR = 0x00000020, + CullOpaqueKHR = 0x00000040, + CullNoOpaqueKHR = 0x00000080, + SkipTrianglesKHR = 0x00000100, + SkipAABBsKHR = 0x00000200, + ForceOpacityMicromap2StateEXT = 0x00000400, + }; -enum class RayQueryIntersection : unsigned { - RayQueryCandidateIntersectionKHR = 0, - RayQueryCommittedIntersectionKHR = 1, - Max = 0x7fffffff, -}; + enum class RayQueryIntersection : unsigned + { + RayQueryCandidateIntersectionKHR = 0, + RayQueryCommittedIntersectionKHR = 1, + Max = 0x7fffffff, + }; -enum class RayQueryCommittedIntersectionType : unsigned { - RayQueryCommittedIntersectionNoneKHR = 0, - RayQueryCommittedIntersectionTriangleKHR = 1, - RayQueryCommittedIntersectionGeneratedKHR = 2, - Max = 0x7fffffff, -}; + enum class RayQueryCommittedIntersectionType : unsigned + { + RayQueryCommittedIntersectionNoneKHR = 0, + RayQueryCommittedIntersectionTriangleKHR = 1, + RayQueryCommittedIntersectionGeneratedKHR = 2, + Max = 0x7fffffff, + }; -enum class RayQueryCandidateIntersectionType : unsigned { - RayQueryCandidateIntersectionTriangleKHR = 0, - RayQueryCandidateIntersectionAABBKHR = 1, - Max = 0x7fffffff, -}; + enum class RayQueryCandidateIntersectionType : unsigned + { + RayQueryCandidateIntersectionTriangleKHR = 0, + RayQueryCandidateIntersectionAABBKHR = 1, + Max = 0x7fffffff, + }; -enum class FragmentShadingRateShift : unsigned { - Vertical2Pixels = 0, - Vertical4Pixels = 1, - Horizontal2Pixels = 2, - Horizontal4Pixels = 3, - Max = 0x7fffffff, -}; + enum class FragmentShadingRateShift : unsigned + { + Vertical2Pixels = 0, + Vertical4Pixels = 1, + Horizontal2Pixels = 2, + Horizontal4Pixels = 3, + Max = 0x7fffffff, + }; -enum class FragmentShadingRateMask : unsigned { - MaskNone = 0, - Vertical2Pixels = 0x00000001, - Vertical4Pixels = 0x00000002, - Horizontal2Pixels = 0x00000004, - Horizontal4Pixels = 0x00000008, -}; + enum class FragmentShadingRateMask : unsigned + { + MaskNone = 0, + Vertical2Pixels = 0x00000001, + Vertical4Pixels = 0x00000002, + Horizontal2Pixels = 0x00000004, + Horizontal4Pixels = 0x00000008, + }; -enum class FPDenormMode : unsigned { - Preserve = 0, - FlushToZero = 1, - Max = 0x7fffffff, -}; + enum class FPDenormMode : unsigned + { + Preserve = 0, + FlushToZero = 1, + Max = 0x7fffffff, + }; -enum class FPOperationMode : unsigned { - IEEE = 0, - ALT = 1, - Max = 0x7fffffff, -}; + enum class FPOperationMode : unsigned + { + IEEE = 0, + ALT = 1, + Max = 0x7fffffff, + }; -enum class QuantizationModes : unsigned { - TRN = 0, - TRN_ZERO = 1, - RND = 2, - RND_ZERO = 3, - RND_INF = 4, - RND_MIN_INF = 5, - RND_CONV = 6, - RND_CONV_ODD = 7, - Max = 0x7fffffff, -}; + enum class QuantizationModes : unsigned + { + TRN = 0, + TRN_ZERO = 1, + RND = 2, + RND_ZERO = 3, + RND_INF = 4, + RND_MIN_INF = 5, + RND_CONV = 6, + RND_CONV_ODD = 7, + Max = 0x7fffffff, + }; -enum class OverflowModes : unsigned { - WRAP = 0, - SAT = 1, - SAT_ZERO = 2, - SAT_SYM = 3, - Max = 0x7fffffff, -}; + enum class OverflowModes : unsigned + { + WRAP = 0, + SAT = 1, + SAT_ZERO = 2, + SAT_SYM = 3, + Max = 0x7fffffff, + }; -enum class PackedVectorFormat : unsigned { - PackedVectorFormat4x8Bit = 0, - PackedVectorFormat4x8BitKHR = 0, - Max = 0x7fffffff, -}; + enum class PackedVectorFormat : unsigned + { + PackedVectorFormat4x8Bit = 0, + PackedVectorFormat4x8BitKHR = 0, + Max = 0x7fffffff, + }; -enum class Op : unsigned { - OpNop = 0, - OpUndef = 1, - OpSourceContinued = 2, - OpSource = 3, - OpSourceExtension = 4, - OpName = 5, - OpMemberName = 6, - OpString = 7, - OpLine = 8, - OpExtension = 10, - OpExtInstImport = 11, - OpExtInst = 12, - OpMemoryModel = 14, - OpEntryPoint = 15, - OpExecutionMode = 16, - OpCapability = 17, - OpTypeVoid = 19, - OpTypeBool = 20, - OpTypeInt = 21, - OpTypeFloat = 22, - OpTypeVector = 23, - OpTypeMatrix = 24, - OpTypeImage = 25, - OpTypeSampler = 26, - OpTypeSampledImage = 27, - OpTypeArray = 28, - OpTypeRuntimeArray = 29, - OpTypeStruct = 30, - OpTypeOpaque = 31, - OpTypePointer = 32, - OpTypeFunction = 33, - OpTypeEvent = 34, - OpTypeDeviceEvent = 35, - OpTypeReserveId = 36, - OpTypeQueue = 37, - OpTypePipe = 38, - OpTypeForwardPointer = 39, - OpConstantTrue = 41, - OpConstantFalse = 42, - OpConstant = 43, - OpConstantComposite = 44, - OpConstantSampler = 45, - OpConstantNull = 46, - OpSpecConstantTrue = 48, - OpSpecConstantFalse = 49, - OpSpecConstant = 50, - OpSpecConstantComposite = 51, - OpSpecConstantOp = 52, - OpFunction = 54, - OpFunctionParameter = 55, - OpFunctionEnd = 56, - OpFunctionCall = 57, - OpVariable = 59, - OpImageTexelPointer = 60, - OpLoad = 61, - OpStore = 62, - OpCopyMemory = 63, - OpCopyMemorySized = 64, - OpAccessChain = 65, - OpInBoundsAccessChain = 66, - OpPtrAccessChain = 67, - OpArrayLength = 68, - OpGenericPtrMemSemantics = 69, - OpInBoundsPtrAccessChain = 70, - OpDecorate = 71, - OpMemberDecorate = 72, - OpDecorationGroup = 73, - OpGroupDecorate = 74, - OpGroupMemberDecorate = 75, - OpVectorExtractDynamic = 77, - OpVectorInsertDynamic = 78, - OpVectorShuffle = 79, - OpCompositeConstruct = 80, - OpCompositeExtract = 81, - OpCompositeInsert = 82, - OpCopyObject = 83, - OpTranspose = 84, - OpSampledImage = 86, - OpImageSampleImplicitLod = 87, - OpImageSampleExplicitLod = 88, - OpImageSampleDrefImplicitLod = 89, - OpImageSampleDrefExplicitLod = 90, - OpImageSampleProjImplicitLod = 91, - OpImageSampleProjExplicitLod = 92, - OpImageSampleProjDrefImplicitLod = 93, - OpImageSampleProjDrefExplicitLod = 94, - OpImageFetch = 95, - OpImageGather = 96, - OpImageDrefGather = 97, - OpImageRead = 98, - OpImageWrite = 99, - OpImage = 100, - OpImageQueryFormat = 101, - OpImageQueryOrder = 102, - OpImageQuerySizeLod = 103, - OpImageQuerySize = 104, - OpImageQueryLod = 105, - OpImageQueryLevels = 106, - OpImageQuerySamples = 107, - OpConvertFToU = 109, - OpConvertFToS = 110, - OpConvertSToF = 111, - OpConvertUToF = 112, - OpUConvert = 113, - OpSConvert = 114, - OpFConvert = 115, - OpQuantizeToF16 = 116, - OpConvertPtrToU = 117, - OpSatConvertSToU = 118, - OpSatConvertUToS = 119, - OpConvertUToPtr = 120, - OpPtrCastToGeneric = 121, - OpGenericCastToPtr = 122, - OpGenericCastToPtrExplicit = 123, - OpBitcast = 124, - OpSNegate = 126, - OpFNegate = 127, - OpIAdd = 128, - OpFAdd = 129, - OpISub = 130, - OpFSub = 131, - OpIMul = 132, - OpFMul = 133, - OpUDiv = 134, - OpSDiv = 135, - OpFDiv = 136, - OpUMod = 137, - OpSRem = 138, - OpSMod = 139, - OpFRem = 140, - OpFMod = 141, - OpVectorTimesScalar = 142, - OpMatrixTimesScalar = 143, - OpVectorTimesMatrix = 144, - OpMatrixTimesVector = 145, - OpMatrixTimesMatrix = 146, - OpOuterProduct = 147, - OpDot = 148, - OpIAddCarry = 149, - OpISubBorrow = 150, - OpUMulExtended = 151, - OpSMulExtended = 152, - OpAny = 154, - OpAll = 155, - OpIsNan = 156, - OpIsInf = 157, - OpIsFinite = 158, - OpIsNormal = 159, - OpSignBitSet = 160, - OpLessOrGreater = 161, - OpOrdered = 162, - OpUnordered = 163, - OpLogicalEqual = 164, - OpLogicalNotEqual = 165, - OpLogicalOr = 166, - OpLogicalAnd = 167, - OpLogicalNot = 168, - OpSelect = 169, - OpIEqual = 170, - OpINotEqual = 171, - OpUGreaterThan = 172, - OpSGreaterThan = 173, - OpUGreaterThanEqual = 174, - OpSGreaterThanEqual = 175, - OpULessThan = 176, - OpSLessThan = 177, - OpULessThanEqual = 178, - OpSLessThanEqual = 179, - OpFOrdEqual = 180, - OpFUnordEqual = 181, - OpFOrdNotEqual = 182, - OpFUnordNotEqual = 183, - OpFOrdLessThan = 184, - OpFUnordLessThan = 185, - OpFOrdGreaterThan = 186, - OpFUnordGreaterThan = 187, - OpFOrdLessThanEqual = 188, - OpFUnordLessThanEqual = 189, - OpFOrdGreaterThanEqual = 190, - OpFUnordGreaterThanEqual = 191, - OpShiftRightLogical = 194, - OpShiftRightArithmetic = 195, - OpShiftLeftLogical = 196, - OpBitwiseOr = 197, - OpBitwiseXor = 198, - OpBitwiseAnd = 199, - OpNot = 200, - OpBitFieldInsert = 201, - OpBitFieldSExtract = 202, - OpBitFieldUExtract = 203, - OpBitReverse = 204, - OpBitCount = 205, - OpDPdx = 207, - OpDPdy = 208, - OpFwidth = 209, - OpDPdxFine = 210, - OpDPdyFine = 211, - OpFwidthFine = 212, - OpDPdxCoarse = 213, - OpDPdyCoarse = 214, - OpFwidthCoarse = 215, - OpEmitVertex = 218, - OpEndPrimitive = 219, - OpEmitStreamVertex = 220, - OpEndStreamPrimitive = 221, - OpControlBarrier = 224, - OpMemoryBarrier = 225, - OpAtomicLoad = 227, - OpAtomicStore = 228, - OpAtomicExchange = 229, - OpAtomicCompareExchange = 230, - OpAtomicCompareExchangeWeak = 231, - OpAtomicIIncrement = 232, - OpAtomicIDecrement = 233, - OpAtomicIAdd = 234, - OpAtomicISub = 235, - OpAtomicSMin = 236, - OpAtomicUMin = 237, - OpAtomicSMax = 238, - OpAtomicUMax = 239, - OpAtomicAnd = 240, - OpAtomicOr = 241, - OpAtomicXor = 242, - OpPhi = 245, - OpLoopMerge = 246, - OpSelectionMerge = 247, - OpLabel = 248, - OpBranch = 249, - OpBranchConditional = 250, - OpSwitch = 251, - OpKill = 252, - OpReturn = 253, - OpReturnValue = 254, - OpUnreachable = 255, - OpLifetimeStart = 256, - OpLifetimeStop = 257, - OpGroupAsyncCopy = 259, - OpGroupWaitEvents = 260, - OpGroupAll = 261, - OpGroupAny = 262, - OpGroupBroadcast = 263, - OpGroupIAdd = 264, - OpGroupFAdd = 265, - OpGroupFMin = 266, - OpGroupUMin = 267, - OpGroupSMin = 268, - OpGroupFMax = 269, - OpGroupUMax = 270, - OpGroupSMax = 271, - OpReadPipe = 274, - OpWritePipe = 275, - OpReservedReadPipe = 276, - OpReservedWritePipe = 277, - OpReserveReadPipePackets = 278, - OpReserveWritePipePackets = 279, - OpCommitReadPipe = 280, - OpCommitWritePipe = 281, - OpIsValidReserveId = 282, - OpGetNumPipePackets = 283, - OpGetMaxPipePackets = 284, - OpGroupReserveReadPipePackets = 285, - OpGroupReserveWritePipePackets = 286, - OpGroupCommitReadPipe = 287, - OpGroupCommitWritePipe = 288, - OpEnqueueMarker = 291, - OpEnqueueKernel = 292, - OpGetKernelNDrangeSubGroupCount = 293, - OpGetKernelNDrangeMaxSubGroupSize = 294, - OpGetKernelWorkGroupSize = 295, - OpGetKernelPreferredWorkGroupSizeMultiple = 296, - OpRetainEvent = 297, - OpReleaseEvent = 298, - OpCreateUserEvent = 299, - OpIsValidEvent = 300, - OpSetUserEventStatus = 301, - OpCaptureEventProfilingInfo = 302, - OpGetDefaultQueue = 303, - OpBuildNDRange = 304, - OpImageSparseSampleImplicitLod = 305, - OpImageSparseSampleExplicitLod = 306, - OpImageSparseSampleDrefImplicitLod = 307, - OpImageSparseSampleDrefExplicitLod = 308, - OpImageSparseSampleProjImplicitLod = 309, - OpImageSparseSampleProjExplicitLod = 310, - OpImageSparseSampleProjDrefImplicitLod = 311, - OpImageSparseSampleProjDrefExplicitLod = 312, - OpImageSparseFetch = 313, - OpImageSparseGather = 314, - OpImageSparseDrefGather = 315, - OpImageSparseTexelsResident = 316, - OpNoLine = 317, - OpAtomicFlagTestAndSet = 318, - OpAtomicFlagClear = 319, - OpImageSparseRead = 320, - OpSizeOf = 321, - OpTypePipeStorage = 322, - OpConstantPipeStorage = 323, - OpCreatePipeFromPipeStorage = 324, - OpGetKernelLocalSizeForSubgroupCount = 325, - OpGetKernelMaxNumSubgroups = 326, - OpTypeNamedBarrier = 327, - OpNamedBarrierInitialize = 328, - OpMemoryNamedBarrier = 329, - OpModuleProcessed = 330, - OpExecutionModeId = 331, - OpDecorateId = 332, - OpGroupNonUniformElect = 333, - OpGroupNonUniformAll = 334, - OpGroupNonUniformAny = 335, - OpGroupNonUniformAllEqual = 336, - OpGroupNonUniformBroadcast = 337, - OpGroupNonUniformBroadcastFirst = 338, - OpGroupNonUniformBallot = 339, - OpGroupNonUniformInverseBallot = 340, - OpGroupNonUniformBallotBitExtract = 341, - OpGroupNonUniformBallotBitCount = 342, - OpGroupNonUniformBallotFindLSB = 343, - OpGroupNonUniformBallotFindMSB = 344, - OpGroupNonUniformShuffle = 345, - OpGroupNonUniformShuffleXor = 346, - OpGroupNonUniformShuffleUp = 347, - OpGroupNonUniformShuffleDown = 348, - OpGroupNonUniformIAdd = 349, - OpGroupNonUniformFAdd = 350, - OpGroupNonUniformIMul = 351, - OpGroupNonUniformFMul = 352, - OpGroupNonUniformSMin = 353, - OpGroupNonUniformUMin = 354, - OpGroupNonUniformFMin = 355, - OpGroupNonUniformSMax = 356, - OpGroupNonUniformUMax = 357, - OpGroupNonUniformFMax = 358, - OpGroupNonUniformBitwiseAnd = 359, - OpGroupNonUniformBitwiseOr = 360, - OpGroupNonUniformBitwiseXor = 361, - OpGroupNonUniformLogicalAnd = 362, - OpGroupNonUniformLogicalOr = 363, - OpGroupNonUniformLogicalXor = 364, - OpGroupNonUniformQuadBroadcast = 365, - OpGroupNonUniformQuadSwap = 366, - OpCopyLogical = 400, - OpPtrEqual = 401, - OpPtrNotEqual = 402, - OpPtrDiff = 403, - OpColorAttachmentReadEXT = 4160, - OpDepthAttachmentReadEXT = 4161, - OpStencilAttachmentReadEXT = 4162, - OpTerminateInvocation = 4416, - OpSubgroupBallotKHR = 4421, - OpSubgroupFirstInvocationKHR = 4422, - OpSubgroupAllKHR = 4428, - OpSubgroupAnyKHR = 4429, - OpSubgroupAllEqualKHR = 4430, - OpGroupNonUniformRotateKHR = 4431, - OpSubgroupReadInvocationKHR = 4432, - OpTraceRayKHR = 4445, - OpExecuteCallableKHR = 4446, - OpConvertUToAccelerationStructureKHR = 4447, - OpIgnoreIntersectionKHR = 4448, - OpTerminateRayKHR = 4449, - OpSDot = 4450, - OpSDotKHR = 4450, - OpUDot = 4451, - OpUDotKHR = 4451, - OpSUDot = 4452, - OpSUDotKHR = 4452, - OpSDotAccSat = 4453, - OpSDotAccSatKHR = 4453, - OpUDotAccSat = 4454, - OpUDotAccSatKHR = 4454, - OpSUDotAccSat = 4455, - OpSUDotAccSatKHR = 4455, - OpTypeRayQueryKHR = 4472, - OpRayQueryInitializeKHR = 4473, - OpRayQueryTerminateKHR = 4474, - OpRayQueryGenerateIntersectionKHR = 4475, - OpRayQueryConfirmIntersectionKHR = 4476, - OpRayQueryProceedKHR = 4477, - OpRayQueryGetIntersectionTypeKHR = 4479, - OpImageSampleWeightedQCOM = 4480, - OpImageBoxFilterQCOM = 4481, - OpImageBlockMatchSSDQCOM = 4482, - OpImageBlockMatchSADQCOM = 4483, - OpGroupIAddNonUniformAMD = 5000, - OpGroupFAddNonUniformAMD = 5001, - OpGroupFMinNonUniformAMD = 5002, - OpGroupUMinNonUniformAMD = 5003, - OpGroupSMinNonUniformAMD = 5004, - OpGroupFMaxNonUniformAMD = 5005, - OpGroupUMaxNonUniformAMD = 5006, - OpGroupSMaxNonUniformAMD = 5007, - OpFragmentMaskFetchAMD = 5011, - OpFragmentFetchAMD = 5012, - OpReadClockKHR = 5056, - OpHitObjectRecordHitMotionNV = 5249, - OpHitObjectRecordHitWithIndexMotionNV = 5250, - OpHitObjectRecordMissMotionNV = 5251, - OpHitObjectGetWorldToObjectNV = 5252, - OpHitObjectGetObjectToWorldNV = 5253, - OpHitObjectGetObjectRayDirectionNV = 5254, - OpHitObjectGetObjectRayOriginNV = 5255, - OpHitObjectTraceRayMotionNV = 5256, - OpHitObjectGetShaderRecordBufferHandleNV = 5257, - OpHitObjectGetShaderBindingTableRecordIndexNV = 5258, - OpHitObjectRecordEmptyNV = 5259, - OpHitObjectTraceRayNV = 5260, - OpHitObjectRecordHitNV = 5261, - OpHitObjectRecordHitWithIndexNV = 5262, - OpHitObjectRecordMissNV = 5263, - OpHitObjectExecuteShaderNV = 5264, - OpHitObjectGetCurrentTimeNV = 5265, - OpHitObjectGetAttributesNV = 5266, - OpHitObjectGetHitKindNV = 5267, - OpHitObjectGetPrimitiveIndexNV = 5268, - OpHitObjectGetGeometryIndexNV = 5269, - OpHitObjectGetInstanceIdNV = 5270, - OpHitObjectGetInstanceCustomIndexNV = 5271, - OpHitObjectGetWorldRayDirectionNV = 5272, - OpHitObjectGetWorldRayOriginNV = 5273, - OpHitObjectGetRayTMaxNV = 5274, - OpHitObjectGetRayTMinNV = 5275, - OpHitObjectIsEmptyNV = 5276, - OpHitObjectIsHitNV = 5277, - OpHitObjectIsMissNV = 5278, - OpReorderThreadWithHitObjectNV = 5279, - OpReorderThreadWithHintNV = 5280, - OpTypeHitObjectNV = 5281, - OpImageSampleFootprintNV = 5283, - OpEmitMeshTasksEXT = 5294, - OpSetMeshOutputsEXT = 5295, - OpGroupNonUniformPartitionNV = 5296, - OpWritePackedPrimitiveIndices4x8NV = 5299, - OpReportIntersectionKHR = 5334, - OpReportIntersectionNV = 5334, - OpIgnoreIntersectionNV = 5335, - OpTerminateRayNV = 5336, - OpTraceNV = 5337, - OpTraceMotionNV = 5338, - OpTraceRayMotionNV = 5339, - OpRayQueryGetIntersectionTriangleVertexPositionsKHR = 5340, - OpTypeAccelerationStructureKHR = 5341, - OpTypeAccelerationStructureNV = 5341, - OpExecuteCallableNV = 5344, - OpTypeCooperativeMatrixNV = 5358, - OpCooperativeMatrixLoadNV = 5359, - OpCooperativeMatrixStoreNV = 5360, - OpCooperativeMatrixMulAddNV = 5361, - OpCooperativeMatrixLengthNV = 5362, - OpBeginInvocationInterlockEXT = 5364, - OpEndInvocationInterlockEXT = 5365, - OpDemoteToHelperInvocation = 5380, - OpDemoteToHelperInvocationEXT = 5380, - OpIsHelperInvocationEXT = 5381, - OpConvertUToImageNV = 5391, - OpConvertUToSamplerNV = 5392, - OpConvertImageToUNV = 5393, - OpConvertSamplerToUNV = 5394, - OpConvertUToSampledImageNV = 5395, - OpConvertSampledImageToUNV = 5396, - OpSamplerImageAddressingModeNV = 5397, - OpSubgroupShuffleINTEL = 5571, - OpSubgroupShuffleDownINTEL = 5572, - OpSubgroupShuffleUpINTEL = 5573, - OpSubgroupShuffleXorINTEL = 5574, - OpSubgroupBlockReadINTEL = 5575, - OpSubgroupBlockWriteINTEL = 5576, - OpSubgroupImageBlockReadINTEL = 5577, - OpSubgroupImageBlockWriteINTEL = 5578, - OpSubgroupImageMediaBlockReadINTEL = 5580, - OpSubgroupImageMediaBlockWriteINTEL = 5581, - OpUCountLeadingZerosINTEL = 5585, - OpUCountTrailingZerosINTEL = 5586, - OpAbsISubINTEL = 5587, - OpAbsUSubINTEL = 5588, - OpIAddSatINTEL = 5589, - OpUAddSatINTEL = 5590, - OpIAverageINTEL = 5591, - OpUAverageINTEL = 5592, - OpIAverageRoundedINTEL = 5593, - OpUAverageRoundedINTEL = 5594, - OpISubSatINTEL = 5595, - OpUSubSatINTEL = 5596, - OpIMul32x16INTEL = 5597, - OpUMul32x16INTEL = 5598, - OpConstantFunctionPointerINTEL = 5600, - OpFunctionPointerCallINTEL = 5601, - OpAsmTargetINTEL = 5609, - OpAsmINTEL = 5610, - OpAsmCallINTEL = 5611, - OpAtomicFMinEXT = 5614, - OpAtomicFMaxEXT = 5615, - OpAssumeTrueKHR = 5630, - OpExpectKHR = 5631, - OpDecorateString = 5632, - OpDecorateStringGOOGLE = 5632, - OpMemberDecorateString = 5633, - OpMemberDecorateStringGOOGLE = 5633, - OpVmeImageINTEL = 5699, - OpTypeVmeImageINTEL = 5700, - OpTypeAvcImePayloadINTEL = 5701, - OpTypeAvcRefPayloadINTEL = 5702, - OpTypeAvcSicPayloadINTEL = 5703, - OpTypeAvcMcePayloadINTEL = 5704, - OpTypeAvcMceResultINTEL = 5705, - OpTypeAvcImeResultINTEL = 5706, - OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, - OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, - OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, - OpTypeAvcImeDualReferenceStreaminINTEL = 5710, - OpTypeAvcRefResultINTEL = 5711, - OpTypeAvcSicResultINTEL = 5712, - OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, - OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, - OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, - OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, - OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, - OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, - OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, - OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, - OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, - OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, - OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, - OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, - OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, - OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, - OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, - OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, - OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, - OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, - OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, - OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, - OpSubgroupAvcMceConvertToImeResultINTEL = 5733, - OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, - OpSubgroupAvcMceConvertToRefResultINTEL = 5735, - OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, - OpSubgroupAvcMceConvertToSicResultINTEL = 5737, - OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, - OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, - OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, - OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, - OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, - OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, - OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, - OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, - OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, - OpSubgroupAvcImeInitializeINTEL = 5747, - OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, - OpSubgroupAvcImeSetDualReferenceINTEL = 5749, - OpSubgroupAvcImeRefWindowSizeINTEL = 5750, - OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, - OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, - OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, - OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, - OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, - OpSubgroupAvcImeSetWeightedSadINTEL = 5756, - OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, - OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, - OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, - OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, - OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, - OpSubgroupAvcImeConvertToMceResultINTEL = 5765, - OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, - OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, - OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, - OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = - 5770, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, - OpSubgroupAvcImeGetBorderReachedINTEL = 5776, - OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, - OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, - OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, - OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, - OpSubgroupAvcFmeInitializeINTEL = 5781, - OpSubgroupAvcBmeInitializeINTEL = 5782, - OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, - OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, - OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, - OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, - OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, - OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, - OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, - OpSubgroupAvcRefConvertToMceResultINTEL = 5790, - OpSubgroupAvcSicInitializeINTEL = 5791, - OpSubgroupAvcSicConfigureSkcINTEL = 5792, - OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, - OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, - OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, - OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, - OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, - OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, - OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, - OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, - OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, - OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, - OpSubgroupAvcSicEvaluateIpeINTEL = 5803, - OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, - OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, - OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, - OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, - OpSubgroupAvcSicConvertToMceResultINTEL = 5808, - OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, - OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, - OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, - OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, - OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, - OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, - OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, - OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, - OpVariableLengthArrayINTEL = 5818, - OpSaveMemoryINTEL = 5819, - OpRestoreMemoryINTEL = 5820, - OpArbitraryFloatSinCosPiINTEL = 5840, - OpArbitraryFloatCastINTEL = 5841, - OpArbitraryFloatCastFromIntINTEL = 5842, - OpArbitraryFloatCastToIntINTEL = 5843, - OpArbitraryFloatAddINTEL = 5846, - OpArbitraryFloatSubINTEL = 5847, - OpArbitraryFloatMulINTEL = 5848, - OpArbitraryFloatDivINTEL = 5849, - OpArbitraryFloatGTINTEL = 5850, - OpArbitraryFloatGEINTEL = 5851, - OpArbitraryFloatLTINTEL = 5852, - OpArbitraryFloatLEINTEL = 5853, - OpArbitraryFloatEQINTEL = 5854, - OpArbitraryFloatRecipINTEL = 5855, - OpArbitraryFloatRSqrtINTEL = 5856, - OpArbitraryFloatCbrtINTEL = 5857, - OpArbitraryFloatHypotINTEL = 5858, - OpArbitraryFloatSqrtINTEL = 5859, - OpArbitraryFloatLogINTEL = 5860, - OpArbitraryFloatLog2INTEL = 5861, - OpArbitraryFloatLog10INTEL = 5862, - OpArbitraryFloatLog1pINTEL = 5863, - OpArbitraryFloatExpINTEL = 5864, - OpArbitraryFloatExp2INTEL = 5865, - OpArbitraryFloatExp10INTEL = 5866, - OpArbitraryFloatExpm1INTEL = 5867, - OpArbitraryFloatSinINTEL = 5868, - OpArbitraryFloatCosINTEL = 5869, - OpArbitraryFloatSinCosINTEL = 5870, - OpArbitraryFloatSinPiINTEL = 5871, - OpArbitraryFloatCosPiINTEL = 5872, - OpArbitraryFloatASinINTEL = 5873, - OpArbitraryFloatASinPiINTEL = 5874, - OpArbitraryFloatACosINTEL = 5875, - OpArbitraryFloatACosPiINTEL = 5876, - OpArbitraryFloatATanINTEL = 5877, - OpArbitraryFloatATanPiINTEL = 5878, - OpArbitraryFloatATan2INTEL = 5879, - OpArbitraryFloatPowINTEL = 5880, - OpArbitraryFloatPowRINTEL = 5881, - OpArbitraryFloatPowNINTEL = 5882, - OpLoopControlINTEL = 5887, - OpAliasDomainDeclINTEL = 5911, - OpAliasScopeDeclINTEL = 5912, - OpAliasScopeListDeclINTEL = 5913, - OpFixedSqrtINTEL = 5923, - OpFixedRecipINTEL = 5924, - OpFixedRsqrtINTEL = 5925, - OpFixedSinINTEL = 5926, - OpFixedCosINTEL = 5927, - OpFixedSinCosINTEL = 5928, - OpFixedSinPiINTEL = 5929, - OpFixedCosPiINTEL = 5930, - OpFixedSinCosPiINTEL = 5931, - OpFixedLogINTEL = 5932, - OpFixedExpINTEL = 5933, - OpPtrCastToCrossWorkgroupINTEL = 5934, - OpCrossWorkgroupCastToPtrINTEL = 5938, - OpReadPipeBlockingINTEL = 5946, - OpWritePipeBlockingINTEL = 5947, - OpFPGARegINTEL = 5949, - OpRayQueryGetRayTMinKHR = 6016, - OpRayQueryGetRayFlagsKHR = 6017, - OpRayQueryGetIntersectionTKHR = 6018, - OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, - OpRayQueryGetIntersectionInstanceIdKHR = 6020, - OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, - OpRayQueryGetIntersectionGeometryIndexKHR = 6022, - OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, - OpRayQueryGetIntersectionBarycentricsKHR = 6024, - OpRayQueryGetIntersectionFrontFaceKHR = 6025, - OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, - OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, - OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, - OpRayQueryGetWorldRayDirectionKHR = 6029, - OpRayQueryGetWorldRayOriginKHR = 6030, - OpRayQueryGetIntersectionObjectToWorldKHR = 6031, - OpRayQueryGetIntersectionWorldToObjectKHR = 6032, - OpAtomicFAddEXT = 6035, - OpTypeBufferSurfaceINTEL = 6086, - OpTypeStructContinuedINTEL = 6090, - OpConstantCompositeContinuedINTEL = 6091, - OpSpecConstantCompositeContinuedINTEL = 6092, - OpConvertFToBF16INTEL = 6116, - OpConvertBF16ToFINTEL = 6117, - OpControlBarrierArriveINTEL = 6142, - OpControlBarrierWaitINTEL = 6143, - OpGroupIMulKHR = 6401, - OpGroupFMulKHR = 6402, - OpGroupBitwiseAndKHR = 6403, - OpGroupBitwiseOrKHR = 6404, - OpGroupBitwiseXorKHR = 6405, - OpGroupLogicalAndKHR = 6406, - OpGroupLogicalOrKHR = 6407, - OpGroupLogicalXorKHR = 6408, - Max = 0x7fffffff, -}; + enum class Op : unsigned + { + OpNop = 0, + OpUndef = 1, + OpSourceContinued = 2, + OpSource = 3, + OpSourceExtension = 4, + OpName = 5, + OpMemberName = 6, + OpString = 7, + OpLine = 8, + OpExtension = 10, + OpExtInstImport = 11, + OpExtInst = 12, + OpMemoryModel = 14, + OpEntryPoint = 15, + OpExecutionMode = 16, + OpCapability = 17, + OpTypeVoid = 19, + OpTypeBool = 20, + OpTypeInt = 21, + OpTypeFloat = 22, + OpTypeVector = 23, + OpTypeMatrix = 24, + OpTypeImage = 25, + OpTypeSampler = 26, + OpTypeSampledImage = 27, + OpTypeArray = 28, + OpTypeRuntimeArray = 29, + OpTypeStruct = 30, + OpTypeOpaque = 31, + OpTypePointer = 32, + OpTypeFunction = 33, + OpTypeEvent = 34, + OpTypeDeviceEvent = 35, + OpTypeReserveId = 36, + OpTypeQueue = 37, + OpTypePipe = 38, + OpTypeForwardPointer = 39, + OpConstantTrue = 41, + OpConstantFalse = 42, + OpConstant = 43, + OpConstantComposite = 44, + OpConstantSampler = 45, + OpConstantNull = 46, + OpSpecConstantTrue = 48, + OpSpecConstantFalse = 49, + OpSpecConstant = 50, + OpSpecConstantComposite = 51, + OpSpecConstantOp = 52, + OpFunction = 54, + OpFunctionParameter = 55, + OpFunctionEnd = 56, + OpFunctionCall = 57, + OpVariable = 59, + OpImageTexelPointer = 60, + OpLoad = 61, + OpStore = 62, + OpCopyMemory = 63, + OpCopyMemorySized = 64, + OpAccessChain = 65, + OpInBoundsAccessChain = 66, + OpPtrAccessChain = 67, + OpArrayLength = 68, + OpGenericPtrMemSemantics = 69, + OpInBoundsPtrAccessChain = 70, + OpDecorate = 71, + OpMemberDecorate = 72, + OpDecorationGroup = 73, + OpGroupDecorate = 74, + OpGroupMemberDecorate = 75, + OpVectorExtractDynamic = 77, + OpVectorInsertDynamic = 78, + OpVectorShuffle = 79, + OpCompositeConstruct = 80, + OpCompositeExtract = 81, + OpCompositeInsert = 82, + OpCopyObject = 83, + OpTranspose = 84, + OpSampledImage = 86, + OpImageSampleImplicitLod = 87, + OpImageSampleExplicitLod = 88, + OpImageSampleDrefImplicitLod = 89, + OpImageSampleDrefExplicitLod = 90, + OpImageSampleProjImplicitLod = 91, + OpImageSampleProjExplicitLod = 92, + OpImageSampleProjDrefImplicitLod = 93, + OpImageSampleProjDrefExplicitLod = 94, + OpImageFetch = 95, + OpImageGather = 96, + OpImageDrefGather = 97, + OpImageRead = 98, + OpImageWrite = 99, + OpImage = 100, + OpImageQueryFormat = 101, + OpImageQueryOrder = 102, + OpImageQuerySizeLod = 103, + OpImageQuerySize = 104, + OpImageQueryLod = 105, + OpImageQueryLevels = 106, + OpImageQuerySamples = 107, + OpConvertFToU = 109, + OpConvertFToS = 110, + OpConvertSToF = 111, + OpConvertUToF = 112, + OpUConvert = 113, + OpSConvert = 114, + OpFConvert = 115, + OpQuantizeToF16 = 116, + OpConvertPtrToU = 117, + OpSatConvertSToU = 118, + OpSatConvertUToS = 119, + OpConvertUToPtr = 120, + OpPtrCastToGeneric = 121, + OpGenericCastToPtr = 122, + OpGenericCastToPtrExplicit = 123, + OpBitcast = 124, + OpSNegate = 126, + OpFNegate = 127, + OpIAdd = 128, + OpFAdd = 129, + OpISub = 130, + OpFSub = 131, + OpIMul = 132, + OpFMul = 133, + OpUDiv = 134, + OpSDiv = 135, + OpFDiv = 136, + OpUMod = 137, + OpSRem = 138, + OpSMod = 139, + OpFRem = 140, + OpFMod = 141, + OpVectorTimesScalar = 142, + OpMatrixTimesScalar = 143, + OpVectorTimesMatrix = 144, + OpMatrixTimesVector = 145, + OpMatrixTimesMatrix = 146, + OpOuterProduct = 147, + OpDot = 148, + OpIAddCarry = 149, + OpISubBorrow = 150, + OpUMulExtended = 151, + OpSMulExtended = 152, + OpAny = 154, + OpAll = 155, + OpIsNan = 156, + OpIsInf = 157, + OpIsFinite = 158, + OpIsNormal = 159, + OpSignBitSet = 160, + OpLessOrGreater = 161, + OpOrdered = 162, + OpUnordered = 163, + OpLogicalEqual = 164, + OpLogicalNotEqual = 165, + OpLogicalOr = 166, + OpLogicalAnd = 167, + OpLogicalNot = 168, + OpSelect = 169, + OpIEqual = 170, + OpINotEqual = 171, + OpUGreaterThan = 172, + OpSGreaterThan = 173, + OpUGreaterThanEqual = 174, + OpSGreaterThanEqual = 175, + OpULessThan = 176, + OpSLessThan = 177, + OpULessThanEqual = 178, + OpSLessThanEqual = 179, + OpFOrdEqual = 180, + OpFUnordEqual = 181, + OpFOrdNotEqual = 182, + OpFUnordNotEqual = 183, + OpFOrdLessThan = 184, + OpFUnordLessThan = 185, + OpFOrdGreaterThan = 186, + OpFUnordGreaterThan = 187, + OpFOrdLessThanEqual = 188, + OpFUnordLessThanEqual = 189, + OpFOrdGreaterThanEqual = 190, + OpFUnordGreaterThanEqual = 191, + OpShiftRightLogical = 194, + OpShiftRightArithmetic = 195, + OpShiftLeftLogical = 196, + OpBitwiseOr = 197, + OpBitwiseXor = 198, + OpBitwiseAnd = 199, + OpNot = 200, + OpBitFieldInsert = 201, + OpBitFieldSExtract = 202, + OpBitFieldUExtract = 203, + OpBitReverse = 204, + OpBitCount = 205, + OpDPdx = 207, + OpDPdy = 208, + OpFwidth = 209, + OpDPdxFine = 210, + OpDPdyFine = 211, + OpFwidthFine = 212, + OpDPdxCoarse = 213, + OpDPdyCoarse = 214, + OpFwidthCoarse = 215, + OpEmitVertex = 218, + OpEndPrimitive = 219, + OpEmitStreamVertex = 220, + OpEndStreamPrimitive = 221, + OpControlBarrier = 224, + OpMemoryBarrier = 225, + OpAtomicLoad = 227, + OpAtomicStore = 228, + OpAtomicExchange = 229, + OpAtomicCompareExchange = 230, + OpAtomicCompareExchangeWeak = 231, + OpAtomicIIncrement = 232, + OpAtomicIDecrement = 233, + OpAtomicIAdd = 234, + OpAtomicISub = 235, + OpAtomicSMin = 236, + OpAtomicUMin = 237, + OpAtomicSMax = 238, + OpAtomicUMax = 239, + OpAtomicAnd = 240, + OpAtomicOr = 241, + OpAtomicXor = 242, + OpPhi = 245, + OpLoopMerge = 246, + OpSelectionMerge = 247, + OpLabel = 248, + OpBranch = 249, + OpBranchConditional = 250, + OpSwitch = 251, + OpKill = 252, + OpReturn = 253, + OpReturnValue = 254, + OpUnreachable = 255, + OpLifetimeStart = 256, + OpLifetimeStop = 257, + OpGroupAsyncCopy = 259, + OpGroupWaitEvents = 260, + OpGroupAll = 261, + OpGroupAny = 262, + OpGroupBroadcast = 263, + OpGroupIAdd = 264, + OpGroupFAdd = 265, + OpGroupFMin = 266, + OpGroupUMin = 267, + OpGroupSMin = 268, + OpGroupFMax = 269, + OpGroupUMax = 270, + OpGroupSMax = 271, + OpReadPipe = 274, + OpWritePipe = 275, + OpReservedReadPipe = 276, + OpReservedWritePipe = 277, + OpReserveReadPipePackets = 278, + OpReserveWritePipePackets = 279, + OpCommitReadPipe = 280, + OpCommitWritePipe = 281, + OpIsValidReserveId = 282, + OpGetNumPipePackets = 283, + OpGetMaxPipePackets = 284, + OpGroupReserveReadPipePackets = 285, + OpGroupReserveWritePipePackets = 286, + OpGroupCommitReadPipe = 287, + OpGroupCommitWritePipe = 288, + OpEnqueueMarker = 291, + OpEnqueueKernel = 292, + OpGetKernelNDrangeSubGroupCount = 293, + OpGetKernelNDrangeMaxSubGroupSize = 294, + OpGetKernelWorkGroupSize = 295, + OpGetKernelPreferredWorkGroupSizeMultiple = 296, + OpRetainEvent = 297, + OpReleaseEvent = 298, + OpCreateUserEvent = 299, + OpIsValidEvent = 300, + OpSetUserEventStatus = 301, + OpCaptureEventProfilingInfo = 302, + OpGetDefaultQueue = 303, + OpBuildNDRange = 304, + OpImageSparseSampleImplicitLod = 305, + OpImageSparseSampleExplicitLod = 306, + OpImageSparseSampleDrefImplicitLod = 307, + OpImageSparseSampleDrefExplicitLod = 308, + OpImageSparseSampleProjImplicitLod = 309, + OpImageSparseSampleProjExplicitLod = 310, + OpImageSparseSampleProjDrefImplicitLod = 311, + OpImageSparseSampleProjDrefExplicitLod = 312, + OpImageSparseFetch = 313, + OpImageSparseGather = 314, + OpImageSparseDrefGather = 315, + OpImageSparseTexelsResident = 316, + OpNoLine = 317, + OpAtomicFlagTestAndSet = 318, + OpAtomicFlagClear = 319, + OpImageSparseRead = 320, + OpSizeOf = 321, + OpTypePipeStorage = 322, + OpConstantPipeStorage = 323, + OpCreatePipeFromPipeStorage = 324, + OpGetKernelLocalSizeForSubgroupCount = 325, + OpGetKernelMaxNumSubgroups = 326, + OpTypeNamedBarrier = 327, + OpNamedBarrierInitialize = 328, + OpMemoryNamedBarrier = 329, + OpModuleProcessed = 330, + OpExecutionModeId = 331, + OpDecorateId = 332, + OpGroupNonUniformElect = 333, + OpGroupNonUniformAll = 334, + OpGroupNonUniformAny = 335, + OpGroupNonUniformAllEqual = 336, + OpGroupNonUniformBroadcast = 337, + OpGroupNonUniformBroadcastFirst = 338, + OpGroupNonUniformBallot = 339, + OpGroupNonUniformInverseBallot = 340, + OpGroupNonUniformBallotBitExtract = 341, + OpGroupNonUniformBallotBitCount = 342, + OpGroupNonUniformBallotFindLSB = 343, + OpGroupNonUniformBallotFindMSB = 344, + OpGroupNonUniformShuffle = 345, + OpGroupNonUniformShuffleXor = 346, + OpGroupNonUniformShuffleUp = 347, + OpGroupNonUniformShuffleDown = 348, + OpGroupNonUniformIAdd = 349, + OpGroupNonUniformFAdd = 350, + OpGroupNonUniformIMul = 351, + OpGroupNonUniformFMul = 352, + OpGroupNonUniformSMin = 353, + OpGroupNonUniformUMin = 354, + OpGroupNonUniformFMin = 355, + OpGroupNonUniformSMax = 356, + OpGroupNonUniformUMax = 357, + OpGroupNonUniformFMax = 358, + OpGroupNonUniformBitwiseAnd = 359, + OpGroupNonUniformBitwiseOr = 360, + OpGroupNonUniformBitwiseXor = 361, + OpGroupNonUniformLogicalAnd = 362, + OpGroupNonUniformLogicalOr = 363, + OpGroupNonUniformLogicalXor = 364, + OpGroupNonUniformQuadBroadcast = 365, + OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, + OpColorAttachmentReadEXT = 4160, + OpDepthAttachmentReadEXT = 4161, + OpStencilAttachmentReadEXT = 4162, + OpTerminateInvocation = 4416, + OpSubgroupBallotKHR = 4421, + OpSubgroupFirstInvocationKHR = 4422, + OpSubgroupAllKHR = 4428, + OpSubgroupAnyKHR = 4429, + OpSubgroupAllEqualKHR = 4430, + OpGroupNonUniformRotateKHR = 4431, + OpSubgroupReadInvocationKHR = 4432, + OpTraceRayKHR = 4445, + OpExecuteCallableKHR = 4446, + OpConvertUToAccelerationStructureKHR = 4447, + OpIgnoreIntersectionKHR = 4448, + OpTerminateRayKHR = 4449, + OpSDot = 4450, + OpSDotKHR = 4450, + OpUDot = 4451, + OpUDotKHR = 4451, + OpSUDot = 4452, + OpSUDotKHR = 4452, + OpSDotAccSat = 4453, + OpSDotAccSatKHR = 4453, + OpUDotAccSat = 4454, + OpUDotAccSatKHR = 4454, + OpSUDotAccSat = 4455, + OpSUDotAccSatKHR = 4455, + OpTypeRayQueryKHR = 4472, + OpRayQueryInitializeKHR = 4473, + OpRayQueryTerminateKHR = 4474, + OpRayQueryGenerateIntersectionKHR = 4475, + OpRayQueryConfirmIntersectionKHR = 4476, + OpRayQueryProceedKHR = 4477, + OpRayQueryGetIntersectionTypeKHR = 4479, + OpImageSampleWeightedQCOM = 4480, + OpImageBoxFilterQCOM = 4481, + OpImageBlockMatchSSDQCOM = 4482, + OpImageBlockMatchSADQCOM = 4483, + OpGroupIAddNonUniformAMD = 5000, + OpGroupFAddNonUniformAMD = 5001, + OpGroupFMinNonUniformAMD = 5002, + OpGroupUMinNonUniformAMD = 5003, + OpGroupSMinNonUniformAMD = 5004, + OpGroupFMaxNonUniformAMD = 5005, + OpGroupUMaxNonUniformAMD = 5006, + OpGroupSMaxNonUniformAMD = 5007, + OpFragmentMaskFetchAMD = 5011, + OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpHitObjectRecordHitMotionNV = 5249, + OpHitObjectRecordHitWithIndexMotionNV = 5250, + OpHitObjectRecordMissMotionNV = 5251, + OpHitObjectGetWorldToObjectNV = 5252, + OpHitObjectGetObjectToWorldNV = 5253, + OpHitObjectGetObjectRayDirectionNV = 5254, + OpHitObjectGetObjectRayOriginNV = 5255, + OpHitObjectTraceRayMotionNV = 5256, + OpHitObjectGetShaderRecordBufferHandleNV = 5257, + OpHitObjectGetShaderBindingTableRecordIndexNV = 5258, + OpHitObjectRecordEmptyNV = 5259, + OpHitObjectTraceRayNV = 5260, + OpHitObjectRecordHitNV = 5261, + OpHitObjectRecordHitWithIndexNV = 5262, + OpHitObjectRecordMissNV = 5263, + OpHitObjectExecuteShaderNV = 5264, + OpHitObjectGetCurrentTimeNV = 5265, + OpHitObjectGetAttributesNV = 5266, + OpHitObjectGetHitKindNV = 5267, + OpHitObjectGetPrimitiveIndexNV = 5268, + OpHitObjectGetGeometryIndexNV = 5269, + OpHitObjectGetInstanceIdNV = 5270, + OpHitObjectGetInstanceCustomIndexNV = 5271, + OpHitObjectGetWorldRayDirectionNV = 5272, + OpHitObjectGetWorldRayOriginNV = 5273, + OpHitObjectGetRayTMaxNV = 5274, + OpHitObjectGetRayTMinNV = 5275, + OpHitObjectIsEmptyNV = 5276, + OpHitObjectIsHitNV = 5277, + OpHitObjectIsMissNV = 5278, + OpReorderThreadWithHitObjectNV = 5279, + OpReorderThreadWithHintNV = 5280, + OpTypeHitObjectNV = 5281, + OpImageSampleFootprintNV = 5283, + OpEmitMeshTasksEXT = 5294, + OpSetMeshOutputsEXT = 5295, + OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionKHR = 5334, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, + OpRayQueryGetIntersectionTriangleVertexPositionsKHR = 5340, + OpTypeAccelerationStructureKHR = 5341, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocation = 5380, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, + OpSubgroupShuffleINTEL = 5571, + OpSubgroupShuffleDownINTEL = 5572, + OpSubgroupShuffleUpINTEL = 5573, + OpSubgroupShuffleXorINTEL = 5574, + OpSubgroupBlockReadINTEL = 5575, + OpSubgroupBlockWriteINTEL = 5576, + OpSubgroupImageBlockReadINTEL = 5577, + OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpConstantFunctionPointerINTEL = 5600, + OpFunctionPointerCallINTEL = 5601, + OpAsmTargetINTEL = 5609, + OpAsmINTEL = 5610, + OpAsmCallINTEL = 5611, + OpAtomicFMinEXT = 5614, + OpAtomicFMaxEXT = 5615, + OpAssumeTrueKHR = 5630, + OpExpectKHR = 5631, + OpDecorateString = 5632, + OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, + OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = + 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, + OpArbitraryFloatSinCosPiINTEL = 5840, + OpArbitraryFloatCastINTEL = 5841, + OpArbitraryFloatCastFromIntINTEL = 5842, + OpArbitraryFloatCastToIntINTEL = 5843, + OpArbitraryFloatAddINTEL = 5846, + OpArbitraryFloatSubINTEL = 5847, + OpArbitraryFloatMulINTEL = 5848, + OpArbitraryFloatDivINTEL = 5849, + OpArbitraryFloatGTINTEL = 5850, + OpArbitraryFloatGEINTEL = 5851, + OpArbitraryFloatLTINTEL = 5852, + OpArbitraryFloatLEINTEL = 5853, + OpArbitraryFloatEQINTEL = 5854, + OpArbitraryFloatRecipINTEL = 5855, + OpArbitraryFloatRSqrtINTEL = 5856, + OpArbitraryFloatCbrtINTEL = 5857, + OpArbitraryFloatHypotINTEL = 5858, + OpArbitraryFloatSqrtINTEL = 5859, + OpArbitraryFloatLogINTEL = 5860, + OpArbitraryFloatLog2INTEL = 5861, + OpArbitraryFloatLog10INTEL = 5862, + OpArbitraryFloatLog1pINTEL = 5863, + OpArbitraryFloatExpINTEL = 5864, + OpArbitraryFloatExp2INTEL = 5865, + OpArbitraryFloatExp10INTEL = 5866, + OpArbitraryFloatExpm1INTEL = 5867, + OpArbitraryFloatSinINTEL = 5868, + OpArbitraryFloatCosINTEL = 5869, + OpArbitraryFloatSinCosINTEL = 5870, + OpArbitraryFloatSinPiINTEL = 5871, + OpArbitraryFloatCosPiINTEL = 5872, + OpArbitraryFloatASinINTEL = 5873, + OpArbitraryFloatASinPiINTEL = 5874, + OpArbitraryFloatACosINTEL = 5875, + OpArbitraryFloatACosPiINTEL = 5876, + OpArbitraryFloatATanINTEL = 5877, + OpArbitraryFloatATanPiINTEL = 5878, + OpArbitraryFloatATan2INTEL = 5879, + OpArbitraryFloatPowINTEL = 5880, + OpArbitraryFloatPowRINTEL = 5881, + OpArbitraryFloatPowNINTEL = 5882, + OpLoopControlINTEL = 5887, + OpAliasDomainDeclINTEL = 5911, + OpAliasScopeDeclINTEL = 5912, + OpAliasScopeListDeclINTEL = 5913, + OpFixedSqrtINTEL = 5923, + OpFixedRecipINTEL = 5924, + OpFixedRsqrtINTEL = 5925, + OpFixedSinINTEL = 5926, + OpFixedCosINTEL = 5927, + OpFixedSinCosINTEL = 5928, + OpFixedSinPiINTEL = 5929, + OpFixedCosPiINTEL = 5930, + OpFixedSinCosPiINTEL = 5931, + OpFixedLogINTEL = 5932, + OpFixedExpINTEL = 5933, + OpPtrCastToCrossWorkgroupINTEL = 5934, + OpCrossWorkgroupCastToPtrINTEL = 5938, + OpReadPipeBlockingINTEL = 5946, + OpWritePipeBlockingINTEL = 5947, + OpFPGARegINTEL = 5949, + OpRayQueryGetRayTMinKHR = 6016, + OpRayQueryGetRayFlagsKHR = 6017, + OpRayQueryGetIntersectionTKHR = 6018, + OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, + OpRayQueryGetIntersectionInstanceIdKHR = 6020, + OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, + OpRayQueryGetIntersectionGeometryIndexKHR = 6022, + OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, + OpRayQueryGetIntersectionBarycentricsKHR = 6024, + OpRayQueryGetIntersectionFrontFaceKHR = 6025, + OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, + OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, + OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, + OpRayQueryGetWorldRayDirectionKHR = 6029, + OpRayQueryGetWorldRayOriginKHR = 6030, + OpRayQueryGetIntersectionObjectToWorldKHR = 6031, + OpRayQueryGetIntersectionWorldToObjectKHR = 6032, + OpAtomicFAddEXT = 6035, + OpTypeBufferSurfaceINTEL = 6086, + OpTypeStructContinuedINTEL = 6090, + OpConstantCompositeContinuedINTEL = 6091, + OpSpecConstantCompositeContinuedINTEL = 6092, + OpConvertFToBF16INTEL = 6116, + OpConvertBF16ToFINTEL = 6117, + OpControlBarrierArriveINTEL = 6142, + OpControlBarrierWaitINTEL = 6143, + OpGroupIMulKHR = 6401, + OpGroupFMulKHR = 6402, + OpGroupBitwiseAndKHR = 6403, + OpGroupBitwiseOrKHR = 6404, + OpGroupBitwiseXorKHR = 6405, + OpGroupLogicalAndKHR = 6406, + OpGroupLogicalOrKHR = 6407, + OpGroupLogicalXorKHR = 6408, + Max = 0x7fffffff, + }; #ifdef SPV_ENABLE_UTILITY_CODE #ifndef __cplusplus #include #endif -inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { - *hasResult = *hasResultType = false; - switch (opcode) { - default: /* unknown opcode */ - break; - case Op::OpNop: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpUndef: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSourceContinued: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSource: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSourceExtension: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpName: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpMemberName: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpString: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpLine: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExtension: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExtInstImport: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpExtInst: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpMemoryModel: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEntryPoint: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExecutionMode: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCapability: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTypeVoid: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeBool: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeInt: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeFloat: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeVector: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeMatrix: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeImage: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeSampler: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeSampledImage: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeArray: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeRuntimeArray: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeStruct: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeOpaque: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypePointer: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeFunction: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeEvent: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeDeviceEvent: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeReserveId: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeQueue: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypePipe: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeForwardPointer: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpConstantTrue: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstantFalse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstant: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstantComposite: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstantSampler: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstantNull: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSpecConstantTrue: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSpecConstantFalse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSpecConstant: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSpecConstantComposite: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSpecConstantOp: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFunction: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFunctionParameter: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFunctionEnd: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpFunctionCall: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVariable: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageTexelPointer: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLoad: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpStore: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCopyMemory: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCopyMemorySized: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpAccessChain: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpInBoundsAccessChain: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrAccessChain: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArrayLength: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGenericPtrMemSemantics: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpInBoundsPtrAccessChain: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDecorate: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpMemberDecorate: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpDecorationGroup: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpGroupDecorate: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupMemberDecorate: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpVectorExtractDynamic: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVectorInsertDynamic: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVectorShuffle: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCompositeConstruct: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCompositeExtract: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCompositeInsert: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCopyObject: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTranspose: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSampledImage: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleDrefImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleDrefExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleProjImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleProjExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleProjDrefImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleProjDrefExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageFetch: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageGather: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageDrefGather: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageRead: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageWrite: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpImage: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQueryFormat: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQueryOrder: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQuerySizeLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQuerySize: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQueryLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQueryLevels: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageQuerySamples: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertFToU: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertFToS: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertSToF: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertUToF: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUConvert: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSConvert: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFConvert: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpQuantizeToF16: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertPtrToU: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSatConvertSToU: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSatConvertUToS: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertUToPtr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrCastToGeneric: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGenericCastToPtr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGenericCastToPtrExplicit: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitcast: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSNegate: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFNegate: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpISub: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFSub: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIMul: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFMul: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUDiv: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSDiv: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFDiv: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUMod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSRem: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSMod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFRem: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFMod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVectorTimesScalar: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpMatrixTimesScalar: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVectorTimesMatrix: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpMatrixTimesVector: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpMatrixTimesMatrix: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpOuterProduct: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIAddCarry: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpISubBorrow: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUMulExtended: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSMulExtended: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAny: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAll: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIsNan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIsInf: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIsFinite: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIsNormal: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSignBitSet: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLessOrGreater: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpOrdered: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUnordered: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLogicalEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLogicalNotEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLogicalOr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLogicalAnd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLogicalNot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSelect: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpINotEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUGreaterThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSGreaterThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUGreaterThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSGreaterThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpULessThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSLessThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpULessThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSLessThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdNotEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordNotEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdLessThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordLessThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdGreaterThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordGreaterThan: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdLessThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordLessThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFOrdGreaterThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFUnordGreaterThanEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpShiftRightLogical: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpShiftRightArithmetic: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpShiftLeftLogical: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitwiseOr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitwiseXor: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitwiseAnd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpNot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitFieldInsert: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitFieldSExtract: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitFieldUExtract: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitReverse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBitCount: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdx: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdy: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFwidth: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdxFine: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdyFine: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFwidthFine: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdxCoarse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDPdyCoarse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFwidthCoarse: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpEmitVertex: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEndPrimitive: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEmitStreamVertex: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEndStreamPrimitive: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpControlBarrier: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpMemoryBarrier: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpAtomicLoad: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicStore: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpAtomicExchange: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicCompareExchange: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicCompareExchangeWeak: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicIIncrement: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicIDecrement: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicIAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicISub: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicSMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicUMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicSMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicUMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicAnd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicOr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicXor: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPhi: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLoopMerge: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSelectionMerge: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpLabel: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpBranch: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpBranchConditional: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSwitch: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpKill: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpReturn: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpReturnValue: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpUnreachable: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpLifetimeStart: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpLifetimeStop: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupAsyncCopy: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupWaitEvents: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupAll: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupAny: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupBroadcast: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupIAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupUMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupSMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupUMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupSMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReadPipe: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpWritePipe: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReservedReadPipe: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReservedWritePipe: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReserveReadPipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReserveWritePipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCommitReadPipe: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCommitWritePipe: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpIsValidReserveId: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetNumPipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetMaxPipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupReserveReadPipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupReserveWritePipePackets: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupCommitReadPipe: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupCommitWritePipe: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEnqueueMarker: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpEnqueueKernel: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelNDrangeSubGroupCount: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelNDrangeMaxSubGroupSize: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelWorkGroupSize: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelPreferredWorkGroupSizeMultiple: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRetainEvent: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpReleaseEvent: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCreateUserEvent: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIsValidEvent: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSetUserEventStatus: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCaptureEventProfilingInfo: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGetDefaultQueue: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBuildNDRange: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleDrefImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleDrefExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleProjImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleProjExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleProjDrefImplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseSampleProjDrefExplicitLod: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseFetch: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseGather: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseDrefGather: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSparseTexelsResident: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpNoLine: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpAtomicFlagTestAndSet: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicFlagClear: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpImageSparseRead: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSizeOf: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypePipeStorage: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpConstantPipeStorage: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCreatePipeFromPipeStorage: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelLocalSizeForSubgroupCount: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGetKernelMaxNumSubgroups: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypeNamedBarrier: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpNamedBarrierInitialize: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpMemoryNamedBarrier: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpModuleProcessed: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExecutionModeId: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpDecorateId: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupNonUniformElect: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformAll: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformAny: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformAllEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBroadcast: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBroadcastFirst: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBallot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformInverseBallot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBallotBitExtract: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBallotBitCount: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBallotFindLSB: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBallotFindMSB: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformShuffle: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformShuffleXor: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformShuffleUp: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformShuffleDown: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformIAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformFAdd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformIMul: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformFMul: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformSMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformUMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformFMin: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformSMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformUMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformFMax: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBitwiseAnd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBitwiseOr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformBitwiseXor: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformLogicalAnd: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformLogicalOr: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformLogicalXor: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformQuadBroadcast: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformQuadSwap: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCopyLogical: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrNotEqual: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrDiff: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpColorAttachmentReadEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDepthAttachmentReadEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpStencilAttachmentReadEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTerminateInvocation: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSubgroupBallotKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupFirstInvocationKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAllKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAnyKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAllEqualKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupNonUniformRotateKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupReadInvocationKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTraceRayKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExecuteCallableKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpConvertUToAccelerationStructureKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIgnoreIntersectionKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTerminateRayKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSDot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUDot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSUDot: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSDotAccSat: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUDotAccSat: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSUDotAccSat: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypeRayQueryKHR: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpRayQueryInitializeKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpRayQueryTerminateKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpRayQueryGenerateIntersectionKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpRayQueryConfirmIntersectionKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpRayQueryProceedKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionTypeKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageSampleWeightedQCOM: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageBoxFilterQCOM: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageBlockMatchSSDQCOM: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpImageBlockMatchSADQCOM: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupIAddNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFAddNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFMinNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupUMinNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupSMinNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFMaxNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupUMaxNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupSMaxNonUniformAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFragmentMaskFetchAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFragmentFetchAMD: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReadClockKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectRecordHitMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectRecordHitWithIndexMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectRecordMissMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectGetWorldToObjectNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetObjectToWorldNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetObjectRayDirectionNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetObjectRayOriginNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectTraceRayMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectGetShaderRecordBufferHandleNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetShaderBindingTableRecordIndexNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectRecordEmptyNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectTraceRayNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectRecordHitNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectRecordHitWithIndexNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectRecordMissNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectExecuteShaderNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectGetCurrentTimeNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetAttributesNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpHitObjectGetHitKindNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetPrimitiveIndexNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetGeometryIndexNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetInstanceIdNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetInstanceCustomIndexNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetWorldRayDirectionNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetWorldRayOriginNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetRayTMaxNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectGetRayTMinNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectIsEmptyNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectIsHitNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpHitObjectIsMissNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReorderThreadWithHitObjectNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpReorderThreadWithHintNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTypeHitObjectNV: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpImageSampleFootprintNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpEmitMeshTasksEXT: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSetMeshOutputsEXT: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupNonUniformPartitionNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpWritePackedPrimitiveIndices4x8NV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpReportIntersectionNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIgnoreIntersectionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTerminateRayNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTraceNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTraceMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTraceRayMotionNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpRayQueryGetIntersectionTriangleVertexPositionsKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypeAccelerationStructureNV: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpExecuteCallableNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpTypeCooperativeMatrixNV: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpCooperativeMatrixLoadNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCooperativeMatrixStoreNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpCooperativeMatrixMulAddNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCooperativeMatrixLengthNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpBeginInvocationInterlockEXT: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpEndInvocationInterlockEXT: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpDemoteToHelperInvocation: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpIsHelperInvocationEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertUToImageNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertUToSamplerNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertImageToUNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertSamplerToUNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertUToSampledImageNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertSampledImageToUNV: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSamplerImageAddressingModeNV: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSubgroupShuffleINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupShuffleDownINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupShuffleUpINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupShuffleXorINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupBlockReadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupBlockWriteINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSubgroupImageBlockReadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupImageBlockWriteINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSubgroupImageMediaBlockReadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupImageMediaBlockWriteINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpUCountLeadingZerosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUCountTrailingZerosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAbsISubINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAbsUSubINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIAddSatINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUAddSatINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIAverageINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUAverageINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIAverageRoundedINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUAverageRoundedINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpISubSatINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUSubSatINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpIMul32x16INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpUMul32x16INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConstantFunctionPointerINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFunctionPointerCallINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAsmTargetINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAsmINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAsmCallINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicFMinEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicFMaxEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAssumeTrueKHR: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpExpectKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpDecorateString: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpMemberDecorateString: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpVmeImageINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypeVmeImageINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImePayloadINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcRefPayloadINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcSicPayloadINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcMcePayloadINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcMceResultINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImeResultINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImeResultSingleReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImeResultDualReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImeSingleReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcImeDualReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcRefResultINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeAvcSicResultINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetInterShapePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetAcOnlyHaarINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToImePayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToImeResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToRefPayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToRefResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToSicPayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceConvertToSicResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetMotionVectorsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterDistortionsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetBestInterDistortionsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterMajorShapeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterMinorShapeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterDirectionsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterMotionVectorCountINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterReferenceIdsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeInitializeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetSingleReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetDualReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeRefWindowSizeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeAdjustRefOffsetINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeConvertToMcePayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeSetWeightedSadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeConvertToMceResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetDualReferenceStreaminINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op:: - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op:: - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op:: - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op:: - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetBorderReachedINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcFmeInitializeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcBmeInitializeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefConvertToMcePayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefSetBilinearFilterEnableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcRefConvertToMceResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicInitializeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicConfigureSkcINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicConfigureIpeLumaINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetMotionVectorMaskINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicConvertToMcePayloadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetBilinearFilterEnableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicEvaluateIpeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicConvertToMceResultINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetIpeLumaShapeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetIpeChromaModeINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSubgroupAvcSicGetInterRawSadsINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpVariableLengthArrayINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpSaveMemoryINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRestoreMemoryINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpArbitraryFloatSinCosPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCastINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCastFromIntINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCastToIntINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatAddINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatSubINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatMulINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatDivINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatGTINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatGEINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLTINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLEINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatEQINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatRecipINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatRSqrtINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCbrtINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatHypotINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatSqrtINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLogINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLog2INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLog10INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatLog1pINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatExpINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatExp2INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatExp10INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatExpm1INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatSinINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatSinCosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatSinPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatCosPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatASinINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatASinPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatACosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatACosPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatATanINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatATanPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatATan2INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatPowINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatPowRINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpArbitraryFloatPowNINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpLoopControlINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpAliasDomainDeclINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpAliasScopeDeclINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpAliasScopeListDeclINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpFixedSqrtINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedRecipINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedRsqrtINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedSinINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedCosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedSinCosINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedSinPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedCosPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedSinCosPiINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedLogINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFixedExpINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpPtrCastToCrossWorkgroupINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpCrossWorkgroupCastToPtrINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpReadPipeBlockingINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpWritePipeBlockingINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpFPGARegINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetRayTMinKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetRayFlagsKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionTKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionInstanceCustomIndexKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionInstanceIdKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionGeometryIndexKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionPrimitiveIndexKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionBarycentricsKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionFrontFaceKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionObjectRayDirectionKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionObjectRayOriginKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetWorldRayDirectionKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetWorldRayOriginKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionObjectToWorldKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpRayQueryGetIntersectionWorldToObjectKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpAtomicFAddEXT: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpTypeBufferSurfaceINTEL: - *hasResult = true; - *hasResultType = false; - break; - case Op::OpTypeStructContinuedINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpConstantCompositeContinuedINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpSpecConstantCompositeContinuedINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpConvertFToBF16INTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpConvertBF16ToFINTEL: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpControlBarrierArriveINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpControlBarrierWaitINTEL: - *hasResult = false; - *hasResultType = false; - break; - case Op::OpGroupIMulKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupFMulKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupBitwiseAndKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupBitwiseOrKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupBitwiseXorKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupLogicalAndKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupLogicalOrKHR: - *hasResult = true; - *hasResultType = true; - break; - case Op::OpGroupLogicalXorKHR: - *hasResult = true; - *hasResultType = true; - break; - } -} + inline void HasResultAndType(Op opcode, bool* hasResult, bool* hasResultType) + { + *hasResult = *hasResultType = false; + switch (opcode) + { + default: /* unknown opcode */ + break; + case Op::OpNop: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpUndef: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSourceContinued: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSource: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSourceExtension: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpName: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpMemberName: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpString: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpLine: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExtension: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExtInstImport: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpExtInst: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpMemoryModel: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEntryPoint: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExecutionMode: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCapability: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTypeVoid: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeBool: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeInt: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeFloat: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeVector: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeMatrix: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeImage: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeSampler: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeSampledImage: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeArray: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeRuntimeArray: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeStruct: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeOpaque: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypePointer: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeFunction: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeEvent: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeDeviceEvent: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeReserveId: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeQueue: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypePipe: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeForwardPointer: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpConstantTrue: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstantFalse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstant: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstantComposite: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstantSampler: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstantNull: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSpecConstantTrue: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSpecConstantFalse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSpecConstant: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSpecConstantComposite: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSpecConstantOp: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFunction: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFunctionParameter: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFunctionEnd: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpFunctionCall: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVariable: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageTexelPointer: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLoad: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpStore: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCopyMemory: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCopyMemorySized: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpAccessChain: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpInBoundsAccessChain: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrAccessChain: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArrayLength: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGenericPtrMemSemantics: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpInBoundsPtrAccessChain: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDecorate: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpMemberDecorate: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpDecorationGroup: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpGroupDecorate: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupMemberDecorate: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpVectorExtractDynamic: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVectorInsertDynamic: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVectorShuffle: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCompositeConstruct: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCompositeExtract: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCompositeInsert: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCopyObject: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTranspose: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSampledImage: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleDrefImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleDrefExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleProjImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleProjExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleProjDrefImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleProjDrefExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageFetch: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageGather: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageDrefGather: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageRead: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageWrite: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpImage: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQueryFormat: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQueryOrder: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQuerySizeLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQuerySize: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQueryLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQueryLevels: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageQuerySamples: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertFToU: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertFToS: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertSToF: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertUToF: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUConvert: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSConvert: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFConvert: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpQuantizeToF16: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertPtrToU: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSatConvertSToU: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSatConvertUToS: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertUToPtr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrCastToGeneric: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGenericCastToPtr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGenericCastToPtrExplicit: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitcast: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSNegate: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFNegate: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpISub: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFSub: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIMul: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFMul: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUDiv: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSDiv: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFDiv: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUMod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSRem: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSMod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFRem: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFMod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVectorTimesScalar: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpMatrixTimesScalar: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVectorTimesMatrix: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpMatrixTimesVector: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpMatrixTimesMatrix: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpOuterProduct: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIAddCarry: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpISubBorrow: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUMulExtended: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSMulExtended: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAny: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAll: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIsNan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIsInf: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIsFinite: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIsNormal: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSignBitSet: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLessOrGreater: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpOrdered: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUnordered: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLogicalEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLogicalNotEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLogicalOr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLogicalAnd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLogicalNot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSelect: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpINotEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUGreaterThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSGreaterThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUGreaterThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSGreaterThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpULessThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSLessThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpULessThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSLessThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdNotEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordNotEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdLessThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordLessThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdGreaterThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordGreaterThan: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdLessThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordLessThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFOrdGreaterThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFUnordGreaterThanEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpShiftRightLogical: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpShiftRightArithmetic: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpShiftLeftLogical: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitwiseOr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitwiseXor: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitwiseAnd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpNot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitFieldInsert: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitFieldSExtract: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitFieldUExtract: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitReverse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBitCount: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdx: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdy: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFwidth: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdxFine: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdyFine: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFwidthFine: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdxCoarse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDPdyCoarse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFwidthCoarse: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpEmitVertex: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEndPrimitive: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEmitStreamVertex: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEndStreamPrimitive: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpControlBarrier: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpMemoryBarrier: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpAtomicLoad: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicStore: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpAtomicExchange: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicCompareExchange: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicCompareExchangeWeak: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicIIncrement: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicIDecrement: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicIAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicISub: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicSMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicUMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicSMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicUMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicAnd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicOr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicXor: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPhi: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLoopMerge: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSelectionMerge: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpLabel: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpBranch: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpBranchConditional: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSwitch: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpKill: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpReturn: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpReturnValue: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpUnreachable: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpLifetimeStart: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpLifetimeStop: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupAsyncCopy: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupWaitEvents: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupAll: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupAny: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupBroadcast: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupIAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupUMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupSMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupUMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupSMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReadPipe: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpWritePipe: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReservedReadPipe: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReservedWritePipe: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReserveReadPipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReserveWritePipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCommitReadPipe: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCommitWritePipe: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpIsValidReserveId: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetNumPipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetMaxPipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupReserveReadPipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupReserveWritePipePackets: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupCommitReadPipe: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupCommitWritePipe: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEnqueueMarker: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpEnqueueKernel: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelNDrangeSubGroupCount: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelNDrangeMaxSubGroupSize: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelWorkGroupSize: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelPreferredWorkGroupSizeMultiple: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRetainEvent: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpReleaseEvent: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCreateUserEvent: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIsValidEvent: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSetUserEventStatus: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCaptureEventProfilingInfo: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGetDefaultQueue: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBuildNDRange: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleDrefImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleDrefExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleProjImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleProjExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleProjDrefImplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseSampleProjDrefExplicitLod: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseFetch: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseGather: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseDrefGather: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSparseTexelsResident: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpNoLine: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpAtomicFlagTestAndSet: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicFlagClear: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpImageSparseRead: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSizeOf: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypePipeStorage: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpConstantPipeStorage: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCreatePipeFromPipeStorage: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelLocalSizeForSubgroupCount: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGetKernelMaxNumSubgroups: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypeNamedBarrier: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpNamedBarrierInitialize: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpMemoryNamedBarrier: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpModuleProcessed: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExecutionModeId: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpDecorateId: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupNonUniformElect: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformAll: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformAny: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformAllEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBroadcast: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBroadcastFirst: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBallot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformInverseBallot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBallotBitExtract: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBallotBitCount: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBallotFindLSB: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBallotFindMSB: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformShuffle: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformShuffleXor: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformShuffleUp: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformShuffleDown: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformIAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformFAdd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformIMul: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformFMul: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformSMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformUMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformFMin: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformSMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformUMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformFMax: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBitwiseAnd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBitwiseOr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformBitwiseXor: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformLogicalAnd: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformLogicalOr: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformLogicalXor: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformQuadBroadcast: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformQuadSwap: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCopyLogical: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrNotEqual: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrDiff: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpColorAttachmentReadEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDepthAttachmentReadEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpStencilAttachmentReadEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTerminateInvocation: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSubgroupBallotKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupFirstInvocationKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAllKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAnyKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAllEqualKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupNonUniformRotateKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupReadInvocationKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTraceRayKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExecuteCallableKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpConvertUToAccelerationStructureKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIgnoreIntersectionKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTerminateRayKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSDot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUDot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSUDot: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSDotAccSat: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUDotAccSat: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSUDotAccSat: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypeRayQueryKHR: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpRayQueryInitializeKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpRayQueryTerminateKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpRayQueryGenerateIntersectionKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpRayQueryConfirmIntersectionKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpRayQueryProceedKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionTypeKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageSampleWeightedQCOM: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageBoxFilterQCOM: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageBlockMatchSSDQCOM: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpImageBlockMatchSADQCOM: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupIAddNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFAddNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFMinNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupUMinNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupSMinNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFMaxNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupUMaxNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupSMaxNonUniformAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFragmentMaskFetchAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFragmentFetchAMD: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReadClockKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectRecordHitMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectRecordHitWithIndexMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectRecordMissMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectGetWorldToObjectNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetObjectToWorldNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetObjectRayDirectionNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetObjectRayOriginNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectTraceRayMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectGetShaderRecordBufferHandleNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetShaderBindingTableRecordIndexNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectRecordEmptyNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectTraceRayNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectRecordHitNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectRecordHitWithIndexNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectRecordMissNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectExecuteShaderNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectGetCurrentTimeNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetAttributesNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpHitObjectGetHitKindNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetPrimitiveIndexNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetGeometryIndexNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetInstanceIdNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetInstanceCustomIndexNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetWorldRayDirectionNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetWorldRayOriginNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetRayTMaxNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectGetRayTMinNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectIsEmptyNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectIsHitNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpHitObjectIsMissNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReorderThreadWithHitObjectNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpReorderThreadWithHintNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTypeHitObjectNV: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpImageSampleFootprintNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpEmitMeshTasksEXT: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSetMeshOutputsEXT: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupNonUniformPartitionNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpWritePackedPrimitiveIndices4x8NV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpReportIntersectionNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIgnoreIntersectionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTerminateRayNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTraceNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTraceMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTraceRayMotionNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpRayQueryGetIntersectionTriangleVertexPositionsKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypeAccelerationStructureNV: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpExecuteCallableNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpTypeCooperativeMatrixNV: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpCooperativeMatrixLoadNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCooperativeMatrixStoreNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpCooperativeMatrixMulAddNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCooperativeMatrixLengthNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpBeginInvocationInterlockEXT: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpEndInvocationInterlockEXT: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpDemoteToHelperInvocation: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpIsHelperInvocationEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertUToImageNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertUToSamplerNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertImageToUNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertSamplerToUNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertUToSampledImageNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertSampledImageToUNV: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSamplerImageAddressingModeNV: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSubgroupShuffleINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupShuffleDownINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupShuffleUpINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupShuffleXorINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupBlockReadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupBlockWriteINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSubgroupImageBlockReadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupImageBlockWriteINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSubgroupImageMediaBlockReadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupImageMediaBlockWriteINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpUCountLeadingZerosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUCountTrailingZerosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAbsISubINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAbsUSubINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIAddSatINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUAddSatINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIAverageINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUAverageINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIAverageRoundedINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUAverageRoundedINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpISubSatINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUSubSatINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpIMul32x16INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpUMul32x16INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConstantFunctionPointerINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFunctionPointerCallINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAsmTargetINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAsmINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAsmCallINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicFMinEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicFMaxEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAssumeTrueKHR: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpExpectKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpDecorateString: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpMemberDecorateString: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpVmeImageINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypeVmeImageINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImePayloadINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcRefPayloadINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcSicPayloadINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcMcePayloadINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcMceResultINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImeResultINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImeResultSingleReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImeResultDualReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImeSingleReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcImeDualReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcRefResultINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeAvcSicResultINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetInterShapePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetAcOnlyHaarINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToImePayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToImeResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToRefPayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToRefResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToSicPayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceConvertToSicResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetMotionVectorsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterDistortionsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetBestInterDistortionsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterMajorShapeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterMinorShapeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterDirectionsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterMotionVectorCountINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterReferenceIdsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeInitializeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetSingleReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetDualReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeRefWindowSizeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeAdjustRefOffsetINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeConvertToMcePayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeSetWeightedSadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeConvertToMceResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetDualReferenceStreaminINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op:: + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op:: + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op:: + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op:: + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetBorderReachedINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcFmeInitializeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcBmeInitializeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefConvertToMcePayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefSetBilinearFilterEnableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcRefConvertToMceResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicInitializeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicConfigureSkcINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicConfigureIpeLumaINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetMotionVectorMaskINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicConvertToMcePayloadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetBilinearFilterEnableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicEvaluateIpeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicConvertToMceResultINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetIpeLumaShapeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetIpeChromaModeINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSubgroupAvcSicGetInterRawSadsINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpVariableLengthArrayINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpSaveMemoryINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRestoreMemoryINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpArbitraryFloatSinCosPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCastINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCastFromIntINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCastToIntINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatAddINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatSubINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatMulINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatDivINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatGTINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatGEINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLTINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLEINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatEQINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatRecipINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatRSqrtINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCbrtINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatHypotINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatSqrtINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLogINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLog2INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLog10INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatLog1pINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatExpINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatExp2INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatExp10INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatExpm1INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatSinINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatSinCosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatSinPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatCosPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatASinINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatASinPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatACosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatACosPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatATanINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatATanPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatATan2INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatPowINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatPowRINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpArbitraryFloatPowNINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpLoopControlINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpAliasDomainDeclINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpAliasScopeDeclINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpAliasScopeListDeclINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpFixedSqrtINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedRecipINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedRsqrtINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedSinINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedCosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedSinCosINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedSinPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedCosPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedSinCosPiINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedLogINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFixedExpINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpPtrCastToCrossWorkgroupINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpCrossWorkgroupCastToPtrINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpReadPipeBlockingINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpWritePipeBlockingINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpFPGARegINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetRayTMinKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetRayFlagsKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionTKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionInstanceCustomIndexKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionInstanceIdKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionGeometryIndexKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionPrimitiveIndexKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionBarycentricsKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionFrontFaceKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionObjectRayDirectionKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionObjectRayOriginKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetWorldRayDirectionKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetWorldRayOriginKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionObjectToWorldKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpRayQueryGetIntersectionWorldToObjectKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpAtomicFAddEXT: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpTypeBufferSurfaceINTEL: + *hasResult = true; + *hasResultType = false; + break; + case Op::OpTypeStructContinuedINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpConstantCompositeContinuedINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpSpecConstantCompositeContinuedINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpConvertFToBF16INTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpConvertBF16ToFINTEL: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpControlBarrierArriveINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpControlBarrierWaitINTEL: + *hasResult = false; + *hasResultType = false; + break; + case Op::OpGroupIMulKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupFMulKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupBitwiseAndKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupBitwiseOrKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupBitwiseXorKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupLogicalAndKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupLogicalOrKHR: + *hasResult = true; + *hasResultType = true; + break; + case Op::OpGroupLogicalXorKHR: + *hasResult = true; + *hasResultType = true; + break; + } + } #endif /* SPV_ENABLE_UTILITY_CODE */ -// Overload bitwise operators for mask bit combining + // Overload bitwise operators for mask bit combining -constexpr ImageOperandsMask operator|(ImageOperandsMask a, - ImageOperandsMask b) { - return ImageOperandsMask(unsigned(a) | unsigned(b)); -} -constexpr ImageOperandsMask operator&(ImageOperandsMask a, - ImageOperandsMask b) { - return ImageOperandsMask(unsigned(a) & unsigned(b)); -} -constexpr ImageOperandsMask operator^(ImageOperandsMask a, - ImageOperandsMask b) { - return ImageOperandsMask(unsigned(a) ^ unsigned(b)); -} -constexpr ImageOperandsMask operator~(ImageOperandsMask a) { - return ImageOperandsMask(~unsigned(a)); -} -constexpr FPFastMathModeMask operator|(FPFastMathModeMask a, - FPFastMathModeMask b) { - return FPFastMathModeMask(unsigned(a) | unsigned(b)); -} -constexpr FPFastMathModeMask operator&(FPFastMathModeMask a, - FPFastMathModeMask b) { - return FPFastMathModeMask(unsigned(a) & unsigned(b)); -} -constexpr FPFastMathModeMask operator^(FPFastMathModeMask a, - FPFastMathModeMask b) { - return FPFastMathModeMask(unsigned(a) ^ unsigned(b)); -} -constexpr FPFastMathModeMask operator~(FPFastMathModeMask a) { - return FPFastMathModeMask(~unsigned(a)); -} -constexpr SelectionControlMask operator|(SelectionControlMask a, - SelectionControlMask b) { - return SelectionControlMask(unsigned(a) | unsigned(b)); -} -constexpr SelectionControlMask operator&(SelectionControlMask a, - SelectionControlMask b) { - return SelectionControlMask(unsigned(a) & unsigned(b)); -} -constexpr SelectionControlMask operator^(SelectionControlMask a, - SelectionControlMask b) { - return SelectionControlMask(unsigned(a) ^ unsigned(b)); -} -constexpr SelectionControlMask operator~(SelectionControlMask a) { - return SelectionControlMask(~unsigned(a)); -} -constexpr LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { - return LoopControlMask(unsigned(a) | unsigned(b)); -} -constexpr LoopControlMask operator&(LoopControlMask a, LoopControlMask b) { - return LoopControlMask(unsigned(a) & unsigned(b)); -} -constexpr LoopControlMask operator^(LoopControlMask a, LoopControlMask b) { - return LoopControlMask(unsigned(a) ^ unsigned(b)); -} -constexpr LoopControlMask operator~(LoopControlMask a) { - return LoopControlMask(~unsigned(a)); -} -constexpr FunctionControlMask operator|(FunctionControlMask a, - FunctionControlMask b) { - return FunctionControlMask(unsigned(a) | unsigned(b)); -} -constexpr FunctionControlMask operator&(FunctionControlMask a, - FunctionControlMask b) { - return FunctionControlMask(unsigned(a) & unsigned(b)); -} -constexpr FunctionControlMask operator^(FunctionControlMask a, - FunctionControlMask b) { - return FunctionControlMask(unsigned(a) ^ unsigned(b)); -} -constexpr FunctionControlMask operator~(FunctionControlMask a) { - return FunctionControlMask(~unsigned(a)); -} -constexpr MemorySemanticsMask operator|(MemorySemanticsMask a, - MemorySemanticsMask b) { - return MemorySemanticsMask(unsigned(a) | unsigned(b)); -} -constexpr MemorySemanticsMask operator&(MemorySemanticsMask a, - MemorySemanticsMask b) { - return MemorySemanticsMask(unsigned(a) & unsigned(b)); -} -constexpr MemorySemanticsMask operator^(MemorySemanticsMask a, - MemorySemanticsMask b) { - return MemorySemanticsMask(unsigned(a) ^ unsigned(b)); -} -constexpr MemorySemanticsMask operator~(MemorySemanticsMask a) { - return MemorySemanticsMask(~unsigned(a)); -} -constexpr MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { - return MemoryAccessMask(unsigned(a) | unsigned(b)); -} -constexpr MemoryAccessMask operator&(MemoryAccessMask a, MemoryAccessMask b) { - return MemoryAccessMask(unsigned(a) & unsigned(b)); -} -constexpr MemoryAccessMask operator^(MemoryAccessMask a, MemoryAccessMask b) { - return MemoryAccessMask(unsigned(a) ^ unsigned(b)); -} -constexpr MemoryAccessMask operator~(MemoryAccessMask a) { - return MemoryAccessMask(~unsigned(a)); -} -constexpr KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, - KernelProfilingInfoMask b) { - return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); -} -constexpr KernelProfilingInfoMask operator&(KernelProfilingInfoMask a, - KernelProfilingInfoMask b) { - return KernelProfilingInfoMask(unsigned(a) & unsigned(b)); -} -constexpr KernelProfilingInfoMask operator^(KernelProfilingInfoMask a, - KernelProfilingInfoMask b) { - return KernelProfilingInfoMask(unsigned(a) ^ unsigned(b)); -} -constexpr KernelProfilingInfoMask operator~(KernelProfilingInfoMask a) { - return KernelProfilingInfoMask(~unsigned(a)); -} -constexpr RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { - return RayFlagsMask(unsigned(a) | unsigned(b)); -} -constexpr RayFlagsMask operator&(RayFlagsMask a, RayFlagsMask b) { - return RayFlagsMask(unsigned(a) & unsigned(b)); -} -constexpr RayFlagsMask operator^(RayFlagsMask a, RayFlagsMask b) { - return RayFlagsMask(unsigned(a) ^ unsigned(b)); -} -constexpr RayFlagsMask operator~(RayFlagsMask a) { - return RayFlagsMask(~unsigned(a)); -} -constexpr FragmentShadingRateMask operator|(FragmentShadingRateMask a, - FragmentShadingRateMask b) { - return FragmentShadingRateMask(unsigned(a) | unsigned(b)); -} -constexpr FragmentShadingRateMask operator&(FragmentShadingRateMask a, - FragmentShadingRateMask b) { - return FragmentShadingRateMask(unsigned(a) & unsigned(b)); -} -constexpr FragmentShadingRateMask operator^(FragmentShadingRateMask a, - FragmentShadingRateMask b) { - return FragmentShadingRateMask(unsigned(a) ^ unsigned(b)); -} -constexpr FragmentShadingRateMask operator~(FragmentShadingRateMask a) { - return FragmentShadingRateMask(~unsigned(a)); -} + constexpr ImageOperandsMask operator|(ImageOperandsMask a, + ImageOperandsMask b) + { + return ImageOperandsMask(unsigned(a) | unsigned(b)); + } + constexpr ImageOperandsMask operator&(ImageOperandsMask a, + ImageOperandsMask b) + { + return ImageOperandsMask(unsigned(a) & unsigned(b)); + } + constexpr ImageOperandsMask operator^(ImageOperandsMask a, + ImageOperandsMask b) + { + return ImageOperandsMask(unsigned(a) ^ unsigned(b)); + } + constexpr ImageOperandsMask operator~(ImageOperandsMask a) + { + return ImageOperandsMask(~unsigned(a)); + } + constexpr FPFastMathModeMask operator|(FPFastMathModeMask a, + FPFastMathModeMask b) + { + return FPFastMathModeMask(unsigned(a) | unsigned(b)); + } + constexpr FPFastMathModeMask operator&(FPFastMathModeMask a, + FPFastMathModeMask b) + { + return FPFastMathModeMask(unsigned(a) & unsigned(b)); + } + constexpr FPFastMathModeMask operator^(FPFastMathModeMask a, + FPFastMathModeMask b) + { + return FPFastMathModeMask(unsigned(a) ^ unsigned(b)); + } + constexpr FPFastMathModeMask operator~(FPFastMathModeMask a) + { + return FPFastMathModeMask(~unsigned(a)); + } + constexpr SelectionControlMask operator|(SelectionControlMask a, + SelectionControlMask b) + { + return SelectionControlMask(unsigned(a) | unsigned(b)); + } + constexpr SelectionControlMask operator&(SelectionControlMask a, + SelectionControlMask b) + { + return SelectionControlMask(unsigned(a) & unsigned(b)); + } + constexpr SelectionControlMask operator^(SelectionControlMask a, + SelectionControlMask b) + { + return SelectionControlMask(unsigned(a) ^ unsigned(b)); + } + constexpr SelectionControlMask operator~(SelectionControlMask a) + { + return SelectionControlMask(~unsigned(a)); + } + constexpr LoopControlMask operator|(LoopControlMask a, LoopControlMask b) + { + return LoopControlMask(unsigned(a) | unsigned(b)); + } + constexpr LoopControlMask operator&(LoopControlMask a, LoopControlMask b) + { + return LoopControlMask(unsigned(a) & unsigned(b)); + } + constexpr LoopControlMask operator^(LoopControlMask a, LoopControlMask b) + { + return LoopControlMask(unsigned(a) ^ unsigned(b)); + } + constexpr LoopControlMask operator~(LoopControlMask a) + { + return LoopControlMask(~unsigned(a)); + } + constexpr FunctionControlMask operator|(FunctionControlMask a, + FunctionControlMask b) + { + return FunctionControlMask(unsigned(a) | unsigned(b)); + } + constexpr FunctionControlMask operator&(FunctionControlMask a, + FunctionControlMask b) + { + return FunctionControlMask(unsigned(a) & unsigned(b)); + } + constexpr FunctionControlMask operator^(FunctionControlMask a, + FunctionControlMask b) + { + return FunctionControlMask(unsigned(a) ^ unsigned(b)); + } + constexpr FunctionControlMask operator~(FunctionControlMask a) + { + return FunctionControlMask(~unsigned(a)); + } + constexpr MemorySemanticsMask operator|(MemorySemanticsMask a, + MemorySemanticsMask b) + { + return MemorySemanticsMask(unsigned(a) | unsigned(b)); + } + constexpr MemorySemanticsMask operator&(MemorySemanticsMask a, + MemorySemanticsMask b) + { + return MemorySemanticsMask(unsigned(a) & unsigned(b)); + } + constexpr MemorySemanticsMask operator^(MemorySemanticsMask a, + MemorySemanticsMask b) + { + return MemorySemanticsMask(unsigned(a) ^ unsigned(b)); + } + constexpr MemorySemanticsMask operator~(MemorySemanticsMask a) + { + return MemorySemanticsMask(~unsigned(a)); + } + constexpr MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) + { + return MemoryAccessMask(unsigned(a) | unsigned(b)); + } + constexpr MemoryAccessMask operator&(MemoryAccessMask a, MemoryAccessMask b) + { + return MemoryAccessMask(unsigned(a) & unsigned(b)); + } + constexpr MemoryAccessMask operator^(MemoryAccessMask a, MemoryAccessMask b) + { + return MemoryAccessMask(unsigned(a) ^ unsigned(b)); + } + constexpr MemoryAccessMask operator~(MemoryAccessMask a) + { + return MemoryAccessMask(~unsigned(a)); + } + constexpr KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, + KernelProfilingInfoMask b) + { + return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); + } + constexpr KernelProfilingInfoMask operator&(KernelProfilingInfoMask a, + KernelProfilingInfoMask b) + { + return KernelProfilingInfoMask(unsigned(a) & unsigned(b)); + } + constexpr KernelProfilingInfoMask operator^(KernelProfilingInfoMask a, + KernelProfilingInfoMask b) + { + return KernelProfilingInfoMask(unsigned(a) ^ unsigned(b)); + } + constexpr KernelProfilingInfoMask operator~(KernelProfilingInfoMask a) + { + return KernelProfilingInfoMask(~unsigned(a)); + } + constexpr RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) + { + return RayFlagsMask(unsigned(a) | unsigned(b)); + } + constexpr RayFlagsMask operator&(RayFlagsMask a, RayFlagsMask b) + { + return RayFlagsMask(unsigned(a) & unsigned(b)); + } + constexpr RayFlagsMask operator^(RayFlagsMask a, RayFlagsMask b) + { + return RayFlagsMask(unsigned(a) ^ unsigned(b)); + } + constexpr RayFlagsMask operator~(RayFlagsMask a) + { + return RayFlagsMask(~unsigned(a)); + } + constexpr FragmentShadingRateMask operator|(FragmentShadingRateMask a, + FragmentShadingRateMask b) + { + return FragmentShadingRateMask(unsigned(a) | unsigned(b)); + } + constexpr FragmentShadingRateMask operator&(FragmentShadingRateMask a, + FragmentShadingRateMask b) + { + return FragmentShadingRateMask(unsigned(a) & unsigned(b)); + } + constexpr FragmentShadingRateMask operator^(FragmentShadingRateMask a, + FragmentShadingRateMask b) + { + return FragmentShadingRateMask(unsigned(a) ^ unsigned(b)); + } + constexpr FragmentShadingRateMask operator~(FragmentShadingRateMask a) + { + return FragmentShadingRateMask(~unsigned(a)); + } } // end namespace spv diff --git a/hw/amdgpu/shader/include/amdgpu/shader/AccessOp.hpp b/hw/amdgpu/shader/include/amdgpu/shader/AccessOp.hpp index 42155352..520e97ba 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/AccessOp.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/AccessOp.hpp @@ -1,21 +1,32 @@ #pragma once -namespace amdgpu::shader { -enum class AccessOp { None = 0, Load = 1 << 0, Store = 1 << 1 }; +namespace amdgpu::shader +{ + enum class AccessOp + { + None = 0, + Load = 1 << 0, + Store = 1 << 1 + }; -constexpr AccessOp operator|(AccessOp lhs, AccessOp rhs) { - return static_cast(static_cast(lhs) | static_cast(rhs)); -} -constexpr AccessOp operator&(AccessOp lhs, AccessOp rhs) { - return static_cast(static_cast(lhs) & static_cast(rhs)); -} -constexpr AccessOp operator~(AccessOp rhs) { - return static_cast(~static_cast(rhs)); -} -constexpr AccessOp &operator|=(AccessOp &lhs, AccessOp rhs) { - return ((lhs = lhs | rhs)); -} -constexpr AccessOp &operator&=(AccessOp &lhs, AccessOp rhs) { - return ((lhs = lhs & rhs)); -} + constexpr AccessOp operator|(AccessOp lhs, AccessOp rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + constexpr AccessOp operator&(AccessOp lhs, AccessOp rhs) + { + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + constexpr AccessOp operator~(AccessOp rhs) + { + return static_cast(~static_cast(rhs)); + } + constexpr AccessOp& operator|=(AccessOp& lhs, AccessOp rhs) + { + return ((lhs = lhs | rhs)); + } + constexpr AccessOp& operator&=(AccessOp& lhs, AccessOp rhs) + { + return ((lhs = lhs & rhs)); + } } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/BufferKind.hpp b/hw/amdgpu/shader/include/amdgpu/shader/BufferKind.hpp index 09dc226e..00451597 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/BufferKind.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/BufferKind.hpp @@ -1,5 +1,10 @@ #pragma once -namespace amdgpu::shader { -enum class BufferKind { VBuffer, TBuffer }; +namespace amdgpu::shader +{ + enum class BufferKind + { + VBuffer, + TBuffer + }; } diff --git a/hw/amdgpu/shader/include/amdgpu/shader/CfBuilder.hpp b/hw/amdgpu/shader/include/amdgpu/shader/CfBuilder.hpp index 92ad6093..0564dc3d 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/CfBuilder.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/CfBuilder.hpp @@ -2,7 +2,8 @@ #include "cf.hpp" #include -namespace amdgpu::shader { -cf::BasicBlock *buildCf(cf::Context &ctxt, RemoteMemory memory, - std::uint64_t entryPoint); +namespace amdgpu::shader +{ + cf::BasicBlock* buildCf(cf::Context& ctxt, RemoteMemory memory, + std::uint64_t entryPoint); } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Converter.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Converter.hpp index ee8a9662..406094ff 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Converter.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Converter.hpp @@ -10,23 +10,32 @@ #include #include -namespace amdgpu::shader { -struct Shader { - enum class UniformKind { Buffer, Sampler, StorageImage, Image }; +namespace amdgpu::shader +{ + struct Shader + { + enum class UniformKind + { + Buffer, + Sampler, + StorageImage, + Image + }; - struct UniformInfo { - std::uint32_t binding; - std::uint32_t buffer[8]; - UniformKind kind; - AccessOp accessOp; - }; + struct UniformInfo + { + std::uint32_t binding; + std::uint32_t buffer[8]; + UniformKind kind; + AccessOp accessOp; + }; - std::vector uniforms; - std::vector spirv; -}; + std::vector uniforms; + std::vector spirv; + }; -Shader convert(RemoteMemory memory, Stage stage, std::uint64_t entry, - std::span userSpgrs, std::uint32_t dimX, - std::uint32_t dimY, std::uint32_t dimZ, - util::MemoryAreaTable<> &dependencies); + Shader convert(RemoteMemory memory, Stage stage, std::uint64_t entry, + std::span userSpgrs, std::uint32_t dimX, + std::uint32_t dimY, std::uint32_t dimZ, + util::MemoryAreaTable<>& dependencies); } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/ConverterContext.hpp b/hw/amdgpu/shader/include/amdgpu/shader/ConverterContext.hpp index c492926c..9f14fa6f 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/ConverterContext.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/ConverterContext.hpp @@ -19,8 +19,9 @@ #include #include -namespace amdgpu::shader { -/* +namespace amdgpu::shader +{ + /* struct MaterializedFunction { spirv::Function function; spirv::FunctionType type; @@ -31,237 +32,275 @@ struct MaterializedFunction { }; */ -class ConverterContext { - Stage mStage; - RemoteMemory mMemory; - spirv::IdGenerator mGenerator; - spirv::SpirvBuilder mBuilder{mGenerator, 1024}; - static constexpr auto kGenericTypesCount = - static_cast(TypeId::Void) + 1; - spirv::Type mTypes[kGenericTypesCount]; - spirv::PointerType mPtrTypes[13][kGenericTypesCount]; - spirv::RuntimeArrayType mRuntimeArrayTypes[kGenericTypesCount]; - spirv::VariableValue mThreadId; - spirv::VariableValue mWorkgroupId; - spirv::VariableValue mLocalInvocationId; - spirv::VariableValue mPerVertex; - spirv::VariableValue mFragCoord; - std::vector mInterfaces; - std::map mIns; - std::map mOuts; - - std::map mConstantFloat32Map; - std::map mConstantUint32Map; - std::map mConstantSint32Map; - std::map mConstantUint64Map; - - struct FunctionType { - spirv::Type resultType; - std::vector params; - spirv::FunctionType id; - }; - - std::vector mFunctionTypes; - - struct StructTypeEntry { - spirv::StructType id; - std::vector members; - spirv::PointerType ptrTypes[13]; - - bool match(std::span other) { - if (members.size() != other.size()) { - return false; - } - - for (std::size_t i = 0; i < other.size(); ++i) { - if (members[i] != other[i]) { - return false; - } - } - - return true; - } - }; - - std::vector mStructTypes; - - std::forward_list mFragments; - std::forward_list mFunctions; - - spirv::ConstantBool mTrue; - spirv::ConstantBool mFalse; - - std::vector mUniforms; - spirv::ExtInstSet mGlslStd450; - spirv::Function mDiscardFn; - -public: - util::MemoryAreaTable<> *dependencies = nullptr; - - ConverterContext(RemoteMemory memory, Stage stage, - util::MemoryAreaTable<> *dependencies) - : mStage(stage), mMemory(memory), dependencies(dependencies) { - mGlslStd450 = mBuilder.createExtInstImport("GLSL.std.450"); - } - - const decltype(mInterfaces) &getInterfaces() const { return mInterfaces; } - - spirv::SpirvBuilder &getBuilder() { return mBuilder; } - RemoteMemory getMemory() const { return mMemory; } - spirv::ExtInstSet getGlslStd450() const { return mGlslStd450; } - std::optional getTypeIdOf(spirv::Type type) const; - - spirv::StructType findStructType(std::span members); - spirv::StructType getStructType(std::span members); - spirv::PointerType getStructPointerType(spv::StorageClass storageClass, - spirv::StructType structType); - spirv::Type getType(TypeId id); - - spirv::PointerType getPointerType(spv::StorageClass storageClass, TypeId id) { - assert(static_cast(storageClass) < 13); - auto &type = mPtrTypes[static_cast(storageClass)] - [static_cast(id)]; - - if (!type) { - type = mBuilder.createTypePointer(storageClass, getType(id)); - } - - return type; - } - - spirv::RuntimeArrayType getRuntimeArrayType(TypeId id); - - spirv::UIntType getUInt32Type() { - return spirv::cast(getType(TypeId::UInt32)); - } - spirv::UIntType getUInt64Type() { - return spirv::cast(getType(TypeId::UInt64)); - } - spirv::UIntType getUInt8Type() { - return spirv::cast(getType(TypeId::UInt8)); - } - - spirv::VectorOfType getUint32x2Type() { - return spirv::cast>( - getType(TypeId::UInt32x2)); - } - - spirv::VectorOfType getUint32x3Type() { - return spirv::cast>( - getType(TypeId::UInt32x3)); - } - - spirv::VectorOfType getUint32x4Type() { - return spirv::cast>( - getType(TypeId::UInt32x4)); - } - - spirv::ArrayOfType getArrayUint32x8Type() { - return spirv::cast>( - getType(TypeId::ArrayUInt32x8)); - } - - spirv::ArrayOfType getArrayUint32x16Type() { - return spirv::cast>( - getType(TypeId::ArrayUInt32x16)); - } - - spirv::SIntType getSint32Type() { - return spirv::cast(getType(TypeId::SInt32)); - } - spirv::SIntType getSint64Type() { - return spirv::cast(getType(TypeId::SInt64)); - } - - spirv::FloatType getFloat16Type() { - return spirv::cast(getType(TypeId::Float16)); - } - spirv::FloatType getFloat32Type() { - return spirv::cast(getType(TypeId::Float32)); - } - - spirv::VectorOfType getFloat32x4Type() { - return spirv::cast>( - getType(TypeId::Float32x4)); - } - - spirv::VectorOfType getFloat32x3Type() { - return spirv::cast>( - getType(TypeId::Float32x3)); - } - - spirv::VectorOfType getFloat32x2Type() { - return spirv::cast>( - getType(TypeId::Float32x2)); - } - - spirv::BoolType getBoolType() { - return spirv::cast(getType(TypeId::Bool)); - } - - spirv::VoidType getVoidType() { - return spirv::cast(getType(TypeId::Void)); - } - - spirv::ConstantBool getTrue() { - if (!mTrue) { - mTrue = mBuilder.createConstantTrue(getBoolType()); - } - return mTrue; - } - spirv::ConstantBool getFalse() { - if (!mFalse) { - mFalse = mBuilder.createConstantFalse(getBoolType()); - } - return mFalse; - } - - spirv::ConstantUInt getUInt64(std::uint64_t value); - spirv::ConstantUInt getUInt32(std::uint32_t value); - spirv::ConstantSInt getSInt32(std::uint32_t value); - spirv::ConstantFloat getFloat32Raw(std::uint32_t value); - - spirv::ConstantFloat getFloat32(float id) { - return getFloat32Raw(std::bit_cast(id)); - } - - spirv::SamplerType getSamplerType() { - return spirv::cast(getType(TypeId::Sampler)); - } - spirv::ImageType getImage2DType() { - return spirv::cast(getType(TypeId::Image2D)); - } - spirv::ImageType getStorageImage2DType() { - return spirv::cast(getType(TypeId::StorageImage2D)); - } - spirv::SampledImageType getSampledImage2DType() { - return spirv::cast( - getType(TypeId::SampledImage2D)); - } - - UniformInfo *createStorageBuffer(TypeId type); - UniformInfo *getOrCreateStorageBuffer(std::uint32_t *vbuffer, TypeId type); - UniformInfo *getOrCreateUniformConstant(std::uint32_t *buffer, - std::size_t size, TypeId type); - spirv::VariableValue getThreadId(); - spirv::VariableValue getWorkgroupId(); - spirv::VariableValue getLocalInvocationId(); - spirv::VariableValue getPerVertex(); - spirv::VariableValue getFragCoord(); - spirv::VariableValue getIn(unsigned location); - spirv::VariableValue getOut(unsigned location); - - spirv::Function getDiscardFn(); - - std::optional findUint32Value(spirv::Value id) const; - std::optional findSint32Value(spirv::Value id) const; - std::optional findFloat32Value(spirv::Value id) const; - spirv::FunctionType getFunctionType(spirv::Type resultType, - std::span params); - - Function *createFunction(std::size_t expectedSize); - Fragment *createFragment(std::size_t expectedSize); - - std::vector &getUniforms() { return mUniforms; } -}; + class ConverterContext + { + Stage mStage; + RemoteMemory mMemory; + spirv::IdGenerator mGenerator; + spirv::SpirvBuilder mBuilder{mGenerator, 1024}; + static constexpr auto kGenericTypesCount = + static_cast(TypeId::Void) + 1; + spirv::Type mTypes[kGenericTypesCount]; + spirv::PointerType mPtrTypes[13][kGenericTypesCount]; + spirv::RuntimeArrayType mRuntimeArrayTypes[kGenericTypesCount]; + spirv::VariableValue mThreadId; + spirv::VariableValue mWorkgroupId; + spirv::VariableValue mLocalInvocationId; + spirv::VariableValue mPerVertex; + spirv::VariableValue mFragCoord; + std::vector mInterfaces; + std::map mIns; + std::map mOuts; + + std::map mConstantFloat32Map; + std::map mConstantUint32Map; + std::map mConstantSint32Map; + std::map mConstantUint64Map; + + struct FunctionType + { + spirv::Type resultType; + std::vector params; + spirv::FunctionType id; + }; + + std::vector mFunctionTypes; + + struct StructTypeEntry + { + spirv::StructType id; + std::vector members; + spirv::PointerType ptrTypes[13]; + + bool match(std::span other) + { + if (members.size() != other.size()) + { + return false; + } + + for (std::size_t i = 0; i < other.size(); ++i) + { + if (members[i] != other[i]) + { + return false; + } + } + + return true; + } + }; + + std::vector mStructTypes; + + std::forward_list mFragments; + std::forward_list mFunctions; + + spirv::ConstantBool mTrue; + spirv::ConstantBool mFalse; + + std::vector mUniforms; + spirv::ExtInstSet mGlslStd450; + spirv::Function mDiscardFn; + + public: + util::MemoryAreaTable<>* dependencies = nullptr; + + ConverterContext(RemoteMemory memory, Stage stage, + util::MemoryAreaTable<>* dependencies) + : mStage(stage) + , mMemory(memory) + , dependencies(dependencies) + { + mGlslStd450 = mBuilder.createExtInstImport("GLSL.std.450"); + } + + const decltype(mInterfaces)& getInterfaces() const { return mInterfaces; } + + spirv::SpirvBuilder& getBuilder() { return mBuilder; } + RemoteMemory getMemory() const { return mMemory; } + spirv::ExtInstSet getGlslStd450() const { return mGlslStd450; } + std::optional getTypeIdOf(spirv::Type type) const; + + spirv::StructType findStructType(std::span members); + spirv::StructType getStructType(std::span members); + spirv::PointerType getStructPointerType(spv::StorageClass storageClass, + spirv::StructType structType); + spirv::Type getType(TypeId id); + + spirv::PointerType getPointerType(spv::StorageClass storageClass, TypeId id) + { + assert(static_cast(storageClass) < 13); + auto& type = mPtrTypes[static_cast(storageClass)] + [static_cast(id)]; + + if (!type) + { + type = mBuilder.createTypePointer(storageClass, getType(id)); + } + + return type; + } + + spirv::RuntimeArrayType getRuntimeArrayType(TypeId id); + + spirv::UIntType getUInt32Type() + { + return spirv::cast(getType(TypeId::UInt32)); + } + spirv::UIntType getUInt64Type() + { + return spirv::cast(getType(TypeId::UInt64)); + } + spirv::UIntType getUInt8Type() + { + return spirv::cast(getType(TypeId::UInt8)); + } + + spirv::VectorOfType getUint32x2Type() + { + return spirv::cast>( + getType(TypeId::UInt32x2)); + } + + spirv::VectorOfType getUint32x3Type() + { + return spirv::cast>( + getType(TypeId::UInt32x3)); + } + + spirv::VectorOfType getUint32x4Type() + { + return spirv::cast>( + getType(TypeId::UInt32x4)); + } + + spirv::ArrayOfType getArrayUint32x8Type() + { + return spirv::cast>( + getType(TypeId::ArrayUInt32x8)); + } + + spirv::ArrayOfType getArrayUint32x16Type() + { + return spirv::cast>( + getType(TypeId::ArrayUInt32x16)); + } + + spirv::SIntType getSint32Type() + { + return spirv::cast(getType(TypeId::SInt32)); + } + spirv::SIntType getSint64Type() + { + return spirv::cast(getType(TypeId::SInt64)); + } + + spirv::FloatType getFloat16Type() + { + return spirv::cast(getType(TypeId::Float16)); + } + spirv::FloatType getFloat32Type() + { + return spirv::cast(getType(TypeId::Float32)); + } + + spirv::VectorOfType getFloat32x4Type() + { + return spirv::cast>( + getType(TypeId::Float32x4)); + } + + spirv::VectorOfType getFloat32x3Type() + { + return spirv::cast>( + getType(TypeId::Float32x3)); + } + + spirv::VectorOfType getFloat32x2Type() + { + return spirv::cast>( + getType(TypeId::Float32x2)); + } + + spirv::BoolType getBoolType() + { + return spirv::cast(getType(TypeId::Bool)); + } + + spirv::VoidType getVoidType() + { + return spirv::cast(getType(TypeId::Void)); + } + + spirv::ConstantBool getTrue() + { + if (!mTrue) + { + mTrue = mBuilder.createConstantTrue(getBoolType()); + } + return mTrue; + } + spirv::ConstantBool getFalse() + { + if (!mFalse) + { + mFalse = mBuilder.createConstantFalse(getBoolType()); + } + return mFalse; + } + + spirv::ConstantUInt getUInt64(std::uint64_t value); + spirv::ConstantUInt getUInt32(std::uint32_t value); + spirv::ConstantSInt getSInt32(std::uint32_t value); + spirv::ConstantFloat getFloat32Raw(std::uint32_t value); + + spirv::ConstantFloat getFloat32(float id) + { + return getFloat32Raw(std::bit_cast(id)); + } + + spirv::SamplerType getSamplerType() + { + return spirv::cast(getType(TypeId::Sampler)); + } + spirv::ImageType getImage2DType() + { + return spirv::cast(getType(TypeId::Image2D)); + } + spirv::ImageType getStorageImage2DType() + { + return spirv::cast(getType(TypeId::StorageImage2D)); + } + spirv::SampledImageType getSampledImage2DType() + { + return spirv::cast( + getType(TypeId::SampledImage2D)); + } + + UniformInfo* createStorageBuffer(TypeId type); + UniformInfo* getOrCreateStorageBuffer(std::uint32_t* vbuffer, TypeId type); + UniformInfo* getOrCreateUniformConstant(std::uint32_t* buffer, + std::size_t size, TypeId type); + spirv::VariableValue getThreadId(); + spirv::VariableValue getWorkgroupId(); + spirv::VariableValue getLocalInvocationId(); + spirv::VariableValue getPerVertex(); + spirv::VariableValue getFragCoord(); + spirv::VariableValue getIn(unsigned location); + spirv::VariableValue getOut(unsigned location); + + spirv::Function getDiscardFn(); + + std::optional findUint32Value(spirv::Value id) const; + std::optional findSint32Value(spirv::Value id) const; + std::optional findFloat32Value(spirv::Value id) const; + spirv::FunctionType getFunctionType(spirv::Type resultType, + std::span params); + + Function* createFunction(std::size_t expectedSize); + Fragment* createFragment(std::size_t expectedSize); + + std::vector& getUniforms() { return mUniforms; } + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Fragment.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Fragment.hpp index 8a52f267..ab09920c 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Fragment.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Fragment.hpp @@ -9,77 +9,89 @@ #include #include -namespace amdgpu::shader { -enum class OperandGetFlags { None, PreserveType = 1 << 0 }; +namespace amdgpu::shader +{ + enum class OperandGetFlags + { + None, + PreserveType = 1 << 0 + }; -struct Function; -class ConverterContext; + struct Function; + class ConverterContext; -struct Fragment { - ConverterContext *context = nullptr; - Function *function = nullptr; - spirv::Block entryBlockId; - spirv::BlockBuilder builder; - RegisterState *registers = nullptr; + struct Fragment + { + ConverterContext* context = nullptr; + Function* function = nullptr; + spirv::Block entryBlockId; + spirv::BlockBuilder builder; + RegisterState* registers = nullptr; - std::set values; - std::set outputs; + std::set values; + std::set outputs; - std::vector predecessors; - std::uint64_t jumpAddress = 0; - spirv::BoolValue branchCondition; - bool hasTerminator = false; + std::vector predecessors; + std::uint64_t jumpAddress = 0; + spirv::BoolValue branchCondition; + bool hasTerminator = false; - void appendBranch(Fragment &other) { other.predecessors.push_back(this); } + void appendBranch(Fragment& other) { other.predecessors.push_back(this); } - void injectValuesFromPreds(); + void injectValuesFromPreds(); - // std::optional findInput(spirv::Value value); - // Value addInput(RegisterId id, spirv::Type type); - spirv::SamplerValue createSampler(RegisterId base); - spirv::ImageValue createImage(RegisterId base, bool r128, bool sampled, - AccessOp access); // TODO: params - Value createCompositeExtract(Value composite, std::uint32_t member); - Value getOperand(RegisterId id, TypeId type, - OperandGetFlags flags = OperandGetFlags::None); - void setOperand(RegisterId id, Value value); - void setVcc(Value value); - void setScc(Value value); - spirv::BoolValue getScc(); - spirv::Value createBitcast(spirv::Type to, spirv::Type from, - spirv::Value value); + // std::optional findInput(spirv::Value value); + // Value addInput(RegisterId id, spirv::Type type); + spirv::SamplerValue createSampler(RegisterId base); + spirv::ImageValue createImage(RegisterId base, bool r128, bool sampled, + AccessOp access); // TODO: params + Value createCompositeExtract(Value composite, std::uint32_t member); + Value getOperand(RegisterId id, TypeId type, + OperandGetFlags flags = OperandGetFlags::None); + void setOperand(RegisterId id, Value value); + void setVcc(Value value); + void setScc(Value value); + spirv::BoolValue getScc(); + spirv::Value createBitcast(spirv::Type to, spirv::Type from, + spirv::Value value); - Value getScalarOperand(int id, TypeId type, - OperandGetFlags flags = OperandGetFlags::None) { - return getOperand(RegisterId::Scalar(id), type, flags); - } - Value getVectorOperand(int id, TypeId type, - OperandGetFlags flags = OperandGetFlags::None) { - return getOperand(RegisterId::Vector(id), type, flags); - } - Value getAttrOperand(int id, TypeId type, - OperandGetFlags flags = OperandGetFlags::None) { - return getOperand(RegisterId::Attr(id), type, flags); - } - Value getVccLo() { return getOperand(RegisterId::VccLo, TypeId::UInt32); } - Value getVccHi() { return getOperand(RegisterId::VccHi, TypeId::UInt32); } - Value getExecLo() { return getOperand(RegisterId::ExecLo, TypeId::UInt32); } - Value getExecHi() { return getOperand(RegisterId::ExecHi, TypeId::UInt32); } - void setScalarOperand(int id, Value value) { - setOperand(RegisterId::Scalar(id), value); - } - void setVectorOperand(int id, Value value) { - setOperand(RegisterId::Vector(id), value); - } - void setExportTarget(int id, Value value) { - setOperand(RegisterId::Export(id), value); - } - // void createCallTo(MaterializedFunction *other); - void convert(std::uint64_t size); + Value getScalarOperand(int id, TypeId type, + OperandGetFlags flags = OperandGetFlags::None) + { + return getOperand(RegisterId::Scalar(id), type, flags); + } + Value getVectorOperand(int id, TypeId type, + OperandGetFlags flags = OperandGetFlags::None) + { + return getOperand(RegisterId::Vector(id), type, flags); + } + Value getAttrOperand(int id, TypeId type, + OperandGetFlags flags = OperandGetFlags::None) + { + return getOperand(RegisterId::Attr(id), type, flags); + } + Value getVccLo() { return getOperand(RegisterId::VccLo, TypeId::UInt32); } + Value getVccHi() { return getOperand(RegisterId::VccHi, TypeId::UInt32); } + Value getExecLo() { return getOperand(RegisterId::ExecLo, TypeId::UInt32); } + Value getExecHi() { return getOperand(RegisterId::ExecHi, TypeId::UInt32); } + void setScalarOperand(int id, Value value) + { + setOperand(RegisterId::Scalar(id), value); + } + void setVectorOperand(int id, Value value) + { + setOperand(RegisterId::Vector(id), value); + } + void setExportTarget(int id, Value value) + { + setOperand(RegisterId::Export(id), value); + } + // void createCallTo(MaterializedFunction *other); + void convert(std::uint64_t size); -private: - Value getRegister(RegisterId id); - Value getRegister(RegisterId id, spirv::Type type); - void setRegister(RegisterId id, Value value); -}; + private: + Value getRegister(RegisterId id); + Value getRegister(RegisterId id, spirv::Type type); + void setRegister(RegisterId id, Value value); + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/FragmentTerminator.hpp b/hw/amdgpu/shader/include/amdgpu/shader/FragmentTerminator.hpp index 48ad5a03..0da50949 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/FragmentTerminator.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/FragmentTerminator.hpp @@ -1,11 +1,13 @@ #pragma once -namespace amdgpu::shader { -enum class FragmentTerminator { - None, - EndProgram, - CallToReg, - BranchToReg, - Branch, -}; +namespace amdgpu::shader +{ + enum class FragmentTerminator + { + None, + EndProgram, + CallToReg, + BranchToReg, + Branch, + }; } diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Function.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Function.hpp index 80d82566..bb63d73e 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Function.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Function.hpp @@ -5,35 +5,38 @@ #include "spirv/spirv-builder.hpp" #include -namespace amdgpu::shader { -class ConverterContext; +namespace amdgpu::shader +{ + class ConverterContext; -struct Function { - ConverterContext *context = nullptr; - Stage stage = Stage::None; - std::span userSgprs; - std::span userVgprs; - Fragment entryFragment; - Fragment exitFragment; - std::map inputs; - spirv::FunctionBuilder builder; - std::vector fragments; + struct Function + { + ConverterContext* context = nullptr; + Stage stage = Stage::None; + std::span userSgprs; + std::span userVgprs; + Fragment entryFragment; + Fragment exitFragment; + std::map inputs; + spirv::FunctionBuilder builder; + std::vector fragments; - Value getInput(RegisterId id); - Value createInput(RegisterId id); - void createExport(spirv::BlockBuilder &builder, unsigned index, Value value); - spirv::Type getResultType(); - spirv::FunctionType getFunctionType(); + Value getInput(RegisterId id); + Value createInput(RegisterId id); + void createExport(spirv::BlockBuilder& builder, unsigned index, Value value); + spirv::Type getResultType(); + spirv::FunctionType getFunctionType(); - Fragment *createFragment() { - auto result = createDetachedFragment(); - appendFragment(result); - return result; - } + Fragment* createFragment() + { + auto result = createDetachedFragment(); + appendFragment(result); + return result; + } - Fragment *createDetachedFragment(); - void appendFragment(Fragment *fragment) { fragments.push_back(fragment); } + Fragment* createDetachedFragment(); + void appendFragment(Fragment* fragment) { fragments.push_back(fragment); } - void insertReturn(); -}; + void insertReturn(); + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Instruction.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Instruction.hpp index 2d73e554..d387d4b2 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Instruction.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Instruction.hpp @@ -3,1971 +3,2079 @@ #include #include -namespace amdgpu::shader { -inline constexpr std::uint32_t genMask(std::uint32_t offset, - std::uint32_t bitCount) { - return ((1u << bitCount) - 1u) << offset; -} - -inline constexpr std::uint32_t getMaskEnd(std::uint32_t mask) { - return 32 - std::countl_zero(mask); -} - -inline constexpr std::uint32_t fetchMaskedValue(std::uint32_t hex, - std::uint32_t mask) { - return (hex & mask) >> std::countr_zero(mask); -} - -enum SurfaceFormat { - kSurfaceFormatInvalid = 0x00000000, - kSurfaceFormat8 = 0x00000001, - kSurfaceFormat16 = 0x00000002, - kSurfaceFormat8_8 = 0x00000003, - kSurfaceFormat32 = 0x00000004, - kSurfaceFormat16_16 = 0x00000005, - kSurfaceFormat10_11_11 = 0x00000006, - kSurfaceFormat11_11_10 = 0x00000007, - kSurfaceFormat10_10_10_2 = 0x00000008, - kSurfaceFormat2_10_10_10 = 0x00000009, - kSurfaceFormat8_8_8_8 = 0x0000000a, - kSurfaceFormat32_32 = 0x0000000b, - kSurfaceFormat16_16_16_16 = 0x0000000c, - kSurfaceFormat32_32_32 = 0x0000000d, - kSurfaceFormat32_32_32_32 = 0x0000000e, -}; -enum TextureChannelType { - kTextureChannelTypeUNorm = 0x00000000, - kTextureChannelTypeSNorm = 0x00000001, - kTextureChannelTypeUScaled = 0x00000002, - kTextureChannelTypeSScaled = 0x00000003, - kTextureChannelTypeUInt = 0x00000004, - kTextureChannelTypeSInt = 0x00000005, - kTextureChannelTypeSNormNoZero = 0x00000006, - kTextureChannelTypeFloat = 0x00000007, -}; - -inline int getScalarInstSize(int id) { return id == 255 ? 1 : 0; } - -struct Sop1 { - enum class Op { - S_MOV_B32 = 3, - S_MOV_B64, - S_CMOV_B32, - S_CMOV_B64, - S_NOT_B32, - S_NOT_B64, - S_WQM_B32, - S_WQM_B64, - S_BREV_B32, - S_BREV_B64, - S_BCNT0_I32_B32, - S_BCNT0_I32_B64, - S_BCNT1_I32_B32, - S_BCNT1_I32_B64, - S_FF0_I32_B32, - S_FF0_I32_B64, - S_FF1_I32_B32, - S_FF1_I32_B64, - S_FLBIT_I32_B32, - S_FLBIT_I32_B64, - S_FLBIT_I32, - S_FLBIT_I32_I64, - S_SEXT_I32_I8, - S_SEXT_I32_I16, - S_BITSET0_B32, - S_BITSET0_B64, - S_BITSET1_B32, - S_BITSET1_B64, - S_GETPC_B64, - S_SETPC_B64, - S_SWAPPC_B64, - S_RFE_B64, - S_AND_SAVEEXEC_B64 = 36, - S_OR_SAVEEXEC_B64, - S_XOR_SAVEEXEC_B64, - S_ANDN2_SAVEEXEC_B64, - S_ORN2_SAVEEXEC_B64, - S_NAND_SAVEEXEC_B64, - S_NOR_SAVEEXEC_B64, - S_XNOR_SAVEEXEC_B64, - S_QUADMASK_B32, - S_QUADMASK_B64, - S_MOVRELS_B32, - S_MOVRELS_B64, - S_MOVRELD_B32, - S_MOVRELD_B64, - S_CBRANCH_JOIN, - S_ABS_I32 = 52, - S_MOV_FED_B32, - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto ssrc0Mask = genMask(0, 8); - static constexpr auto opMask = genMask(getMaskEnd(ssrc0Mask), 8); - static constexpr auto sdstMask = genMask(getMaskEnd(opMask), 7); - - const std::uint32_t *inst; - - const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); - - Sop1(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize + getScalarInstSize(ssrc0); } - - void dump() const; -}; - -struct Sopk { - enum class Op { - S_MOVK_I32, - S_CMOVK_I32 = 2, - S_CMPK_EQ_I32, - S_CMPK_LG_I32, - S_CMPK_GT_I32, - S_CMPK_GE_I32, - S_CMPK_LT_I32, - S_CMPK_LE_I32, - S_CMPK_EQ_U32, - S_CMPK_LG_U32, - S_CMPK_GT_U32, - S_CMPK_GE_U32, - S_CMPK_LT_U32, - S_CMPK_LE_U32, - S_ADDK_I32, - S_MULK_I32, - S_CBRANCH_I_FORK, - S_GETREG_B32, - S_SETREG_B32, - S_SETREG_IMM - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto simmMask = genMask(0, 16); - static constexpr auto sdstMask = genMask(getMaskEnd(simmMask), 7); - static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 5); - - const std::uint32_t *inst; - - const std::int16_t simm = (std::int16_t)fetchMaskedValue(inst[0], simmMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); - - Sopk(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Sopc { - enum class Op { - S_CMP_EQ_I32, - S_CMP_LG_I32, - S_CMP_GT_I32, - S_CMP_GE_I32, - S_CMP_LT_I32, - S_CMP_LE_I32, - S_CMP_EQ_U32, - S_CMP_LG_U32, - S_CMP_GT_U32, - S_CMP_GE_U32, - S_CMP_LT_U32, - S_CMP_LE_U32, - S_BITCMP0_B32, - S_BITCMP1_B32, - S_BITCMP0_B64, - S_BITCMP1_B64, - S_SETVSKIP, - S_ILLEGALD - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto ssrc0Mask = genMask(0, 8); - static constexpr auto ssrc1Mask = genMask(getMaskEnd(ssrc0Mask), 8); - static constexpr auto opMask = genMask(getMaskEnd(ssrc1Mask), 7); - - const std::uint32_t *inst; - - const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); - const std::uint32_t ssrc1 = fetchMaskedValue(inst[0], ssrc1Mask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Sopc(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize + getScalarInstSize(ssrc0); } - - void dump() const; -}; - -struct Sop2 { - enum class Op { - S_ADD_U32, - S_SUB_U32, - S_ADD_I32, - S_SUB_I32, - S_ADDC_U32, - S_SUBB_U32, - S_MIN_I32, - S_MIN_U32, - S_MAX_I32, - S_MAX_U32, - S_CSELECT_B32, - S_CSELECT_B64, - S_AND_B32 = 14, - S_AND_B64, - S_OR_B32, - S_OR_B64, - S_XOR_B32, - S_XOR_B64, - S_ANDN2_B32, - S_ANDN2_B64, - S_ORN2_B32, - S_ORN2_B64, - S_NAND_B32, - S_NAND_B64, - S_NOR_B32, - S_NOR_B64, - S_XNOR_B32, - S_XNOR_B64, - S_LSHL_B32, - S_LSHL_B64, - S_LSHR_B32, - S_LSHR_B64, - S_ASHR_I32, - S_ASHR_I64, - S_BFM_B32, - S_BFM_B64, - S_MUL_I32, - S_BFE_U32, - S_BFE_I32, - S_BFE_U64, - S_BFE_I64, - S_CBRANCH_G_FORK, - S_ABSDIFF_I32, - S_LSHL1_ADD_U32, - S_LSHL2_ADD_U32, - S_LSHL3_ADD_U32, - S_LSHL4_ADD_U32, - S_PACK_LL_B32_B16, - S_PACK_LH_B32_B16, - S_PACK_HH_B32_B16, - S_MUL_HI_U32, - S_MUL_HI_I32, - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto ssrc0Mask = genMask(0, 8); - static constexpr auto ssrc1Mask = genMask(getMaskEnd(ssrc0Mask), 8); - static constexpr auto sdstMask = genMask(getMaskEnd(ssrc1Mask), 7); - static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 7); - - const std::uint32_t *inst; - const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); - const std::uint32_t ssrc1 = fetchMaskedValue(inst[0], ssrc1Mask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); - - Sop2(const std::uint32_t *inst) : inst(inst) {} - - int size() const { - return kMinInstSize + getScalarInstSize(ssrc0) + getScalarInstSize(ssrc1); - } - - void dump() const; -}; - -struct Sopp { - enum class Op { - S_NOP, - S_ENDPGM, - S_BRANCH, - S_CBRANCH_SCC0 = 4, - S_CBRANCH_SCC1, - S_CBRANCH_VCCZ, - S_CBRANCH_VCCNZ, - S_CBRANCH_EXECZ, - S_CBRANCH_EXECNZ, - S_BARRIER, - S_WAITCNT = 12, - S_SETHALT, - S_SLEEP, - S_SETPRIO, - S_SENDMSG, - S_SENDMSGHALT, - S_TRAP, - S_ICACHE_INV, - S_INCPERFLEVEL, - S_DECPERFLEVEL, - S_TTRACEDATA, - S_CBRANCH_CDBGSYS = 23, - S_CBRANCH_CDBGUSER = 24, - S_CBRANCH_CDBGSYS_OR_USER = 25, - S_CBRANCH_CDBGSYS_AND_USER = 26, - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto simmMask = genMask(0, 16); - static constexpr auto opMask = genMask(getMaskEnd(simmMask), 7); - - const std::uint32_t *inst; - const std::int16_t simm = (std::int16_t)fetchMaskedValue(inst[0], simmMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Sopp(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Vop1 { - enum class Op { - V_NOP, - V_MOV_B32, - V_READFIRSTLANE_B32, - V_CVT_I32_F64, - V_CVT_F64_I32, - V_CVT_F32_I32, - V_CVT_F32_U32, - V_CVT_U32_F32, - V_CVT_I32_F32, - V_MOV_FED_B32, - V_CVT_F16_F32, - V_CVT_F32_F16, - V_CVT_RPI_I32_F32, - V_CVT_FLR_I32_F32, - V_CVT_OFF_F32_I4, - V_CVT_F32_F64, - V_CVT_F64_F32, - V_CVT_F32_UBYTE0, - V_CVT_F32_UBYTE1, - V_CVT_F32_UBYTE2, - V_CVT_F32_UBYTE3, - V_CVT_U32_F64, - V_CVT_F64_U32, - V_FRACT_F32 = 32, - V_TRUNC_F32, - V_CEIL_F32, - V_RNDNE_F32, - V_FLOOR_F32, - V_EXP_F32, - V_LOG_CLAMP_F32, - V_LOG_F32, - V_RCP_CLAMP_F32, - V_RCP_LEGACY_F32, - V_RCP_F32, - V_RCP_IFLAG_F32, - V_RSQ_CLAMP_F32, - V_RSQ_LEGACY_F32, - V_RSQ_F32, - V_RCP_F64, - V_RCP_CLAMP_F64, - V_RSQ_F64, - V_RSQ_CLAMP_F64, - V_SQRT_F32, - V_SQRT_F64, - V_SIN_F32, - V_COS_F32, - V_NOT_B32, - V_BFREV_B32, - V_FFBH_U32, - V_FFBL_B32, - V_FFBH_I32, - V_FREXP_EXP_I32_F64, - V_FREXP_MANT_F64, - V_FRACT_F64, - V_FREXP_EXP_I32_F32, - V_FREXP_MANT_F32, - V_CLREXCP, - V_MOVRELD_B32, - V_MOVRELS_B32, - V_MOVRELSD_B32, - V_CVT_F16_U16 = 80, - V_CVT_F16_I16, - V_CVT_U16_F16, - V_CVT_I16_F16, - V_RCP_F16, - V_SQRT_F16, - V_RSQ_F16, - V_LOG_F16, - V_EXP_F16, - V_FREXP_MANT_F16, - V_FREXP_EXP_I16_F16, - V_FLOOR_F16, - V_CEIL_F16, - V_TRUNC_F16, - V_RNDNE_F16, - V_FRACT_F16, - V_SIN_F16, - V_COS_F16, - V_SAT_PK_U8_I16, - V_CVT_NORM_I16_F16, - V_CVT_NORM_U16_F16, - V_SWAP_B32, - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto src0Mask = genMask(0, 9); - static constexpr auto opMask = genMask(getMaskEnd(src0Mask), 8); - static constexpr auto vdstMask = genMask(getMaskEnd(opMask), 8); - - const std::uint32_t *inst; - const std::uint32_t src0 = fetchMaskedValue(inst[0], src0Mask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); - - int size() const { return kMinInstSize + getScalarInstSize(src0); } - - Vop1(const std::uint32_t *inst) : inst(inst) {} - - void dump() const; -}; - -struct Vop2 { - enum class Op { - V_CNDMASK_B32, - V_READLANE_B32, - V_WRITELANE_B32, - V_ADD_F32, - V_SUB_F32, - V_SUBREV_F32, - V_MAC_LEGACY_F32, - V_MUL_LEGACY_F32, - V_MUL_F32, - V_MUL_I32_I24, - V_MUL_HI_I32_I24, - V_MUL_U32_U24, - V_MUL_HI_U32_U24, - V_MIN_LEGACY_F32, - V_MAX_LEGACY_F32, - V_MIN_F32, - V_MAX_F32, - V_MIN_I32, - V_MAX_I32, - V_MIN_U32, - V_MAX_U32, - V_LSHR_B32, - V_LSHRREV_B32, - V_ASHR_I32, - V_ASHRREV_I32, - V_LSHL_B32, - V_LSHLREV_B32, - V_AND_B32, - V_OR_B32, - V_XOR_B32, - V_BFM_B32, - V_MAC_F32, - V_MADMK_F32, - V_MADAK_F32, - V_BCNT_U32_B32, - V_MBCNT_LO_U32_B32, - V_MBCNT_HI_U32_B32, - V_ADD_I32, - V_SUB_I32, - V_SUBREV_I32, - V_ADDC_U32, - V_SUBB_U32, - V_SUBBREV_U32, - V_LDEXP_F32, - V_CVT_PKACCUM_U8_F32, - V_CVT_PKNORM_I16_F32, - V_CVT_PKNORM_U16_F32, - V_CVT_PKRTZ_F16_F32, - V_CVT_PK_U16_U32, - V_CVT_PK_I16_I32, - }; - - static constexpr int kMinInstSize = 1; - static constexpr auto src0Mask = genMask(0, 9); - static constexpr auto vsrc1Mask = genMask(getMaskEnd(src0Mask), 8); - static constexpr auto vdstMask = genMask(getMaskEnd(vsrc1Mask), 8); - static constexpr auto opMask = genMask(getMaskEnd(vdstMask), 6); - - const std::uint32_t *inst; - const std::uint32_t src0 = fetchMaskedValue(inst[0], src0Mask); - const std::uint32_t vsrc1 = fetchMaskedValue(inst[0], vsrc1Mask); - const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Vop2(const std::uint32_t *inst) : inst(inst) {} - - int size() const { - int result = kMinInstSize + getScalarInstSize(src0); - - if (op == Vop2::Op::V_MADMK_F32 || op == Vop2::Op::V_MADAK_F32) { - result += 1; - } - - return result; - } - void dump() const; -}; - -struct Vop3 { - enum class Op { - V3_CMP_F_F32, - V3_CMP_LT_F32, - V3_CMP_EQ_F32, - V3_CMP_LE_F32, - V3_CMP_GT_F32, - V3_CMP_LG_F32, - V3_CMP_GE_F32, - V3_CMP_O_F32, - V3_CMP_U_F32, - V3_CMP_NGE_F32, - V3_CMP_NLG_F32, - V3_CMP_NGT_F32, - V3_CMP_NLE_F32, - V3_CMP_NEQ_F32, - V3_CMP_NLT_F32, - V3_CMP_TRU_F32, - V3_CMPX_F_F32, - V3_CMPX_LT_F32, - V3_CMPX_EQ_F32, - V3_CMPX_LE_F32, - V3_CMPX_GT_F32, - V3_CMPX_LG_F32, - V3_CMPX_GE_F32, - V3_CMPX_O_F32, - V3_CMPX_U_F32, - V3_CMPX_NGE_F32, - V3_CMPX_NLG_F32, - V3_CMPX_NGT_F32, - V3_CMPX_NLE_F32, - V3_CMPX_NEQ_F32, - V3_CMPX_NLT_F32, - V3_CMPX_TRU_F32, - V3_CMP_F_F64, - V3_CMP_LT_F64, - V3_CMP_EQ_F64, - V3_CMP_LE_F64, - V3_CMP_GT_F64, - V3_CMP_LG_F64, - V3_CMP_GE_F64, - V3_CMP_O_F64, - V3_CMP_U_F64, - V3_CMP_NGE_F64, - V3_CMP_NLG_F64, - V3_CMP_NGT_F64, - V3_CMP_NLE_F64, - V3_CMP_NEQ_F64, - V3_CMP_NLT_F64, - V3_CMP_TRU_F64, - V3_CMPX_F_F64, - V3_CMPX_LT_F64, - V3_CMPX_EQ_F64, - V3_CMPX_LE_F64, - V3_CMPX_GT_F64, - V3_CMPX_LG_F64, - V3_CMPX_GE_F64, - V3_CMPX_O_F64, - V3_CMPX_U_F64, - V3_CMPX_NGE_F64, - V3_CMPX_NLG_F64, - V3_CMPX_NGT_F64, - V3_CMPX_NLE_F64, - V3_CMPX_NEQ_F64, - V3_CMPX_NLT_F64, - V3_CMPX_TRU_F64, - V3_CMPS_F_F32, - V3_CMPS_LT_F32, - V3_CMPS_EQ_F32, - V3_CMPS_LE_F32, - V3_CMPS_GT_F32, - V3_CMPS_LG_F32, - V3_CMPS_GE_F32, - V3_CMPS_O_F32, - V3_CMPS_U_F32, - V3_CMPS_NGE_F32, - V3_CMPS_NLG_F32, - V3_CMPS_NGT_F32, - V3_CMPS_NLE_F32, - V3_CMPS_NEQ_F32, - V3_CMPS_NLT_F32, - V3_CMPS_TRU_F32, - V3_CMPSX_F_F32, - V3_CMPSX_LT_F32, - V3_CMPSX_EQ_F32, - V3_CMPSX_LE_F32, - V3_CMPSX_GT_F32, - V3_CMPSX_LG_F32, - V3_CMPSX_GE_F32, - V3_CMPSX_O_F32, - V3_CMPSX_U_F32, - V3_CMPSX_NGE_F32, - V3_CMPSX_NLG_F32, - V3_CMPSX_NGT_F32, - V3_CMPSX_NLE_F32, - V3_CMPSX_NEQ_F32, - V3_CMPSX_NLT_F32, - V3_CMPSX_TRU_F32, - V3_CMPS_F_F64, - V3_CMPS_LT_F64, - V3_CMPS_EQ_F64, - V3_CMPS_LE_F64, - V3_CMPS_GT_F64, - V3_CMPS_LG_F64, - V3_CMPS_GE_F64, - V3_CMPS_O_F64, - V3_CMPS_U_F64, - V3_CMPS_NGE_F64, - V3_CMPS_NLG_F64, - V3_CMPS_NGT_F64, - V3_CMPS_NLE_F64, - V3_CMPS_NEQ_F64, - V3_CMPS_NLT_F64, - V3_CMPS_TRU_F64, - V3_CMPSX_F_F64, - V3_CMPSX_LT_F64, - V3_CMPSX_EQ_F64, - V3_CMPSX_LE_F64, - V3_CMPSX_GT_F64, - V3_CMPSX_LG_F64, - V3_CMPSX_GE_F64, - V3_CMPSX_O_F64, - V3_CMPSX_U_F64, - V3_CMPSX_NGE_F64, - V3_CMPSX_NLG_F64, - V3_CMPSX_NGT_F64, - V3_CMPSX_NLE_F64, - V3_CMPSX_NEQ_F64, - V3_CMPSX_NLT_F64, - V3_CMPSX_TRU_F64, - V3_CMP_F_I32, - V3_CMP_LT_I32, - V3_CMP_EQ_I32, - V3_CMP_LE_I32, - V3_CMP_GT_I32, - V3_CMP_NE_I32, - V3_CMP_GE_I32, - V3_CMP_T_I32, - V3_CMP_CLASS_F32, - V3_CMP_LT_I16, - V3_CMP_EQ_I16, - V3_CMP_LE_I16, - V3_CMP_GT_I16, - V3_CMP_NE_I16, - V3_CMP_GE_I16, - V3_CMP_CLASS_F16, - V3_CMPX_F_I32, - V3_CMPX_LT_I32, - V3_CMPX_EQ_I32, - V3_CMPX_LE_I32, - V3_CMPX_GT_I32, - V3_CMPX_NE_I32, - V3_CMPX_GE_I32, - V3_CMPX_T_I32, - V3_CMPX_CLASS_F32, - V3_CMPX_LT_I16, - V3_CMPX_EQ_I16, - V3_CMPX_LE_I16, - V3_CMPX_GT_I16, - V3_CMPX_NE_I16, - V3_CMPX_GE_I16, - V3_CMPX_CLASS_F16, - V3_CMP_F_I64, - V3_CMP_LT_I64, - V3_CMP_EQ_I64, - V3_CMP_LE_I64, - V3_CMP_GT_I64, - V3_CMP_NE_I64, - V3_CMP_GE_I64, - V3_CMP_T_I64, - V3_CMP_CLASS_F64, - V3_CMP_LT_U16, - V3_CMP_EQ_U16, - V3_CMP_LE_U16, - V3_CMP_GT_U16, - V3_CMP_NE_U16, - V3_CMP_GE_U16, - V3_CMPX_F_I64 = 176, - V3_CMPX_LT_I64, - V3_CMPX_EQ_I64, - V3_CMPX_LE_I64, - V3_CMPX_GT_I64, - V3_CMPX_NE_I64, - V3_CMPX_GE_I64, - V3_CMPX_T_I64, - V3_CMPX_CLASS_F64, - V3_CMPX_LT_U16, - V3_CMPX_EQ_U16, - V3_CMPX_LE_U16, - V3_CMPX_GT_U16, - V3_CMPX_NE_U16, - V3_CMPX_GE_U16, - V3_CMP_F_U32 = 192, - V3_CMP_LT_U32, - V3_CMP_EQ_U32, - V3_CMP_LE_U32, - V3_CMP_GT_U32, - V3_CMP_NE_U32, - V3_CMP_GE_U32, - V3_CMP_T_U32, - V3_CMP_F_F16, - V3_CMP_LT_F16, - V3_CMP_EQ_F16, - V3_CMP_LE_F16, - V3_CMP_GT_F16, - V3_CMP_LG_F16, - V3_CMP_GE_F16, - V3_CMP_O_F16, - V3_CMPX_F_U32, - V3_CMPX_LT_U32, - V3_CMPX_EQ_U32, - V3_CMPX_LE_U32, - V3_CMPX_GT_U32, - V3_CMPX_NE_U32, - V3_CMPX_GE_U32, - V3_CMPX_T_U32, - V3_CMPX_F_F16, - V3_CMPX_LT_F16, - V3_CMPX_EQ_F16, - V3_CMPX_LE_F16, - V3_CMPX_GT_F16, - V3_CMPX_LG_F16, - V3_CMPX_GE_F16, - V3_CMPX_O_F16, - V3_CMP_F_U64, - V3_CMP_LT_U64, - V3_CMP_EQ_U64, - V3_CMP_LE_U64, - V3_CMP_GT_U64, - V3_CMP_NE_U64, - V3_CMP_GE_U64, - V3_CMP_T_U64, - V3_CMP_U_F16, - V3_CMP_NGE_F16, - V3_CMP_NLG_F16, - V3_CMP_NGT_F16, - V3_CMP_NLE_F16, - V3_CMP_NEQ_F16, - V3_CMP_NLT_F16, - V3_CMP_TRU_F16, - V3_CMPX_F_U64, - V3_CMPX_LT_U64, - V3_CMPX_EQ_U64, - V3_CMPX_LE_U64, - V3_CMPX_GT_U64, - V3_CMPX_NE_U64, - V3_CMPX_GE_U64, - V3_CMPX_T_U64, - V3_CNDMASK_B32 = 256, - V3_READLANE_B32, - V3_WRITELANE_B32, - V3_ADD_F32, - V3_SUB_F32, - V3_SUBREV_F32, - V3_MAC_LEGACY_F32, - V3_MUL_LEGACY_F32, - V3_MUL_F32, - V3_MUL_I32_I24, - V3_MUL_HI_I32_I24, - V3_MUL_U32_U24, - V3_MUL_HI_U32_U24, - V3_MIN_LEGACY_F32, - V3_MAX_LEGACY_F32, - V3_MIN_F32, - V3_MAX_F32, - V3_MIN_I32, - V3_MAX_I32, - V3_MIN_U32, - V3_MAX_U32, - V3_LSHR_B32, - V3_LSHRREV_B32, - V3_ASHR_I32, - V3_ASHRREV_I32, - V3_LSHL_B32, - V3_LSHLREV_B32, - V3_AND_B32, - V3_OR_B32, - V3_XOR_B32, - V3_BFM_B32, - V3_MAC_F32, - V3_MADMK_F32, - V3_MADAK_F32, - V3_BCNT_U32_B32, - V3_MBCNT_LO_U32_B32, - V3_MBCNT_HI_U32_B32, - V3_ADD_I32, - V3_SUB_I32, - V3_SUBREV_I32, - V3_ADDC_U32, - V3_SUBB_U32, - V3_SUBBREV_U32, - V3_LDEXP_F32, - V3_CVT_PKACCUM_U8_F32, - V3_CVT_PKNORM_I16_F32, - V3_CVT_PKNORM_U16_F32, - V3_CVT_PKRTZ_F16_F32, - V3_CVT_PK_U16_U32, - V3_CVT_PK_I16_I32, - V3_MAD_LEGACY_F32 = 320, - V3_MAD_F32, - V3_MAD_I32_I24, - V3_MAD_U32_U24, - V3_CUBEID_F32, - V3_CUBESC_F32, - V3_CUBETC_F32, - V3_CUBEMA_F32, - V3_BFE_U32, - V3_BFE_I32, - V3_BFI_B32, - V3_FMA_F32, - V3_FMA_F64, - V3_LERP_U8, - V3_ALIGNBIT_B32, - V3_ALIGNBYTE_B32, - V3_MULLIT_F32, - V3_MIN3_F32, - V3_MIN3_I32, - V3_MIN3_U32, - V3_MAX3_F32, - V3_MAX3_I32, - V3_MAX3_U32, - V3_MED3_F32, - V3_MED3_I32, - V3_MED3_U32, - V3_SAD_U8, - V3_SAD_HI_U8, - V3_SAD_U16, - V3_SAD_U32, - V3_CVT_PK_U8_F32, - V3_DIV_FIXUP_F32, - V3_DIV_FIXUP_F64, - V3_LSHL_B64, - V3_LSHR_B64, - V3_ASHR_I64, - V3_ADD_F64, - V3_MUL_F64, - V3_MIN_F64, - V3_MAX_F64, - V3_LDEXP_F64, - V3_MUL_LO_U32, - V3_MUL_HI_U32, - V3_MUL_LO_I32, - V3_MUL_HI_I32, - V3_DIV_SCALE_F32, - V3_DIV_SCALE_F64, - V3_DIV_FMAS_F32, - V3_DIV_FMAS_F64, - V3_MSAD_U8, - V3_QSAD_U8, - V3_MQSAD_U8, - V3_TRIG_PREOP_F64, - V3_NOP = 384, - V3_MOV_B32, - V3_READFIRSTLANE_B32, - V3_CVT_I32_F64, - V3_CVT_F64_I32, - V3_CVT_F32_I32, - V3_CVT_F32_U32, - V3_CVT_U32_F32, - V3_CVT_I32_F32, - V3_MOV_FED_B32, - V3_CVT_F16_F32, - V3_CVT_F32_F16, - V3_CVT_RPI_I32_F32, - V3_CVT_FLR_I32_F32, - V3_CVT_OFF_F32_I4, - V3_CVT_F32_F64, - V3_CVT_F64_F32, - V3_CVT_F32_UBYTE0, - V3_CVT_F32_UBYTE1, - V3_CVT_F32_UBYTE2, - V3_CVT_F32_UBYTE3, - V3_CVT_U32_F64, - V3_CVT_F64_U32, - V3_FRACT_F32 = 416, - V3_TRUNC_F32, - V3_CEIL_F32, - V3_RNDNE_F32, - V3_FLOOR_F32, - V3_EXP_F32, - V3_LOG_CLAMP_F32, - V3_LOG_F32, - V3_RCP_CLAMP_F32, - V3_RCP_LEGACY_F32, - V3_RCP_F32, - V3_RCP_IFLAG_F32, - V3_RSQ_CLAMP_F32, - V3_RSQ_LEGACY_F32, - V3_RSQ_F32, - V3_RCP_F64, - V3_RCP_CLAMP_F64, - V3_RSQ_F64, - V3_RSQ_CLAMP_F64, - V3_SQRT_F32, - V3_SQRT_F64, - V3_SIN_F32, - V3_COS_F32, - V3_NOT_B32, - V3_BFREV_B32, - V3_FFBH_U32, - V3_FFBL_B32, - V3_FFBH_I32, - V3_FREXP_EXP_I32_F64, - V3_FREXP_MANT_F64, - V3_FRACT_F64, - V3_FREXP_EXP_I32_F32, - V3_FREXP_MANT_F32, - V3_CLREXCP, - V3_MOVRELD_B32, - V3_MOVRELS_B32, - V3_MOVRELSD_B32, - }; - - static constexpr int kMinInstSize = 2; - static constexpr auto vdstMask = genMask(0, 8); - - static constexpr auto absMask = genMask(getMaskEnd(vdstMask), 3); - static constexpr auto abs0Mask = genMask(getMaskEnd(vdstMask), 1); - static constexpr auto abs1Mask = genMask(getMaskEnd(abs0Mask), 1); - static constexpr auto abs2Mask = genMask(getMaskEnd(abs1Mask), 1); - static constexpr auto clmpMask = genMask(getMaskEnd(absMask), 1); - - static constexpr auto sdstMask = genMask(getMaskEnd(vdstMask), 7); - - static_assert(getMaskEnd(clmpMask) + 5 == getMaskEnd(sdstMask) + 2); - - static constexpr auto opMask = genMask(getMaskEnd(clmpMask) + 5, 9); - - static constexpr auto src0Mask = genMask(0, 9); - static constexpr auto src1Mask = genMask(getMaskEnd(src0Mask), 9); - static constexpr auto src2Mask = genMask(getMaskEnd(src1Mask), 9); - static constexpr auto omodMask = genMask(getMaskEnd(src2Mask), 2); - static constexpr auto negMask = genMask(getMaskEnd(omodMask), 3); - static constexpr auto neg0Mask = genMask(getMaskEnd(omodMask), 1); - static constexpr auto neg1Mask = genMask(getMaskEnd(neg0Mask), 1); - static constexpr auto neg2Mask = genMask(getMaskEnd(neg1Mask), 1); - - const std::uint32_t *inst; - const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); - const std::uint32_t abs = fetchMaskedValue(inst[0], absMask); - const std::uint32_t clmp = fetchMaskedValue(inst[0], clmpMask); - const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - const std::uint32_t src0 = fetchMaskedValue(inst[1], src0Mask); - const std::uint32_t src1 = fetchMaskedValue(inst[1], src1Mask); - const std::uint32_t src2 = fetchMaskedValue(inst[1], src2Mask); - const std::uint32_t omod = fetchMaskedValue(inst[1], omodMask); - const std::uint32_t neg = fetchMaskedValue(inst[1], negMask); - - Vop3(const std::uint32_t *inst) : inst(inst) {} - - int size() const { - return kMinInstSize + getScalarInstSize(src0) + getScalarInstSize(src1) + - getScalarInstSize(src2); - } - - void dump() const; -}; - -struct Vopc { - enum class Op { - V_CMP_F_F32, - V_CMP_LT_F32, - V_CMP_EQ_F32, - V_CMP_LE_F32, - V_CMP_GT_F32, - V_CMP_LG_F32, - V_CMP_GE_F32, - V_CMP_O_F32, - V_CMP_U_F32, - V_CMP_NGE_F32, - V_CMP_NLG_F32, - V_CMP_NGT_F32, - V_CMP_NLE_F32, - V_CMP_NEQ_F32, - V_CMP_NLT_F32, - V_CMP_TRU_F32, - V_CMPX_F_F32, - V_CMPX_LT_F32, - V_CMPX_EQ_F32, - V_CMPX_LE_F32, - V_CMPX_GT_F32, - V_CMPX_LG_F32, - V_CMPX_GE_F32, - V_CMPX_O_F32, - V_CMPX_U_F32, - V_CMPX_NGE_F32, - V_CMPX_NLG_F32, - V_CMPX_NGT_F32, - V_CMPX_NLE_F32, - V_CMPX_NEQ_F32, - V_CMPX_NLT_F32, - V_CMPX_TRU_F32, - V_CMP_F_F64, - V_CMP_LT_F64, - V_CMP_EQ_F64, - V_CMP_LE_F64, - V_CMP_GT_F64, - V_CMP_LG_F64, - V_CMP_GE_F64, - V_CMP_O_F64, - V_CMP_U_F64, - V_CMP_NGE_F64, - V_CMP_NLG_F64, - V_CMP_NGT_F64, - V_CMP_NLE_F64, - V_CMP_NEQ_F64, - V_CMP_NLT_F64, - V_CMP_TRU_F64, - V_CMPX_F_F64, - V_CMPX_LT_F64, - V_CMPX_EQ_F64, - V_CMPX_LE_F64, - V_CMPX_GT_F64, - V_CMPX_LG_F64, - V_CMPX_GE_F64, - V_CMPX_O_F64, - V_CMPX_U_F64, - V_CMPX_NGE_F64, - V_CMPX_NLG_F64, - V_CMPX_NGT_F64, - V_CMPX_NLE_F64, - V_CMPX_NEQ_F64, - V_CMPX_NLT_F64, - V_CMPX_TRU_F64, - V_CMPS_F_F32, - V_CMPS_LT_F32, - V_CMPS_EQ_F32, - V_CMPS_LE_F32, - V_CMPS_GT_F32, - V_CMPS_LG_F32, - V_CMPS_GE_F32, - V_CMPS_O_F32, - V_CMPS_U_F32, - V_CMPS_NGE_F32, - V_CMPS_NLG_F32, - V_CMPS_NGT_F32, - V_CMPS_NLE_F32, - V_CMPS_NEQ_F32, - V_CMPS_NLT_F32, - V_CMPS_TRU_F32, - V_CMPSX_F_F32, - V_CMPSX_LT_F32, - V_CMPSX_EQ_F32, - V_CMPSX_LE_F32, - V_CMPSX_GT_F32, - V_CMPSX_LG_F32, - V_CMPSX_GE_F32, - V_CMPSX_O_F32, - V_CMPSX_U_F32, - V_CMPSX_NGE_F32, - V_CMPSX_NLG_F32, - V_CMPSX_NGT_F32, - V_CMPSX_NLE_F32, - V_CMPSX_NEQ_F32, - V_CMPSX_NLT_F32, - V_CMPSX_TRU_F32, - V_CMPS_F_F64, - V_CMPS_LT_F64, - V_CMPS_EQ_F64, - V_CMPS_LE_F64, - V_CMPS_GT_F64, - V_CMPS_LG_F64, - V_CMPS_GE_F64, - V_CMPS_O_F64, - V_CMPS_U_F64, - V_CMPS_NGE_F64, - V_CMPS_NLG_F64, - V_CMPS_NGT_F64, - V_CMPS_NLE_F64, - V_CMPS_NEQ_F64, - V_CMPS_NLT_F64, - V_CMPS_TRU_F64, - V_CMPSX_F_F64, - V_CMPSX_LT_F64, - V_CMPSX_EQ_F64, - V_CMPSX_LE_F64, - V_CMPSX_GT_F64, - V_CMPSX_LG_F64, - V_CMPSX_GE_F64, - V_CMPSX_O_F64, - V_CMPSX_U_F64, - V_CMPSX_NGE_F64, - V_CMPSX_NLG_F64, - V_CMPSX_NGT_F64, - V_CMPSX_NLE_F64, - V_CMPSX_NEQ_F64, - V_CMPSX_NLT_F64, - V_CMPSX_TRU_F64, - V_CMP_F_I32, - V_CMP_LT_I32, - V_CMP_EQ_I32, - V_CMP_LE_I32, - V_CMP_GT_I32, - V_CMP_NE_I32, - V_CMP_GE_I32, - V_CMP_T_I32, - V_CMP_CLASS_F32, - V_CMP_LT_I16, - V_CMP_EQ_I16, - V_CMP_LE_I16, - V_CMP_GT_I16, - V_CMP_NE_I16, - V_CMP_GE_I16, - V_CMP_CLASS_F16, - V_CMPX_F_I32, - V_CMPX_LT_I32, - V_CMPX_EQ_I32, - V_CMPX_LE_I32, - V_CMPX_GT_I32, - V_CMPX_NE_I32, - V_CMPX_GE_I32, - V_CMPX_T_I32, - V_CMPX_CLASS_F32, - V_CMPX_LT_I16, - V_CMPX_EQ_I16, - V_CMPX_LE_I16, - V_CMPX_GT_I16, - V_CMPX_NE_I16, - V_CMPX_GE_I16, - V_CMPX_CLASS_F16, - V_CMP_F_I64, - V_CMP_LT_I64, - V_CMP_EQ_I64, - V_CMP_LE_I64, - V_CMP_GT_I64, - V_CMP_NE_I64, - V_CMP_GE_I64, - V_CMP_T_I64, - V_CMP_CLASS_F64, - V_CMP_LT_U16, - V_CMP_EQ_U16, - V_CMP_LE_U16, - V_CMP_GT_U16, - V_CMP_NE_U16, - V_CMP_GE_U16, - V_CMPX_F_I64 = 176, - V_CMPX_LT_I64, - V_CMPX_EQ_I64, - V_CMPX_LE_I64, - V_CMPX_GT_I64, - V_CMPX_NE_I64, - V_CMPX_GE_I64, - V_CMPX_T_I64, - V_CMPX_CLASS_F64, - V_CMPX_LT_U16, - V_CMPX_EQ_U16, - V_CMPX_LE_U16, - V_CMPX_GT_U16, - V_CMPX_NE_U16, - V_CMPX_GE_U16, - V_CMP_F_U32 = 192, - V_CMP_LT_U32, - V_CMP_EQ_U32, - V_CMP_LE_U32, - V_CMP_GT_U32, - V_CMP_NE_U32, - V_CMP_GE_U32, - V_CMP_T_U32, - V_CMP_F_F16, - V_CMP_LT_F16, - V_CMP_EQ_F16, - V_CMP_LE_F16, - V_CMP_GT_F16, - V_CMP_LG_F16, - V_CMP_GE_F16, - V_CMP_O_F16, - V_CMPX_F_U32, - V_CMPX_LT_U32, - V_CMPX_EQ_U32, - V_CMPX_LE_U32, - V_CMPX_GT_U32, - V_CMPX_NE_U32, - V_CMPX_GE_U32, - V_CMPX_T_U32, - V_CMPX_F_F16, - V_CMPX_LT_F16, - V_CMPX_EQ_F16, - V_CMPX_LE_F16, - V_CMPX_GT_F16, - V_CMPX_LG_F16, - V_CMPX_GE_F16, - V_CMPX_O_F16, - V_CMP_F_U64, - V_CMP_LT_U64, - V_CMP_EQ_U64, - V_CMP_LE_U64, - V_CMP_GT_U64, - V_CMP_NE_U64, - V_CMP_GE_U64, - V_CMP_T_U64, - V_CMP_U_F16, - V_CMP_NGE_F16, - V_CMP_NLG_F16, - V_CMP_NGT_F16, - V_CMP_NLE_F16, - V_CMP_NEQ_F16, - V_CMP_NLT_F16, - V_CMP_TRU_F16, - V_CMPX_F_U64, - V_CMPX_LT_U64, - V_CMPX_EQ_U64, - V_CMPX_LE_U64, - V_CMPX_GT_U64, - V_CMPX_NE_U64, - V_CMPX_GE_U64, - V_CMPX_T_U64, - V_CMPX_U_F16, - V_CMPX_NGE_F16, - V_CMPX_NLG_F16, - V_CMPX_NGT_F16, - V_CMPX_NLE_F16, - V_CMPX_NEQ_F16, - V_CMPX_NLT_F16, - V_CMPX_TRU_F16, - }; - - static constexpr int kMinInstSize = 1; - - static constexpr auto src0Mask = genMask(0, 9); - static constexpr auto vsrc1Mask = genMask(getMaskEnd(src0Mask), 8); - static constexpr auto opMask = genMask(getMaskEnd(vsrc1Mask), 8); - - const std::uint32_t *inst; - const std::uint16_t src0 = fetchMaskedValue(inst[0], src0Mask); - const std::uint8_t vsrc1 = fetchMaskedValue(inst[0], vsrc1Mask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Vopc(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Smrd { - enum class Op { - S_LOAD_DWORD, - S_LOAD_DWORDX2, - S_LOAD_DWORDX4, - S_LOAD_DWORDX8, - S_LOAD_DWORDX16, - S_BUFFER_LOAD_DWORD = 8, - S_BUFFER_LOAD_DWORDX2, - S_BUFFER_LOAD_DWORDX4, - S_BUFFER_LOAD_DWORDX8, - S_BUFFER_LOAD_DWORDX16, - S_DCACHE_INV_VOL = 29, - S_MEMTIME, - S_DCACHE_INV, - }; - - static constexpr int kMinInstSize = 1; - static constexpr auto offsetMask = genMask(0, 8); - static constexpr auto immMask = genMask(getMaskEnd(offsetMask), 1); - static constexpr auto sbaseMask = genMask(getMaskEnd(immMask), 6); - static constexpr auto sdstMask = genMask(getMaskEnd(sbaseMask), 7); - static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 5); - - const std::uint32_t *inst; - const std::uint32_t offset = fetchMaskedValue(inst[0], offsetMask); - const std::uint32_t imm = fetchMaskedValue(inst[0], immMask); - const std::uint32_t sbase = fetchMaskedValue(inst[0], sbaseMask); - const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Smrd(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - void dump() const; -}; - -struct Mubuf { - enum class Op { - BUFFER_LOAD_FORMAT_X, - BUFFER_LOAD_FORMAT_XY, - BUFFER_LOAD_FORMAT_XYZ, - BUFFER_LOAD_FORMAT_XYZW, - BUFFER_STORE_FORMAT_X, - BUFFER_STORE_FORMAT_XY, - BUFFER_STORE_FORMAT_XYZ, - BUFFER_STORE_FORMAT_XYZW, - BUFFER_LOAD_UBYTE, - BUFFER_LOAD_SBYTE, - BUFFER_LOAD_USHORT, - BUFFER_LOAD_SSHORT, - BUFFER_LOAD_DWORD, - BUFFER_LOAD_DWORDX2, - BUFFER_LOAD_DWORDX4, - BUFFER_LOAD_DWORDX3, - BUFFER_STORE_BYTE = 24, - BUFFER_STORE_SHORT = 26, - BUFFER_STORE_DWORD = 28, - BUFFER_STORE_DWORDX2, - BUFFER_STORE_DWORDX4, - BUFFER_STORE_DWORDX3, - BUFFER_ATOMIC_SWAP = 48, - BUFFER_ATOMIC_CMPSWAP, - BUFFER_ATOMIC_ADD, - BUFFER_ATOMIC_SUB, - BUFFER_ATOMIC_RSUB, - BUFFER_ATOMIC_SMIN, - BUFFER_ATOMIC_UMIN, - BUFFER_ATOMIC_SMAX, - BUFFER_ATOMIC_UMAX, - BUFFER_ATOMIC_AND, - BUFFER_ATOMIC_OR, - BUFFER_ATOMIC_XOR, - BUFFER_ATOMIC_INC, - BUFFER_ATOMIC_DEC, - BUFFER_ATOMIC_FCMPSWAP, - BUFFER_ATOMIC_FMIN, - BUFFER_ATOMIC_FMAX, - BUFFER_ATOMIC_SWAP_X2 = 80, - BUFFER_ATOMIC_CMPSWAP_X2, - BUFFER_ATOMIC_ADD_X2, - BUFFER_ATOMIC_SUB_X2, - BUFFER_ATOMIC_RSUB_X2, - BUFFER_ATOMIC_SMIN_X2, - BUFFER_ATOMIC_UMIN_X2, - BUFFER_ATOMIC_SMAX_X2, - BUFFER_ATOMIC_UMAX_X2, - BUFFER_ATOMIC_AND_X2, - BUFFER_ATOMIC_OR_X2, - BUFFER_ATOMIC_XOR_X2, - BUFFER_ATOMIC_INC_X2, - BUFFER_ATOMIC_DEC_X2, - BUFFER_ATOMIC_FCMPSWAP_X2, - BUFFER_ATOMIC_FMIN_X2, - BUFFER_ATOMIC_FMAX_X2, - BUFFER_WBINVL1_SC_VOL = 112, - BUFFER_WBINVL1, - }; - - static constexpr int kMinInstSize = 2; - static constexpr auto offsetMask = genMask(0, 12); - static constexpr auto offenMask = genMask(getMaskEnd(offsetMask), 1); - static constexpr auto idxenMask = genMask(getMaskEnd(offenMask), 1); - static constexpr auto glcMask = genMask(getMaskEnd(idxenMask), 1); - static constexpr auto ldsMask = genMask(getMaskEnd(glcMask) + 1, 1); - static constexpr auto opMask = genMask(getMaskEnd(ldsMask) + 1, 7); - - static constexpr auto vaddrMask = genMask(0, 8); - static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); - static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); - static constexpr auto slcMask = genMask(getMaskEnd(srsrcMask) + 1, 1); - static constexpr auto tfeMask = genMask(getMaskEnd(slcMask), 1); - static constexpr auto soffsetMask = genMask(getMaskEnd(tfeMask), 8); - - const std::uint32_t *inst; - std::uint16_t offset = fetchMaskedValue(inst[0], offsetMask); - bool offen = fetchMaskedValue(inst[0], offenMask); - bool idxen = fetchMaskedValue(inst[0], idxenMask); - bool glc = fetchMaskedValue(inst[0], glcMask); - bool lds = fetchMaskedValue(inst[0], ldsMask); - Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); - std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); - std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); - bool slc = fetchMaskedValue(inst[1], slcMask); - bool tfe = fetchMaskedValue(inst[1], tfeMask); - std::uint8_t soffset = fetchMaskedValue(inst[1], soffsetMask); - - Mubuf(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Mtbuf { - enum class Op { - TBUFFER_LOAD_FORMAT_X, - TBUFFER_LOAD_FORMAT_XY, - TBUFFER_LOAD_FORMAT_XYZ, - TBUFFER_LOAD_FORMAT_XYZW, - TBUFFER_STORE_FORMAT_X, - TBUFFER_STORE_FORMAT_XY, - TBUFFER_STORE_FORMAT_XYZ, - TBUFFER_STORE_FORMAT_XYZW, - }; - static constexpr int kMinInstSize = 2; - - static constexpr auto offsetMask = genMask(0, 12); - static constexpr auto offenMask = genMask(getMaskEnd(offsetMask), 1); - static constexpr auto idxenMask = genMask(getMaskEnd(offenMask), 1); - static constexpr auto glcMask = genMask(getMaskEnd(idxenMask), 1); - static constexpr auto opMask = genMask(getMaskEnd(glcMask) + 1, 3); - static constexpr auto dfmtMask = genMask(getMaskEnd(opMask), 4); - static constexpr auto nfmtMask = genMask(getMaskEnd(dfmtMask), 4); - - static constexpr auto vaddrMask = genMask(0, 8); - static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); - static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); - static constexpr auto slcMask = genMask(getMaskEnd(srsrcMask) + 1, 1); - static constexpr auto tfeMask = genMask(getMaskEnd(slcMask), 1); - static constexpr auto soffsetMask = genMask(getMaskEnd(tfeMask), 8); - - const std::uint32_t *inst; - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - std::uint16_t offset = fetchMaskedValue(inst[0], offsetMask); - bool offen = fetchMaskedValue(inst[0], offenMask); - bool idxen = fetchMaskedValue(inst[0], idxenMask); - bool glc = fetchMaskedValue(inst[0], glcMask); - SurfaceFormat dfmt = (SurfaceFormat)fetchMaskedValue(inst[0], dfmtMask); - TextureChannelType nfmt = - (TextureChannelType)fetchMaskedValue(inst[0], nfmtMask); - - std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); - std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); - std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); - bool slc = fetchMaskedValue(inst[1], slcMask); - bool tfe = fetchMaskedValue(inst[1], tfeMask); - std::uint8_t soffset = fetchMaskedValue(inst[1], soffsetMask); - - Mtbuf(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Mimg { - enum class Op { - IMAGE_LOAD, - IMAGE_LOAD_MIP, - IMAGE_LOAD_PCK, - IMAGE_LOAD_PCK_SGN, - IMAGE_LOAD_MIP_PCK, - IMAGE_LOAD_MIP_PCK_SGN, - IMAGE_STORE = 8, - IMAGE_STORE_MIP, - IMAGE_STORE_PCK, - IMAGE_STORE_MIP_PCK, - IMAGE_GET_RESINFO = 14, - IMAGE_ATOMIC_SWAP, - IMAGE_ATOMIC_CMPSWAP, - IMAGE_ATOMIC_ADD, - IMAGE_ATOMIC_SUB, - IMAGE_ATOMIC_RSUB, - IMAGE_ATOMIC_SMIN, - IMAGE_ATOMIC_UMIN, - IMAGE_ATOMIC_SMAX, - IMAGE_ATOMIC_UMAX, - IMAGE_ATOMIC_AND, - IMAGE_ATOMIC_OR, - IMAGE_ATOMIC_XOR, - IMAGE_ATOMIC_INC, - IMAGE_ATOMIC_DEC, - IMAGE_ATOMIC_FCMPSWAP, - IMAGE_ATOMIC_FMIN, - IMAGE_ATOMIC_FMAX, - IMAGE_SAMPLE, - IMAGE_SAMPLE_CL, - IMAGE_SAMPLE_D, - IMAGE_SAMPLE_D_CL, - IMAGE_SAMPLE_L, - IMAGE_SAMPLE_B, - IMAGE_SAMPLE_B_CL, - IMAGE_SAMPLE_LZ, - IMAGE_SAMPLE_C, - IMAGE_SAMPLE_C_CL, - IMAGE_SAMPLE_C_D, - IMAGE_SAMPLE_C_D_CL, - IMAGE_SAMPLE_C_L, - IMAGE_SAMPLE_C_B, - IMAGE_SAMPLE_C_B_CL, - IMAGE_SAMPLE_C_LZ, - IMAGE_SAMPLE_O, - IMAGE_SAMPLE_CL_O, - IMAGE_SAMPLE_D_O, - IMAGE_SAMPLE_D_CL_O, - IMAGE_SAMPLE_L_O, - IMAGE_SAMPLE_B_O, - IMAGE_SAMPLE_B_CL_O, - IMAGE_SAMPLE_LZ_O, - IMAGE_SAMPLE_C_O, - IMAGE_SAMPLE_C_CL_O, - IMAGE_SAMPLE_C_D_O, - IMAGE_SAMPLE_C_D_CL_O, - IMAGE_SAMPLE_C_L_O, - IMAGE_SAMPLE_C_B_O, - IMAGE_SAMPLE_C_B_CL_O, - IMAGE_SAMPLE_C_LZ_O, - IMAGE_GATHER4, - IMAGE_GATHER4_CL, - IMAGE_GATHER4_L = 68, - IMAGE_GATHER4_B, - IMAGE_GATHER4_B_CL, - IMAGE_GATHER4_LZ, - IMAGE_GATHER4_C, - IMAGE_GATHER4_C_CL, - IMAGE_GATHER4_C_L = 76, - IMAGE_GATHER4_C_B, - IMAGE_GATHER4_C_B_CL, - IMAGE_GATHER4_C_LZ, - IMAGE_GATHER4_O, - IMAGE_GATHER4_CL_O, - IMAGE_GATHER4_L_O = 84, - IMAGE_GATHER4_B_O, - IMAGE_GATHER4_B_CL_O, - IMAGE_GATHER4_LZ_O, - IMAGE_GATHER4_C_O, - IMAGE_GATHER4_C_CL_O, - IMAGE_GATHER4_C_L_O = 92, - IMAGE_GATHER4_C_B_O, - IMAGE_GATHER4_C_B_CL_O, - IMAGE_GATHER4_C_LZ_O, - IMAGE_GET_LOD, - IMAGE_SAMPLE_CD = 104, - IMAGE_SAMPLE_CD_CL, - IMAGE_SAMPLE_C_CD, - IMAGE_SAMPLE_C_CD_CL, - IMAGE_SAMPLE_CD_O, - IMAGE_SAMPLE_CD_CL_O, - IMAGE_SAMPLE_C_CD_O, - IMAGE_SAMPLE_C_CD_CL_O, - }; - - static constexpr int kMinInstSize = 2; - - static constexpr auto dmaskMask = genMask(8, 4); - static constexpr auto unrmMask = genMask(getMaskEnd(dmaskMask), 1); - static constexpr auto glcMask = genMask(getMaskEnd(unrmMask), 1); - static constexpr auto daMask = genMask(getMaskEnd(glcMask), 1); - static constexpr auto r128Mask = genMask(getMaskEnd(daMask), 1); - static constexpr auto tfeMask = genMask(getMaskEnd(r128Mask), 1); - static constexpr auto lweMask = genMask(getMaskEnd(tfeMask), 1); - static constexpr auto opMask = genMask(getMaskEnd(lweMask), 7); - static constexpr auto slcMask = genMask(getMaskEnd(opMask), 1); - - static constexpr auto vaddrMask = genMask(0, 8); - static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); - static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); - static constexpr auto ssampMask = genMask(getMaskEnd(srsrcMask), 5); - - const std::uint32_t *inst; - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - std::uint8_t dmask = fetchMaskedValue(inst[0], dmaskMask); - bool unrm = fetchMaskedValue(inst[0], unrmMask); - bool glc = fetchMaskedValue(inst[0], glcMask); - bool da = fetchMaskedValue(inst[0], daMask); - bool r128 = fetchMaskedValue(inst[0], r128Mask); - bool tfe = fetchMaskedValue(inst[0], tfeMask); - bool lwe = fetchMaskedValue(inst[0], lweMask); - bool slc = fetchMaskedValue(inst[0], slcMask); - - std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); - std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); - std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); - std::uint8_t ssamp = fetchMaskedValue(inst[1], ssampMask); - - Mimg(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Ds { - enum class Op { - DS_ADD_U32, - DS_SUB_U32, - DS_RSUB_U32, - DS_INC_U32, - DS_DEC_U32, - DS_MIN_I32, - DS_MAX_I32, - DS_MIN_U32, - DS_MAX_U32, - DS_AND_B32, - DS_OR_B32, - DS_XOR_B32, - DS_MSKOR_B32, - DS_WRITE_B32, - DS_WRITE2_B32, - DS_WRITE2ST64_B32, - DS_CMPST_B32, - DS_CMPST_F32, - DS_MIN_F32, - DS_MAX_F32, - DS_NOP, - DS_GWS_SEMA_RELEASE_ALL = 24, - DS_GWS_INIT, - DS_GWS_SEMA_V, - DS_GWS_SEMA_BR, - DS_GWS_SEMA_P, - DS_GWS_BARRIER, - DS_WRITE_B8, - DS_WRITE_B16, - DS_ADD_RTN_U32, - DS_SUB_RTN_U32, - DS_RSUB_RTN_U32, - DS_INC_RTN_U32, - DS_DEC_RTN_U32, - DS_MIN_RTN_I32, - DS_MAX_RTN_I32, - DS_MIN_RTN_U32, - DS_MAX_RTN_U32, - DS_AND_RTN_B32, - DS_OR_RTN_B32, - DS_XOR_RTN_B32, - DS_MSKOR_RTN_B32, - DS_WRXCHG_RTN_B32, - DS_WRXCHG2_RTN_B32, - DS_WRXCHG2ST64_RTN_B32, - DS_CMPST_RTN_B32, - DS_CMPST_RTN_F32, - DS_MIN_RTN_F32, - DS_MAX_RTN_F32, - DS_WRAP_RTN_B32, - DS_SWIZZLE_B32, - DS_READ_B32, - DS_READ2_B32, - DS_READ2ST64_B32, - DS_READ_I8, - DS_READ_U8, - DS_READ_I16, - DS_READ_U16, - DS_CONSUME, - DS_APPEND, - DS_ORDERED_COUNT, - DS_ADD_U64, - DS_SUB_U64, - DS_RSUB_U64, - DS_INC_U64, - DS_DEC_U64, - DS_MIN_I64, - DS_MAX_I64, - DS_MIN_U64, - DS_MAX_U64, - DS_AND_B64, - DS_OR_B64, - DS_XOR_B64, - DS_MSKOR_B64, - DS_WRITE_B64, - DS_WRITE2_B64, - DS_WRITE2ST64_B64, - DS_CMPST_B64, - DS_CMPST_F64, - DS_MIN_F64, - DS_MAX_F64, - DS_ADD_RTN_U64 = 96, - DS_SUB_RTN_U64, - DS_RSUB_RTN_U64, - DS_INC_RTN_U64, - DS_DEC_RTN_U64, - DS_MIN_RTN_I64, - DS_MAX_RTN_I64, - DS_MIN_RTN_U64, - DS_MAX_RTN_U64, - DS_AND_RTN_B64, - DS_OR_RTN_B64, - DS_XOR_RTN_B64, - DS_MSKOR_RTN_B64, - DS_WRXCHG_RTN_B64, - DS_WRXCHG2_RTN_B64, - DS_WRXCHG2ST64_RTN_B64, - DS_CMPST_RTN_B64, - DS_CMPST_RTN_F64, - DS_MIN_RTN_F64, - DS_MAX_RTN_F64, - DS_READ_B64 = 118, - DS_READ2_B64, - DS_READ2ST64_B64, - DS_CONDXCHG32_RTN_B64 = 126, - DS_ADD_SRC2_U32 = 128, - DS_SUB_SRC2_U32, - DS_RSUB_SRC2_U32, - DS_INC_SRC2_U32, - DS_DEC_SRC2_U32, - DS_MIN_SRC2_I32, - DS_MAX_SRC2_I32, - DS_MIN_SRC2_U32, - DS_MAX_SRC2_U32, - DS_AND_SRC2_B32, - DS_OR_SRC2_B32, - DS_XOR_SRC2_B32, - DS_WRITE_SRC2_B32, - DS_MIN_SRC2_F32 = 146, - DS_MAX_SRC2_F32, - DS_ADD_SRC2_U64 = 192, - DS_SUB_SRC2_U64, - DS_RSUB_SRC2_U64, - DS_INC_SRC2_U64, - DS_DEC_SRC2_U64, - DS_MIN_SRC2_I64, - DS_MAX_SRC2_I64, - DS_MIN_SRC2_U64, - DS_MAX_SRC2_U64, - DS_AND_SRC2_B64, - DS_OR_SRC2_B64, - DS_XOR_SRC2_B64, - DS_WRITE_SRC2_B64, - DS_MIN_SRC2_F64 = 210, - DS_MAX_SRC2_F64, - DS_WRITE_B96 = 222, - DS_WRITE_B128, - DS_CONDXCHG32_RTN_B128 = 253, - DS_READ_B96, - DS_READ_B128, - }; - - static constexpr int kMinInstSize = 2; - static constexpr auto offset0Mask = genMask(0, 8); - static constexpr auto offset1Mask = genMask(getMaskEnd(offset0Mask), 8); - static constexpr auto gdsMask = genMask(getMaskEnd(offset1Mask) + 1, 1); - static constexpr auto opMask = genMask(getMaskEnd(gdsMask), 8); - - static constexpr auto addrMask = genMask(0, 8); - static constexpr auto data0Mask = genMask(getMaskEnd(addrMask), 8); - static constexpr auto data1Mask = genMask(getMaskEnd(data0Mask), 8); - static constexpr auto vdstMask = genMask(getMaskEnd(data1Mask), 8); - - const std::uint32_t *inst; - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - - Ds(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Vintrp { - enum class Op { V_INTERP_P1_F32, V_INTERP_P2_F32, V_INTERP_MOV_F32 }; - - static constexpr int kMinInstSize = 1; - static constexpr auto vsrcMask = genMask(0, 8); - static constexpr auto attrChanMask = genMask(getMaskEnd(vsrcMask), 2); - static constexpr auto attrMask = genMask(getMaskEnd(attrChanMask), 6); - static constexpr auto opMask = genMask(getMaskEnd(attrMask), 2); - static constexpr auto vdstMask = genMask(getMaskEnd(opMask), 8); - - const std::uint32_t *inst; - uint32_t vsrc = fetchMaskedValue(inst[0], vsrcMask); - uint32_t attrChan = fetchMaskedValue(inst[0], attrChanMask); - uint32_t attr = fetchMaskedValue(inst[0], attrMask); - const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); - uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); - - Vintrp(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -struct Exp { - static constexpr int kMinInstSize = 2; - - static constexpr auto enMask = genMask(0, 4); - static constexpr auto targetMask = genMask(getMaskEnd(enMask), 6); - static constexpr auto comprMask = genMask(getMaskEnd(targetMask), 1); - static constexpr auto doneMask = genMask(getMaskEnd(comprMask), 1); - static constexpr auto vmMask = genMask(getMaskEnd(doneMask), 1); - - static constexpr auto vsrc0Mask = genMask(0, 8); - static constexpr auto vsrc1Mask = genMask(getMaskEnd(vsrc0Mask), 8); - static constexpr auto vsrc2Mask = genMask(getMaskEnd(vsrc1Mask), 8); - static constexpr auto vsrc3Mask = genMask(getMaskEnd(vsrc2Mask), 8); - - const std::uint32_t *inst; - - std::uint8_t en = fetchMaskedValue(inst[0], enMask); - std::uint8_t target = fetchMaskedValue(inst[0], targetMask); - bool compr = fetchMaskedValue(inst[0], comprMask); - bool done = fetchMaskedValue(inst[0], doneMask); - bool vm = fetchMaskedValue(inst[0], vmMask); - std::uint8_t vsrc0 = fetchMaskedValue(inst[1], vsrc0Mask); - std::uint8_t vsrc1 = fetchMaskedValue(inst[1], vsrc1Mask); - std::uint8_t vsrc2 = fetchMaskedValue(inst[1], vsrc2Mask); - std::uint8_t vsrc3 = fetchMaskedValue(inst[1], vsrc3Mask); - - Exp(const std::uint32_t *inst) : inst(inst) {} - - int size() const { return kMinInstSize; } - - void dump() const; -}; - -enum class InstructionClass : std::uint8_t { - Invalid, - Vop2, - Sop2, - Sopk, - Smrd, - Vop3, - Mubuf, - Mtbuf, - Mimg, - Ds, - Vintrp, - Exp, - Vop1, - Vopc, - Sop1, - Sopc, - Sopp, -}; - -static constexpr std::uint32_t kInstMask1 = - static_cast(~0u << (32 - 1)); -static constexpr std::uint32_t kInstMask2 = - static_cast(~0u << (32 - 2)); -static constexpr std::uint32_t kInstMask4 = - static_cast(~0u << (32 - 4)); -static constexpr std::uint32_t kInstMask5 = - static_cast(~0u << (32 - 5)); -static constexpr std::uint32_t kInstMask6 = - static_cast(~0u << (32 - 6)); -static constexpr std::uint32_t kInstMask7 = - static_cast(~0u << (32 - 7)); -static constexpr std::uint32_t kInstMask9 = - static_cast(~0u << (32 - 9)); - -static constexpr std::uint32_t kInstMaskValVop2 = 0b0u << (32 - 1); -static constexpr std::uint32_t kInstMaskValSop2 = 0b10u << (32 - 2); -static constexpr std::uint32_t kInstMaskValSopk = 0b1011u << (32 - 4); -static constexpr std::uint32_t kInstMaskValSmrd = 0b11000u << (32 - 5); -static constexpr std::uint32_t kInstMaskValVop3 = 0b110100u << (32 - 6); -static constexpr std::uint32_t kInstMaskValMubuf = 0b111000u << (32 - 6); -static constexpr std::uint32_t kInstMaskValMtbuf = 0b111010u << (32 - 6); -static constexpr std::uint32_t kInstMaskValMimg = 0b111100u << (32 - 6); -static constexpr std::uint32_t kInstMaskValDs = 0b110110u << (32 - 6); -static constexpr std::uint32_t kInstMaskValVintrp = 0b110010u << (32 - 6); -static constexpr std::uint32_t kInstMaskValExp = 0b111110u << (32 - 6); -static constexpr std::uint32_t kInstMaskValVop1 = 0b0111111u << (32 - 7); -static constexpr std::uint32_t kInstMaskValVopC = 0b0111110u << (32 - 7); -static constexpr std::uint32_t kInstMaskValSop1 = 0b101111101u << (32 - 9); -static constexpr std::uint32_t kInstMaskValSopc = 0b101111110u << (32 - 9); -static constexpr std::uint32_t kInstMaskValSopp = 0b101111111u << (32 - 9); - -inline InstructionClass getInstructionClass(std::uint32_t instr) { - switch (instr & kInstMask9) { - case kInstMaskValSop1: - return InstructionClass::Sop1; - case kInstMaskValSopc: - return InstructionClass::Sopc; - case kInstMaskValSopp: - return InstructionClass::Sopp; - } - - switch (instr & kInstMask7) { - case kInstMaskValVop1: - return InstructionClass::Vop1; - case kInstMaskValVopC: - return InstructionClass::Vopc; - } - - switch (instr & kInstMask6) { - case kInstMaskValVop3: - return InstructionClass::Vop3; - case kInstMaskValMubuf: - return InstructionClass::Mubuf; - case kInstMaskValMtbuf: - return InstructionClass::Mtbuf; - case kInstMaskValMimg: - return InstructionClass::Mimg; - case kInstMaskValDs: - return InstructionClass::Ds; - case kInstMaskValVintrp: - return InstructionClass::Vintrp; - case kInstMaskValExp: - return InstructionClass::Exp; - } - - if ((instr & kInstMask5) == kInstMaskValSmrd) { - return InstructionClass::Smrd; - } - - if ((instr & kInstMask4) == kInstMaskValSopk) { - return InstructionClass::Sopk; - } - - if ((instr & kInstMask2) == kInstMaskValSop2) { - return InstructionClass::Sop2; - } - - if ((instr & kInstMask1) == kInstMaskValVop2) { - return InstructionClass::Vop2; - } - - return InstructionClass::Invalid; -} - -struct Instruction { - const std::uint32_t *inst; - InstructionClass instClass = getInstructionClass(*inst); - - Instruction(const std::uint32_t *inst) : inst(inst) {} - - int size() const { - switch (instClass) { - case InstructionClass::Vop2: - return Vop2(inst).size(); - case InstructionClass::Sop2: - return Sop2(inst).size(); - case InstructionClass::Sopk: - return Sopk(inst).size(); - case InstructionClass::Smrd: - return Smrd(inst).size(); - case InstructionClass::Vop3: - return Vop3(inst).size(); - case InstructionClass::Mubuf: - return Mubuf(inst).size(); - case InstructionClass::Mtbuf: - return Mtbuf(inst).size(); - case InstructionClass::Mimg: - return Mimg(inst).size(); - case InstructionClass::Ds: - return Ds(inst).size(); - case InstructionClass::Vintrp: - return Vintrp(inst).size(); - case InstructionClass::Exp: - return Exp(inst).size(); - case InstructionClass::Vop1: - return Vop1(inst).size(); - case InstructionClass::Vopc: - return Vopc(inst).size(); - case InstructionClass::Sop1: - return Sop1(inst).size(); - case InstructionClass::Sopc: - return Sopc(inst).size(); - case InstructionClass::Sopp: - return Sopp(inst).size(); - - case InstructionClass::Invalid: - break; - } - - return 1; - } - - void dump() const; -}; - -const char *instructionClassToString(InstructionClass instrClass); -const char *opcodeToString(InstructionClass instClass, int op); - -const char *sop1OpcodeToString(Sop1::Op op); -const char *sop2OpcodeToString(Sop2::Op op); -const char *sopkOpcodeToString(Sopk::Op op); -const char *sopcOpcodeToString(Sopc::Op op); -const char *soppOpcodeToString(Sopp::Op op); -const char *vop2OpcodeToString(Vop2::Op op); -const char *vop1OpcodeToString(Vop1::Op op); -const char *vopcOpcodeToString(Vopc::Op op); -const char *vop3OpcodeToString(Vop3::Op op); -const char *smrdOpcodeToString(Smrd::Op op); -const char *mubufOpcodeToString(Mubuf::Op op); -const char *mtbufOpcodeToString(Mtbuf::Op op); -const char *mimgOpcodeToString(Mimg::Op op); -const char *dsOpcodeToString(Ds::Op op); -const char *vintrpOpcodeToString(Vintrp::Op op); +namespace amdgpu::shader +{ + inline constexpr std::uint32_t genMask(std::uint32_t offset, + std::uint32_t bitCount) + { + return ((1u << bitCount) - 1u) << offset; + } + + inline constexpr std::uint32_t getMaskEnd(std::uint32_t mask) + { + return 32 - std::countl_zero(mask); + } + + inline constexpr std::uint32_t fetchMaskedValue(std::uint32_t hex, + std::uint32_t mask) + { + return (hex & mask) >> std::countr_zero(mask); + } + + enum SurfaceFormat + { + kSurfaceFormatInvalid = 0x00000000, + kSurfaceFormat8 = 0x00000001, + kSurfaceFormat16 = 0x00000002, + kSurfaceFormat8_8 = 0x00000003, + kSurfaceFormat32 = 0x00000004, + kSurfaceFormat16_16 = 0x00000005, + kSurfaceFormat10_11_11 = 0x00000006, + kSurfaceFormat11_11_10 = 0x00000007, + kSurfaceFormat10_10_10_2 = 0x00000008, + kSurfaceFormat2_10_10_10 = 0x00000009, + kSurfaceFormat8_8_8_8 = 0x0000000a, + kSurfaceFormat32_32 = 0x0000000b, + kSurfaceFormat16_16_16_16 = 0x0000000c, + kSurfaceFormat32_32_32 = 0x0000000d, + kSurfaceFormat32_32_32_32 = 0x0000000e, + }; + enum TextureChannelType + { + kTextureChannelTypeUNorm = 0x00000000, + kTextureChannelTypeSNorm = 0x00000001, + kTextureChannelTypeUScaled = 0x00000002, + kTextureChannelTypeSScaled = 0x00000003, + kTextureChannelTypeUInt = 0x00000004, + kTextureChannelTypeSInt = 0x00000005, + kTextureChannelTypeSNormNoZero = 0x00000006, + kTextureChannelTypeFloat = 0x00000007, + }; + + inline int getScalarInstSize(int id) { return id == 255 ? 1 : 0; } + + struct Sop1 + { + enum class Op + { + S_MOV_B32 = 3, + S_MOV_B64, + S_CMOV_B32, + S_CMOV_B64, + S_NOT_B32, + S_NOT_B64, + S_WQM_B32, + S_WQM_B64, + S_BREV_B32, + S_BREV_B64, + S_BCNT0_I32_B32, + S_BCNT0_I32_B64, + S_BCNT1_I32_B32, + S_BCNT1_I32_B64, + S_FF0_I32_B32, + S_FF0_I32_B64, + S_FF1_I32_B32, + S_FF1_I32_B64, + S_FLBIT_I32_B32, + S_FLBIT_I32_B64, + S_FLBIT_I32, + S_FLBIT_I32_I64, + S_SEXT_I32_I8, + S_SEXT_I32_I16, + S_BITSET0_B32, + S_BITSET0_B64, + S_BITSET1_B32, + S_BITSET1_B64, + S_GETPC_B64, + S_SETPC_B64, + S_SWAPPC_B64, + S_RFE_B64, + S_AND_SAVEEXEC_B64 = 36, + S_OR_SAVEEXEC_B64, + S_XOR_SAVEEXEC_B64, + S_ANDN2_SAVEEXEC_B64, + S_ORN2_SAVEEXEC_B64, + S_NAND_SAVEEXEC_B64, + S_NOR_SAVEEXEC_B64, + S_XNOR_SAVEEXEC_B64, + S_QUADMASK_B32, + S_QUADMASK_B64, + S_MOVRELS_B32, + S_MOVRELS_B64, + S_MOVRELD_B32, + S_MOVRELD_B64, + S_CBRANCH_JOIN, + S_ABS_I32 = 52, + S_MOV_FED_B32, + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto ssrc0Mask = genMask(0, 8); + static constexpr auto opMask = genMask(getMaskEnd(ssrc0Mask), 8); + static constexpr auto sdstMask = genMask(getMaskEnd(opMask), 7); + + const std::uint32_t* inst; + + const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); + + Sop1(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize + getScalarInstSize(ssrc0); } + + void dump() const; + }; + + struct Sopk + { + enum class Op + { + S_MOVK_I32, + S_CMOVK_I32 = 2, + S_CMPK_EQ_I32, + S_CMPK_LG_I32, + S_CMPK_GT_I32, + S_CMPK_GE_I32, + S_CMPK_LT_I32, + S_CMPK_LE_I32, + S_CMPK_EQ_U32, + S_CMPK_LG_U32, + S_CMPK_GT_U32, + S_CMPK_GE_U32, + S_CMPK_LT_U32, + S_CMPK_LE_U32, + S_ADDK_I32, + S_MULK_I32, + S_CBRANCH_I_FORK, + S_GETREG_B32, + S_SETREG_B32, + S_SETREG_IMM + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto simmMask = genMask(0, 16); + static constexpr auto sdstMask = genMask(getMaskEnd(simmMask), 7); + static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 5); + + const std::uint32_t* inst; + + const std::int16_t simm = (std::int16_t)fetchMaskedValue(inst[0], simmMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); + + Sopk(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Sopc + { + enum class Op + { + S_CMP_EQ_I32, + S_CMP_LG_I32, + S_CMP_GT_I32, + S_CMP_GE_I32, + S_CMP_LT_I32, + S_CMP_LE_I32, + S_CMP_EQ_U32, + S_CMP_LG_U32, + S_CMP_GT_U32, + S_CMP_GE_U32, + S_CMP_LT_U32, + S_CMP_LE_U32, + S_BITCMP0_B32, + S_BITCMP1_B32, + S_BITCMP0_B64, + S_BITCMP1_B64, + S_SETVSKIP, + S_ILLEGALD + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto ssrc0Mask = genMask(0, 8); + static constexpr auto ssrc1Mask = genMask(getMaskEnd(ssrc0Mask), 8); + static constexpr auto opMask = genMask(getMaskEnd(ssrc1Mask), 7); + + const std::uint32_t* inst; + + const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); + const std::uint32_t ssrc1 = fetchMaskedValue(inst[0], ssrc1Mask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Sopc(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize + getScalarInstSize(ssrc0); } + + void dump() const; + }; + + struct Sop2 + { + enum class Op + { + S_ADD_U32, + S_SUB_U32, + S_ADD_I32, + S_SUB_I32, + S_ADDC_U32, + S_SUBB_U32, + S_MIN_I32, + S_MIN_U32, + S_MAX_I32, + S_MAX_U32, + S_CSELECT_B32, + S_CSELECT_B64, + S_AND_B32 = 14, + S_AND_B64, + S_OR_B32, + S_OR_B64, + S_XOR_B32, + S_XOR_B64, + S_ANDN2_B32, + S_ANDN2_B64, + S_ORN2_B32, + S_ORN2_B64, + S_NAND_B32, + S_NAND_B64, + S_NOR_B32, + S_NOR_B64, + S_XNOR_B32, + S_XNOR_B64, + S_LSHL_B32, + S_LSHL_B64, + S_LSHR_B32, + S_LSHR_B64, + S_ASHR_I32, + S_ASHR_I64, + S_BFM_B32, + S_BFM_B64, + S_MUL_I32, + S_BFE_U32, + S_BFE_I32, + S_BFE_U64, + S_BFE_I64, + S_CBRANCH_G_FORK, + S_ABSDIFF_I32, + S_LSHL1_ADD_U32, + S_LSHL2_ADD_U32, + S_LSHL3_ADD_U32, + S_LSHL4_ADD_U32, + S_PACK_LL_B32_B16, + S_PACK_LH_B32_B16, + S_PACK_HH_B32_B16, + S_MUL_HI_U32, + S_MUL_HI_I32, + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto ssrc0Mask = genMask(0, 8); + static constexpr auto ssrc1Mask = genMask(getMaskEnd(ssrc0Mask), 8); + static constexpr auto sdstMask = genMask(getMaskEnd(ssrc1Mask), 7); + static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 7); + + const std::uint32_t* inst; + const std::uint32_t ssrc0 = fetchMaskedValue(inst[0], ssrc0Mask); + const std::uint32_t ssrc1 = fetchMaskedValue(inst[0], ssrc1Mask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); + + Sop2(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const + { + return kMinInstSize + getScalarInstSize(ssrc0) + getScalarInstSize(ssrc1); + } + + void dump() const; + }; + + struct Sopp + { + enum class Op + { + S_NOP, + S_ENDPGM, + S_BRANCH, + S_CBRANCH_SCC0 = 4, + S_CBRANCH_SCC1, + S_CBRANCH_VCCZ, + S_CBRANCH_VCCNZ, + S_CBRANCH_EXECZ, + S_CBRANCH_EXECNZ, + S_BARRIER, + S_WAITCNT = 12, + S_SETHALT, + S_SLEEP, + S_SETPRIO, + S_SENDMSG, + S_SENDMSGHALT, + S_TRAP, + S_ICACHE_INV, + S_INCPERFLEVEL, + S_DECPERFLEVEL, + S_TTRACEDATA, + S_CBRANCH_CDBGSYS = 23, + S_CBRANCH_CDBGUSER = 24, + S_CBRANCH_CDBGSYS_OR_USER = 25, + S_CBRANCH_CDBGSYS_AND_USER = 26, + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto simmMask = genMask(0, 16); + static constexpr auto opMask = genMask(getMaskEnd(simmMask), 7); + + const std::uint32_t* inst; + const std::int16_t simm = (std::int16_t)fetchMaskedValue(inst[0], simmMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Sopp(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Vop1 + { + enum class Op + { + V_NOP, + V_MOV_B32, + V_READFIRSTLANE_B32, + V_CVT_I32_F64, + V_CVT_F64_I32, + V_CVT_F32_I32, + V_CVT_F32_U32, + V_CVT_U32_F32, + V_CVT_I32_F32, + V_MOV_FED_B32, + V_CVT_F16_F32, + V_CVT_F32_F16, + V_CVT_RPI_I32_F32, + V_CVT_FLR_I32_F32, + V_CVT_OFF_F32_I4, + V_CVT_F32_F64, + V_CVT_F64_F32, + V_CVT_F32_UBYTE0, + V_CVT_F32_UBYTE1, + V_CVT_F32_UBYTE2, + V_CVT_F32_UBYTE3, + V_CVT_U32_F64, + V_CVT_F64_U32, + V_FRACT_F32 = 32, + V_TRUNC_F32, + V_CEIL_F32, + V_RNDNE_F32, + V_FLOOR_F32, + V_EXP_F32, + V_LOG_CLAMP_F32, + V_LOG_F32, + V_RCP_CLAMP_F32, + V_RCP_LEGACY_F32, + V_RCP_F32, + V_RCP_IFLAG_F32, + V_RSQ_CLAMP_F32, + V_RSQ_LEGACY_F32, + V_RSQ_F32, + V_RCP_F64, + V_RCP_CLAMP_F64, + V_RSQ_F64, + V_RSQ_CLAMP_F64, + V_SQRT_F32, + V_SQRT_F64, + V_SIN_F32, + V_COS_F32, + V_NOT_B32, + V_BFREV_B32, + V_FFBH_U32, + V_FFBL_B32, + V_FFBH_I32, + V_FREXP_EXP_I32_F64, + V_FREXP_MANT_F64, + V_FRACT_F64, + V_FREXP_EXP_I32_F32, + V_FREXP_MANT_F32, + V_CLREXCP, + V_MOVRELD_B32, + V_MOVRELS_B32, + V_MOVRELSD_B32, + V_CVT_F16_U16 = 80, + V_CVT_F16_I16, + V_CVT_U16_F16, + V_CVT_I16_F16, + V_RCP_F16, + V_SQRT_F16, + V_RSQ_F16, + V_LOG_F16, + V_EXP_F16, + V_FREXP_MANT_F16, + V_FREXP_EXP_I16_F16, + V_FLOOR_F16, + V_CEIL_F16, + V_TRUNC_F16, + V_RNDNE_F16, + V_FRACT_F16, + V_SIN_F16, + V_COS_F16, + V_SAT_PK_U8_I16, + V_CVT_NORM_I16_F16, + V_CVT_NORM_U16_F16, + V_SWAP_B32, + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto src0Mask = genMask(0, 9); + static constexpr auto opMask = genMask(getMaskEnd(src0Mask), 8); + static constexpr auto vdstMask = genMask(getMaskEnd(opMask), 8); + + const std::uint32_t* inst; + const std::uint32_t src0 = fetchMaskedValue(inst[0], src0Mask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); + + int size() const { return kMinInstSize + getScalarInstSize(src0); } + + Vop1(const std::uint32_t* inst) + : inst(inst) + { + } + + void dump() const; + }; + + struct Vop2 + { + enum class Op + { + V_CNDMASK_B32, + V_READLANE_B32, + V_WRITELANE_B32, + V_ADD_F32, + V_SUB_F32, + V_SUBREV_F32, + V_MAC_LEGACY_F32, + V_MUL_LEGACY_F32, + V_MUL_F32, + V_MUL_I32_I24, + V_MUL_HI_I32_I24, + V_MUL_U32_U24, + V_MUL_HI_U32_U24, + V_MIN_LEGACY_F32, + V_MAX_LEGACY_F32, + V_MIN_F32, + V_MAX_F32, + V_MIN_I32, + V_MAX_I32, + V_MIN_U32, + V_MAX_U32, + V_LSHR_B32, + V_LSHRREV_B32, + V_ASHR_I32, + V_ASHRREV_I32, + V_LSHL_B32, + V_LSHLREV_B32, + V_AND_B32, + V_OR_B32, + V_XOR_B32, + V_BFM_B32, + V_MAC_F32, + V_MADMK_F32, + V_MADAK_F32, + V_BCNT_U32_B32, + V_MBCNT_LO_U32_B32, + V_MBCNT_HI_U32_B32, + V_ADD_I32, + V_SUB_I32, + V_SUBREV_I32, + V_ADDC_U32, + V_SUBB_U32, + V_SUBBREV_U32, + V_LDEXP_F32, + V_CVT_PKACCUM_U8_F32, + V_CVT_PKNORM_I16_F32, + V_CVT_PKNORM_U16_F32, + V_CVT_PKRTZ_F16_F32, + V_CVT_PK_U16_U32, + V_CVT_PK_I16_I32, + }; + + static constexpr int kMinInstSize = 1; + static constexpr auto src0Mask = genMask(0, 9); + static constexpr auto vsrc1Mask = genMask(getMaskEnd(src0Mask), 8); + static constexpr auto vdstMask = genMask(getMaskEnd(vsrc1Mask), 8); + static constexpr auto opMask = genMask(getMaskEnd(vdstMask), 6); + + const std::uint32_t* inst; + const std::uint32_t src0 = fetchMaskedValue(inst[0], src0Mask); + const std::uint32_t vsrc1 = fetchMaskedValue(inst[0], vsrc1Mask); + const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Vop2(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const + { + int result = kMinInstSize + getScalarInstSize(src0); + + if (op == Vop2::Op::V_MADMK_F32 || op == Vop2::Op::V_MADAK_F32) + { + result += 1; + } + + return result; + } + void dump() const; + }; + + struct Vop3 + { + enum class Op + { + V3_CMP_F_F32, + V3_CMP_LT_F32, + V3_CMP_EQ_F32, + V3_CMP_LE_F32, + V3_CMP_GT_F32, + V3_CMP_LG_F32, + V3_CMP_GE_F32, + V3_CMP_O_F32, + V3_CMP_U_F32, + V3_CMP_NGE_F32, + V3_CMP_NLG_F32, + V3_CMP_NGT_F32, + V3_CMP_NLE_F32, + V3_CMP_NEQ_F32, + V3_CMP_NLT_F32, + V3_CMP_TRU_F32, + V3_CMPX_F_F32, + V3_CMPX_LT_F32, + V3_CMPX_EQ_F32, + V3_CMPX_LE_F32, + V3_CMPX_GT_F32, + V3_CMPX_LG_F32, + V3_CMPX_GE_F32, + V3_CMPX_O_F32, + V3_CMPX_U_F32, + V3_CMPX_NGE_F32, + V3_CMPX_NLG_F32, + V3_CMPX_NGT_F32, + V3_CMPX_NLE_F32, + V3_CMPX_NEQ_F32, + V3_CMPX_NLT_F32, + V3_CMPX_TRU_F32, + V3_CMP_F_F64, + V3_CMP_LT_F64, + V3_CMP_EQ_F64, + V3_CMP_LE_F64, + V3_CMP_GT_F64, + V3_CMP_LG_F64, + V3_CMP_GE_F64, + V3_CMP_O_F64, + V3_CMP_U_F64, + V3_CMP_NGE_F64, + V3_CMP_NLG_F64, + V3_CMP_NGT_F64, + V3_CMP_NLE_F64, + V3_CMP_NEQ_F64, + V3_CMP_NLT_F64, + V3_CMP_TRU_F64, + V3_CMPX_F_F64, + V3_CMPX_LT_F64, + V3_CMPX_EQ_F64, + V3_CMPX_LE_F64, + V3_CMPX_GT_F64, + V3_CMPX_LG_F64, + V3_CMPX_GE_F64, + V3_CMPX_O_F64, + V3_CMPX_U_F64, + V3_CMPX_NGE_F64, + V3_CMPX_NLG_F64, + V3_CMPX_NGT_F64, + V3_CMPX_NLE_F64, + V3_CMPX_NEQ_F64, + V3_CMPX_NLT_F64, + V3_CMPX_TRU_F64, + V3_CMPS_F_F32, + V3_CMPS_LT_F32, + V3_CMPS_EQ_F32, + V3_CMPS_LE_F32, + V3_CMPS_GT_F32, + V3_CMPS_LG_F32, + V3_CMPS_GE_F32, + V3_CMPS_O_F32, + V3_CMPS_U_F32, + V3_CMPS_NGE_F32, + V3_CMPS_NLG_F32, + V3_CMPS_NGT_F32, + V3_CMPS_NLE_F32, + V3_CMPS_NEQ_F32, + V3_CMPS_NLT_F32, + V3_CMPS_TRU_F32, + V3_CMPSX_F_F32, + V3_CMPSX_LT_F32, + V3_CMPSX_EQ_F32, + V3_CMPSX_LE_F32, + V3_CMPSX_GT_F32, + V3_CMPSX_LG_F32, + V3_CMPSX_GE_F32, + V3_CMPSX_O_F32, + V3_CMPSX_U_F32, + V3_CMPSX_NGE_F32, + V3_CMPSX_NLG_F32, + V3_CMPSX_NGT_F32, + V3_CMPSX_NLE_F32, + V3_CMPSX_NEQ_F32, + V3_CMPSX_NLT_F32, + V3_CMPSX_TRU_F32, + V3_CMPS_F_F64, + V3_CMPS_LT_F64, + V3_CMPS_EQ_F64, + V3_CMPS_LE_F64, + V3_CMPS_GT_F64, + V3_CMPS_LG_F64, + V3_CMPS_GE_F64, + V3_CMPS_O_F64, + V3_CMPS_U_F64, + V3_CMPS_NGE_F64, + V3_CMPS_NLG_F64, + V3_CMPS_NGT_F64, + V3_CMPS_NLE_F64, + V3_CMPS_NEQ_F64, + V3_CMPS_NLT_F64, + V3_CMPS_TRU_F64, + V3_CMPSX_F_F64, + V3_CMPSX_LT_F64, + V3_CMPSX_EQ_F64, + V3_CMPSX_LE_F64, + V3_CMPSX_GT_F64, + V3_CMPSX_LG_F64, + V3_CMPSX_GE_F64, + V3_CMPSX_O_F64, + V3_CMPSX_U_F64, + V3_CMPSX_NGE_F64, + V3_CMPSX_NLG_F64, + V3_CMPSX_NGT_F64, + V3_CMPSX_NLE_F64, + V3_CMPSX_NEQ_F64, + V3_CMPSX_NLT_F64, + V3_CMPSX_TRU_F64, + V3_CMP_F_I32, + V3_CMP_LT_I32, + V3_CMP_EQ_I32, + V3_CMP_LE_I32, + V3_CMP_GT_I32, + V3_CMP_NE_I32, + V3_CMP_GE_I32, + V3_CMP_T_I32, + V3_CMP_CLASS_F32, + V3_CMP_LT_I16, + V3_CMP_EQ_I16, + V3_CMP_LE_I16, + V3_CMP_GT_I16, + V3_CMP_NE_I16, + V3_CMP_GE_I16, + V3_CMP_CLASS_F16, + V3_CMPX_F_I32, + V3_CMPX_LT_I32, + V3_CMPX_EQ_I32, + V3_CMPX_LE_I32, + V3_CMPX_GT_I32, + V3_CMPX_NE_I32, + V3_CMPX_GE_I32, + V3_CMPX_T_I32, + V3_CMPX_CLASS_F32, + V3_CMPX_LT_I16, + V3_CMPX_EQ_I16, + V3_CMPX_LE_I16, + V3_CMPX_GT_I16, + V3_CMPX_NE_I16, + V3_CMPX_GE_I16, + V3_CMPX_CLASS_F16, + V3_CMP_F_I64, + V3_CMP_LT_I64, + V3_CMP_EQ_I64, + V3_CMP_LE_I64, + V3_CMP_GT_I64, + V3_CMP_NE_I64, + V3_CMP_GE_I64, + V3_CMP_T_I64, + V3_CMP_CLASS_F64, + V3_CMP_LT_U16, + V3_CMP_EQ_U16, + V3_CMP_LE_U16, + V3_CMP_GT_U16, + V3_CMP_NE_U16, + V3_CMP_GE_U16, + V3_CMPX_F_I64 = 176, + V3_CMPX_LT_I64, + V3_CMPX_EQ_I64, + V3_CMPX_LE_I64, + V3_CMPX_GT_I64, + V3_CMPX_NE_I64, + V3_CMPX_GE_I64, + V3_CMPX_T_I64, + V3_CMPX_CLASS_F64, + V3_CMPX_LT_U16, + V3_CMPX_EQ_U16, + V3_CMPX_LE_U16, + V3_CMPX_GT_U16, + V3_CMPX_NE_U16, + V3_CMPX_GE_U16, + V3_CMP_F_U32 = 192, + V3_CMP_LT_U32, + V3_CMP_EQ_U32, + V3_CMP_LE_U32, + V3_CMP_GT_U32, + V3_CMP_NE_U32, + V3_CMP_GE_U32, + V3_CMP_T_U32, + V3_CMP_F_F16, + V3_CMP_LT_F16, + V3_CMP_EQ_F16, + V3_CMP_LE_F16, + V3_CMP_GT_F16, + V3_CMP_LG_F16, + V3_CMP_GE_F16, + V3_CMP_O_F16, + V3_CMPX_F_U32, + V3_CMPX_LT_U32, + V3_CMPX_EQ_U32, + V3_CMPX_LE_U32, + V3_CMPX_GT_U32, + V3_CMPX_NE_U32, + V3_CMPX_GE_U32, + V3_CMPX_T_U32, + V3_CMPX_F_F16, + V3_CMPX_LT_F16, + V3_CMPX_EQ_F16, + V3_CMPX_LE_F16, + V3_CMPX_GT_F16, + V3_CMPX_LG_F16, + V3_CMPX_GE_F16, + V3_CMPX_O_F16, + V3_CMP_F_U64, + V3_CMP_LT_U64, + V3_CMP_EQ_U64, + V3_CMP_LE_U64, + V3_CMP_GT_U64, + V3_CMP_NE_U64, + V3_CMP_GE_U64, + V3_CMP_T_U64, + V3_CMP_U_F16, + V3_CMP_NGE_F16, + V3_CMP_NLG_F16, + V3_CMP_NGT_F16, + V3_CMP_NLE_F16, + V3_CMP_NEQ_F16, + V3_CMP_NLT_F16, + V3_CMP_TRU_F16, + V3_CMPX_F_U64, + V3_CMPX_LT_U64, + V3_CMPX_EQ_U64, + V3_CMPX_LE_U64, + V3_CMPX_GT_U64, + V3_CMPX_NE_U64, + V3_CMPX_GE_U64, + V3_CMPX_T_U64, + V3_CNDMASK_B32 = 256, + V3_READLANE_B32, + V3_WRITELANE_B32, + V3_ADD_F32, + V3_SUB_F32, + V3_SUBREV_F32, + V3_MAC_LEGACY_F32, + V3_MUL_LEGACY_F32, + V3_MUL_F32, + V3_MUL_I32_I24, + V3_MUL_HI_I32_I24, + V3_MUL_U32_U24, + V3_MUL_HI_U32_U24, + V3_MIN_LEGACY_F32, + V3_MAX_LEGACY_F32, + V3_MIN_F32, + V3_MAX_F32, + V3_MIN_I32, + V3_MAX_I32, + V3_MIN_U32, + V3_MAX_U32, + V3_LSHR_B32, + V3_LSHRREV_B32, + V3_ASHR_I32, + V3_ASHRREV_I32, + V3_LSHL_B32, + V3_LSHLREV_B32, + V3_AND_B32, + V3_OR_B32, + V3_XOR_B32, + V3_BFM_B32, + V3_MAC_F32, + V3_MADMK_F32, + V3_MADAK_F32, + V3_BCNT_U32_B32, + V3_MBCNT_LO_U32_B32, + V3_MBCNT_HI_U32_B32, + V3_ADD_I32, + V3_SUB_I32, + V3_SUBREV_I32, + V3_ADDC_U32, + V3_SUBB_U32, + V3_SUBBREV_U32, + V3_LDEXP_F32, + V3_CVT_PKACCUM_U8_F32, + V3_CVT_PKNORM_I16_F32, + V3_CVT_PKNORM_U16_F32, + V3_CVT_PKRTZ_F16_F32, + V3_CVT_PK_U16_U32, + V3_CVT_PK_I16_I32, + V3_MAD_LEGACY_F32 = 320, + V3_MAD_F32, + V3_MAD_I32_I24, + V3_MAD_U32_U24, + V3_CUBEID_F32, + V3_CUBESC_F32, + V3_CUBETC_F32, + V3_CUBEMA_F32, + V3_BFE_U32, + V3_BFE_I32, + V3_BFI_B32, + V3_FMA_F32, + V3_FMA_F64, + V3_LERP_U8, + V3_ALIGNBIT_B32, + V3_ALIGNBYTE_B32, + V3_MULLIT_F32, + V3_MIN3_F32, + V3_MIN3_I32, + V3_MIN3_U32, + V3_MAX3_F32, + V3_MAX3_I32, + V3_MAX3_U32, + V3_MED3_F32, + V3_MED3_I32, + V3_MED3_U32, + V3_SAD_U8, + V3_SAD_HI_U8, + V3_SAD_U16, + V3_SAD_U32, + V3_CVT_PK_U8_F32, + V3_DIV_FIXUP_F32, + V3_DIV_FIXUP_F64, + V3_LSHL_B64, + V3_LSHR_B64, + V3_ASHR_I64, + V3_ADD_F64, + V3_MUL_F64, + V3_MIN_F64, + V3_MAX_F64, + V3_LDEXP_F64, + V3_MUL_LO_U32, + V3_MUL_HI_U32, + V3_MUL_LO_I32, + V3_MUL_HI_I32, + V3_DIV_SCALE_F32, + V3_DIV_SCALE_F64, + V3_DIV_FMAS_F32, + V3_DIV_FMAS_F64, + V3_MSAD_U8, + V3_QSAD_U8, + V3_MQSAD_U8, + V3_TRIG_PREOP_F64, + V3_NOP = 384, + V3_MOV_B32, + V3_READFIRSTLANE_B32, + V3_CVT_I32_F64, + V3_CVT_F64_I32, + V3_CVT_F32_I32, + V3_CVT_F32_U32, + V3_CVT_U32_F32, + V3_CVT_I32_F32, + V3_MOV_FED_B32, + V3_CVT_F16_F32, + V3_CVT_F32_F16, + V3_CVT_RPI_I32_F32, + V3_CVT_FLR_I32_F32, + V3_CVT_OFF_F32_I4, + V3_CVT_F32_F64, + V3_CVT_F64_F32, + V3_CVT_F32_UBYTE0, + V3_CVT_F32_UBYTE1, + V3_CVT_F32_UBYTE2, + V3_CVT_F32_UBYTE3, + V3_CVT_U32_F64, + V3_CVT_F64_U32, + V3_FRACT_F32 = 416, + V3_TRUNC_F32, + V3_CEIL_F32, + V3_RNDNE_F32, + V3_FLOOR_F32, + V3_EXP_F32, + V3_LOG_CLAMP_F32, + V3_LOG_F32, + V3_RCP_CLAMP_F32, + V3_RCP_LEGACY_F32, + V3_RCP_F32, + V3_RCP_IFLAG_F32, + V3_RSQ_CLAMP_F32, + V3_RSQ_LEGACY_F32, + V3_RSQ_F32, + V3_RCP_F64, + V3_RCP_CLAMP_F64, + V3_RSQ_F64, + V3_RSQ_CLAMP_F64, + V3_SQRT_F32, + V3_SQRT_F64, + V3_SIN_F32, + V3_COS_F32, + V3_NOT_B32, + V3_BFREV_B32, + V3_FFBH_U32, + V3_FFBL_B32, + V3_FFBH_I32, + V3_FREXP_EXP_I32_F64, + V3_FREXP_MANT_F64, + V3_FRACT_F64, + V3_FREXP_EXP_I32_F32, + V3_FREXP_MANT_F32, + V3_CLREXCP, + V3_MOVRELD_B32, + V3_MOVRELS_B32, + V3_MOVRELSD_B32, + }; + + static constexpr int kMinInstSize = 2; + static constexpr auto vdstMask = genMask(0, 8); + + static constexpr auto absMask = genMask(getMaskEnd(vdstMask), 3); + static constexpr auto abs0Mask = genMask(getMaskEnd(vdstMask), 1); + static constexpr auto abs1Mask = genMask(getMaskEnd(abs0Mask), 1); + static constexpr auto abs2Mask = genMask(getMaskEnd(abs1Mask), 1); + static constexpr auto clmpMask = genMask(getMaskEnd(absMask), 1); + + static constexpr auto sdstMask = genMask(getMaskEnd(vdstMask), 7); + + static_assert(getMaskEnd(clmpMask) + 5 == getMaskEnd(sdstMask) + 2); + + static constexpr auto opMask = genMask(getMaskEnd(clmpMask) + 5, 9); + + static constexpr auto src0Mask = genMask(0, 9); + static constexpr auto src1Mask = genMask(getMaskEnd(src0Mask), 9); + static constexpr auto src2Mask = genMask(getMaskEnd(src1Mask), 9); + static constexpr auto omodMask = genMask(getMaskEnd(src2Mask), 2); + static constexpr auto negMask = genMask(getMaskEnd(omodMask), 3); + static constexpr auto neg0Mask = genMask(getMaskEnd(omodMask), 1); + static constexpr auto neg1Mask = genMask(getMaskEnd(neg0Mask), 1); + static constexpr auto neg2Mask = genMask(getMaskEnd(neg1Mask), 1); + + const std::uint32_t* inst; + const std::uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); + const std::uint32_t abs = fetchMaskedValue(inst[0], absMask); + const std::uint32_t clmp = fetchMaskedValue(inst[0], clmpMask); + const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + const std::uint32_t src0 = fetchMaskedValue(inst[1], src0Mask); + const std::uint32_t src1 = fetchMaskedValue(inst[1], src1Mask); + const std::uint32_t src2 = fetchMaskedValue(inst[1], src2Mask); + const std::uint32_t omod = fetchMaskedValue(inst[1], omodMask); + const std::uint32_t neg = fetchMaskedValue(inst[1], negMask); + + Vop3(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const + { + return kMinInstSize + getScalarInstSize(src0) + getScalarInstSize(src1) + + getScalarInstSize(src2); + } + + void dump() const; + }; + + struct Vopc + { + enum class Op + { + V_CMP_F_F32, + V_CMP_LT_F32, + V_CMP_EQ_F32, + V_CMP_LE_F32, + V_CMP_GT_F32, + V_CMP_LG_F32, + V_CMP_GE_F32, + V_CMP_O_F32, + V_CMP_U_F32, + V_CMP_NGE_F32, + V_CMP_NLG_F32, + V_CMP_NGT_F32, + V_CMP_NLE_F32, + V_CMP_NEQ_F32, + V_CMP_NLT_F32, + V_CMP_TRU_F32, + V_CMPX_F_F32, + V_CMPX_LT_F32, + V_CMPX_EQ_F32, + V_CMPX_LE_F32, + V_CMPX_GT_F32, + V_CMPX_LG_F32, + V_CMPX_GE_F32, + V_CMPX_O_F32, + V_CMPX_U_F32, + V_CMPX_NGE_F32, + V_CMPX_NLG_F32, + V_CMPX_NGT_F32, + V_CMPX_NLE_F32, + V_CMPX_NEQ_F32, + V_CMPX_NLT_F32, + V_CMPX_TRU_F32, + V_CMP_F_F64, + V_CMP_LT_F64, + V_CMP_EQ_F64, + V_CMP_LE_F64, + V_CMP_GT_F64, + V_CMP_LG_F64, + V_CMP_GE_F64, + V_CMP_O_F64, + V_CMP_U_F64, + V_CMP_NGE_F64, + V_CMP_NLG_F64, + V_CMP_NGT_F64, + V_CMP_NLE_F64, + V_CMP_NEQ_F64, + V_CMP_NLT_F64, + V_CMP_TRU_F64, + V_CMPX_F_F64, + V_CMPX_LT_F64, + V_CMPX_EQ_F64, + V_CMPX_LE_F64, + V_CMPX_GT_F64, + V_CMPX_LG_F64, + V_CMPX_GE_F64, + V_CMPX_O_F64, + V_CMPX_U_F64, + V_CMPX_NGE_F64, + V_CMPX_NLG_F64, + V_CMPX_NGT_F64, + V_CMPX_NLE_F64, + V_CMPX_NEQ_F64, + V_CMPX_NLT_F64, + V_CMPX_TRU_F64, + V_CMPS_F_F32, + V_CMPS_LT_F32, + V_CMPS_EQ_F32, + V_CMPS_LE_F32, + V_CMPS_GT_F32, + V_CMPS_LG_F32, + V_CMPS_GE_F32, + V_CMPS_O_F32, + V_CMPS_U_F32, + V_CMPS_NGE_F32, + V_CMPS_NLG_F32, + V_CMPS_NGT_F32, + V_CMPS_NLE_F32, + V_CMPS_NEQ_F32, + V_CMPS_NLT_F32, + V_CMPS_TRU_F32, + V_CMPSX_F_F32, + V_CMPSX_LT_F32, + V_CMPSX_EQ_F32, + V_CMPSX_LE_F32, + V_CMPSX_GT_F32, + V_CMPSX_LG_F32, + V_CMPSX_GE_F32, + V_CMPSX_O_F32, + V_CMPSX_U_F32, + V_CMPSX_NGE_F32, + V_CMPSX_NLG_F32, + V_CMPSX_NGT_F32, + V_CMPSX_NLE_F32, + V_CMPSX_NEQ_F32, + V_CMPSX_NLT_F32, + V_CMPSX_TRU_F32, + V_CMPS_F_F64, + V_CMPS_LT_F64, + V_CMPS_EQ_F64, + V_CMPS_LE_F64, + V_CMPS_GT_F64, + V_CMPS_LG_F64, + V_CMPS_GE_F64, + V_CMPS_O_F64, + V_CMPS_U_F64, + V_CMPS_NGE_F64, + V_CMPS_NLG_F64, + V_CMPS_NGT_F64, + V_CMPS_NLE_F64, + V_CMPS_NEQ_F64, + V_CMPS_NLT_F64, + V_CMPS_TRU_F64, + V_CMPSX_F_F64, + V_CMPSX_LT_F64, + V_CMPSX_EQ_F64, + V_CMPSX_LE_F64, + V_CMPSX_GT_F64, + V_CMPSX_LG_F64, + V_CMPSX_GE_F64, + V_CMPSX_O_F64, + V_CMPSX_U_F64, + V_CMPSX_NGE_F64, + V_CMPSX_NLG_F64, + V_CMPSX_NGT_F64, + V_CMPSX_NLE_F64, + V_CMPSX_NEQ_F64, + V_CMPSX_NLT_F64, + V_CMPSX_TRU_F64, + V_CMP_F_I32, + V_CMP_LT_I32, + V_CMP_EQ_I32, + V_CMP_LE_I32, + V_CMP_GT_I32, + V_CMP_NE_I32, + V_CMP_GE_I32, + V_CMP_T_I32, + V_CMP_CLASS_F32, + V_CMP_LT_I16, + V_CMP_EQ_I16, + V_CMP_LE_I16, + V_CMP_GT_I16, + V_CMP_NE_I16, + V_CMP_GE_I16, + V_CMP_CLASS_F16, + V_CMPX_F_I32, + V_CMPX_LT_I32, + V_CMPX_EQ_I32, + V_CMPX_LE_I32, + V_CMPX_GT_I32, + V_CMPX_NE_I32, + V_CMPX_GE_I32, + V_CMPX_T_I32, + V_CMPX_CLASS_F32, + V_CMPX_LT_I16, + V_CMPX_EQ_I16, + V_CMPX_LE_I16, + V_CMPX_GT_I16, + V_CMPX_NE_I16, + V_CMPX_GE_I16, + V_CMPX_CLASS_F16, + V_CMP_F_I64, + V_CMP_LT_I64, + V_CMP_EQ_I64, + V_CMP_LE_I64, + V_CMP_GT_I64, + V_CMP_NE_I64, + V_CMP_GE_I64, + V_CMP_T_I64, + V_CMP_CLASS_F64, + V_CMP_LT_U16, + V_CMP_EQ_U16, + V_CMP_LE_U16, + V_CMP_GT_U16, + V_CMP_NE_U16, + V_CMP_GE_U16, + V_CMPX_F_I64 = 176, + V_CMPX_LT_I64, + V_CMPX_EQ_I64, + V_CMPX_LE_I64, + V_CMPX_GT_I64, + V_CMPX_NE_I64, + V_CMPX_GE_I64, + V_CMPX_T_I64, + V_CMPX_CLASS_F64, + V_CMPX_LT_U16, + V_CMPX_EQ_U16, + V_CMPX_LE_U16, + V_CMPX_GT_U16, + V_CMPX_NE_U16, + V_CMPX_GE_U16, + V_CMP_F_U32 = 192, + V_CMP_LT_U32, + V_CMP_EQ_U32, + V_CMP_LE_U32, + V_CMP_GT_U32, + V_CMP_NE_U32, + V_CMP_GE_U32, + V_CMP_T_U32, + V_CMP_F_F16, + V_CMP_LT_F16, + V_CMP_EQ_F16, + V_CMP_LE_F16, + V_CMP_GT_F16, + V_CMP_LG_F16, + V_CMP_GE_F16, + V_CMP_O_F16, + V_CMPX_F_U32, + V_CMPX_LT_U32, + V_CMPX_EQ_U32, + V_CMPX_LE_U32, + V_CMPX_GT_U32, + V_CMPX_NE_U32, + V_CMPX_GE_U32, + V_CMPX_T_U32, + V_CMPX_F_F16, + V_CMPX_LT_F16, + V_CMPX_EQ_F16, + V_CMPX_LE_F16, + V_CMPX_GT_F16, + V_CMPX_LG_F16, + V_CMPX_GE_F16, + V_CMPX_O_F16, + V_CMP_F_U64, + V_CMP_LT_U64, + V_CMP_EQ_U64, + V_CMP_LE_U64, + V_CMP_GT_U64, + V_CMP_NE_U64, + V_CMP_GE_U64, + V_CMP_T_U64, + V_CMP_U_F16, + V_CMP_NGE_F16, + V_CMP_NLG_F16, + V_CMP_NGT_F16, + V_CMP_NLE_F16, + V_CMP_NEQ_F16, + V_CMP_NLT_F16, + V_CMP_TRU_F16, + V_CMPX_F_U64, + V_CMPX_LT_U64, + V_CMPX_EQ_U64, + V_CMPX_LE_U64, + V_CMPX_GT_U64, + V_CMPX_NE_U64, + V_CMPX_GE_U64, + V_CMPX_T_U64, + V_CMPX_U_F16, + V_CMPX_NGE_F16, + V_CMPX_NLG_F16, + V_CMPX_NGT_F16, + V_CMPX_NLE_F16, + V_CMPX_NEQ_F16, + V_CMPX_NLT_F16, + V_CMPX_TRU_F16, + }; + + static constexpr int kMinInstSize = 1; + + static constexpr auto src0Mask = genMask(0, 9); + static constexpr auto vsrc1Mask = genMask(getMaskEnd(src0Mask), 8); + static constexpr auto opMask = genMask(getMaskEnd(vsrc1Mask), 8); + + const std::uint32_t* inst; + const std::uint16_t src0 = fetchMaskedValue(inst[0], src0Mask); + const std::uint8_t vsrc1 = fetchMaskedValue(inst[0], vsrc1Mask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Vopc(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Smrd + { + enum class Op + { + S_LOAD_DWORD, + S_LOAD_DWORDX2, + S_LOAD_DWORDX4, + S_LOAD_DWORDX8, + S_LOAD_DWORDX16, + S_BUFFER_LOAD_DWORD = 8, + S_BUFFER_LOAD_DWORDX2, + S_BUFFER_LOAD_DWORDX4, + S_BUFFER_LOAD_DWORDX8, + S_BUFFER_LOAD_DWORDX16, + S_DCACHE_INV_VOL = 29, + S_MEMTIME, + S_DCACHE_INV, + }; + + static constexpr int kMinInstSize = 1; + static constexpr auto offsetMask = genMask(0, 8); + static constexpr auto immMask = genMask(getMaskEnd(offsetMask), 1); + static constexpr auto sbaseMask = genMask(getMaskEnd(immMask), 6); + static constexpr auto sdstMask = genMask(getMaskEnd(sbaseMask), 7); + static constexpr auto opMask = genMask(getMaskEnd(sdstMask), 5); + + const std::uint32_t* inst; + const std::uint32_t offset = fetchMaskedValue(inst[0], offsetMask); + const std::uint32_t imm = fetchMaskedValue(inst[0], immMask); + const std::uint32_t sbase = fetchMaskedValue(inst[0], sbaseMask); + const std::uint32_t sdst = fetchMaskedValue(inst[0], sdstMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Smrd(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + void dump() const; + }; + + struct Mubuf + { + enum class Op + { + BUFFER_LOAD_FORMAT_X, + BUFFER_LOAD_FORMAT_XY, + BUFFER_LOAD_FORMAT_XYZ, + BUFFER_LOAD_FORMAT_XYZW, + BUFFER_STORE_FORMAT_X, + BUFFER_STORE_FORMAT_XY, + BUFFER_STORE_FORMAT_XYZ, + BUFFER_STORE_FORMAT_XYZW, + BUFFER_LOAD_UBYTE, + BUFFER_LOAD_SBYTE, + BUFFER_LOAD_USHORT, + BUFFER_LOAD_SSHORT, + BUFFER_LOAD_DWORD, + BUFFER_LOAD_DWORDX2, + BUFFER_LOAD_DWORDX4, + BUFFER_LOAD_DWORDX3, + BUFFER_STORE_BYTE = 24, + BUFFER_STORE_SHORT = 26, + BUFFER_STORE_DWORD = 28, + BUFFER_STORE_DWORDX2, + BUFFER_STORE_DWORDX4, + BUFFER_STORE_DWORDX3, + BUFFER_ATOMIC_SWAP = 48, + BUFFER_ATOMIC_CMPSWAP, + BUFFER_ATOMIC_ADD, + BUFFER_ATOMIC_SUB, + BUFFER_ATOMIC_RSUB, + BUFFER_ATOMIC_SMIN, + BUFFER_ATOMIC_UMIN, + BUFFER_ATOMIC_SMAX, + BUFFER_ATOMIC_UMAX, + BUFFER_ATOMIC_AND, + BUFFER_ATOMIC_OR, + BUFFER_ATOMIC_XOR, + BUFFER_ATOMIC_INC, + BUFFER_ATOMIC_DEC, + BUFFER_ATOMIC_FCMPSWAP, + BUFFER_ATOMIC_FMIN, + BUFFER_ATOMIC_FMAX, + BUFFER_ATOMIC_SWAP_X2 = 80, + BUFFER_ATOMIC_CMPSWAP_X2, + BUFFER_ATOMIC_ADD_X2, + BUFFER_ATOMIC_SUB_X2, + BUFFER_ATOMIC_RSUB_X2, + BUFFER_ATOMIC_SMIN_X2, + BUFFER_ATOMIC_UMIN_X2, + BUFFER_ATOMIC_SMAX_X2, + BUFFER_ATOMIC_UMAX_X2, + BUFFER_ATOMIC_AND_X2, + BUFFER_ATOMIC_OR_X2, + BUFFER_ATOMIC_XOR_X2, + BUFFER_ATOMIC_INC_X2, + BUFFER_ATOMIC_DEC_X2, + BUFFER_ATOMIC_FCMPSWAP_X2, + BUFFER_ATOMIC_FMIN_X2, + BUFFER_ATOMIC_FMAX_X2, + BUFFER_WBINVL1_SC_VOL = 112, + BUFFER_WBINVL1, + }; + + static constexpr int kMinInstSize = 2; + static constexpr auto offsetMask = genMask(0, 12); + static constexpr auto offenMask = genMask(getMaskEnd(offsetMask), 1); + static constexpr auto idxenMask = genMask(getMaskEnd(offenMask), 1); + static constexpr auto glcMask = genMask(getMaskEnd(idxenMask), 1); + static constexpr auto ldsMask = genMask(getMaskEnd(glcMask) + 1, 1); + static constexpr auto opMask = genMask(getMaskEnd(ldsMask) + 1, 7); + + static constexpr auto vaddrMask = genMask(0, 8); + static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); + static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); + static constexpr auto slcMask = genMask(getMaskEnd(srsrcMask) + 1, 1); + static constexpr auto tfeMask = genMask(getMaskEnd(slcMask), 1); + static constexpr auto soffsetMask = genMask(getMaskEnd(tfeMask), 8); + + const std::uint32_t* inst; + std::uint16_t offset = fetchMaskedValue(inst[0], offsetMask); + bool offen = fetchMaskedValue(inst[0], offenMask); + bool idxen = fetchMaskedValue(inst[0], idxenMask); + bool glc = fetchMaskedValue(inst[0], glcMask); + bool lds = fetchMaskedValue(inst[0], ldsMask); + Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); + std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); + std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); + bool slc = fetchMaskedValue(inst[1], slcMask); + bool tfe = fetchMaskedValue(inst[1], tfeMask); + std::uint8_t soffset = fetchMaskedValue(inst[1], soffsetMask); + + Mubuf(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Mtbuf + { + enum class Op + { + TBUFFER_LOAD_FORMAT_X, + TBUFFER_LOAD_FORMAT_XY, + TBUFFER_LOAD_FORMAT_XYZ, + TBUFFER_LOAD_FORMAT_XYZW, + TBUFFER_STORE_FORMAT_X, + TBUFFER_STORE_FORMAT_XY, + TBUFFER_STORE_FORMAT_XYZ, + TBUFFER_STORE_FORMAT_XYZW, + }; + static constexpr int kMinInstSize = 2; + + static constexpr auto offsetMask = genMask(0, 12); + static constexpr auto offenMask = genMask(getMaskEnd(offsetMask), 1); + static constexpr auto idxenMask = genMask(getMaskEnd(offenMask), 1); + static constexpr auto glcMask = genMask(getMaskEnd(idxenMask), 1); + static constexpr auto opMask = genMask(getMaskEnd(glcMask) + 1, 3); + static constexpr auto dfmtMask = genMask(getMaskEnd(opMask), 4); + static constexpr auto nfmtMask = genMask(getMaskEnd(dfmtMask), 4); + + static constexpr auto vaddrMask = genMask(0, 8); + static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); + static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); + static constexpr auto slcMask = genMask(getMaskEnd(srsrcMask) + 1, 1); + static constexpr auto tfeMask = genMask(getMaskEnd(slcMask), 1); + static constexpr auto soffsetMask = genMask(getMaskEnd(tfeMask), 8); + + const std::uint32_t* inst; + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + std::uint16_t offset = fetchMaskedValue(inst[0], offsetMask); + bool offen = fetchMaskedValue(inst[0], offenMask); + bool idxen = fetchMaskedValue(inst[0], idxenMask); + bool glc = fetchMaskedValue(inst[0], glcMask); + SurfaceFormat dfmt = (SurfaceFormat)fetchMaskedValue(inst[0], dfmtMask); + TextureChannelType nfmt = + (TextureChannelType)fetchMaskedValue(inst[0], nfmtMask); + + std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); + std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); + std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); + bool slc = fetchMaskedValue(inst[1], slcMask); + bool tfe = fetchMaskedValue(inst[1], tfeMask); + std::uint8_t soffset = fetchMaskedValue(inst[1], soffsetMask); + + Mtbuf(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Mimg + { + enum class Op + { + IMAGE_LOAD, + IMAGE_LOAD_MIP, + IMAGE_LOAD_PCK, + IMAGE_LOAD_PCK_SGN, + IMAGE_LOAD_MIP_PCK, + IMAGE_LOAD_MIP_PCK_SGN, + IMAGE_STORE = 8, + IMAGE_STORE_MIP, + IMAGE_STORE_PCK, + IMAGE_STORE_MIP_PCK, + IMAGE_GET_RESINFO = 14, + IMAGE_ATOMIC_SWAP, + IMAGE_ATOMIC_CMPSWAP, + IMAGE_ATOMIC_ADD, + IMAGE_ATOMIC_SUB, + IMAGE_ATOMIC_RSUB, + IMAGE_ATOMIC_SMIN, + IMAGE_ATOMIC_UMIN, + IMAGE_ATOMIC_SMAX, + IMAGE_ATOMIC_UMAX, + IMAGE_ATOMIC_AND, + IMAGE_ATOMIC_OR, + IMAGE_ATOMIC_XOR, + IMAGE_ATOMIC_INC, + IMAGE_ATOMIC_DEC, + IMAGE_ATOMIC_FCMPSWAP, + IMAGE_ATOMIC_FMIN, + IMAGE_ATOMIC_FMAX, + IMAGE_SAMPLE, + IMAGE_SAMPLE_CL, + IMAGE_SAMPLE_D, + IMAGE_SAMPLE_D_CL, + IMAGE_SAMPLE_L, + IMAGE_SAMPLE_B, + IMAGE_SAMPLE_B_CL, + IMAGE_SAMPLE_LZ, + IMAGE_SAMPLE_C, + IMAGE_SAMPLE_C_CL, + IMAGE_SAMPLE_C_D, + IMAGE_SAMPLE_C_D_CL, + IMAGE_SAMPLE_C_L, + IMAGE_SAMPLE_C_B, + IMAGE_SAMPLE_C_B_CL, + IMAGE_SAMPLE_C_LZ, + IMAGE_SAMPLE_O, + IMAGE_SAMPLE_CL_O, + IMAGE_SAMPLE_D_O, + IMAGE_SAMPLE_D_CL_O, + IMAGE_SAMPLE_L_O, + IMAGE_SAMPLE_B_O, + IMAGE_SAMPLE_B_CL_O, + IMAGE_SAMPLE_LZ_O, + IMAGE_SAMPLE_C_O, + IMAGE_SAMPLE_C_CL_O, + IMAGE_SAMPLE_C_D_O, + IMAGE_SAMPLE_C_D_CL_O, + IMAGE_SAMPLE_C_L_O, + IMAGE_SAMPLE_C_B_O, + IMAGE_SAMPLE_C_B_CL_O, + IMAGE_SAMPLE_C_LZ_O, + IMAGE_GATHER4, + IMAGE_GATHER4_CL, + IMAGE_GATHER4_L = 68, + IMAGE_GATHER4_B, + IMAGE_GATHER4_B_CL, + IMAGE_GATHER4_LZ, + IMAGE_GATHER4_C, + IMAGE_GATHER4_C_CL, + IMAGE_GATHER4_C_L = 76, + IMAGE_GATHER4_C_B, + IMAGE_GATHER4_C_B_CL, + IMAGE_GATHER4_C_LZ, + IMAGE_GATHER4_O, + IMAGE_GATHER4_CL_O, + IMAGE_GATHER4_L_O = 84, + IMAGE_GATHER4_B_O, + IMAGE_GATHER4_B_CL_O, + IMAGE_GATHER4_LZ_O, + IMAGE_GATHER4_C_O, + IMAGE_GATHER4_C_CL_O, + IMAGE_GATHER4_C_L_O = 92, + IMAGE_GATHER4_C_B_O, + IMAGE_GATHER4_C_B_CL_O, + IMAGE_GATHER4_C_LZ_O, + IMAGE_GET_LOD, + IMAGE_SAMPLE_CD = 104, + IMAGE_SAMPLE_CD_CL, + IMAGE_SAMPLE_C_CD, + IMAGE_SAMPLE_C_CD_CL, + IMAGE_SAMPLE_CD_O, + IMAGE_SAMPLE_CD_CL_O, + IMAGE_SAMPLE_C_CD_O, + IMAGE_SAMPLE_C_CD_CL_O, + }; + + static constexpr int kMinInstSize = 2; + + static constexpr auto dmaskMask = genMask(8, 4); + static constexpr auto unrmMask = genMask(getMaskEnd(dmaskMask), 1); + static constexpr auto glcMask = genMask(getMaskEnd(unrmMask), 1); + static constexpr auto daMask = genMask(getMaskEnd(glcMask), 1); + static constexpr auto r128Mask = genMask(getMaskEnd(daMask), 1); + static constexpr auto tfeMask = genMask(getMaskEnd(r128Mask), 1); + static constexpr auto lweMask = genMask(getMaskEnd(tfeMask), 1); + static constexpr auto opMask = genMask(getMaskEnd(lweMask), 7); + static constexpr auto slcMask = genMask(getMaskEnd(opMask), 1); + + static constexpr auto vaddrMask = genMask(0, 8); + static constexpr auto vdataMask = genMask(getMaskEnd(vaddrMask), 8); + static constexpr auto srsrcMask = genMask(getMaskEnd(vdataMask), 5); + static constexpr auto ssampMask = genMask(getMaskEnd(srsrcMask), 5); + + const std::uint32_t* inst; + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + std::uint8_t dmask = fetchMaskedValue(inst[0], dmaskMask); + bool unrm = fetchMaskedValue(inst[0], unrmMask); + bool glc = fetchMaskedValue(inst[0], glcMask); + bool da = fetchMaskedValue(inst[0], daMask); + bool r128 = fetchMaskedValue(inst[0], r128Mask); + bool tfe = fetchMaskedValue(inst[0], tfeMask); + bool lwe = fetchMaskedValue(inst[0], lweMask); + bool slc = fetchMaskedValue(inst[0], slcMask); + + std::uint8_t vaddr = fetchMaskedValue(inst[1], vaddrMask); + std::uint8_t vdata = fetchMaskedValue(inst[1], vdataMask); + std::uint8_t srsrc = fetchMaskedValue(inst[1], srsrcMask); + std::uint8_t ssamp = fetchMaskedValue(inst[1], ssampMask); + + Mimg(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Ds + { + enum class Op + { + DS_ADD_U32, + DS_SUB_U32, + DS_RSUB_U32, + DS_INC_U32, + DS_DEC_U32, + DS_MIN_I32, + DS_MAX_I32, + DS_MIN_U32, + DS_MAX_U32, + DS_AND_B32, + DS_OR_B32, + DS_XOR_B32, + DS_MSKOR_B32, + DS_WRITE_B32, + DS_WRITE2_B32, + DS_WRITE2ST64_B32, + DS_CMPST_B32, + DS_CMPST_F32, + DS_MIN_F32, + DS_MAX_F32, + DS_NOP, + DS_GWS_SEMA_RELEASE_ALL = 24, + DS_GWS_INIT, + DS_GWS_SEMA_V, + DS_GWS_SEMA_BR, + DS_GWS_SEMA_P, + DS_GWS_BARRIER, + DS_WRITE_B8, + DS_WRITE_B16, + DS_ADD_RTN_U32, + DS_SUB_RTN_U32, + DS_RSUB_RTN_U32, + DS_INC_RTN_U32, + DS_DEC_RTN_U32, + DS_MIN_RTN_I32, + DS_MAX_RTN_I32, + DS_MIN_RTN_U32, + DS_MAX_RTN_U32, + DS_AND_RTN_B32, + DS_OR_RTN_B32, + DS_XOR_RTN_B32, + DS_MSKOR_RTN_B32, + DS_WRXCHG_RTN_B32, + DS_WRXCHG2_RTN_B32, + DS_WRXCHG2ST64_RTN_B32, + DS_CMPST_RTN_B32, + DS_CMPST_RTN_F32, + DS_MIN_RTN_F32, + DS_MAX_RTN_F32, + DS_WRAP_RTN_B32, + DS_SWIZZLE_B32, + DS_READ_B32, + DS_READ2_B32, + DS_READ2ST64_B32, + DS_READ_I8, + DS_READ_U8, + DS_READ_I16, + DS_READ_U16, + DS_CONSUME, + DS_APPEND, + DS_ORDERED_COUNT, + DS_ADD_U64, + DS_SUB_U64, + DS_RSUB_U64, + DS_INC_U64, + DS_DEC_U64, + DS_MIN_I64, + DS_MAX_I64, + DS_MIN_U64, + DS_MAX_U64, + DS_AND_B64, + DS_OR_B64, + DS_XOR_B64, + DS_MSKOR_B64, + DS_WRITE_B64, + DS_WRITE2_B64, + DS_WRITE2ST64_B64, + DS_CMPST_B64, + DS_CMPST_F64, + DS_MIN_F64, + DS_MAX_F64, + DS_ADD_RTN_U64 = 96, + DS_SUB_RTN_U64, + DS_RSUB_RTN_U64, + DS_INC_RTN_U64, + DS_DEC_RTN_U64, + DS_MIN_RTN_I64, + DS_MAX_RTN_I64, + DS_MIN_RTN_U64, + DS_MAX_RTN_U64, + DS_AND_RTN_B64, + DS_OR_RTN_B64, + DS_XOR_RTN_B64, + DS_MSKOR_RTN_B64, + DS_WRXCHG_RTN_B64, + DS_WRXCHG2_RTN_B64, + DS_WRXCHG2ST64_RTN_B64, + DS_CMPST_RTN_B64, + DS_CMPST_RTN_F64, + DS_MIN_RTN_F64, + DS_MAX_RTN_F64, + DS_READ_B64 = 118, + DS_READ2_B64, + DS_READ2ST64_B64, + DS_CONDXCHG32_RTN_B64 = 126, + DS_ADD_SRC2_U32 = 128, + DS_SUB_SRC2_U32, + DS_RSUB_SRC2_U32, + DS_INC_SRC2_U32, + DS_DEC_SRC2_U32, + DS_MIN_SRC2_I32, + DS_MAX_SRC2_I32, + DS_MIN_SRC2_U32, + DS_MAX_SRC2_U32, + DS_AND_SRC2_B32, + DS_OR_SRC2_B32, + DS_XOR_SRC2_B32, + DS_WRITE_SRC2_B32, + DS_MIN_SRC2_F32 = 146, + DS_MAX_SRC2_F32, + DS_ADD_SRC2_U64 = 192, + DS_SUB_SRC2_U64, + DS_RSUB_SRC2_U64, + DS_INC_SRC2_U64, + DS_DEC_SRC2_U64, + DS_MIN_SRC2_I64, + DS_MAX_SRC2_I64, + DS_MIN_SRC2_U64, + DS_MAX_SRC2_U64, + DS_AND_SRC2_B64, + DS_OR_SRC2_B64, + DS_XOR_SRC2_B64, + DS_WRITE_SRC2_B64, + DS_MIN_SRC2_F64 = 210, + DS_MAX_SRC2_F64, + DS_WRITE_B96 = 222, + DS_WRITE_B128, + DS_CONDXCHG32_RTN_B128 = 253, + DS_READ_B96, + DS_READ_B128, + }; + + static constexpr int kMinInstSize = 2; + static constexpr auto offset0Mask = genMask(0, 8); + static constexpr auto offset1Mask = genMask(getMaskEnd(offset0Mask), 8); + static constexpr auto gdsMask = genMask(getMaskEnd(offset1Mask) + 1, 1); + static constexpr auto opMask = genMask(getMaskEnd(gdsMask), 8); + + static constexpr auto addrMask = genMask(0, 8); + static constexpr auto data0Mask = genMask(getMaskEnd(addrMask), 8); + static constexpr auto data1Mask = genMask(getMaskEnd(data0Mask), 8); + static constexpr auto vdstMask = genMask(getMaskEnd(data1Mask), 8); + + const std::uint32_t* inst; + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + + Ds(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Vintrp + { + enum class Op + { + V_INTERP_P1_F32, + V_INTERP_P2_F32, + V_INTERP_MOV_F32 + }; + + static constexpr int kMinInstSize = 1; + static constexpr auto vsrcMask = genMask(0, 8); + static constexpr auto attrChanMask = genMask(getMaskEnd(vsrcMask), 2); + static constexpr auto attrMask = genMask(getMaskEnd(attrChanMask), 6); + static constexpr auto opMask = genMask(getMaskEnd(attrMask), 2); + static constexpr auto vdstMask = genMask(getMaskEnd(opMask), 8); + + const std::uint32_t* inst; + uint32_t vsrc = fetchMaskedValue(inst[0], vsrcMask); + uint32_t attrChan = fetchMaskedValue(inst[0], attrChanMask); + uint32_t attr = fetchMaskedValue(inst[0], attrMask); + const Op op = static_cast(fetchMaskedValue(inst[0], opMask)); + uint32_t vdst = fetchMaskedValue(inst[0], vdstMask); + + Vintrp(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + struct Exp + { + static constexpr int kMinInstSize = 2; + + static constexpr auto enMask = genMask(0, 4); + static constexpr auto targetMask = genMask(getMaskEnd(enMask), 6); + static constexpr auto comprMask = genMask(getMaskEnd(targetMask), 1); + static constexpr auto doneMask = genMask(getMaskEnd(comprMask), 1); + static constexpr auto vmMask = genMask(getMaskEnd(doneMask), 1); + + static constexpr auto vsrc0Mask = genMask(0, 8); + static constexpr auto vsrc1Mask = genMask(getMaskEnd(vsrc0Mask), 8); + static constexpr auto vsrc2Mask = genMask(getMaskEnd(vsrc1Mask), 8); + static constexpr auto vsrc3Mask = genMask(getMaskEnd(vsrc2Mask), 8); + + const std::uint32_t* inst; + + std::uint8_t en = fetchMaskedValue(inst[0], enMask); + std::uint8_t target = fetchMaskedValue(inst[0], targetMask); + bool compr = fetchMaskedValue(inst[0], comprMask); + bool done = fetchMaskedValue(inst[0], doneMask); + bool vm = fetchMaskedValue(inst[0], vmMask); + std::uint8_t vsrc0 = fetchMaskedValue(inst[1], vsrc0Mask); + std::uint8_t vsrc1 = fetchMaskedValue(inst[1], vsrc1Mask); + std::uint8_t vsrc2 = fetchMaskedValue(inst[1], vsrc2Mask); + std::uint8_t vsrc3 = fetchMaskedValue(inst[1], vsrc3Mask); + + Exp(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const { return kMinInstSize; } + + void dump() const; + }; + + enum class InstructionClass : std::uint8_t + { + Invalid, + Vop2, + Sop2, + Sopk, + Smrd, + Vop3, + Mubuf, + Mtbuf, + Mimg, + Ds, + Vintrp, + Exp, + Vop1, + Vopc, + Sop1, + Sopc, + Sopp, + }; + + static constexpr std::uint32_t kInstMask1 = + static_cast(~0u << (32 - 1)); + static constexpr std::uint32_t kInstMask2 = + static_cast(~0u << (32 - 2)); + static constexpr std::uint32_t kInstMask4 = + static_cast(~0u << (32 - 4)); + static constexpr std::uint32_t kInstMask5 = + static_cast(~0u << (32 - 5)); + static constexpr std::uint32_t kInstMask6 = + static_cast(~0u << (32 - 6)); + static constexpr std::uint32_t kInstMask7 = + static_cast(~0u << (32 - 7)); + static constexpr std::uint32_t kInstMask9 = + static_cast(~0u << (32 - 9)); + + static constexpr std::uint32_t kInstMaskValVop2 = 0b0u << (32 - 1); + static constexpr std::uint32_t kInstMaskValSop2 = 0b10u << (32 - 2); + static constexpr std::uint32_t kInstMaskValSopk = 0b1011u << (32 - 4); + static constexpr std::uint32_t kInstMaskValSmrd = 0b11000u << (32 - 5); + static constexpr std::uint32_t kInstMaskValVop3 = 0b110100u << (32 - 6); + static constexpr std::uint32_t kInstMaskValMubuf = 0b111000u << (32 - 6); + static constexpr std::uint32_t kInstMaskValMtbuf = 0b111010u << (32 - 6); + static constexpr std::uint32_t kInstMaskValMimg = 0b111100u << (32 - 6); + static constexpr std::uint32_t kInstMaskValDs = 0b110110u << (32 - 6); + static constexpr std::uint32_t kInstMaskValVintrp = 0b110010u << (32 - 6); + static constexpr std::uint32_t kInstMaskValExp = 0b111110u << (32 - 6); + static constexpr std::uint32_t kInstMaskValVop1 = 0b0111111u << (32 - 7); + static constexpr std::uint32_t kInstMaskValVopC = 0b0111110u << (32 - 7); + static constexpr std::uint32_t kInstMaskValSop1 = 0b101111101u << (32 - 9); + static constexpr std::uint32_t kInstMaskValSopc = 0b101111110u << (32 - 9); + static constexpr std::uint32_t kInstMaskValSopp = 0b101111111u << (32 - 9); + + inline InstructionClass getInstructionClass(std::uint32_t instr) + { + switch (instr & kInstMask9) + { + case kInstMaskValSop1: + return InstructionClass::Sop1; + case kInstMaskValSopc: + return InstructionClass::Sopc; + case kInstMaskValSopp: + return InstructionClass::Sopp; + } + + switch (instr & kInstMask7) + { + case kInstMaskValVop1: + return InstructionClass::Vop1; + case kInstMaskValVopC: + return InstructionClass::Vopc; + } + + switch (instr & kInstMask6) + { + case kInstMaskValVop3: + return InstructionClass::Vop3; + case kInstMaskValMubuf: + return InstructionClass::Mubuf; + case kInstMaskValMtbuf: + return InstructionClass::Mtbuf; + case kInstMaskValMimg: + return InstructionClass::Mimg; + case kInstMaskValDs: + return InstructionClass::Ds; + case kInstMaskValVintrp: + return InstructionClass::Vintrp; + case kInstMaskValExp: + return InstructionClass::Exp; + } + + if ((instr & kInstMask5) == kInstMaskValSmrd) + { + return InstructionClass::Smrd; + } + + if ((instr & kInstMask4) == kInstMaskValSopk) + { + return InstructionClass::Sopk; + } + + if ((instr & kInstMask2) == kInstMaskValSop2) + { + return InstructionClass::Sop2; + } + + if ((instr & kInstMask1) == kInstMaskValVop2) + { + return InstructionClass::Vop2; + } + + return InstructionClass::Invalid; + } + + struct Instruction + { + const std::uint32_t* inst; + InstructionClass instClass = getInstructionClass(*inst); + + Instruction(const std::uint32_t* inst) + : inst(inst) + { + } + + int size() const + { + switch (instClass) + { + case InstructionClass::Vop2: + return Vop2(inst).size(); + case InstructionClass::Sop2: + return Sop2(inst).size(); + case InstructionClass::Sopk: + return Sopk(inst).size(); + case InstructionClass::Smrd: + return Smrd(inst).size(); + case InstructionClass::Vop3: + return Vop3(inst).size(); + case InstructionClass::Mubuf: + return Mubuf(inst).size(); + case InstructionClass::Mtbuf: + return Mtbuf(inst).size(); + case InstructionClass::Mimg: + return Mimg(inst).size(); + case InstructionClass::Ds: + return Ds(inst).size(); + case InstructionClass::Vintrp: + return Vintrp(inst).size(); + case InstructionClass::Exp: + return Exp(inst).size(); + case InstructionClass::Vop1: + return Vop1(inst).size(); + case InstructionClass::Vopc: + return Vopc(inst).size(); + case InstructionClass::Sop1: + return Sop1(inst).size(); + case InstructionClass::Sopc: + return Sopc(inst).size(); + case InstructionClass::Sopp: + return Sopp(inst).size(); + + case InstructionClass::Invalid: + break; + } + + return 1; + } + + void dump() const; + }; + + const char* instructionClassToString(InstructionClass instrClass); + const char* opcodeToString(InstructionClass instClass, int op); + + const char* sop1OpcodeToString(Sop1::Op op); + const char* sop2OpcodeToString(Sop2::Op op); + const char* sopkOpcodeToString(Sopk::Op op); + const char* sopcOpcodeToString(Sopc::Op op); + const char* soppOpcodeToString(Sopp::Op op); + const char* vop2OpcodeToString(Vop2::Op op); + const char* vop1OpcodeToString(Vop1::Op op); + const char* vopcOpcodeToString(Vopc::Op op); + const char* vop3OpcodeToString(Vop3::Op op); + const char* smrdOpcodeToString(Smrd::Op op); + const char* mubufOpcodeToString(Mubuf::Op op); + const char* mtbufOpcodeToString(Mtbuf::Op op); + const char* mimgOpcodeToString(Mimg::Op op); + const char* dsOpcodeToString(Ds::Op op); + const char* vintrpOpcodeToString(Vintrp::Op op); } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/RegisterId.hpp b/hw/amdgpu/shader/include/amdgpu/shader/RegisterId.hpp index d4fd1309..55fb696d 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/RegisterId.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/RegisterId.hpp @@ -2,101 +2,121 @@ #include -namespace amdgpu::shader { -class RegisterId { - static constexpr std::uint32_t kScalarOperandsOffset = 0; - static constexpr std::uint32_t kScalarOperandsCount = 256; - static constexpr std::uint32_t kVectorOperandsOffset = - kScalarOperandsOffset + kScalarOperandsCount; - static constexpr std::uint32_t kVectorOperandsCount = 512; - static constexpr std::uint32_t kExportOperandsOffset = - kVectorOperandsOffset + kVectorOperandsCount; - static constexpr std::uint32_t kExportOperandsCount = 64; - static constexpr std::uint32_t kAttrOperandsOffset = - kExportOperandsOffset + kExportOperandsCount; - static constexpr std::uint32_t kAttrOperandsCount = 32; - static constexpr std::uint32_t kOperandsCount = - kAttrOperandsOffset + kAttrOperandsCount; +namespace amdgpu::shader +{ + class RegisterId + { + static constexpr std::uint32_t kScalarOperandsOffset = 0; + static constexpr std::uint32_t kScalarOperandsCount = 256; + static constexpr std::uint32_t kVectorOperandsOffset = + kScalarOperandsOffset + kScalarOperandsCount; + static constexpr std::uint32_t kVectorOperandsCount = 512; + static constexpr std::uint32_t kExportOperandsOffset = + kVectorOperandsOffset + kVectorOperandsCount; + static constexpr std::uint32_t kExportOperandsCount = 64; + static constexpr std::uint32_t kAttrOperandsOffset = + kExportOperandsOffset + kExportOperandsCount; + static constexpr std::uint32_t kAttrOperandsCount = 32; + static constexpr std::uint32_t kOperandsCount = + kAttrOperandsOffset + kAttrOperandsCount; - static constexpr std::uint32_t kRegisterVccLoId = kScalarOperandsOffset + 106; - static constexpr std::uint32_t kRegisterVccHiId = kScalarOperandsOffset + 107; - static constexpr std::uint32_t kRegisterM0Id = kScalarOperandsOffset + 124; - static constexpr std::uint32_t kRegisterExecLoId = - kScalarOperandsOffset + 126; - static constexpr std::uint32_t kRegisterExecHiId = - kScalarOperandsOffset + 127; - static constexpr std::uint32_t kRegisterSccId = kScalarOperandsOffset + 253; - static constexpr std::uint32_t kRegisterLdsDirect = - kScalarOperandsOffset + 254; + static constexpr std::uint32_t kRegisterVccLoId = kScalarOperandsOffset + 106; + static constexpr std::uint32_t kRegisterVccHiId = kScalarOperandsOffset + 107; + static constexpr std::uint32_t kRegisterM0Id = kScalarOperandsOffset + 124; + static constexpr std::uint32_t kRegisterExecLoId = + kScalarOperandsOffset + 126; + static constexpr std::uint32_t kRegisterExecHiId = + kScalarOperandsOffset + 127; + static constexpr std::uint32_t kRegisterSccId = kScalarOperandsOffset + 253; + static constexpr std::uint32_t kRegisterLdsDirect = + kScalarOperandsOffset + 254; -public: - enum enum_type : std::uint32_t { - Invalid = ~static_cast(0), + public: + enum enum_type : std::uint32_t + { + Invalid = ~static_cast(0), - VccLo = kRegisterVccLoId, - VccHi = kRegisterVccHiId, - M0 = kRegisterM0Id, - ExecLo = kRegisterExecLoId, - ExecHi = kRegisterExecHiId, - Scc = kRegisterSccId, - LdsDirect = kRegisterLdsDirect, - } raw = Invalid; + VccLo = kRegisterVccLoId, + VccHi = kRegisterVccHiId, + M0 = kRegisterM0Id, + ExecLo = kRegisterExecLoId, + ExecHi = kRegisterExecHiId, + Scc = kRegisterSccId, + LdsDirect = kRegisterLdsDirect, + } raw = Invalid; - RegisterId(enum_type value) : raw(value) {} + RegisterId(enum_type value) + : raw(value) + { + } - operator enum_type() const { return raw; } + operator enum_type() const { return raw; } - static RegisterId Raw(std::uint32_t index) { - return static_cast(index); - } - static RegisterId Scalar(std::uint32_t index) { - return static_cast(index + kScalarOperandsOffset); - } - static RegisterId Vector(std::uint32_t index) { - return static_cast(index + kVectorOperandsOffset); - } - static RegisterId Export(std::uint32_t index) { - return static_cast(index + kExportOperandsOffset); - } - static RegisterId Attr(std::uint32_t index) { - return static_cast(index + kAttrOperandsOffset); - } + static RegisterId Raw(std::uint32_t index) + { + return static_cast(index); + } + static RegisterId Scalar(std::uint32_t index) + { + return static_cast(index + kScalarOperandsOffset); + } + static RegisterId Vector(std::uint32_t index) + { + return static_cast(index + kVectorOperandsOffset); + } + static RegisterId Export(std::uint32_t index) + { + return static_cast(index + kExportOperandsOffset); + } + static RegisterId Attr(std::uint32_t index) + { + return static_cast(index + kAttrOperandsOffset); + } - bool isScalar() const { - return raw >= kScalarOperandsOffset && - raw < kScalarOperandsOffset + kScalarOperandsCount; - } - bool isVector() const { - return raw >= kVectorOperandsOffset && - raw < kVectorOperandsOffset + kVectorOperandsCount; - } - bool isExport() const { - return raw >= kExportOperandsOffset && - raw < kExportOperandsOffset + kExportOperandsCount; - } - bool isAttr() const { - return raw >= kAttrOperandsOffset && - raw < kAttrOperandsOffset + kAttrOperandsCount; - } + bool isScalar() const + { + return raw >= kScalarOperandsOffset && + raw < kScalarOperandsOffset + kScalarOperandsCount; + } + bool isVector() const + { + return raw >= kVectorOperandsOffset && + raw < kVectorOperandsOffset + kVectorOperandsCount; + } + bool isExport() const + { + return raw >= kExportOperandsOffset && + raw < kExportOperandsOffset + kExportOperandsCount; + } + bool isAttr() const + { + return raw >= kAttrOperandsOffset && + raw < kAttrOperandsOffset + kAttrOperandsCount; + } - unsigned getOffset() const { - if (isScalar()) { - return raw - kScalarOperandsOffset; - } + unsigned getOffset() const + { + if (isScalar()) + { + return raw - kScalarOperandsOffset; + } - if (isVector()) { - return raw - kVectorOperandsOffset; - } + if (isVector()) + { + return raw - kVectorOperandsOffset; + } - if (isExport()) { - return raw - kExportOperandsOffset; - } + if (isExport()) + { + return raw - kExportOperandsOffset; + } - if (isAttr()) { - return raw - kAttrOperandsOffset; - } + if (isAttr()) + { + return raw - kAttrOperandsOffset; + } - return raw; - } -}; + return raw; + } + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/RegisterState.hpp b/hw/amdgpu/shader/include/amdgpu/shader/RegisterState.hpp index c0f11f76..f20dbd46 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/RegisterState.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/RegisterState.hpp @@ -3,25 +3,27 @@ #include "Value.hpp" #include -namespace amdgpu::shader { -struct RegisterState { - std::uint64_t pc; +namespace amdgpu::shader +{ + struct RegisterState + { + std::uint64_t pc; - Value sgprs[104]; - Value vccLo; - Value vccHi; - Value m0; - Value execLo; - Value execHi; - Value scc; - Value ldsDirect; - Value vgprs[512]; - Value attrs[32]; + Value sgprs[104]; + Value vccLo; + Value vccHi; + Value m0; + Value execLo; + Value execHi; + Value scc; + Value ldsDirect; + Value vgprs[512]; + Value attrs[32]; - Value getRegister(RegisterId regId); - void setRegister(RegisterId regId, Value value); + Value getRegister(RegisterId regId); + void setRegister(RegisterId regId, Value value); -private: - Value getRegisterImpl(RegisterId regId); -}; + private: + Value getRegisterImpl(RegisterId regId); + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Stage.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Stage.hpp index 7b247ed9..dd159290 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Stage.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Stage.hpp @@ -1,5 +1,13 @@ #pragma once -namespace amdgpu::shader { -enum class Stage : unsigned char { None, Vertex, Fragment, Geometry, Compute }; +namespace amdgpu::shader +{ + enum class Stage : unsigned char + { + None, + Vertex, + Fragment, + Geometry, + Compute + }; } diff --git a/hw/amdgpu/shader/include/amdgpu/shader/TypeId.hpp b/hw/amdgpu/shader/include/amdgpu/shader/TypeId.hpp index 84c2471f..aed32e56 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/TypeId.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/TypeId.hpp @@ -2,57 +2,65 @@ #include -namespace amdgpu::shader { -struct TypeId { - enum { - Bool, - SInt8, - UInt8, - SInt16, - UInt16, - SInt32, - UInt32, - UInt32x2, - UInt32x3, - UInt32x4, - UInt64, - SInt64, - ArrayUInt32x8, - ArrayUInt32x16, - Float16, - Float32, - Float32x2, - Float32x3, - Float32x4, - Float64, - ArrayFloat32x8, - ArrayFloat32x16, - Sampler, - Image2D, - StorageImage2D, - SampledImage2D, - - Void // should be last - } raw = Void; - - using enum_type = decltype(raw); - - TypeId() = default; - TypeId(enum_type value) : raw(value) {} - operator enum_type() const { return raw; } - - TypeId getBaseType() const; - std::size_t getSize() const; - std::size_t getElementsCount() const; - - bool isSignedInt() const { - return raw == TypeId::SInt8 || raw == TypeId::SInt16 || - raw == TypeId::SInt32 || raw == TypeId::SInt64; - } - - bool isFloatPoint() const { - return raw == TypeId::Float16 || raw == TypeId::Float32 || - raw == TypeId::Float64; - } -}; +namespace amdgpu::shader +{ + struct TypeId + { + enum + { + Bool, + SInt8, + UInt8, + SInt16, + UInt16, + SInt32, + UInt32, + UInt32x2, + UInt32x3, + UInt32x4, + UInt64, + SInt64, + ArrayUInt32x8, + ArrayUInt32x16, + Float16, + Float32, + Float32x2, + Float32x3, + Float32x4, + Float64, + ArrayFloat32x8, + ArrayFloat32x16, + Sampler, + Image2D, + StorageImage2D, + SampledImage2D, + + Void // should be last + } raw = Void; + + using enum_type = decltype(raw); + + TypeId() = default; + TypeId(enum_type value) + : raw(value) + { + } + operator enum_type() const { return raw; } + + TypeId getBaseType() const; + std::size_t getSize() const; + std::size_t getElementsCount() const; + + bool isSignedInt() const + { + return raw == TypeId::SInt8 || raw == TypeId::SInt16 || + raw == TypeId::SInt32 || raw == TypeId::SInt64; + } + + bool isFloatPoint() const + { + return raw == TypeId::Float16 || raw == TypeId::Float32 || + raw == TypeId::Float64; + } + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Uniform.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Uniform.hpp index ab887891..c710cb6d 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Uniform.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Uniform.hpp @@ -7,14 +7,16 @@ #include #include -namespace amdgpu::shader { -struct UniformInfo { - std::uint32_t buffer[8]; - int index; - TypeId typeId; - spirv::PointerType type; - spirv::VariableValue variable; - AccessOp accessOp = AccessOp::None; - bool isBuffer; -}; +namespace amdgpu::shader +{ + struct UniformInfo + { + std::uint32_t buffer[8]; + int index; + TypeId typeId; + spirv::PointerType type; + spirv::VariableValue variable; + AccessOp accessOp = AccessOp::None; + bool isBuffer; + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/UniformBindings.hpp b/hw/amdgpu/shader/include/amdgpu/shader/UniformBindings.hpp index f90635bf..af5c4ede 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/UniformBindings.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/UniformBindings.hpp @@ -3,70 +3,82 @@ #include "Stage.hpp" #include "util/unreachable.hpp" -namespace amdgpu::shader { -struct UniformBindings { - static constexpr auto kBufferSlots = 16; - static constexpr auto kImageSlots = 16; - static constexpr auto kSamplerSlots = 16; - static constexpr auto kStorageImageSlots = 16; - - static constexpr auto kBufferOffset = 0; - static constexpr auto kImageOffset = kBufferOffset + kBufferSlots; - static constexpr auto kSamplerOffset = kImageOffset + kImageSlots; - static constexpr auto kStorageImageOffset = kSamplerOffset + kSamplerSlots; - - static constexpr auto kStageSize = kStorageImageOffset + kStorageImageSlots; - - static constexpr auto kVertexOffset = 0; - static constexpr auto kFragmentOffset = kStageSize; - - static unsigned getBufferBinding(Stage stage, unsigned index) { - if (index >= kBufferSlots) { - util::unreachable(); - } - - return index + getStageOffset(stage) + kBufferOffset; - } - - static unsigned getImageBinding(Stage stage, unsigned index) { - if (index >= kImageSlots) { - util::unreachable(); - } - - return index + getStageOffset(stage) + kImageOffset; - } - - static unsigned getStorageImageBinding(Stage stage, unsigned index) { - if (index >= kStorageImageSlots) { - util::unreachable(); - } - - return index + getStageOffset(stage) + kStorageImageOffset; - } - - static unsigned getSamplerBinding(Stage stage, unsigned index) { - if (index >= kSamplerSlots) { - util::unreachable(); - } - - return index + getStageOffset(stage) + kSamplerOffset; - } - -private: - static unsigned getStageOffset(Stage stage) { - switch (stage) { - case Stage::Fragment: - return kFragmentOffset; - - case Stage::Vertex: - return kVertexOffset; - - case Stage::Compute: - return kVertexOffset; - - default: - util::unreachable(); - } - } -}; +namespace amdgpu::shader +{ + struct UniformBindings + { + static constexpr auto kBufferSlots = 16; + static constexpr auto kImageSlots = 16; + static constexpr auto kSamplerSlots = 16; + static constexpr auto kStorageImageSlots = 16; + + static constexpr auto kBufferOffset = 0; + static constexpr auto kImageOffset = kBufferOffset + kBufferSlots; + static constexpr auto kSamplerOffset = kImageOffset + kImageSlots; + static constexpr auto kStorageImageOffset = kSamplerOffset + kSamplerSlots; + + static constexpr auto kStageSize = kStorageImageOffset + kStorageImageSlots; + + static constexpr auto kVertexOffset = 0; + static constexpr auto kFragmentOffset = kStageSize; + + static unsigned getBufferBinding(Stage stage, unsigned index) + { + if (index >= kBufferSlots) + { + util::unreachable(); + } + + return index + getStageOffset(stage) + kBufferOffset; + } + + static unsigned getImageBinding(Stage stage, unsigned index) + { + if (index >= kImageSlots) + { + util::unreachable(); + } + + return index + getStageOffset(stage) + kImageOffset; + } + + static unsigned getStorageImageBinding(Stage stage, unsigned index) + { + if (index >= kStorageImageSlots) + { + util::unreachable(); + } + + return index + getStageOffset(stage) + kStorageImageOffset; + } + + static unsigned getSamplerBinding(Stage stage, unsigned index) + { + if (index >= kSamplerSlots) + { + util::unreachable(); + } + + return index + getStageOffset(stage) + kSamplerOffset; + } + + private: + static unsigned getStageOffset(Stage stage) + { + switch (stage) + { + case Stage::Fragment: + return kFragmentOffset; + + case Stage::Vertex: + return kVertexOffset; + + case Stage::Compute: + return kVertexOffset; + + default: + util::unreachable(); + } + } + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/Value.hpp b/hw/amdgpu/shader/include/amdgpu/shader/Value.hpp index b98d93d8..ccc57e41 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/Value.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/Value.hpp @@ -1,15 +1,21 @@ #pragma once #include -namespace amdgpu::shader { -struct Value { - spirv::Type type; - spirv::Value value; +namespace amdgpu::shader +{ + struct Value + { + spirv::Type type; + spirv::Value value; - Value() = default; - Value(spirv::Type type, spirv::Value value) : type(type), value(value) {} + Value() = default; + Value(spirv::Type type, spirv::Value value) + : type(type) + , value(value) + { + } - explicit operator bool() const { return static_cast(value); } - bool operator==(Value other) const { return value == other.value; } -}; + explicit operator bool() const { return static_cast(value); } + bool operator==(Value other) const { return value == other.value; } + }; } // namespace amdgpu::shader diff --git a/hw/amdgpu/shader/include/amdgpu/shader/cf.hpp b/hw/amdgpu/shader/include/amdgpu/shader/cf.hpp index e3936225..01bb37f8 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/cf.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/cf.hpp @@ -5,145 +5,175 @@ #include #include -namespace cf { -enum class TerminatorKind { - None, - Branch, - BranchToUnknown, - Return, -}; - -class BasicBlock { - std::uint64_t address; - std::uint64_t size = 0; - - std::set predecessors; - BasicBlock *successors[2]{}; - TerminatorKind terminator = TerminatorKind::None; - -public: - explicit BasicBlock(std::uint64_t address, std::uint64_t size = 0) - : address(address), size(size) {} - - BasicBlock(const BasicBlock &) = delete; - - void setSize(std::uint64_t newSize) { size = newSize; } - std::uint64_t getSize() const { return size; } - std::uint64_t getAddress() const { return address; } - TerminatorKind getTerminator() const { return terminator; } - - void createConditionalBranch(BasicBlock *ifTrue, BasicBlock *ifFalse); - void createBranch(BasicBlock *target); - void createBranchToUnknown(); - void createReturn(); - - void replaceSuccessor(BasicBlock *origBB, BasicBlock *newBB); - void replacePredecessor(BasicBlock *origBB, BasicBlock *newBB) { - origBB->replaceSuccessor(this, newBB); - } - - template T> void walk(T &&cb) { - std::vector workStack; - std::set processed; - - workStack.push_back(this); - processed.insert(this); - - while (!workStack.empty()) { - auto block = workStack.back(); - workStack.pop_back(); - - block->walkSuccessors([&](BasicBlock *successor) { - if (processed.insert(successor).second) { - workStack.push_back(successor); - } - }); - - cb(*block); - } - } - - template T> void walkSuccessors(T &&cb) const { - if (successors[0]) { - cb(successors[0]); - - if (successors[1]) { - cb(successors[1]); - } - } - } - - template T> - void walkPredecessors(T &&cb) const { - for (auto pred : predecessors) { - cb(pred); - } - } - - std::size_t getPredecessorsCount() const { return predecessors.size(); } - - bool hasDirectPredecessor(const BasicBlock &block) const; - bool hasPredecessor(const BasicBlock &block) const; - - std::size_t getSuccessorsCount() const { - if (successors[0] == nullptr) { - return 0; - } - - return successors[1] != nullptr ? 2 : 1; - } - - BasicBlock *getSuccessor(std::size_t index) const { - return successors[index]; - } - - void split(BasicBlock *target); -}; - -class Context { - std::map> basicBlocks; - -public: - BasicBlock *getBasicBlockAt(std::uint64_t address) { - if (auto it = basicBlocks.find(address); it != basicBlocks.end()) { - return &it->second; - } - - return nullptr; - } - - BasicBlock *getBasicBlock(std::uint64_t address) { - if (auto it = basicBlocks.lower_bound(address); it != basicBlocks.end()) { - auto bb = &it->second; - - if (bb->getAddress() <= address && - bb->getAddress() + bb->getSize() > address) { - return bb; - } - } - - return nullptr; - } - - BasicBlock *getOrCreateBasicBlock(std::uint64_t address, bool split = true) { - auto it = basicBlocks.lower_bound(address); - - if (it != basicBlocks.end()) { - auto bb = &it->second; - - if (bb->getAddress() <= address && - bb->getAddress() + bb->getSize() > address) { - if (split && bb->getAddress() != address) { - auto result = &basicBlocks.emplace_hint(it, address, address)->second; - bb->split(result); - return result; - } - - return bb; - } - } - - return &basicBlocks.emplace_hint(it, address, address)->second; - } -}; +namespace cf +{ + enum class TerminatorKind + { + None, + Branch, + BranchToUnknown, + Return, + }; + + class BasicBlock + { + std::uint64_t address; + std::uint64_t size = 0; + + std::set predecessors; + BasicBlock* successors[2]{}; + TerminatorKind terminator = TerminatorKind::None; + + public: + explicit BasicBlock(std::uint64_t address, std::uint64_t size = 0) + : address(address) + , size(size) + { + } + + BasicBlock(const BasicBlock&) = delete; + + void setSize(std::uint64_t newSize) { size = newSize; } + std::uint64_t getSize() const { return size; } + std::uint64_t getAddress() const { return address; } + TerminatorKind getTerminator() const { return terminator; } + + void createConditionalBranch(BasicBlock* ifTrue, BasicBlock* ifFalse); + void createBranch(BasicBlock* target); + void createBranchToUnknown(); + void createReturn(); + + void replaceSuccessor(BasicBlock* origBB, BasicBlock* newBB); + void replacePredecessor(BasicBlock* origBB, BasicBlock* newBB) + { + origBB->replaceSuccessor(this, newBB); + } + + template T> + void walk(T&& cb) + { + std::vector workStack; + std::set processed; + + workStack.push_back(this); + processed.insert(this); + + while (!workStack.empty()) + { + auto block = workStack.back(); + workStack.pop_back(); + + block->walkSuccessors([&](BasicBlock* successor) { + if (processed.insert(successor).second) + { + workStack.push_back(successor); + } + }); + + cb(*block); + } + } + + template T> + void walkSuccessors(T&& cb) const + { + if (successors[0]) + { + cb(successors[0]); + + if (successors[1]) + { + cb(successors[1]); + } + } + } + + template T> + void walkPredecessors(T&& cb) const + { + for (auto pred : predecessors) + { + cb(pred); + } + } + + std::size_t getPredecessorsCount() const { return predecessors.size(); } + + bool hasDirectPredecessor(const BasicBlock& block) const; + bool hasPredecessor(const BasicBlock& block) const; + + std::size_t getSuccessorsCount() const + { + if (successors[0] == nullptr) + { + return 0; + } + + return successors[1] != nullptr ? 2 : 1; + } + + BasicBlock* getSuccessor(std::size_t index) const + { + return successors[index]; + } + + void split(BasicBlock* target); + }; + + class Context + { + std::map> basicBlocks; + + public: + BasicBlock* getBasicBlockAt(std::uint64_t address) + { + if (auto it = basicBlocks.find(address); it != basicBlocks.end()) + { + return &it->second; + } + + return nullptr; + } + + BasicBlock* getBasicBlock(std::uint64_t address) + { + if (auto it = basicBlocks.lower_bound(address); it != basicBlocks.end()) + { + auto bb = &it->second; + + if (bb->getAddress() <= address && + bb->getAddress() + bb->getSize() > address) + { + return bb; + } + } + + return nullptr; + } + + BasicBlock* getOrCreateBasicBlock(std::uint64_t address, bool split = true) + { + auto it = basicBlocks.lower_bound(address); + + if (it != basicBlocks.end()) + { + auto bb = &it->second; + + if (bb->getAddress() <= address && + bb->getAddress() + bb->getSize() > address) + { + if (split && bb->getAddress() != address) + { + auto result = &basicBlocks.emplace_hint(it, address, address)->second; + bb->split(result); + return result; + } + + return bb; + } + } + + return &basicBlocks.emplace_hint(it, address, address)->second; + } + }; } // namespace cf diff --git a/hw/amdgpu/shader/include/amdgpu/shader/scf.hpp b/hw/amdgpu/shader/include/amdgpu/shader/scf.hpp index c9755bc3..bfe0f281 100644 --- a/hw/amdgpu/shader/include/amdgpu/shader/scf.hpp +++ b/hw/amdgpu/shader/include/amdgpu/shader/scf.hpp @@ -6,339 +6,413 @@ #include #include -namespace cf { -class BasicBlock; +namespace cf +{ + class BasicBlock; } -namespace scf { -class BasicBlock; -struct PrintOptions { - unsigned char identCount = 2; - char identChar = ' '; - std::function - blockPrinter; - - std::string makeIdent(unsigned depth) const { - return std::string(depth * identCount, identChar); - } -}; - -class Node { - Node *mParent = nullptr; - Node *mNext = nullptr; - Node *mPrev = nullptr; - -public: - virtual ~Node() = default; - virtual void print(const PrintOptions &options, unsigned depth) = 0; - virtual bool isEqual(const Node &other) const { return this == &other; } - - void dump() { print({}, 0); } - - void setParent(Node *parent) { mParent = parent; } - - Node *getParent() const { return mParent; } - - template - requires(std::is_base_of_v) - auto getParent() const -> decltype(dynCast(mParent)) { - return dynCast(mParent); - } - - Node *getNext() const { return mNext; } - - Node *getPrev() const { return mPrev; } - - friend class Block; -}; - -template - requires(std::is_base_of_v && std::is_base_of_v) && - requires(ST *s) { dynamic_cast(s); } -T *dynCast(ST *s) { - return dynamic_cast(s); -} - -template - requires(std::is_base_of_v && std::is_base_of_v) && - requires(const ST *s) { dynamic_cast(s); } -const T *dynCast(const ST *s) { - return dynamic_cast(s); -} - -inline bool isNodeEqual(const Node *lhs, const Node *rhs) { - if (lhs == rhs) { - return true; - } - - return lhs != nullptr && rhs != nullptr && lhs->isEqual(*rhs); -} - -struct UnknownBlock final : Node { - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%sunknown\n", options.makeIdent(depth).c_str()); - } - - bool isEqual(const Node &other) const override { - return this == &other || dynCast(&other) != nullptr; - } -}; - -struct Return final : Node { - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%sreturn\n", options.makeIdent(depth).c_str()); - } - - bool isEqual(const Node &other) const override { - return this == &other || dynCast(&other) != nullptr; - } -}; - -class Context; - -class Block final : public Node { - Node *mBegin = nullptr; - Node *mEnd = nullptr; - - void *mUserData = nullptr; - -public: - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%s{\n", options.makeIdent(depth).c_str()); - - for (auto node = mBegin; node != nullptr; node = node->getNext()) { - node->print(options, depth + 1); - } - std::printf("%s}\n", options.makeIdent(depth).c_str()); - } - - bool isEmpty() const { return mBegin == nullptr; } - - Node *getRootNode() const { return mBegin; } - Node *getLastNode() const { return mEnd; } - - void setUserData(void *data) { mUserData = data; } - void *getUserData() const { return mUserData; } - template T *getUserData() const { - return static_cast(mUserData); - } - - void eraseFrom(Node *endBefore); - void splitInto(Block *target, Node *splitPoint); - Block *split(Context &context, Node *splitPoint); - - void append(Node *node) { - assert(node->mParent == nullptr); - assert(node->mPrev == nullptr); - assert(node->mNext == nullptr); - - node->mParent = this; - node->mPrev = mEnd; - - if (mEnd != nullptr) { - mEnd->mNext = node; - } - - if (mBegin == nullptr) { - mBegin = node; - } - - mEnd = node; - } - - void detachNode(Node *node) { - if (node->mPrev != nullptr) { - node->mPrev->mNext = node->mNext; - } - - if (node->mNext != nullptr) { - node->mNext->mPrev = node->mPrev; - } - - if (mBegin == node) { - mBegin = node->mNext; - } - - if (mEnd == node) { - mEnd = node->mPrev; - } - - node->mNext = nullptr; - node->mPrev = nullptr; - node->mParent = nullptr; - } - - bool isEqual(const Node &other) const override { - if (this == &other) { - return true; - } - - auto otherBlock = dynCast(&other); - - if (otherBlock == nullptr) { - return false; - } - - auto thisIt = mBegin; - auto otherIt = otherBlock->mBegin; - - while (thisIt != nullptr && otherIt != nullptr) { - if (!thisIt->isEqual(*otherIt)) { - return false; - } - - thisIt = thisIt->mNext; - otherIt = otherIt->mNext; - } - - return thisIt == otherIt; - } -}; - -class BasicBlock final : public Node { - std::uint64_t address; - std::uint64_t size = 0; - -public: - explicit BasicBlock(std::uint64_t address, std::uint64_t size = 0) - : address(address), size(size) {} - - std::uint64_t getSize() const { return size; } - std::uint64_t getAddress() const { return address; } - - void print(const PrintOptions &options, unsigned depth) override { - std::printf( - "%sbb%lx\n", - std::string(depth * options.identCount, options.identChar).c_str(), - getAddress()); - if (depth != 0 && options.blockPrinter) { - options.blockPrinter(options, depth + 1, this); - } - } - - Block *getBlock() const { return dynCast(getParent()); } - - bool isEqual(const Node &other) const override { - if (this == &other) { - return true; - } - - if (auto otherBlock = dynCast(&other)) { - return address == otherBlock->address; - } - - return false; - } -}; - -struct IfElse final : Node { - Block *ifTrue; - Block *ifFalse; - - IfElse(Block *ifTrue, Block *ifFalse) : ifTrue(ifTrue), ifFalse(ifFalse) { - ifTrue->setParent(this); - ifFalse->setParent(this); - } - - void print(const PrintOptions &options, unsigned depth) override { - if (ifTrue->isEmpty()) { - std::printf("%sif false\n", options.makeIdent(depth).c_str()); - ifFalse->print(options, depth); - return; - } - - std::printf("%sif true\n", options.makeIdent(depth).c_str()); - ifTrue->print(options, depth); - if (!ifFalse->isEmpty()) { - std::printf("%selse\n", options.makeIdent(depth).c_str()); - ifFalse->print(options, depth); - } - } - - bool isEqual(const Node &other) const override { - if (this == &other) { - return true; - } - - if (auto otherBlock = dynCast(&other)) { - return ifTrue->isEqual(*otherBlock->ifTrue) && - ifFalse->isEqual(*otherBlock->ifFalse); - } - - return false; - } -}; - -struct Jump final : Node { - BasicBlock *target; - - Jump(BasicBlock *target) : target(target) {} - - bool isEqual(const Node &other) const override { - if (this == &other) { - return true; - } - - if (auto otherJump = dynCast(&other)) { - return target == otherJump->target; - } - - return false; - } - - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%sjump ", options.makeIdent(depth).c_str()); - target->print(options, 0); - } -}; - -struct Loop final : Node { - Block *body; - - Loop(Block *body) : body(body) { body->setParent(this); } - - bool isEqual(const Node &other) const override { - if (this == &other) { - return true; - } - - if (auto otherLoop = dynCast(&other)) { - return body->isEqual(*otherLoop->body); - } - - return false; - } - - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%sloop {\n", options.makeIdent(depth).c_str()); - body->print(options, depth + 1); - std::printf("%s}\n", options.makeIdent(depth).c_str()); - } -}; - -struct Break final : Node { - bool isEqual(const Node &other) const override { - return this == &other || dynCast(&other) != nullptr; - } - - void print(const PrintOptions &options, unsigned depth) override { - std::printf("%sbreak\n", options.makeIdent(depth).c_str()); - } -}; - -class Context { - std::forward_list> mNodes; - -public: - template - requires(std::is_constructible_v) - T *create(ArgsT &&...args) { - auto result = new T(std::forward(args)...); - mNodes.push_front(std::unique_ptr{result}); - return result; - } -}; - -scf::Block *structurize(Context &ctxt, cf::BasicBlock *bb); -void makeUniqueBasicBlocks(Context &ctxt, Block *block); +namespace scf +{ + class BasicBlock; + struct PrintOptions + { + unsigned char identCount = 2; + char identChar = ' '; + std::function + blockPrinter; + + std::string makeIdent(unsigned depth) const + { + return std::string(depth * identCount, identChar); + } + }; + + class Node + { + Node* mParent = nullptr; + Node* mNext = nullptr; + Node* mPrev = nullptr; + + public: + virtual ~Node() = default; + virtual void print(const PrintOptions& options, unsigned depth) = 0; + virtual bool isEqual(const Node& other) const { return this == &other; } + + void dump() { print({}, 0); } + + void setParent(Node* parent) { mParent = parent; } + + Node* getParent() const { return mParent; } + + template + requires(std::is_base_of_v) auto getParent() const -> decltype(dynCast(mParent)) + { + return dynCast(mParent); + } + + Node* getNext() const { return mNext; } + + Node* getPrev() const { return mPrev; } + + friend class Block; + }; + + template + requires(std::is_base_of_v&& std::is_base_of_v) && + requires(ST* s) { dynamic_cast(s); } + T* dynCast(ST* s) + { + return dynamic_cast(s); + } + + template + requires(std::is_base_of_v&& std::is_base_of_v) && + requires(const ST* s) { dynamic_cast(s); } + const T* dynCast(const ST* s) + { + return dynamic_cast(s); + } + + inline bool isNodeEqual(const Node* lhs, const Node* rhs) + { + if (lhs == rhs) + { + return true; + } + + return lhs != nullptr && rhs != nullptr && lhs->isEqual(*rhs); + } + + struct UnknownBlock final : Node + { + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%sunknown\n", options.makeIdent(depth).c_str()); + } + + bool isEqual(const Node& other) const override + { + return this == &other || dynCast(&other) != nullptr; + } + }; + + struct Return final : Node + { + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%sreturn\n", options.makeIdent(depth).c_str()); + } + + bool isEqual(const Node& other) const override + { + return this == &other || dynCast(&other) != nullptr; + } + }; + + class Context; + + class Block final : public Node + { + Node* mBegin = nullptr; + Node* mEnd = nullptr; + + void* mUserData = nullptr; + + public: + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%s{\n", options.makeIdent(depth).c_str()); + + for (auto node = mBegin; node != nullptr; node = node->getNext()) + { + node->print(options, depth + 1); + } + std::printf("%s}\n", options.makeIdent(depth).c_str()); + } + + bool isEmpty() const { return mBegin == nullptr; } + + Node* getRootNode() const { return mBegin; } + Node* getLastNode() const { return mEnd; } + + void setUserData(void* data) { mUserData = data; } + void* getUserData() const { return mUserData; } + template + T* getUserData() const + { + return static_cast(mUserData); + } + + void eraseFrom(Node* endBefore); + void splitInto(Block* target, Node* splitPoint); + Block* split(Context& context, Node* splitPoint); + + void append(Node* node) + { + assert(node->mParent == nullptr); + assert(node->mPrev == nullptr); + assert(node->mNext == nullptr); + + node->mParent = this; + node->mPrev = mEnd; + + if (mEnd != nullptr) + { + mEnd->mNext = node; + } + + if (mBegin == nullptr) + { + mBegin = node; + } + + mEnd = node; + } + + void detachNode(Node* node) + { + if (node->mPrev != nullptr) + { + node->mPrev->mNext = node->mNext; + } + + if (node->mNext != nullptr) + { + node->mNext->mPrev = node->mPrev; + } + + if (mBegin == node) + { + mBegin = node->mNext; + } + + if (mEnd == node) + { + mEnd = node->mPrev; + } + + node->mNext = nullptr; + node->mPrev = nullptr; + node->mParent = nullptr; + } + + bool isEqual(const Node& other) const override + { + if (this == &other) + { + return true; + } + + auto otherBlock = dynCast(&other); + + if (otherBlock == nullptr) + { + return false; + } + + auto thisIt = mBegin; + auto otherIt = otherBlock->mBegin; + + while (thisIt != nullptr && otherIt != nullptr) + { + if (!thisIt->isEqual(*otherIt)) + { + return false; + } + + thisIt = thisIt->mNext; + otherIt = otherIt->mNext; + } + + return thisIt == otherIt; + } + }; + + class BasicBlock final : public Node + { + std::uint64_t address; + std::uint64_t size = 0; + + public: + explicit BasicBlock(std::uint64_t address, std::uint64_t size = 0) + : address(address) + , size(size) + { + } + + std::uint64_t getSize() const { return size; } + std::uint64_t getAddress() const { return address; } + + void print(const PrintOptions& options, unsigned depth) override + { + std::printf( + "%sbb%lx\n", + std::string(depth * options.identCount, options.identChar).c_str(), + getAddress()); + if (depth != 0 && options.blockPrinter) + { + options.blockPrinter(options, depth + 1, this); + } + } + + Block* getBlock() const { return dynCast(getParent()); } + + bool isEqual(const Node& other) const override + { + if (this == &other) + { + return true; + } + + if (auto otherBlock = dynCast(&other)) + { + return address == otherBlock->address; + } + + return false; + } + }; + + struct IfElse final : Node + { + Block* ifTrue; + Block* ifFalse; + + IfElse(Block* ifTrue, Block* ifFalse) + : ifTrue(ifTrue) + , ifFalse(ifFalse) + { + ifTrue->setParent(this); + ifFalse->setParent(this); + } + + void print(const PrintOptions& options, unsigned depth) override + { + if (ifTrue->isEmpty()) + { + std::printf("%sif false\n", options.makeIdent(depth).c_str()); + ifFalse->print(options, depth); + return; + } + + std::printf("%sif true\n", options.makeIdent(depth).c_str()); + ifTrue->print(options, depth); + if (!ifFalse->isEmpty()) + { + std::printf("%selse\n", options.makeIdent(depth).c_str()); + ifFalse->print(options, depth); + } + } + + bool isEqual(const Node& other) const override + { + if (this == &other) + { + return true; + } + + if (auto otherBlock = dynCast(&other)) + { + return ifTrue->isEqual(*otherBlock->ifTrue) && + ifFalse->isEqual(*otherBlock->ifFalse); + } + + return false; + } + }; + + struct Jump final : Node + { + BasicBlock* target; + + Jump(BasicBlock* target) + : target(target) + { + } + + bool isEqual(const Node& other) const override + { + if (this == &other) + { + return true; + } + + if (auto otherJump = dynCast(&other)) + { + return target == otherJump->target; + } + + return false; + } + + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%sjump ", options.makeIdent(depth).c_str()); + target->print(options, 0); + } + }; + + struct Loop final : Node + { + Block* body; + + Loop(Block* body) + : body(body) + { + body->setParent(this); + } + + bool isEqual(const Node& other) const override + { + if (this == &other) + { + return true; + } + + if (auto otherLoop = dynCast(&other)) + { + return body->isEqual(*otherLoop->body); + } + + return false; + } + + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%sloop {\n", options.makeIdent(depth).c_str()); + body->print(options, depth + 1); + std::printf("%s}\n", options.makeIdent(depth).c_str()); + } + }; + + struct Break final : Node + { + bool isEqual(const Node& other) const override + { + return this == &other || dynCast(&other) != nullptr; + } + + void print(const PrintOptions& options, unsigned depth) override + { + std::printf("%sbreak\n", options.makeIdent(depth).c_str()); + } + }; + + class Context + { + std::forward_list> mNodes; + + public: + template + requires(std::is_constructible_v) + T* create(ArgsT&&... args) + { + auto result = new T(std::forward(args)...); + mNodes.push_front(std::unique_ptr{result}); + return result; + } + }; + + scf::Block* structurize(Context& ctxt, cf::BasicBlock* bb); + void makeUniqueBasicBlocks(Context& ctxt, Block* block); } // namespace scf diff --git a/hw/amdgpu/shader/src/CfBuilder.cpp b/hw/amdgpu/shader/src/CfBuilder.cpp index 8bad8119..02cd9208 100644 --- a/hw/amdgpu/shader/src/CfBuilder.cpp +++ b/hw/amdgpu/shader/src/CfBuilder.cpp @@ -7,172 +7,198 @@ using namespace amdgpu; using namespace amdgpu::shader; -struct CfgBuilder { - cf::Context *context; - RemoteMemory memory; - - std::size_t analyzeBb(cf::BasicBlock *bb, std::uint64_t *successors, - std::size_t *successorsCount) { - auto address = bb->getAddress(); - auto instBegin = memory.getPointer(address); - auto instHex = instBegin; - - while (true) { - auto instruction = Instruction(instHex); - auto size = instruction.size(); - auto pc = address + ((instHex - instBegin) << 2); - instHex += size; - - if (instruction.instClass == InstructionClass::Sop1) { - Sop1 sop1{instHex - size}; - - if (sop1.op == Sop1::Op::S_SETPC_B64 || - sop1.op == Sop1::Op::S_SWAPPC_B64) { - bb->createBranchToUnknown(); - break; - } - - continue; - } - - if (instruction.instClass == InstructionClass::Sopp) { - Sopp sopp{instHex - size}; - - if (sopp.op == Sopp::Op::S_ENDPGM) { - bb->createReturn(); - break; - } - - bool isEnd = false; - switch (sopp.op) { - case Sopp::Op::S_BRANCH: - successors[0] = pc + ((size + sopp.simm) << 2); - *successorsCount = 1; - - isEnd = true; - break; - - case Sopp::Op::S_CBRANCH_SCC0: - case Sopp::Op::S_CBRANCH_SCC1: - case Sopp::Op::S_CBRANCH_VCCZ: - case Sopp::Op::S_CBRANCH_VCCNZ: - case Sopp::Op::S_CBRANCH_EXECZ: - case Sopp::Op::S_CBRANCH_EXECNZ: - successors[0] = pc + ((size + sopp.simm) << 2); - successors[1] = pc + (size << 2); - *successorsCount = 2; - isEnd = true; - break; - - default: - break; - } - - if (isEnd) { - break; - } - continue; - } - - // move instruction that requires EXEC test to separate bb - if (instruction.instClass == InstructionClass::Vop2 || - instruction.instClass == InstructionClass::Vop3 || - instruction.instClass == InstructionClass::Mubuf || - instruction.instClass == InstructionClass::Mtbuf || - instruction.instClass == InstructionClass::Mimg || - instruction.instClass == InstructionClass::Ds || - instruction.instClass == InstructionClass::Vintrp || - instruction.instClass == InstructionClass::Exp || - instruction.instClass == InstructionClass::Vop1 || - instruction.instClass == InstructionClass::Vopc || - instruction.instClass == InstructionClass::Smrd) { - *successorsCount = 1; - - if (instBegin != instHex - size) { - // if it is not first instruction in block, move end to prev - // instruction, successor is current instruction - instHex -= size; - successors[0] = pc; - break; - } - - successors[0] = pc + (size << 2); - break; - } - } - - return (instHex - instBegin) << 2; - } - - cf::BasicBlock *buildCfg(std::uint64_t entryPoint) { - std::vector workList; - workList.push_back(entryPoint); - std::unordered_set processed; - processed.insert(entryPoint); - - struct BranchInfo { - std::uint64_t source; - std::size_t count; - std::uint64_t targets[2]; - }; - - std::vector branches; - - while (!workList.empty()) { - auto address = workList.back(); - workList.pop_back(); - - auto bb = context->getOrCreateBasicBlock(address); - - if (bb->getSize() != 0) { - continue; - } - - std::uint64_t successors[2]; - std::size_t successorsCount = 0; - std::size_t size = analyzeBb(bb, successors, &successorsCount); - bb->setSize(size); - - if (successorsCount == 2) { - branches.push_back( - {address + size - 4, 2, {successors[0], successors[1]}}); - - if (processed.insert(successors[0]).second) { - workList.push_back(successors[0]); - } - if (processed.insert(successors[1]).second) { - workList.push_back(successors[1]); - } - } else if (successorsCount == 1) { - branches.push_back({address + size - 4, 1, {successors[0]}}); - - if (processed.insert(successors[0]).second) { - workList.push_back(successors[0]); - } - } - } - - for (auto branch : branches) { - auto bb = context->getBasicBlock(branch.source); - assert(bb); - if (branch.count == 2) { - bb->createConditionalBranch( - context->getBasicBlockAt(branch.targets[0]), - context->getBasicBlockAt(branch.targets[1])); - } else { - bb->createBranch(context->getBasicBlockAt(branch.targets[0])); - } - } - - return context->getBasicBlockAt(entryPoint); - } +struct CfgBuilder +{ + cf::Context* context; + RemoteMemory memory; + + std::size_t analyzeBb(cf::BasicBlock* bb, std::uint64_t* successors, + std::size_t* successorsCount) + { + auto address = bb->getAddress(); + auto instBegin = memory.getPointer(address); + auto instHex = instBegin; + + while (true) + { + auto instruction = Instruction(instHex); + auto size = instruction.size(); + auto pc = address + ((instHex - instBegin) << 2); + instHex += size; + + if (instruction.instClass == InstructionClass::Sop1) + { + Sop1 sop1{instHex - size}; + + if (sop1.op == Sop1::Op::S_SETPC_B64 || + sop1.op == Sop1::Op::S_SWAPPC_B64) + { + bb->createBranchToUnknown(); + break; + } + + continue; + } + + if (instruction.instClass == InstructionClass::Sopp) + { + Sopp sopp{instHex - size}; + + if (sopp.op == Sopp::Op::S_ENDPGM) + { + bb->createReturn(); + break; + } + + bool isEnd = false; + switch (sopp.op) + { + case Sopp::Op::S_BRANCH: + successors[0] = pc + ((size + sopp.simm) << 2); + *successorsCount = 1; + + isEnd = true; + break; + + case Sopp::Op::S_CBRANCH_SCC0: + case Sopp::Op::S_CBRANCH_SCC1: + case Sopp::Op::S_CBRANCH_VCCZ: + case Sopp::Op::S_CBRANCH_VCCNZ: + case Sopp::Op::S_CBRANCH_EXECZ: + case Sopp::Op::S_CBRANCH_EXECNZ: + successors[0] = pc + ((size + sopp.simm) << 2); + successors[1] = pc + (size << 2); + *successorsCount = 2; + isEnd = true; + break; + + default: + break; + } + + if (isEnd) + { + break; + } + continue; + } + + // move instruction that requires EXEC test to separate bb + if (instruction.instClass == InstructionClass::Vop2 || + instruction.instClass == InstructionClass::Vop3 || + instruction.instClass == InstructionClass::Mubuf || + instruction.instClass == InstructionClass::Mtbuf || + instruction.instClass == InstructionClass::Mimg || + instruction.instClass == InstructionClass::Ds || + instruction.instClass == InstructionClass::Vintrp || + instruction.instClass == InstructionClass::Exp || + instruction.instClass == InstructionClass::Vop1 || + instruction.instClass == InstructionClass::Vopc || + instruction.instClass == InstructionClass::Smrd) + { + *successorsCount = 1; + + if (instBegin != instHex - size) + { + // if it is not first instruction in block, move end to prev + // instruction, successor is current instruction + instHex -= size; + successors[0] = pc; + break; + } + + successors[0] = pc + (size << 2); + break; + } + } + + return (instHex - instBegin) << 2; + } + + cf::BasicBlock* buildCfg(std::uint64_t entryPoint) + { + std::vector workList; + workList.push_back(entryPoint); + std::unordered_set processed; + processed.insert(entryPoint); + + struct BranchInfo + { + std::uint64_t source; + std::size_t count; + std::uint64_t targets[2]; + }; + + std::vector branches; + + while (!workList.empty()) + { + auto address = workList.back(); + workList.pop_back(); + + auto bb = context->getOrCreateBasicBlock(address); + + if (bb->getSize() != 0) + { + continue; + } + + std::uint64_t successors[2]; + std::size_t successorsCount = 0; + std::size_t size = analyzeBb(bb, successors, &successorsCount); + bb->setSize(size); + + if (successorsCount == 2) + { + branches.push_back( + {address + size - 4, 2, {successors[0], successors[1]}}); + + if (processed.insert(successors[0]).second) + { + workList.push_back(successors[0]); + } + if (processed.insert(successors[1]).second) + { + workList.push_back(successors[1]); + } + } + else if (successorsCount == 1) + { + branches.push_back({address + size - 4, 1, {successors[0]}}); + + if (processed.insert(successors[0]).second) + { + workList.push_back(successors[0]); + } + } + } + + for (auto branch : branches) + { + auto bb = context->getBasicBlock(branch.source); + assert(bb); + if (branch.count == 2) + { + bb->createConditionalBranch( + context->getBasicBlockAt(branch.targets[0]), + context->getBasicBlockAt(branch.targets[1])); + } + else + { + bb->createBranch(context->getBasicBlockAt(branch.targets[0])); + } + } + + return context->getBasicBlockAt(entryPoint); + } }; -cf::BasicBlock *amdgpu::shader::buildCf(cf::Context &ctxt, RemoteMemory memory, - std::uint64_t entryPoint) { - CfgBuilder builder; - builder.context = &ctxt; - builder.memory = memory; +cf::BasicBlock* amdgpu::shader::buildCf(cf::Context& ctxt, RemoteMemory memory, + std::uint64_t entryPoint) +{ + CfgBuilder builder; + builder.context = &ctxt; + builder.memory = memory; - return builder.buildCfg(entryPoint); + return builder.buildCfg(entryPoint); } diff --git a/hw/amdgpu/shader/src/Converter.cpp b/hw/amdgpu/shader/src/Converter.cpp index 8175db8e..e2f17ffc 100644 --- a/hw/amdgpu/shader/src/Converter.cpp +++ b/hw/amdgpu/shader/src/Converter.cpp @@ -14,486 +14,541 @@ #include #include -static void printInstructions(const scf::PrintOptions &options, unsigned depth, - std::uint32_t *instBegin, std::size_t size) { - auto instHex = instBegin; - auto instEnd = instBegin + size / sizeof(std::uint32_t); - - while (instHex < instEnd) { - auto instruction = amdgpu::shader::Instruction(instHex); - std::printf("%s", options.makeIdent(depth).c_str()); - instruction.dump(); - std::printf("\n"); - instHex += instruction.size(); - } +static void printInstructions(const scf::PrintOptions& options, unsigned depth, + std::uint32_t* instBegin, std::size_t size) +{ + auto instHex = instBegin; + auto instEnd = instBegin + size / sizeof(std::uint32_t); + + while (instHex < instEnd) + { + auto instruction = amdgpu::shader::Instruction(instHex); + std::printf("%s", options.makeIdent(depth).c_str()); + instruction.dump(); + std::printf("\n"); + instHex += instruction.size(); + } } -namespace amdgpu::shader { -class Converter { - scf::Context *scfContext; - cf::Context cfContext; - RemoteMemory memory; - Function *function = nullptr; - std::forward_list states; - std::vector freeStates; - -public: - void convertFunction(RemoteMemory mem, scf::Context *scfCtxt, - scf::Block *block, Function *fn) { - scfContext = scfCtxt; - function = fn; - memory = mem; - - auto lastFragment = convertBlock(block, &function->entryFragment, nullptr); - - if (lastFragment != nullptr) { - lastFragment->builder.createBranch(fn->exitFragment.entryBlockId); - lastFragment->appendBranch(fn->exitFragment); - } - - initState(&fn->exitFragment); - } - -private: - RegisterState *allocateState() { - if (freeStates.empty()) { - return &states.emplace_front(); - } - - auto result = freeStates.back(); - freeStates.pop_back(); - *result = {}; - return result; - } - - void releaseState(RegisterState *state) { - assert(state != nullptr); - freeStates.push_back(state); - } - - void initState(Fragment *fragment, std::uint64_t address = 0) { - if (fragment->registers == nullptr) { - fragment->registers = allocateState(); - } - - if (address != 0) { - fragment->registers->pc = address; - } - - fragment->injectValuesFromPreds(); - fragment->predecessors.clear(); - } - - void releaseStateOf(Fragment *frag) { - releaseState(frag->registers); - frag->registers = nullptr; - frag->values = {}; - frag->outputs = {}; - } - - bool needInjectExecTest(Fragment *fragment) { - auto inst = memory.getPointer(fragment->registers->pc); - auto instClass = getInstructionClass(*inst); - return instClass == InstructionClass::Vop2 || - instClass == InstructionClass::Vop3 || - instClass == InstructionClass::Mubuf || - instClass == InstructionClass::Mtbuf || - instClass == InstructionClass::Mimg || - instClass == InstructionClass::Ds || - instClass == InstructionClass::Vintrp || - instClass == InstructionClass::Exp || - instClass == InstructionClass::Vop1 || - instClass == InstructionClass::Vopc /* || +namespace amdgpu::shader +{ + class Converter + { + scf::Context* scfContext; + cf::Context cfContext; + RemoteMemory memory; + Function* function = nullptr; + std::forward_list states; + std::vector freeStates; + + public: + void convertFunction(RemoteMemory mem, scf::Context* scfCtxt, + scf::Block* block, Function* fn) + { + scfContext = scfCtxt; + function = fn; + memory = mem; + + auto lastFragment = convertBlock(block, &function->entryFragment, nullptr); + + if (lastFragment != nullptr) + { + lastFragment->builder.createBranch(fn->exitFragment.entryBlockId); + lastFragment->appendBranch(fn->exitFragment); + } + + initState(&fn->exitFragment); + } + + private: + RegisterState* allocateState() + { + if (freeStates.empty()) + { + return &states.emplace_front(); + } + + auto result = freeStates.back(); + freeStates.pop_back(); + *result = {}; + return result; + } + + void releaseState(RegisterState* state) + { + assert(state != nullptr); + freeStates.push_back(state); + } + + void initState(Fragment* fragment, std::uint64_t address = 0) + { + if (fragment->registers == nullptr) + { + fragment->registers = allocateState(); + } + + if (address != 0) + { + fragment->registers->pc = address; + } + + fragment->injectValuesFromPreds(); + fragment->predecessors.clear(); + } + + void releaseStateOf(Fragment* frag) + { + releaseState(frag->registers); + frag->registers = nullptr; + frag->values = {}; + frag->outputs = {}; + } + + bool needInjectExecTest(Fragment* fragment) + { + auto inst = memory.getPointer(fragment->registers->pc); + auto instClass = getInstructionClass(*inst); + return instClass == InstructionClass::Vop2 || + instClass == InstructionClass::Vop3 || + instClass == InstructionClass::Mubuf || + instClass == InstructionClass::Mtbuf || + instClass == InstructionClass::Mimg || + instClass == InstructionClass::Ds || + instClass == InstructionClass::Vintrp || + instClass == InstructionClass::Exp || + instClass == InstructionClass::Vop1 || + instClass == InstructionClass::Vopc /* || instClass == InstructionClass::Smrd*/ - ; - } - - spirv::BoolValue createExecTest(Fragment *fragment) { - auto context = fragment->context; - auto &builder = fragment->builder; - auto boolT = context->getBoolType(); - auto uint32_0 = context->getUInt32(0); - auto loIsNotZero = - builder.createINotEqual(boolT, fragment->getExecLo().value, uint32_0); - auto hiIsNotZero = - builder.createINotEqual(boolT, fragment->getExecHi().value, uint32_0); - - return builder.createLogicalOr(boolT, loIsNotZero, hiIsNotZero); - } - - Fragment *convertBlock(scf::Block *block, Fragment *rootFragment, - Fragment *loopMergeFragment) { - Fragment *currentFragment = nullptr; - - for (scf::Node *node = block->getRootNode(); node != nullptr; - node = node->getNext()) { - - if (auto bb = dynCast(node)) { - if (currentFragment == nullptr) { - currentFragment = rootFragment; - } else { - auto newFragment = function->createFragment(); - currentFragment->appendBranch(*newFragment); - currentFragment->builder.createBranch(newFragment->entryBlockId); - currentFragment = newFragment; - } - - initState(currentFragment, bb->getAddress()); - for (auto pred : currentFragment->predecessors) { - releaseStateOf(pred); - } - - if (needInjectExecTest(currentFragment)) { - auto bodyFragment = function->createFragment(); - auto mergeFragment = function->createFragment(); - - auto cond = createExecTest(currentFragment); - - currentFragment->appendBranch(*bodyFragment); - currentFragment->appendBranch(*mergeFragment); - currentFragment->builder.createSelectionMerge( - mergeFragment->entryBlockId, {}); - currentFragment->builder.createBranchConditional( - cond, bodyFragment->entryBlockId, mergeFragment->entryBlockId); - - initState(bodyFragment, bb->getAddress()); - bodyFragment->convert(bb->getSize()); - - bodyFragment->appendBranch(*mergeFragment); - bodyFragment->builder.createBranch(mergeFragment->entryBlockId); - - initState(mergeFragment); - releaseState(currentFragment->registers); - releaseState(bodyFragment->registers); - - currentFragment = mergeFragment; - } else { - currentFragment->convert(bb->getSize()); - } - continue; - } - - if (auto ifElse = dynCast(node)) { - auto isBreakBlock = [](scf::Block *block) { - if (block->isEmpty()) { - return false; - } - if (block->getLastNode() != block->getRootNode()) { - return false; - } - - return dynamic_cast(block->getRootNode()) != nullptr; - }; - - if (loopMergeFragment != nullptr && ifElse->ifTrue->isEmpty() && - isBreakBlock(ifElse->ifFalse)) { - auto mergeFragment = function->createFragment(); - currentFragment->appendBranch(*mergeFragment); - currentFragment->appendBranch(*loopMergeFragment); - - currentFragment->builder.createBranchConditional( - currentFragment->branchCondition, mergeFragment->entryBlockId, - loopMergeFragment->entryBlockId); - - initState(mergeFragment); - releaseStateOf(currentFragment); - currentFragment = mergeFragment; - continue; - } - - auto ifTrueFragment = function->createFragment(); - auto ifFalseFragment = function->createFragment(); - auto mergeFragment = function->createFragment(); - - currentFragment->appendBranch(*ifTrueFragment); - currentFragment->appendBranch(*ifFalseFragment); - - auto ifTrueLastBlock = - convertBlock(ifElse->ifTrue, ifTrueFragment, loopMergeFragment); - auto ifFalseLastBlock = - convertBlock(ifElse->ifFalse, ifFalseFragment, loopMergeFragment); - - if (ifTrueLastBlock != nullptr) { - if (!ifTrueLastBlock->hasTerminator) { - ifTrueLastBlock->builder.createBranch(mergeFragment->entryBlockId); - ifTrueLastBlock->appendBranch(*mergeFragment); - } - - if (ifTrueLastBlock->registers == nullptr) { - initState(ifTrueLastBlock); - } - } - - if (ifFalseLastBlock != nullptr) { - if (!ifFalseLastBlock->hasTerminator) { - ifFalseLastBlock->builder.createBranch(mergeFragment->entryBlockId); - ifFalseLastBlock->appendBranch(*mergeFragment); - } - - if (ifFalseLastBlock->registers == nullptr) { - initState(ifFalseLastBlock); - } - } - - currentFragment->builder.createSelectionMerge( - mergeFragment->entryBlockId, {}); - - currentFragment->builder.createBranchConditional( - currentFragment->branchCondition, ifTrueFragment->entryBlockId, - ifFalseFragment->entryBlockId); - - releaseStateOf(currentFragment); - initState(mergeFragment); - - if (ifTrueLastBlock != nullptr) { - releaseStateOf(ifTrueLastBlock); - } - - if (ifFalseLastBlock != nullptr) { - releaseStateOf(ifFalseLastBlock); - } - currentFragment = mergeFragment; - continue; - } - - if (auto loop = dynCast(node)) { - auto headerFragment = function->createFragment(); - auto bodyFragment = function->createFragment(); - auto mergeFragment = function->createDetachedFragment(); - auto continueFragment = function->createDetachedFragment(); - - currentFragment->builder.createBranch(headerFragment->entryBlockId); - currentFragment->appendBranch(*headerFragment); - - initState(headerFragment); - releaseStateOf(currentFragment); - - headerFragment->builder.createLoopMerge( - mergeFragment->entryBlockId, continueFragment->entryBlockId, - spv::LoopControlMask::MaskNone, {}); - - headerFragment->builder.createBranch(bodyFragment->entryBlockId); - headerFragment->appendBranch(*bodyFragment); - - auto bodyLastBlock = - convertBlock(loop->body, bodyFragment, mergeFragment); - - if (bodyLastBlock != nullptr) { - if (bodyLastBlock->registers == nullptr) { - initState(bodyLastBlock); - } - - bodyLastBlock->builder.createBranch(continueFragment->entryBlockId); - bodyLastBlock->appendBranch(*continueFragment); - } - - continueFragment->builder.createBranch(headerFragment->entryBlockId); - continueFragment->appendBranch(*headerFragment); - initState(continueFragment); - - releaseStateOf(headerFragment); - initState(mergeFragment); - - if (bodyLastBlock != nullptr) { - releaseStateOf(bodyLastBlock); - } - - function->appendFragment(continueFragment); - function->appendFragment(mergeFragment); - releaseStateOf(continueFragment); - - currentFragment = mergeFragment; - continue; - } - - if (dynCast(node)) { - auto jumpAddress = currentFragment->jumpAddress; - - std::printf("jump to %lx\n", jumpAddress); - std::fflush(stdout); - - if (jumpAddress == 0) { - util::unreachable("no jump register on unknown block"); - } - - auto block = buildCf(cfContext, memory, jumpAddress); - auto basicBlockPrinter = [this](const scf::PrintOptions &opts, - unsigned depth, scf::BasicBlock *bb) { - printInstructions(opts, depth, - memory.getPointer(bb->getAddress()), - bb->getSize()); - }; - auto scfBlock = scf::structurize(*scfContext, block); - scfBlock->print({.blockPrinter = basicBlockPrinter}, 0); - std::fflush(stdout); - - auto targetFragment = function->createFragment(); - currentFragment->builder.createBranch(targetFragment->entryBlockId); - currentFragment->appendBranch(*targetFragment); - auto result = convertBlock(scfBlock, targetFragment, nullptr); - - if (currentFragment->registers == nullptr) { - initState(targetFragment); - releaseStateOf(currentFragment); - } - - return result; - } - - if (dynCast(node)) { - currentFragment->appendBranch(function->exitFragment); - currentFragment->builder.createBranch( - function->exitFragment.entryBlockId); - currentFragment->hasTerminator = true; - return nullptr; - } - - node->dump(); - util::unreachable(); - } - - return currentFragment != nullptr ? currentFragment : rootFragment; - } -}; + ; + } + + spirv::BoolValue createExecTest(Fragment* fragment) + { + auto context = fragment->context; + auto& builder = fragment->builder; + auto boolT = context->getBoolType(); + auto uint32_0 = context->getUInt32(0); + auto loIsNotZero = + builder.createINotEqual(boolT, fragment->getExecLo().value, uint32_0); + auto hiIsNotZero = + builder.createINotEqual(boolT, fragment->getExecHi().value, uint32_0); + + return builder.createLogicalOr(boolT, loIsNotZero, hiIsNotZero); + } + + Fragment* convertBlock(scf::Block* block, Fragment* rootFragment, + Fragment* loopMergeFragment) + { + Fragment* currentFragment = nullptr; + + for (scf::Node* node = block->getRootNode(); node != nullptr; + node = node->getNext()) + { + + if (auto bb = dynCast(node)) + { + if (currentFragment == nullptr) + { + currentFragment = rootFragment; + } + else + { + auto newFragment = function->createFragment(); + currentFragment->appendBranch(*newFragment); + currentFragment->builder.createBranch(newFragment->entryBlockId); + currentFragment = newFragment; + } + + initState(currentFragment, bb->getAddress()); + for (auto pred : currentFragment->predecessors) + { + releaseStateOf(pred); + } + + if (needInjectExecTest(currentFragment)) + { + auto bodyFragment = function->createFragment(); + auto mergeFragment = function->createFragment(); + + auto cond = createExecTest(currentFragment); + + currentFragment->appendBranch(*bodyFragment); + currentFragment->appendBranch(*mergeFragment); + currentFragment->builder.createSelectionMerge( + mergeFragment->entryBlockId, {}); + currentFragment->builder.createBranchConditional( + cond, bodyFragment->entryBlockId, mergeFragment->entryBlockId); + + initState(bodyFragment, bb->getAddress()); + bodyFragment->convert(bb->getSize()); + + bodyFragment->appendBranch(*mergeFragment); + bodyFragment->builder.createBranch(mergeFragment->entryBlockId); + + initState(mergeFragment); + releaseState(currentFragment->registers); + releaseState(bodyFragment->registers); + + currentFragment = mergeFragment; + } + else + { + currentFragment->convert(bb->getSize()); + } + continue; + } + + if (auto ifElse = dynCast(node)) + { + auto isBreakBlock = [](scf::Block* block) { + if (block->isEmpty()) + { + return false; + } + if (block->getLastNode() != block->getRootNode()) + { + return false; + } + + return dynamic_cast(block->getRootNode()) != nullptr; + }; + + if (loopMergeFragment != nullptr && ifElse->ifTrue->isEmpty() && + isBreakBlock(ifElse->ifFalse)) + { + auto mergeFragment = function->createFragment(); + currentFragment->appendBranch(*mergeFragment); + currentFragment->appendBranch(*loopMergeFragment); + + currentFragment->builder.createBranchConditional( + currentFragment->branchCondition, mergeFragment->entryBlockId, + loopMergeFragment->entryBlockId); + + initState(mergeFragment); + releaseStateOf(currentFragment); + currentFragment = mergeFragment; + continue; + } + + auto ifTrueFragment = function->createFragment(); + auto ifFalseFragment = function->createFragment(); + auto mergeFragment = function->createFragment(); + + currentFragment->appendBranch(*ifTrueFragment); + currentFragment->appendBranch(*ifFalseFragment); + + auto ifTrueLastBlock = + convertBlock(ifElse->ifTrue, ifTrueFragment, loopMergeFragment); + auto ifFalseLastBlock = + convertBlock(ifElse->ifFalse, ifFalseFragment, loopMergeFragment); + + if (ifTrueLastBlock != nullptr) + { + if (!ifTrueLastBlock->hasTerminator) + { + ifTrueLastBlock->builder.createBranch(mergeFragment->entryBlockId); + ifTrueLastBlock->appendBranch(*mergeFragment); + } + + if (ifTrueLastBlock->registers == nullptr) + { + initState(ifTrueLastBlock); + } + } + + if (ifFalseLastBlock != nullptr) + { + if (!ifFalseLastBlock->hasTerminator) + { + ifFalseLastBlock->builder.createBranch(mergeFragment->entryBlockId); + ifFalseLastBlock->appendBranch(*mergeFragment); + } + + if (ifFalseLastBlock->registers == nullptr) + { + initState(ifFalseLastBlock); + } + } + + currentFragment->builder.createSelectionMerge( + mergeFragment->entryBlockId, {}); + + currentFragment->builder.createBranchConditional( + currentFragment->branchCondition, ifTrueFragment->entryBlockId, + ifFalseFragment->entryBlockId); + + releaseStateOf(currentFragment); + initState(mergeFragment); + + if (ifTrueLastBlock != nullptr) + { + releaseStateOf(ifTrueLastBlock); + } + + if (ifFalseLastBlock != nullptr) + { + releaseStateOf(ifFalseLastBlock); + } + currentFragment = mergeFragment; + continue; + } + + if (auto loop = dynCast(node)) + { + auto headerFragment = function->createFragment(); + auto bodyFragment = function->createFragment(); + auto mergeFragment = function->createDetachedFragment(); + auto continueFragment = function->createDetachedFragment(); + + currentFragment->builder.createBranch(headerFragment->entryBlockId); + currentFragment->appendBranch(*headerFragment); + + initState(headerFragment); + releaseStateOf(currentFragment); + + headerFragment->builder.createLoopMerge( + mergeFragment->entryBlockId, continueFragment->entryBlockId, + spv::LoopControlMask::MaskNone, {}); + + headerFragment->builder.createBranch(bodyFragment->entryBlockId); + headerFragment->appendBranch(*bodyFragment); + + auto bodyLastBlock = + convertBlock(loop->body, bodyFragment, mergeFragment); + + if (bodyLastBlock != nullptr) + { + if (bodyLastBlock->registers == nullptr) + { + initState(bodyLastBlock); + } + + bodyLastBlock->builder.createBranch(continueFragment->entryBlockId); + bodyLastBlock->appendBranch(*continueFragment); + } + + continueFragment->builder.createBranch(headerFragment->entryBlockId); + continueFragment->appendBranch(*headerFragment); + initState(continueFragment); + + releaseStateOf(headerFragment); + initState(mergeFragment); + + if (bodyLastBlock != nullptr) + { + releaseStateOf(bodyLastBlock); + } + + function->appendFragment(continueFragment); + function->appendFragment(mergeFragment); + releaseStateOf(continueFragment); + + currentFragment = mergeFragment; + continue; + } + + if (dynCast(node)) + { + auto jumpAddress = currentFragment->jumpAddress; + + std::printf("jump to %lx\n", jumpAddress); + std::fflush(stdout); + + if (jumpAddress == 0) + { + util::unreachable("no jump register on unknown block"); + } + + auto block = buildCf(cfContext, memory, jumpAddress); + auto basicBlockPrinter = [this](const scf::PrintOptions& opts, + unsigned depth, scf::BasicBlock* bb) { + printInstructions(opts, depth, + memory.getPointer(bb->getAddress()), + bb->getSize()); + }; + auto scfBlock = scf::structurize(*scfContext, block); + scfBlock->print({.blockPrinter = basicBlockPrinter}, 0); + std::fflush(stdout); + + auto targetFragment = function->createFragment(); + currentFragment->builder.createBranch(targetFragment->entryBlockId); + currentFragment->appendBranch(*targetFragment); + auto result = convertBlock(scfBlock, targetFragment, nullptr); + + if (currentFragment->registers == nullptr) + { + initState(targetFragment); + releaseStateOf(currentFragment); + } + + return result; + } + + if (dynCast(node)) + { + currentFragment->appendBranch(function->exitFragment); + currentFragment->builder.createBranch( + function->exitFragment.entryBlockId); + currentFragment->hasTerminator = true; + return nullptr; + } + + node->dump(); + util::unreachable(); + } + + return currentFragment != nullptr ? currentFragment : rootFragment; + } + }; }; // namespace amdgpu::shader amdgpu::shader::Shader amdgpu::shader::convert(RemoteMemory memory, Stage stage, std::uint64_t entry, - std::span userSpgrs, - std::uint32_t dimX, std::uint32_t dimY, - std::uint32_t dimZ, - util::MemoryAreaTable<> &dependencies) { - ConverterContext ctxt(memory, stage, &dependencies); - auto &builder = ctxt.getBuilder(); - builder.createCapability(spv::Capability::Shader); - builder.createCapability(spv::Capability::ImageQuery); - builder.createCapability(spv::Capability::ImageBuffer); - builder.createCapability(spv::Capability::UniformAndStorageBuffer8BitAccess); - builder.createCapability(spv::Capability::UniformAndStorageBuffer16BitAccess); - builder.createCapability(spv::Capability::Int64); - builder.createCapability(spv::Capability::StorageImageWriteWithoutFormat); - builder.createCapability(spv::Capability::StorageImageReadWithoutFormat); - builder.setMemoryModel(spv::AddressingModel::Logical, - spv::MemoryModel::GLSL450); - - scf::Context scfContext; - scf::Block *entryBlock = nullptr; - { - cf::Context cfContext; - auto entryBB = buildCf(cfContext, memory, entry); - entryBlock = scf::structurize(scfContext, entryBB); - } - - // std::printf("========== stage: %u, user sgprs: %zu\n", (unsigned)stage, - // userSpgrs.size()); - // std::printf("structurized CFG:\n"); - - // auto basicBlockPrinter = [memory](const scf::PrintOptions &opts, - // unsigned depth, scf::BasicBlock *bb) { - // printInstructions(opts, depth, - // memory.getPointer(bb->getAddress()), - // bb->getSize()); - // }; - - // entryBlock->print({.blockPrinter = basicBlockPrinter}, 0); - // std::printf("==========\n"); - - auto mainFunction = ctxt.createFunction(0); - mainFunction->userSgprs = userSpgrs; - mainFunction->stage = stage; - - Converter converter; - converter.convertFunction(memory, &scfContext, entryBlock, mainFunction); - - Shader result; - - std::fflush(stdout); - mainFunction->exitFragment.outputs.clear(); - - std::size_t samplerCount = 0; - std::size_t imageCount = 0; - std::size_t storageImageCount = 0; - std::size_t bufferCount = 0; - - for (auto &uniform : ctxt.getUniforms()) { - auto &newUniform = result.uniforms.emplace_back(); - - for (int i = 0; i < 8; ++i) { - newUniform.buffer[i] = uniform.buffer[i]; - } - - std::uint32_t descriptorSet = 0; - - switch (uniform.typeId) { - case TypeId::Sampler: - newUniform.kind = Shader::UniformKind::Sampler; - newUniform.binding = - UniformBindings::getSamplerBinding(stage, samplerCount++); - break; - case TypeId::StorageImage2D: - newUniform.kind = Shader::UniformKind::StorageImage; - newUniform.binding = - UniformBindings::getStorageImageBinding(stage, storageImageCount++); - break; - case TypeId::Image2D: - newUniform.kind = Shader::UniformKind::Image; - newUniform.binding = - UniformBindings::getImageBinding(stage, imageCount++); - break; - default: - newUniform.kind = Shader::UniformKind::Buffer; - newUniform.binding = - UniformBindings::getBufferBinding(stage, bufferCount++); - break; - } - - ctxt.getBuilder().createDecorate( - uniform.variable, spv::Decoration::DescriptorSet, {{descriptorSet}}); - ctxt.getBuilder().createDecorate(uniform.variable, spv::Decoration::Binding, - {{newUniform.binding}}); - - newUniform.accessOp = uniform.accessOp; - } - - mainFunction->insertReturn(); - - for (auto frag : mainFunction->fragments) { - mainFunction->builder.insertBlock(frag->builder); - } - - mainFunction->builder.insertBlock(mainFunction->exitFragment.builder); - - builder.insertFunction(mainFunction->builder, mainFunction->getResultType(), - spv::FunctionControlMask::MaskNone, - mainFunction->getFunctionType()); - - if (stage == Stage::Vertex) { - builder.createEntryPoint(spv::ExecutionModel::Vertex, - mainFunction->builder.id, "main", - ctxt.getInterfaces()); - } else if (stage == Stage::Fragment) { - builder.createEntryPoint(spv::ExecutionModel::Fragment, - mainFunction->builder.id, "main", - ctxt.getInterfaces()); - builder.createExecutionMode(mainFunction->builder.id, - spv::ExecutionMode::OriginUpperLeft, {}); - } else if (stage == Stage::Compute) { - builder.createEntryPoint(spv::ExecutionModel::GLCompute, - mainFunction->builder.id, "main", - ctxt.getInterfaces()); - builder.createExecutionMode(mainFunction->builder.id, - spv::ExecutionMode::LocalSize, - {{dimX, dimY, dimZ}}); - } - - // auto maxId = ctxt.getBuilder().getIdGenerator()->bounds; - // for (std::size_t i = 1; i < maxId; ++i) { - // spirv::Id id; - // id.id = i; - // if (builder.isIdDefined(id) && !builder.isIdUsed(id)) { - // std::printf("ssa variable %%%zu defined, but not used\n", i); - // } - // } - result.spirv = builder.build(SPV_VERSION, 0); - return result; + std::span userSpgrs, + std::uint32_t dimX, std::uint32_t dimY, + std::uint32_t dimZ, + util::MemoryAreaTable<>& dependencies) +{ + ConverterContext ctxt(memory, stage, &dependencies); + auto& builder = ctxt.getBuilder(); + builder.createCapability(spv::Capability::Shader); + builder.createCapability(spv::Capability::ImageQuery); + builder.createCapability(spv::Capability::ImageBuffer); + builder.createCapability(spv::Capability::UniformAndStorageBuffer8BitAccess); + builder.createCapability(spv::Capability::UniformAndStorageBuffer16BitAccess); + builder.createCapability(spv::Capability::Int64); + builder.createCapability(spv::Capability::StorageImageWriteWithoutFormat); + builder.createCapability(spv::Capability::StorageImageReadWithoutFormat); + builder.setMemoryModel(spv::AddressingModel::Logical, + spv::MemoryModel::GLSL450); + + scf::Context scfContext; + scf::Block* entryBlock = nullptr; + { + cf::Context cfContext; + auto entryBB = buildCf(cfContext, memory, entry); + entryBlock = scf::structurize(scfContext, entryBB); + } + + // std::printf("========== stage: %u, user sgprs: %zu\n", (unsigned)stage, + // userSpgrs.size()); + // std::printf("structurized CFG:\n"); + + // auto basicBlockPrinter = [memory](const scf::PrintOptions &opts, + // unsigned depth, scf::BasicBlock *bb) { + // printInstructions(opts, depth, + // memory.getPointer(bb->getAddress()), + // bb->getSize()); + // }; + + // entryBlock->print({.blockPrinter = basicBlockPrinter}, 0); + // std::printf("==========\n"); + + auto mainFunction = ctxt.createFunction(0); + mainFunction->userSgprs = userSpgrs; + mainFunction->stage = stage; + + Converter converter; + converter.convertFunction(memory, &scfContext, entryBlock, mainFunction); + + Shader result; + + std::fflush(stdout); + mainFunction->exitFragment.outputs.clear(); + + std::size_t samplerCount = 0; + std::size_t imageCount = 0; + std::size_t storageImageCount = 0; + std::size_t bufferCount = 0; + + for (auto& uniform : ctxt.getUniforms()) + { + auto& newUniform = result.uniforms.emplace_back(); + + for (int i = 0; i < 8; ++i) + { + newUniform.buffer[i] = uniform.buffer[i]; + } + + std::uint32_t descriptorSet = 0; + + switch (uniform.typeId) + { + case TypeId::Sampler: + newUniform.kind = Shader::UniformKind::Sampler; + newUniform.binding = + UniformBindings::getSamplerBinding(stage, samplerCount++); + break; + case TypeId::StorageImage2D: + newUniform.kind = Shader::UniformKind::StorageImage; + newUniform.binding = + UniformBindings::getStorageImageBinding(stage, storageImageCount++); + break; + case TypeId::Image2D: + newUniform.kind = Shader::UniformKind::Image; + newUniform.binding = + UniformBindings::getImageBinding(stage, imageCount++); + break; + default: + newUniform.kind = Shader::UniformKind::Buffer; + newUniform.binding = + UniformBindings::getBufferBinding(stage, bufferCount++); + break; + } + + ctxt.getBuilder().createDecorate( + uniform.variable, spv::Decoration::DescriptorSet, {{descriptorSet}}); + ctxt.getBuilder().createDecorate(uniform.variable, spv::Decoration::Binding, + {{newUniform.binding}}); + + newUniform.accessOp = uniform.accessOp; + } + + mainFunction->insertReturn(); + + for (auto frag : mainFunction->fragments) + { + mainFunction->builder.insertBlock(frag->builder); + } + + mainFunction->builder.insertBlock(mainFunction->exitFragment.builder); + + builder.insertFunction(mainFunction->builder, mainFunction->getResultType(), + spv::FunctionControlMask::MaskNone, + mainFunction->getFunctionType()); + + if (stage == Stage::Vertex) + { + builder.createEntryPoint(spv::ExecutionModel::Vertex, + mainFunction->builder.id, "main", + ctxt.getInterfaces()); + } + else if (stage == Stage::Fragment) + { + builder.createEntryPoint(spv::ExecutionModel::Fragment, + mainFunction->builder.id, "main", + ctxt.getInterfaces()); + builder.createExecutionMode(mainFunction->builder.id, + spv::ExecutionMode::OriginUpperLeft, {}); + } + else if (stage == Stage::Compute) + { + builder.createEntryPoint(spv::ExecutionModel::GLCompute, + mainFunction->builder.id, "main", + ctxt.getInterfaces()); + builder.createExecutionMode(mainFunction->builder.id, + spv::ExecutionMode::LocalSize, + {{dimX, dimY, dimZ}}); + } + + // auto maxId = ctxt.getBuilder().getIdGenerator()->bounds; + // for (std::size_t i = 1; i < maxId; ++i) { + // spirv::Id id; + // id.id = i; + // if (builder.isIdDefined(id) && !builder.isIdUsed(id)) { + // std::printf("ssa variable %%%zu defined, but not used\n", i); + // } + // } + result.spirv = builder.build(SPV_VERSION, 0); + return result; } diff --git a/hw/amdgpu/shader/src/ConverterContext.cpp b/hw/amdgpu/shader/src/ConverterContext.cpp index 0dc316a1..b1335e99 100644 --- a/hw/amdgpu/shader/src/ConverterContext.cpp +++ b/hw/amdgpu/shader/src/ConverterContext.cpp @@ -2,571 +2,652 @@ #include "util/unreachable.hpp" using namespace amdgpu::shader; -std::optional ConverterContext::getTypeIdOf(spirv::Type type) const { - for (int i = 0; i < kGenericTypesCount; ++i) { - if (mTypes[i] == type) { - return static_cast(i); - } - } - - return std::nullopt; +std::optional ConverterContext::getTypeIdOf(spirv::Type type) const +{ + for (int i = 0; i < kGenericTypesCount; ++i) + { + if (mTypes[i] == type) + { + return static_cast(i); + } + } + + return std::nullopt; } spirv::StructType -ConverterContext::findStructType(std::span members) { - for (auto &structType : mStructTypes) { - if (structType.match(members)) { - return structType.id; - } - } - - return {}; +ConverterContext::findStructType(std::span members) +{ + for (auto& structType : mStructTypes) + { + if (structType.match(members)) + { + return structType.id; + } + } + + return {}; } spirv::StructType -ConverterContext::getStructType(std::span members) { - for (auto &structType : mStructTypes) { - if (structType.match(members)) { - return structType.id; - } - } - - auto &newType = mStructTypes.emplace_back(); - newType.id = mBuilder.createTypeStruct(members); - newType.members.reserve(members.size()); - for (auto member : members) { - newType.members.push_back(member); - } - return newType.id; +ConverterContext::getStructType(std::span members) +{ + for (auto& structType : mStructTypes) + { + if (structType.match(members)) + { + return structType.id; + } + } + + auto& newType = mStructTypes.emplace_back(); + newType.id = mBuilder.createTypeStruct(members); + newType.members.reserve(members.size()); + for (auto member : members) + { + newType.members.push_back(member); + } + return newType.id; } spirv::PointerType ConverterContext::getStructPointerType(spv::StorageClass storageClass, - spirv::StructType structType) { - StructTypeEntry *entry = nullptr; - for (auto &type : mStructTypes) { - if (type.id != structType) { - continue; - } - - entry = &type; - break; - } - - if (entry == nullptr) { - util::unreachable("Struct type not found"); - } - - auto &ptrType = entry->ptrTypes[static_cast(storageClass)]; - - if (!ptrType) { - ptrType = mBuilder.createTypePointer(storageClass, structType); - } - - return ptrType; + spirv::StructType structType) +{ + StructTypeEntry* entry = nullptr; + for (auto& type : mStructTypes) + { + if (type.id != structType) + { + continue; + } + + entry = &type; + break; + } + + if (entry == nullptr) + { + util::unreachable("Struct type not found"); + } + + auto& ptrType = entry->ptrTypes[static_cast(storageClass)]; + + if (!ptrType) + { + ptrType = mBuilder.createTypePointer(storageClass, structType); + } + + return ptrType; } -spirv::Type ConverterContext::getType(TypeId id) { - auto &type = mTypes[static_cast(id)]; - - if (type) { - return type; - } - - switch (id) { - case TypeId::Void: - return ((type = mBuilder.createTypeVoid())); - case TypeId::Bool: - return ((type = mBuilder.createTypeBool())); - case TypeId::SInt8: - return ((type = mBuilder.createTypeSInt(8))); - case TypeId::UInt8: - return ((type = mBuilder.createTypeUInt(8))); - case TypeId::SInt16: - return ((type = mBuilder.createTypeSInt(16))); - case TypeId::UInt16: - return ((type = mBuilder.createTypeUInt(16))); - case TypeId::SInt32: - return ((type = mBuilder.createTypeSInt(32))); - case TypeId::UInt32: - return ((type = mBuilder.createTypeUInt(32))); - case TypeId::UInt32x2: - return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 2))); - case TypeId::UInt32x3: - return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 3))); - case TypeId::UInt32x4: - return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 4))); - case TypeId::UInt64: - return ((type = mBuilder.createTypeUInt(64))); - case TypeId::SInt64: - return ((type = mBuilder.createTypeSInt(64))); - case TypeId::ArrayUInt32x8: - type = mBuilder.createTypeArray(getType(TypeId::UInt32x4), getUInt32(2)); - getBuilder().createDecorate(type, spv::Decoration::ArrayStride, - std::array{static_cast(16)}); - case TypeId::ArrayUInt32x16: - type = mBuilder.createTypeArray(getType(TypeId::UInt32x4), getUInt32(4)); - getBuilder().createDecorate(type, spv::Decoration::ArrayStride, - std::array{static_cast(16)}); - return type; - case TypeId::Float16: - return ((type = mBuilder.createTypeFloat(16))); - case TypeId::Float32: - return ((type = mBuilder.createTypeFloat(32))); - case TypeId::Float32x2: - return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 2))); - case TypeId::Float32x3: - return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 3))); - case TypeId::Float32x4: - return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 4))); - case TypeId::Float64: - return ((type = mBuilder.createTypeFloat(64))); - case TypeId::ArrayFloat32x8: - type = mBuilder.createTypeArray(getType(TypeId::Float32x4), getUInt32(2)); - getBuilder().createDecorate(type, spv::Decoration::ArrayStride, - std::array{static_cast(16)}); - return type; - case TypeId::ArrayFloat32x16: - type = mBuilder.createTypeArray(getType(TypeId::Float32x4), getUInt32(4)); - getBuilder().createDecorate(type, spv::Decoration::ArrayStride, - std::array{static_cast(16)}); - return type; - - case TypeId::Image2D: - return ((type = getBuilder().createTypeImage(getFloat32Type(), - spv::Dim::Dim2D, 0, 0, 0, 1, - spv::ImageFormat::Unknown))); - case TypeId::StorageImage2D: - return ((type = getBuilder().createTypeImage(getFloat32Type(), - spv::Dim::Dim2D, 0, 0, 0, 2, - spv::ImageFormat::Unknown))); - case TypeId::SampledImage2D: - return ((type = getBuilder().createTypeSampledImage(getImage2DType()))); - - case TypeId::Sampler: - return ((type = getBuilder().createTypeSampler())); - } - - util::unreachable(); +spirv::Type ConverterContext::getType(TypeId id) +{ + auto& type = mTypes[static_cast(id)]; + + if (type) + { + return type; + } + + switch (id) + { + case TypeId::Void: + return ((type = mBuilder.createTypeVoid())); + case TypeId::Bool: + return ((type = mBuilder.createTypeBool())); + case TypeId::SInt8: + return ((type = mBuilder.createTypeSInt(8))); + case TypeId::UInt8: + return ((type = mBuilder.createTypeUInt(8))); + case TypeId::SInt16: + return ((type = mBuilder.createTypeSInt(16))); + case TypeId::UInt16: + return ((type = mBuilder.createTypeUInt(16))); + case TypeId::SInt32: + return ((type = mBuilder.createTypeSInt(32))); + case TypeId::UInt32: + return ((type = mBuilder.createTypeUInt(32))); + case TypeId::UInt32x2: + return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 2))); + case TypeId::UInt32x3: + return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 3))); + case TypeId::UInt32x4: + return ((type = mBuilder.createTypeVector(getType(TypeId::UInt32), 4))); + case TypeId::UInt64: + return ((type = mBuilder.createTypeUInt(64))); + case TypeId::SInt64: + return ((type = mBuilder.createTypeSInt(64))); + case TypeId::ArrayUInt32x8: + type = mBuilder.createTypeArray(getType(TypeId::UInt32x4), getUInt32(2)); + getBuilder().createDecorate(type, spv::Decoration::ArrayStride, + std::array{static_cast(16)}); + case TypeId::ArrayUInt32x16: + type = mBuilder.createTypeArray(getType(TypeId::UInt32x4), getUInt32(4)); + getBuilder().createDecorate(type, spv::Decoration::ArrayStride, + std::array{static_cast(16)}); + return type; + case TypeId::Float16: + return ((type = mBuilder.createTypeFloat(16))); + case TypeId::Float32: + return ((type = mBuilder.createTypeFloat(32))); + case TypeId::Float32x2: + return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 2))); + case TypeId::Float32x3: + return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 3))); + case TypeId::Float32x4: + return ((type = mBuilder.createTypeVector(getType(TypeId::Float32), 4))); + case TypeId::Float64: + return ((type = mBuilder.createTypeFloat(64))); + case TypeId::ArrayFloat32x8: + type = mBuilder.createTypeArray(getType(TypeId::Float32x4), getUInt32(2)); + getBuilder().createDecorate(type, spv::Decoration::ArrayStride, + std::array{static_cast(16)}); + return type; + case TypeId::ArrayFloat32x16: + type = mBuilder.createTypeArray(getType(TypeId::Float32x4), getUInt32(4)); + getBuilder().createDecorate(type, spv::Decoration::ArrayStride, + std::array{static_cast(16)}); + return type; + + case TypeId::Image2D: + return ((type = getBuilder().createTypeImage(getFloat32Type(), + spv::Dim::Dim2D, 0, 0, 0, 1, + spv::ImageFormat::Unknown))); + case TypeId::StorageImage2D: + return ((type = getBuilder().createTypeImage(getFloat32Type(), + spv::Dim::Dim2D, 0, 0, 0, 2, + spv::ImageFormat::Unknown))); + case TypeId::SampledImage2D: + return ((type = getBuilder().createTypeSampledImage(getImage2DType()))); + + case TypeId::Sampler: + return ((type = getBuilder().createTypeSampler())); + } + + util::unreachable(); } -spirv::RuntimeArrayType ConverterContext::getRuntimeArrayType(TypeId id) { - auto &type = mRuntimeArrayTypes[static_cast(id)]; +spirv::RuntimeArrayType ConverterContext::getRuntimeArrayType(TypeId id) +{ + auto& type = mRuntimeArrayTypes[static_cast(id)]; - if (!type) { - type = mBuilder.createTypeRuntimeArray(getType(id)); - mBuilder.createDecorate(type, spv::Decoration::ArrayStride, - {{(std::uint32_t)id.getSize()}}); - } + if (!type) + { + type = mBuilder.createTypeRuntimeArray(getType(id)); + mBuilder.createDecorate(type, spv::Decoration::ArrayStride, + {{(std::uint32_t)id.getSize()}}); + } - return type; + return type; } -spirv::ConstantUInt ConverterContext::getUInt64(std::uint64_t value) { - auto &id = mConstantUint64Map[value]; - if (!id) { - id = mBuilder.createConstant64(getUInt64Type(), value); - } - return id; +spirv::ConstantUInt ConverterContext::getUInt64(std::uint64_t value) +{ + auto& id = mConstantUint64Map[value]; + if (!id) + { + id = mBuilder.createConstant64(getUInt64Type(), value); + } + return id; } -spirv::ConstantUInt ConverterContext::getUInt32(std::uint32_t value) { - auto &id = mConstantUint32Map[value]; - if (!id) { - id = mBuilder.createConstant32(getUInt32Type(), value); - } - return id; +spirv::ConstantUInt ConverterContext::getUInt32(std::uint32_t value) +{ + auto& id = mConstantUint32Map[value]; + if (!id) + { + id = mBuilder.createConstant32(getUInt32Type(), value); + } + return id; } -spirv::ConstantSInt ConverterContext::getSInt32(std::uint32_t value) { - auto &id = mConstantSint32Map[value]; - if (!id) { - id = mBuilder.createConstant32(getSint32Type(), value); - } - return id; +spirv::ConstantSInt ConverterContext::getSInt32(std::uint32_t value) +{ + auto& id = mConstantSint32Map[value]; + if (!id) + { + id = mBuilder.createConstant32(getSint32Type(), value); + } + return id; } -spirv::ConstantFloat ConverterContext::getFloat32Raw(std::uint32_t value) { - auto &id = mConstantFloat32Map[value]; - if (!id) { - id = mBuilder.createConstant32(getFloat32Type(), value); - } - return id; +spirv::ConstantFloat ConverterContext::getFloat32Raw(std::uint32_t value) +{ + auto& id = mConstantFloat32Map[value]; + if (!id) + { + id = mBuilder.createConstant32(getFloat32Type(), value); + } + return id; } -UniformInfo *ConverterContext::createStorageBuffer(TypeId type) { - std::array uniformStructMembers{getRuntimeArrayType(type)}; - auto uniformStruct = findStructType(uniformStructMembers); - - if (!uniformStruct) { - uniformStruct = getStructType(uniformStructMembers); - - getBuilder().createDecorate(uniformStruct, spv::Decoration::Block, {}); - - getBuilder().createMemberDecorate( - uniformStruct, 0, spv::Decoration::Offset, - std::array{static_cast(0)}); - } - - auto uniformType = - getStructPointerType(spv::StorageClass::StorageBuffer, uniformStruct); - auto uniformVariable = getBuilder().createVariable( - uniformType, spv::StorageClass::StorageBuffer); - - mInterfaces.push_back(uniformVariable); - - auto &newUniform = mUniforms.emplace_back(); - newUniform.index = mUniforms.size() - 1; - newUniform.typeId = type; - newUniform.type = uniformType; - newUniform.variable = uniformVariable; - newUniform.isBuffer = true; - std::printf("new storage buffer %u of type %u\n", newUniform.index, - newUniform.typeId.raw); - return &newUniform; +UniformInfo* ConverterContext::createStorageBuffer(TypeId type) +{ + std::array uniformStructMembers{getRuntimeArrayType(type)}; + auto uniformStruct = findStructType(uniformStructMembers); + + if (!uniformStruct) + { + uniformStruct = getStructType(uniformStructMembers); + + getBuilder().createDecorate(uniformStruct, spv::Decoration::Block, {}); + + getBuilder().createMemberDecorate( + uniformStruct, 0, spv::Decoration::Offset, + std::array{static_cast(0)}); + } + + auto uniformType = + getStructPointerType(spv::StorageClass::StorageBuffer, uniformStruct); + auto uniformVariable = getBuilder().createVariable( + uniformType, spv::StorageClass::StorageBuffer); + + mInterfaces.push_back(uniformVariable); + + auto& newUniform = mUniforms.emplace_back(); + newUniform.index = mUniforms.size() - 1; + newUniform.typeId = type; + newUniform.type = uniformType; + newUniform.variable = uniformVariable; + newUniform.isBuffer = true; + std::printf("new storage buffer %u of type %u\n", newUniform.index, + newUniform.typeId.raw); + return &newUniform; } -UniformInfo *ConverterContext::getOrCreateStorageBuffer(std::uint32_t *vbuffer, - TypeId type) { - for (auto &uniform : mUniforms) { - if (std::memcmp(uniform.buffer, vbuffer, sizeof(std::uint32_t) * 4)) { - continue; - } - - if (uniform.typeId != type) { - util::unreachable("getOrCreateStorageBuffer: access to the uniform with " - "different type"); - } - - if (!uniform.isBuffer) { - util::unreachable("getOrCreateStorageBuffer: uniform was constant"); - } - - // std::printf("reuse storage buffer %u of type %u\n", uniform.index, - // uniform.typeId.raw); - return &uniform; - } - - auto newUniform = createStorageBuffer(type); - std::memcpy(newUniform->buffer, vbuffer, sizeof(std::uint32_t) * 4); - return newUniform; +UniformInfo* ConverterContext::getOrCreateStorageBuffer(std::uint32_t* vbuffer, + TypeId type) +{ + for (auto& uniform : mUniforms) + { + if (std::memcmp(uniform.buffer, vbuffer, sizeof(std::uint32_t) * 4)) + { + continue; + } + + if (uniform.typeId != type) + { + util::unreachable("getOrCreateStorageBuffer: access to the uniform with " + "different type"); + } + + if (!uniform.isBuffer) + { + util::unreachable("getOrCreateStorageBuffer: uniform was constant"); + } + + // std::printf("reuse storage buffer %u of type %u\n", uniform.index, + // uniform.typeId.raw); + return &uniform; + } + + auto newUniform = createStorageBuffer(type); + std::memcpy(newUniform->buffer, vbuffer, sizeof(std::uint32_t) * 4); + return newUniform; } -UniformInfo *ConverterContext::getOrCreateUniformConstant(std::uint32_t *buffer, - std::size_t size, - TypeId type) { - for (auto &uniform : mUniforms) { - if (std::memcmp(uniform.buffer, buffer, sizeof(std::uint32_t) * size)) { - continue; - } - - if (uniform.typeId != type) { - util::unreachable( - "getOrCreateUniformConstant: access to the uniform with " - "different type"); - } - - if (uniform.isBuffer) { - util::unreachable("getOrCreateUniformConstant: uniform was buffer"); - } - - return &uniform; - } - - auto uniformType = getPointerType(spv::StorageClass::UniformConstant, type); - auto uniformVariable = getBuilder().createVariable( - uniformType, spv::StorageClass::UniformConstant); - mInterfaces.push_back(uniformVariable); - - auto &newUniform = mUniforms.emplace_back(); - newUniform.index = mUniforms.size() - 1; - newUniform.typeId = type; - newUniform.type = uniformType; - newUniform.variable = uniformVariable; - newUniform.isBuffer = false; - std::memcpy(newUniform.buffer, buffer, sizeof(std::uint32_t) * size); - - return &newUniform; +UniformInfo* ConverterContext::getOrCreateUniformConstant(std::uint32_t* buffer, + std::size_t size, + TypeId type) +{ + for (auto& uniform : mUniforms) + { + if (std::memcmp(uniform.buffer, buffer, sizeof(std::uint32_t) * size)) + { + continue; + } + + if (uniform.typeId != type) + { + util::unreachable( + "getOrCreateUniformConstant: access to the uniform with " + "different type"); + } + + if (uniform.isBuffer) + { + util::unreachable("getOrCreateUniformConstant: uniform was buffer"); + } + + return &uniform; + } + + auto uniformType = getPointerType(spv::StorageClass::UniformConstant, type); + auto uniformVariable = getBuilder().createVariable( + uniformType, spv::StorageClass::UniformConstant); + mInterfaces.push_back(uniformVariable); + + auto& newUniform = mUniforms.emplace_back(); + newUniform.index = mUniforms.size() - 1; + newUniform.typeId = type; + newUniform.type = uniformType; + newUniform.variable = uniformVariable; + newUniform.isBuffer = false; + std::memcpy(newUniform.buffer, buffer, sizeof(std::uint32_t) * size); + + return &newUniform; } -spirv::VariableValue ConverterContext::getThreadId() { - if (mThreadId) { - return mThreadId; - } - - auto inputType = getPointerType(spv::StorageClass::Input, TypeId::UInt32); - mThreadId = mBuilder.createVariable(inputType, spv::StorageClass::Input); - - if (mStage == Stage::Vertex) { - mBuilder.createDecorate( - mThreadId, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::VertexIndex)}); - } else { - util::unreachable(); - } - - mInterfaces.push_back(mThreadId); - - return mThreadId; +spirv::VariableValue ConverterContext::getThreadId() +{ + if (mThreadId) + { + return mThreadId; + } + + auto inputType = getPointerType(spv::StorageClass::Input, TypeId::UInt32); + mThreadId = mBuilder.createVariable(inputType, spv::StorageClass::Input); + + if (mStage == Stage::Vertex) + { + mBuilder.createDecorate( + mThreadId, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::VertexIndex)}); + } + else + { + util::unreachable(); + } + + mInterfaces.push_back(mThreadId); + + return mThreadId; } -spirv::VariableValue ConverterContext::getWorkgroupId() { - if (mWorkgroupId) { - return mWorkgroupId; - } - - if (mStage != Stage::Compute) { - util::unreachable(); - } - - auto workgroupIdType = - getPointerType(spv::StorageClass::Input, TypeId::UInt32x3); - mWorkgroupId = - mBuilder.createVariable(workgroupIdType, spv::StorageClass::Input); - - mBuilder.createDecorate( - mWorkgroupId, spv::Decoration::BuiltIn, - {{static_cast(spv::BuiltIn::WorkgroupId)}}); - mInterfaces.push_back(mWorkgroupId); - - return mWorkgroupId; +spirv::VariableValue ConverterContext::getWorkgroupId() +{ + if (mWorkgroupId) + { + return mWorkgroupId; + } + + if (mStage != Stage::Compute) + { + util::unreachable(); + } + + auto workgroupIdType = + getPointerType(spv::StorageClass::Input, TypeId::UInt32x3); + mWorkgroupId = + mBuilder.createVariable(workgroupIdType, spv::StorageClass::Input); + + mBuilder.createDecorate( + mWorkgroupId, spv::Decoration::BuiltIn, + {{static_cast(spv::BuiltIn::WorkgroupId)}}); + mInterfaces.push_back(mWorkgroupId); + + return mWorkgroupId; } -spirv::VariableValue ConverterContext::getLocalInvocationId() { - if (mLocalInvocationId) { - return mLocalInvocationId; - } +spirv::VariableValue ConverterContext::getLocalInvocationId() +{ + if (mLocalInvocationId) + { + return mLocalInvocationId; + } - if (mStage != Stage::Compute) { - util::unreachable(); - } + if (mStage != Stage::Compute) + { + util::unreachable(); + } - auto localInvocationIdType = - getPointerType(spv::StorageClass::Input, TypeId::UInt32x3); - mLocalInvocationId = - mBuilder.createVariable(localInvocationIdType, spv::StorageClass::Input); + auto localInvocationIdType = + getPointerType(spv::StorageClass::Input, TypeId::UInt32x3); + mLocalInvocationId = + mBuilder.createVariable(localInvocationIdType, spv::StorageClass::Input); - mBuilder.createDecorate( - mLocalInvocationId, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::LocalInvocationId)}); + mBuilder.createDecorate( + mLocalInvocationId, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::LocalInvocationId)}); - mInterfaces.push_back(mLocalInvocationId); + mInterfaces.push_back(mLocalInvocationId); - return mLocalInvocationId; + return mLocalInvocationId; } -spirv::VariableValue ConverterContext::getPerVertex() { - if (mPerVertex) { - return mPerVertex; - } - - auto floatT = getFloat32Type(); - auto float4T = getFloat32x4Type(); - - auto uintConst1 = getUInt32(1); - auto arr1Float = mBuilder.createTypeArray(floatT, uintConst1); - - auto gl_PerVertexStructT = mBuilder.createTypeStruct(std::array{ - static_cast(float4T), - static_cast(floatT), - static_cast(arr1Float), - static_cast(arr1Float), - }); - - mBuilder.createDecorate(gl_PerVertexStructT, spv::Decoration::Block, {}); - mBuilder.createMemberDecorate( - gl_PerVertexStructT, 0, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::Position)}); - mBuilder.createMemberDecorate( - gl_PerVertexStructT, 1, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::PointSize)}); - mBuilder.createMemberDecorate( - gl_PerVertexStructT, 2, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::ClipDistance)}); - mBuilder.createMemberDecorate( - gl_PerVertexStructT, 3, spv::Decoration::BuiltIn, - std::array{static_cast(spv::BuiltIn::CullDistance)}); - - auto gl_PerVertexPtrT = mBuilder.createTypePointer(spv::StorageClass::Output, - gl_PerVertexStructT); - mPerVertex = - mBuilder.createVariable(gl_PerVertexPtrT, spv::StorageClass::Output); - - mInterfaces.push_back(mPerVertex); - return mPerVertex; +spirv::VariableValue ConverterContext::getPerVertex() +{ + if (mPerVertex) + { + return mPerVertex; + } + + auto floatT = getFloat32Type(); + auto float4T = getFloat32x4Type(); + + auto uintConst1 = getUInt32(1); + auto arr1Float = mBuilder.createTypeArray(floatT, uintConst1); + + auto gl_PerVertexStructT = mBuilder.createTypeStruct(std::array{ + static_cast(float4T), + static_cast(floatT), + static_cast(arr1Float), + static_cast(arr1Float), + }); + + mBuilder.createDecorate(gl_PerVertexStructT, spv::Decoration::Block, {}); + mBuilder.createMemberDecorate( + gl_PerVertexStructT, 0, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::Position)}); + mBuilder.createMemberDecorate( + gl_PerVertexStructT, 1, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::PointSize)}); + mBuilder.createMemberDecorate( + gl_PerVertexStructT, 2, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::ClipDistance)}); + mBuilder.createMemberDecorate( + gl_PerVertexStructT, 3, spv::Decoration::BuiltIn, + std::array{static_cast(spv::BuiltIn::CullDistance)}); + + auto gl_PerVertexPtrT = mBuilder.createTypePointer(spv::StorageClass::Output, + gl_PerVertexStructT); + mPerVertex = + mBuilder.createVariable(gl_PerVertexPtrT, spv::StorageClass::Output); + + mInterfaces.push_back(mPerVertex); + return mPerVertex; } -spirv::VariableValue ConverterContext::getFragCoord() { - if (mFragCoord) { - return mFragCoord; - } +spirv::VariableValue ConverterContext::getFragCoord() +{ + if (mFragCoord) + { + return mFragCoord; + } - auto inputType = getPointerType(spv::StorageClass::Input, TypeId::Float32x4); - mFragCoord = mBuilder.createVariable(inputType, spv::StorageClass::Input); + auto inputType = getPointerType(spv::StorageClass::Input, TypeId::Float32x4); + mFragCoord = mBuilder.createVariable(inputType, spv::StorageClass::Input); - mBuilder.createDecorate( - mFragCoord, spv::Decoration::BuiltIn, - {{static_cast(spv::BuiltIn::FragCoord)}}); + mBuilder.createDecorate( + mFragCoord, spv::Decoration::BuiltIn, + {{static_cast(spv::BuiltIn::FragCoord)}}); - mInterfaces.push_back(mFragCoord); - return mFragCoord; + mInterfaces.push_back(mFragCoord); + return mFragCoord; } -spirv::VariableValue ConverterContext::getIn(unsigned location) { - auto [it, inserted] = mIns.try_emplace(location); - if (!inserted) { - return it->second; - } +spirv::VariableValue ConverterContext::getIn(unsigned location) +{ + auto [it, inserted] = mIns.try_emplace(location); + if (!inserted) + { + return it->second; + } - auto inputType = getPointerType(spv::StorageClass::Input, TypeId::Float32x4); - auto inputVariable = - mBuilder.createVariable(inputType, spv::StorageClass::Input); + auto inputType = getPointerType(spv::StorageClass::Input, TypeId::Float32x4); + auto inputVariable = + mBuilder.createVariable(inputType, spv::StorageClass::Input); - mBuilder.createDecorate(inputVariable, spv::Decoration::Location, - {{location}}); + mBuilder.createDecorate(inputVariable, spv::Decoration::Location, + {{location}}); - mInterfaces.push_back(inputVariable); - it->second = inputVariable; - return inputVariable; + mInterfaces.push_back(inputVariable); + it->second = inputVariable; + return inputVariable; } -spirv::VariableValue ConverterContext::getOut(unsigned location) { - auto [it, inserted] = mOuts.try_emplace(location); - if (!inserted) { - return it->second; - } - auto outputType = - getPointerType(spv::StorageClass::Output, TypeId::Float32x4); - auto outputVariable = - mBuilder.createVariable(outputType, spv::StorageClass::Output); - - mBuilder.createDecorate(outputVariable, spv::Decoration::Location, - {{location}}); - - mInterfaces.push_back(outputVariable); - it->second = outputVariable; - return outputVariable; +spirv::VariableValue ConverterContext::getOut(unsigned location) +{ + auto [it, inserted] = mOuts.try_emplace(location); + if (!inserted) + { + return it->second; + } + auto outputType = + getPointerType(spv::StorageClass::Output, TypeId::Float32x4); + auto outputVariable = + mBuilder.createVariable(outputType, spv::StorageClass::Output); + + mBuilder.createDecorate(outputVariable, spv::Decoration::Location, + {{location}}); + + mInterfaces.push_back(outputVariable); + it->second = outputVariable; + return outputVariable; } -spirv::Function ConverterContext::getDiscardFn() { - if (mDiscardFn) { - return mDiscardFn; - } +spirv::Function ConverterContext::getDiscardFn() +{ + if (mDiscardFn) + { + return mDiscardFn; + } - if (mStage != Stage::Fragment) { - util::unreachable(); - } + if (mStage != Stage::Fragment) + { + util::unreachable(); + } - auto fn = mBuilder.createFunctionBuilder(5); - mDiscardFn = fn.id; - auto entry = fn.createBlockBuilder(5); - entry.createKill(); + auto fn = mBuilder.createFunctionBuilder(5); + mDiscardFn = fn.id; + auto entry = fn.createBlockBuilder(5); + entry.createKill(); - fn.insertBlock(entry); - mBuilder.insertFunction(fn, getVoidType(), {}, - getFunctionType(getVoidType(), {})); + fn.insertBlock(entry); + mBuilder.insertFunction(fn, getVoidType(), {}, + getFunctionType(getVoidType(), {})); - return mDiscardFn; + return mDiscardFn; } std::optional -ConverterContext::findUint32Value(spirv::Value id) const { - for (auto [value, constId] : mConstantUint32Map) { - if (constId == id) { - return value; - } - } - - return std::nullopt; +ConverterContext::findUint32Value(spirv::Value id) const +{ + for (auto [value, constId] : mConstantUint32Map) + { + if (constId == id) + { + return value; + } + } + + return std::nullopt; } std::optional -ConverterContext::findSint32Value(spirv::Value id) const { - for (auto [value, constId] : mConstantSint32Map) { - if (constId == id) { - return value; - } - } - - return std::nullopt; +ConverterContext::findSint32Value(spirv::Value id) const +{ + for (auto [value, constId] : mConstantSint32Map) + { + if (constId == id) + { + return value; + } + } + + return std::nullopt; } -std::optional ConverterContext::findFloat32Value(spirv::Value id) const { - for (auto [value, constId] : mConstantFloat32Map) { - if (constId == id) { - return std::bit_cast(value); - } - } - - return std::nullopt; +std::optional ConverterContext::findFloat32Value(spirv::Value id) const +{ + for (auto [value, constId] : mConstantFloat32Map) + { + if (constId == id) + { + return std::bit_cast(value); + } + } + + return std::nullopt; } spirv::FunctionType ConverterContext::getFunctionType(spirv::Type resultType, - std::span params) { - for (auto fnType : mFunctionTypes) { - if (fnType.resultType != resultType) { - continue; - } - - if (fnType.params.size() != params.size()) { - continue; - } - - bool match = true; - for (std::size_t i = 0, end = params.size(); i < end; ++i) { - if (fnType.params[i] != params[i]) { - match = false; - break; - } - } - if (!match) { - continue; - } - - return fnType.id; - } - - auto id = mBuilder.createTypeFunction(resultType, params); - - std::vector paramsVec; - paramsVec.reserve(params.size()); - - for (auto param : params) { - paramsVec.push_back(param); - } - - mFunctionTypes.push_back(FunctionType{ - .resultType = resultType, .params = std::move(paramsVec), .id = id}); - - return id; + std::span params) +{ + for (auto fnType : mFunctionTypes) + { + if (fnType.resultType != resultType) + { + continue; + } + + if (fnType.params.size() != params.size()) + { + continue; + } + + bool match = true; + for (std::size_t i = 0, end = params.size(); i < end; ++i) + { + if (fnType.params[i] != params[i]) + { + match = false; + break; + } + } + if (!match) + { + continue; + } + + return fnType.id; + } + + auto id = mBuilder.createTypeFunction(resultType, params); + + std::vector paramsVec; + paramsVec.reserve(params.size()); + + for (auto param : params) + { + paramsVec.push_back(param); + } + + mFunctionTypes.push_back(FunctionType{ + .resultType = resultType, .params = std::move(paramsVec), .id = id}); + + return id; } -Function *ConverterContext::createFunction(std::size_t expectedSize) { - auto result = &mFunctions.emplace_front(); +Function* ConverterContext::createFunction(std::size_t expectedSize) +{ + auto result = &mFunctions.emplace_front(); - result->context = this; - result->entryFragment.context = this; - result->entryFragment.function = result; - result->entryFragment.builder = mBuilder.createBlockBuilder(expectedSize); - result->entryFragment.entryBlockId = result->entryFragment.builder.id; - result->fragments.push_back(&result->entryFragment); + result->context = this; + result->entryFragment.context = this; + result->entryFragment.function = result; + result->entryFragment.builder = mBuilder.createBlockBuilder(expectedSize); + result->entryFragment.entryBlockId = result->entryFragment.builder.id; + result->fragments.push_back(&result->entryFragment); - result->exitFragment.context = this; - result->exitFragment.function = result; - result->exitFragment.builder = mBuilder.createBlockBuilder(0); - result->exitFragment.entryBlockId = result->exitFragment.builder.id; - result->builder = mBuilder.createFunctionBuilder(expectedSize); + result->exitFragment.context = this; + result->exitFragment.function = result; + result->exitFragment.builder = mBuilder.createBlockBuilder(0); + result->exitFragment.entryBlockId = result->exitFragment.builder.id; + result->builder = mBuilder.createFunctionBuilder(expectedSize); - return result; + return result; } -Fragment *ConverterContext::createFragment(std::size_t expectedSize) { - auto result = &mFragments.emplace_front(); +Fragment* ConverterContext::createFragment(std::size_t expectedSize) +{ + auto result = &mFragments.emplace_front(); - result->context = this; - result->builder = mBuilder.createBlockBuilder(expectedSize); - result->entryBlockId = result->builder.id; + result->context = this; + result->builder = mBuilder.createBlockBuilder(expectedSize); + result->entryBlockId = result->builder.id; - return result; + return result; } diff --git a/hw/amdgpu/shader/src/Fragment.cpp b/hw/amdgpu/shader/src/Fragment.cpp index 696593c8..6479a0f6 100644 --- a/hw/amdgpu/shader/src/Fragment.cpp +++ b/hw/amdgpu/shader/src/Fragment.cpp @@ -14,3972 +14,4308 @@ using namespace amdgpu::shader; -namespace { -std::uint32_t getChannelsCount(SurfaceFormat format) { - switch (format) { - case kSurfaceFormat8: - return 1; - case kSurfaceFormat16: - return 1; - case kSurfaceFormat8_8: - return 2; - case kSurfaceFormat32: - return 1; - case kSurfaceFormat16_16: - return 2; - case kSurfaceFormat10_11_11: - return 3; - case kSurfaceFormat11_11_10: - return 3; - case kSurfaceFormat10_10_10_2: - return 4; - case kSurfaceFormat2_10_10_10: - return 4; - case kSurfaceFormat8_8_8_8: - return 4; - case kSurfaceFormat32_32: - return 2; - case kSurfaceFormat16_16_16_16: - return 4; - case kSurfaceFormat32_32_32: - return 3; - case kSurfaceFormat32_32_32_32: - return 4; - default: - util::unreachable(); - } -} - -std::uint32_t sizeOfFormat(SurfaceFormat format) { - switch (format) { - case kSurfaceFormat8: - return 8; - case kSurfaceFormat16: - return 16; - case kSurfaceFormat8_8: - return 16; - case kSurfaceFormat32: - return 32; - case kSurfaceFormat16_16: - return 32; - case kSurfaceFormat10_11_11: - return 32; - case kSurfaceFormat11_11_10: - return 32; - case kSurfaceFormat10_10_10_2: - return 32; - case kSurfaceFormat2_10_10_10: - return 32; - case kSurfaceFormat8_8_8_8: - return 32; - case kSurfaceFormat32_32: - return 64; - case kSurfaceFormat16_16_16_16: - return 64; - case kSurfaceFormat32_32_32: - return 96; - case kSurfaceFormat32_32_32_32: - return 128; - default: - util::unreachable("unsupported format %u", format); - } -} - -TypeId pickBufferType(SurfaceFormat surfaceFormat, - TextureChannelType channelType) { - auto size = sizeOfFormat(surfaceFormat) / getChannelsCount(surfaceFormat); - - if (size == 8) { - switch (channelType) { - case kTextureChannelTypeUNorm: - case kTextureChannelTypeUScaled: - case kTextureChannelTypeUInt: - return TypeId::UInt8; - - default: - return TypeId::SInt8; - } - } - - if (size == 16) { - switch (channelType) { - case kTextureChannelTypeUNorm: - case kTextureChannelTypeUScaled: - case kTextureChannelTypeUInt: - return TypeId::UInt16; - - case kTextureChannelTypeFloat: - return TypeId::Float16; - - default: - return TypeId::SInt16; - } - } - - if (size == 32) { - switch (channelType) { - case kTextureChannelTypeUNorm: - case kTextureChannelTypeUScaled: - case kTextureChannelTypeUInt: - return TypeId::UInt32; - - case kTextureChannelTypeFloat: - return TypeId::Float32; - - default: - return TypeId::SInt32; - } - } - - if (size == 64) { - switch (channelType) { - case kTextureChannelTypeUNorm: - case kTextureChannelTypeUScaled: - case kTextureChannelTypeUInt: - return TypeId::UInt64; - - case kTextureChannelTypeFloat: - return TypeId::Float64; - - default: - return TypeId::SInt64; - } - } - - util::unreachable(); -} - -spirv::Type convertFromFormat(spirv::Value *result, int count, - Fragment &fragment, std::uint32_t *vBufferData, - spirv::UIntValue offset, - SurfaceFormat surfaceFormat, - TextureChannelType channelType) { - auto loadType = pickBufferType(surfaceFormat, channelType); - - auto uniform = - fragment.context->getOrCreateStorageBuffer(vBufferData, loadType); - uniform->accessOp |= AccessOp::Load; - - auto storageBufferPointerType = fragment.context->getPointerType( - spv::StorageClass::StorageBuffer, loadType); - - auto &builder = fragment.builder; - - switch (surfaceFormat) { - case kSurfaceFormat32: - case kSurfaceFormat32_32: - case kSurfaceFormat32_32_32: - case kSurfaceFormat32_32_32_32: - case kSurfaceFormat16: - case kSurfaceFormat16_16: - case kSurfaceFormat16_16_16_16: - case kSurfaceFormat8: - case kSurfaceFormat8_8: - case kSurfaceFormat8_8_8_8: { - // format not requires bit fetching - auto totalChannelsCount = getChannelsCount(surfaceFormat); - auto channelSize = sizeOfFormat(surfaceFormat) / 8 / totalChannelsCount; - auto channelsCount = std::min(count, totalChannelsCount); - - if (channelSize != 1) { - offset = builder.createUDiv(fragment.context->getUInt32Type(), offset, - fragment.context->getUInt32(channelSize)); - } - - int channel = 0; - auto resultType = fragment.context->getType(loadType); - for (; channel < channelsCount; ++channel) { - auto channelOffset = offset; - - if (channel != 0) { - channelOffset = - builder.createIAdd(fragment.context->getUInt32Type(), channelOffset, - fragment.context->getUInt32(channel)); - } - - auto uniformPointerValue = fragment.builder.createAccessChain( - storageBufferPointerType, uniform->variable, - {{fragment.context->getUInt32(0), channelOffset}}); - - auto channelValue = fragment.builder.createLoad( - fragment.context->getType(loadType), uniformPointerValue); - - switch (channelType) { - case kTextureChannelTypeFloat: { - if (loadType != TypeId::Float32) { - channelValue = fragment.builder.createFConvert( - fragment.context->getFloat32Type(), channelValue); - - resultType = fragment.context->getFloat32Type(); - } - - result[channel] = channelValue; - break; - } - case kTextureChannelTypeSInt: { - if (loadType != TypeId::SInt32) { - channelValue = fragment.builder.createSConvert( - fragment.context->getSint32Type(), - spirv::cast(channelValue)); - - resultType = fragment.context->getSint32Type(); - } - - result[channel] = channelValue; - break; - } - case kTextureChannelTypeUInt: - if (loadType != TypeId::UInt32) { - channelValue = fragment.builder.createUConvert( - fragment.context->getUInt32Type(), - spirv::cast(channelValue)); - - resultType = fragment.context->getUInt32Type(); - } - - result[channel] = channelValue; - break; - - case kTextureChannelTypeUNorm: { - auto maxValue = - (static_cast(1) << (channelSize * 8)) - 1; - - auto uintChannelValue = spirv::cast(channelValue); - - if (loadType != TypeId::UInt32) { - uintChannelValue = builder.createUConvert( - fragment.context->getUInt32Type(), uintChannelValue); - } - - auto floatChannelValue = builder.createConvertUToF( - fragment.context->getFloat32Type(), uintChannelValue); - floatChannelValue = builder.createFDiv( - fragment.context->getFloat32Type(), floatChannelValue, - fragment.context->getFloat32(maxValue)); - result[channel] = floatChannelValue; - resultType = fragment.context->getFloat32Type(); - break; - } - - case kTextureChannelTypeSNorm: { - auto maxValue = - (static_cast(1) << (channelSize * 8 - 1)) - 1; - - auto uintChannelValue = spirv::cast(channelValue); - - if (loadType != TypeId::SInt32) { - uintChannelValue = builder.createSConvert( - fragment.context->getSint32Type(), uintChannelValue); - } - - auto floatChannelValue = builder.createConvertSToF( - fragment.context->getFloat32Type(), uintChannelValue); - - floatChannelValue = builder.createFDiv( - fragment.context->getFloat32Type(), floatChannelValue, - fragment.context->getFloat32(maxValue)); - - auto glslStd450 = fragment.context->getGlslStd450(); - floatChannelValue = - spirv::cast(fragment.builder.createExtInst( - fragment.context->getFloat32Type(), glslStd450, - GLSLstd450FClamp, - {{floatChannelValue, fragment.context->getFloat32(-1), - fragment.context->getFloat32(1)}})); - result[channel] = floatChannelValue; - resultType = fragment.context->getFloat32Type(); - break; - } - - case kTextureChannelTypeUScaled: { - auto uintChannelValue = spirv::cast(channelValue); - - if (loadType != TypeId::UInt32) { - uintChannelValue = builder.createUConvert( - fragment.context->getUInt32Type(), uintChannelValue); - } - - auto floatChannelValue = builder.createConvertUToF( - fragment.context->getFloat32Type(), uintChannelValue); - - result[channel] = floatChannelValue; - resultType = fragment.context->getFloat32Type(); - break; - } - - case kTextureChannelTypeSScaled: { - auto uintChannelValue = spirv::cast(channelValue); - - if (loadType != TypeId::SInt32) { - uintChannelValue = builder.createSConvert( - fragment.context->getSint32Type(), uintChannelValue); - } - - auto floatChannelValue = builder.createConvertSToF( - fragment.context->getFloat32Type(), uintChannelValue); - - result[channel] = floatChannelValue; - resultType = fragment.context->getFloat32Type(); - break; - } - - case kTextureChannelTypeSNormNoZero: { - auto maxValue = - (static_cast(1) << (channelSize * 8)) - 1; - - auto uintChannelValue = spirv::cast(channelValue); - - if (loadType != TypeId::SInt32) { - uintChannelValue = builder.createSConvert( - fragment.context->getSint32Type(), uintChannelValue); - } - - auto floatChannelValue = builder.createConvertSToF( - fragment.context->getFloat32Type(), uintChannelValue); - - floatChannelValue = builder.createFMul( - fragment.context->getFloat32Type(), floatChannelValue, - fragment.context->getFloat32(2)); - floatChannelValue = builder.createFAdd( - fragment.context->getFloat32Type(), floatChannelValue, - fragment.context->getFloat32(1)); - - floatChannelValue = builder.createFDiv( - fragment.context->getFloat32Type(), floatChannelValue, - fragment.context->getFloat32(maxValue)); - - result[channel] = floatChannelValue; - resultType = fragment.context->getFloat32Type(); - break; - } - - default: - util::unreachable("unimplemented channel type %u", channelType); - } - } - - // for (; channel < count; ++channel) { - // result[channel] = fragment.createBitcast( - // resultType, fragment.context->getUInt32Type(), - // fragment.context->getUInt32(0)); - // } - return resultType; - } - - default: - break; - } - - util::unreachable("unimplemented conversion type. %u.%u", surfaceFormat, - channelType); -} - -void convertToFormat(RegisterId sourceRegister, int count, Fragment &fragment, - std::uint32_t *vBufferData, spirv::UIntValue offset, - SurfaceFormat surfaceFormat, - TextureChannelType channelType) { - - auto storeType = pickBufferType(surfaceFormat, channelType); - - auto uniform = - fragment.context->getOrCreateStorageBuffer(vBufferData, storeType); - uniform->accessOp |= AccessOp::Store; - - auto uniformPointerType = fragment.context->getPointerType( - spv::StorageClass::StorageBuffer, storeType); - - auto &builder = fragment.builder; - switch (surfaceFormat) { - case kSurfaceFormat8: - case kSurfaceFormat8_8: - case kSurfaceFormat8_8_8_8: - case kSurfaceFormat16: - case kSurfaceFormat16_16: - case kSurfaceFormat16_16_16_16: - case kSurfaceFormat32: - case kSurfaceFormat32_32: - case kSurfaceFormat32_32_32: - case kSurfaceFormat32_32_32_32: { - // format not requires bit fetching - auto totalChannelsCount = getChannelsCount(surfaceFormat); - auto channelSize = sizeOfFormat(surfaceFormat) / 8 / totalChannelsCount; - auto channelsCount = std::min(count, totalChannelsCount); - - if (channelSize != 1) { - offset = builder.createUDiv(fragment.context->getUInt32Type(), offset, - fragment.context->getUInt32(channelSize)); - } - - int channel = 0; - - for (; channel < channelsCount; ++channel) { - auto channelOffset = offset; - - if (channel != 0) { - channelOffset = - builder.createIAdd(fragment.context->getUInt32Type(), channelOffset, - fragment.context->getUInt32(channel)); - } - - auto uniformPointerValue = fragment.builder.createAccessChain( - uniformPointerType, uniform->variable, - {{fragment.context->getUInt32(0), channelOffset}}); - - spirv::Value channelValue; - - switch (channelType) { - case kTextureChannelTypeUNorm: { - channelValue = - fragment - .getOperand(RegisterId::Raw(sourceRegister + channel), - TypeId::Float32) - .value; - - auto maxValue = - (static_cast(1) << (channelSize * 8)) - 1; - - channelValue = - builder.createFMul(fragment.context->getFloat32Type(), - spirv::cast(channelValue), - fragment.context->getFloat32(maxValue)); - - channelValue = builder.createConvertFToU( - fragment.context->getType(TypeId::UInt32), channelValue); - - if (storeType != TypeId::UInt32) { - channelValue = builder.createUConvert( - fragment.context->getType(storeType), - spirv::cast(channelValue)); - } - break; - } - case kTextureChannelTypeFloat: - channelValue = - fragment - .getOperand(RegisterId::Raw(sourceRegister + channel), - TypeId::Float32) - .value; - - if (storeType != TypeId::Float32) { - channelValue = fragment.builder.createFConvert( - fragment.context->getType(storeType), channelValue); - } - break; - - case kTextureChannelTypeSInt: - channelValue = - fragment - .getOperand(RegisterId::Raw(sourceRegister + channel), - TypeId::SInt32) - .value; - - if (storeType != TypeId::SInt32) { - channelValue = fragment.builder.createSConvert( - fragment.context->getType(storeType), - spirv::cast(channelValue)); - } - break; - case kTextureChannelTypeUInt: - channelValue = - fragment - .getOperand(RegisterId::Raw(sourceRegister + channel), - TypeId::UInt32) - .value; - - if (storeType != TypeId::UInt32) { - channelValue = fragment.builder.createUConvert( - fragment.context->getType(storeType), - spirv::cast(channelValue)); - } - break; - - default: - util::unreachable("unimplemented channel type %u", channelType); - } - - fragment.builder.createStore(uniformPointerValue, channelValue); - } - - for (; channel < count; ++channel) { - auto channelOffset = - builder.createIAdd(fragment.context->getUInt32Type(), offset, - fragment.context->getUInt32(channel)); - auto uniformPointerValue = fragment.builder.createAccessChain( - uniformPointerType, uniform->variable, - {{fragment.context->getUInt32(0), channelOffset}}); - - fragment.builder.createStore( - uniformPointerValue, - fragment.createBitcast(fragment.context->getType(storeType), - fragment.context->getUInt32Type(), - fragment.context->getUInt32(0))); - } - - return; - } - - default: - break; - } - - util::unreachable("unimplemented conversion type. %u.%u", surfaceFormat, - channelType); -} - -struct GnmVBuffer { - uint64_t base : 44; - uint64_t mtype_L1s : 2; - uint64_t mtype_L2 : 2; - uint64_t stride : 14; - uint64_t cache_swizzle : 1; - uint64_t swizzle_en : 1; - - uint32_t num_records; - - uint32_t dst_sel_x : 3; - uint32_t dst_sel_y : 3; - uint32_t dst_sel_z : 3; - uint32_t dst_sel_w : 3; - - TextureChannelType nfmt : 3; - SurfaceFormat dfmt : 4; - uint32_t element_size : 2; - uint32_t index_stride : 2; - uint32_t addtid_en : 1; - uint32_t reserved0 : 1; - uint32_t hash_en : 1; - uint32_t reserved1 : 1; - uint32_t mtype : 3; - uint32_t type : 2; - - std::uint64_t getAddress() const { return base; } - - uint32_t getStride() const { return stride; } - - uint32_t getSize() const { - uint32_t stride = getStride(); - uint32_t numElements = getNumRecords(); - return stride ? numElements * stride : numElements; - } - - uint32_t getNumRecords() const { return num_records; } - uint32_t getElementSize() const { return element_size; } - uint32_t getIndexStrideSize() const { return index_stride; } - SurfaceFormat getSurfaceFormat() const { return (SurfaceFormat)dfmt; } - TextureChannelType getChannelType() const { return (TextureChannelType)nfmt; } -}; - -static_assert(sizeof(GnmVBuffer) == sizeof(std::uint64_t) * 2); - -enum class TextureType { - Dim1D = 8, - Dim2D, - Dim3D, - Cube, - Array1D, - Array2D, - Msaa2D, - MsaaArray2D, -}; - -struct GnmTBuffer { - uint64_t baseaddr256 : 38; - uint64_t mtype_L2 : 2; - uint64_t min_lod : 12; - SurfaceFormat dfmt : 6; - TextureChannelType nfmt : 4; - uint64_t mtype01 : 2; - - uint64_t width : 14; - uint64_t height : 14; - uint64_t perfMod : 3; - uint64_t interlaced : 1; - uint64_t dst_sel_x : 3; - uint64_t dst_sel_y : 3; - uint64_t dst_sel_z : 3; - uint64_t dst_sel_w : 3; - uint64_t base_level : 4; - uint64_t last_level : 4; - uint64_t tiling_idx : 5; - uint64_t pow2pad : 1; - uint64_t mtype2 : 1; - uint64_t : 1; // reserved - TextureType type : 4; - - uint64_t depth : 13; - uint64_t pitch : 14; - uint64_t : 5; // reserved - uint64_t base_array : 13; - uint64_t last_array : 13; - uint64_t : 6; // reserved - - uint64_t min_lod_warn : 12; // fixed point 4.8 - uint64_t counter_bank_id : 8; - uint64_t LOD_hdw_cnt_en : 1; - uint64_t : 42; // reserved - - std::uint64_t getAddress() const { - return static_cast(static_cast(baseaddr256)) - << 8; - } -}; - -static_assert(sizeof(GnmTBuffer) == sizeof(std::uint64_t) * 4); - -enum class CmpKind { - F, - LT, - EQ, - LE, - GT, - LG, - GE, - O, - U, - NGE, - NLG, - NGT, - NLE, - NEQ, - NLT, - NE, - TRU, - T = TRU, - CLASS -}; - -enum class CmpFlags { None = 0, X = 1 << 0, S = 1 << 1, SX = S | X }; -inline CmpFlags operator&(CmpFlags a, CmpFlags b) { - return static_cast(static_cast(a) & static_cast(b)); -} - -Value doCmpOp(Fragment &fragment, TypeId type, spirv::Value src0, - spirv::Value src1, CmpKind kind, CmpFlags flags, - std::uint8_t typeMask = 0) { - spirv::BoolValue cmp; - auto boolT = fragment.context->getBoolType(); - - switch (kind) { - case CmpKind::F: - cmp = fragment.context->getFalse(); - break; - case CmpKind::LT: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdLessThan(boolT, src0, src1); - } else if (type.isSignedInt()) { - cmp = fragment.builder.createSLessThan(boolT, src0, src1); - } else { - cmp = fragment.builder.createULessThan(boolT, src0, src1); - } - break; - case CmpKind::EQ: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdEqual(boolT, src0, src1); - } else { - cmp = fragment.builder.createIEqual(boolT, src0, src1); - } - break; - case CmpKind::LE: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdLessThanEqual(boolT, src0, src1); - } else if (type.isSignedInt()) { - cmp = fragment.builder.createSLessThanEqual(boolT, src0, src1); - } else { - cmp = fragment.builder.createULessThanEqual(boolT, src0, src1); - } - break; - case CmpKind::GT: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdGreaterThan(boolT, src0, src1); - } else if (type.isSignedInt()) { - cmp = fragment.builder.createSGreaterThan(boolT, src0, src1); - } else { - cmp = fragment.builder.createUGreaterThan(boolT, src0, src1); - } - break; - case CmpKind::LG: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdNotEqual(boolT, src0, src1); - } else { - cmp = fragment.builder.createINotEqual(boolT, src0, src1); - } - break; - case CmpKind::GE: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1); - } else if (type.isSignedInt()) { - cmp = fragment.builder.createSGreaterThanEqual(boolT, src0, src1); - } else { - cmp = fragment.builder.createUGreaterThanEqual(boolT, src0, src1); - } - break; - case CmpKind::O: - cmp = fragment.builder.createLogicalAnd( - boolT, fragment.builder.createFOrdEqual(boolT, src0, src0), - fragment.builder.createFOrdEqual(boolT, src1, src1)); - break; - case CmpKind::U: - cmp = fragment.builder.createLogicalAnd( - boolT, fragment.builder.createFUnordNotEqual(boolT, src0, src0), - fragment.builder.createFUnordNotEqual(boolT, src1, src1)); - break; - case CmpKind::NGE: - cmp = fragment.builder.createFUnordLessThan(boolT, src0, src1); - break; - case CmpKind::NLG: - cmp = fragment.builder.createFUnordGreaterThanEqual(boolT, src0, src1); - break; - case CmpKind::NGT: - cmp = fragment.builder.createFUnordLessThanEqual(boolT, src0, src1); - break; - case CmpKind::NLE: - cmp = fragment.builder.createFUnordGreaterThan(boolT, src0, src1); - break; - case CmpKind::NE: - case CmpKind::NEQ: - if (type.isFloatPoint()) { - cmp = fragment.builder.createFUnordNotEqual(boolT, src0, src1); - } else { - cmp = fragment.builder.createINotEqual(boolT, src0, src1); - } - break; - case CmpKind::NLT: - cmp = fragment.builder.createFUnordGreaterThanEqual(boolT, src0, src1); - break; - case CmpKind::TRU: - cmp = fragment.context->getTrue(); - break; - - case CmpKind::CLASS: { - enum class FloatClass { - SNan = 0, - QNan = 1, - NInf = 2, - NNorm = 3, - NDenom = 4, - NZero = 5, - PZero = 6, - PDenom = 7, - PNorm = 8, - PInf = 9, - }; - - auto testCmpClass = [&](FloatClass fclass, - spirv::FloatValue val) -> spirv::BoolValue { - switch (fclass) { - case FloatClass::SNan: - case FloatClass::QNan: - return fragment.builder.createIsNan(boolT, val); - - case FloatClass::NInf: - return fragment.builder.createLogicalAnd( - boolT, - fragment.builder.createFOrdLessThan( - boolT, val, fragment.context->getFloat32(0)), - fragment.builder.createIsInf(boolT, val)); - - case FloatClass::NZero: - case FloatClass::PZero: - return fragment.builder.createFOrdEqual( - boolT, val, fragment.context->getFloat32(0)); - - case FloatClass::NNorm: - case FloatClass::NDenom: - case FloatClass::PDenom: - case FloatClass::PNorm: - util::unreachable(); - - case FloatClass::PInf: - return fragment.builder.createLogicalAnd( - boolT, - fragment.builder.createFOrdGreaterThan( - boolT, val, fragment.context->getFloat32(0)), - fragment.builder.createIsInf(boolT, val)); - } - - util::unreachable(); - }; - - // we cannot differ signaling and quiet nan - if (typeMask & 3) { - typeMask = (typeMask & ~3) | 2; - } - - // we cannot differ positive and negative zero - if (typeMask & 0x60) { - typeMask = (typeMask & ~0x60) | 0x40; - } - - for (int i = 0; i < 10; ++i) { - if (typeMask & (1 << i)) { - auto lhs = - testCmpClass((FloatClass)i, spirv::cast(src0)); - auto rhs = - testCmpClass((FloatClass)i, spirv::cast(src1)); - - auto bitResult = fragment.builder.createLogicalAnd(boolT, lhs, rhs); - - if (cmp) { - cmp = fragment.builder.createLogicalOr(boolT, cmp, bitResult); - } else { - cmp = bitResult; - } - } - } - - if (!cmp) { - cmp = fragment.context->getFalse(); - } - break; - } - } - - if (!cmp) { - util::unreachable(); - } - - auto uint32T = fragment.context->getUInt32Type(); - auto uint32_0 = fragment.context->getUInt32(0); - auto result = fragment.builder.createSelect( - uint32T, cmp, fragment.context->getUInt32(1), uint32_0); - - if ((flags & CmpFlags::X) == CmpFlags::X) { - fragment.setOperand(RegisterId::ExecLo, {uint32T, result}); - fragment.setOperand(RegisterId::ExecHi, {uint32T, uint32_0}); - } - - // TODO: handle flags - return {uint32T, result}; -}; - -void convertVop2(Fragment &fragment, Vop2 inst) { - fragment.registers->pc += Vop2::kMinInstSize * sizeof(std::uint32_t); - switch (inst.op) { - case Vop2::Op::V_CVT_PKRTZ_F16_F32: { - auto float2T = fragment.context->getType(TypeId::Float32x2); - auto uintT = fragment.context->getType(TypeId::UInt32); - auto glslStd450 = fragment.context->getGlslStd450(); - - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value; - - auto src = fragment.builder.createCompositeConstruct( - float2T, std::array{src0, src1}); - auto dst = fragment.builder.createExtInst( - uintT, glslStd450, GLSLstd450PackHalf2x16, std::array{src}); - - fragment.setVectorOperand(inst.vdst, {uintT, dst}); - break; - } - case Vop2::Op::V_AND_B32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createBitwiseAnd(uintT, src0, src1)}); - break; - } - - case Vop2::Op::V_OR_B32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createBitwiseOr(uintT, src0, src1)}); - break; - } - - case Vop2::Op::V_ADD_I32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - auto resultStruct = - fragment.context->getStructType(std::array{uintT, uintT}); - auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(0)})}); - fragment.setVcc( - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(1)})}); - // TODO: update vcc hi - break; - } - - case Vop2::Op::V_SUB_I32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - auto resultStruct = - fragment.context->getStructType(std::array{uintT, uintT}); - auto result = fragment.builder.createISubBorrow(resultStruct, src0, src1); - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(0)})}); - fragment.setVcc( - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(1)})}); - // TODO: update vcc hi - break; - } - - case Vop2::Op::V_MAC_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto dst = spirv::cast( - fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFAdd( - floatT, fragment.builder.createFMul(floatT, src0, src1), dst); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MAC_LEGACY_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto dst = spirv::cast( - fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - auto float0 = fragment.context->getFloat32(0); - - auto src0IsZero = fragment.builder.createFOrdEqual(boolT, src0, float0); - auto src1IsZero = fragment.builder.createFOrdEqual(boolT, src1, float0); - auto anySrcIsZero = - fragment.builder.createLogicalOr(boolT, src0IsZero, src1IsZero); - - auto result = fragment.builder.createFAdd( - floatT, - fragment.builder.createSelect( - floatT, anySrcIsZero, float0, - fragment.builder.createFMul(floatT, src0, src1)), - dst); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MUL_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFMul(floatT, src0, src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_ADD_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFAdd(floatT, src0, src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_SUB_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFSub(floatT, src0, src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop2::Op::V_SUBREV_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFSub(floatT, src1, src0); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop2::Op::V_SUBREV_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); - auto floatT = fragment.context->getSint32Type(); - - auto result = fragment.builder.createISub(floatT, src1, src0); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MIN_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, - src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MAX_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), - src0, src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MUL_LEGACY_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - auto float0 = fragment.context->getFloat32(0); - - auto src0IsZero = fragment.builder.createFOrdEqual(boolT, src0, float0); - auto src1IsZero = fragment.builder.createFOrdEqual(boolT, src1, float0); - auto anySrcIsZero = - fragment.builder.createLogicalOr(boolT, src0IsZero, src1IsZero); - - auto result = fragment.builder.createSelect( - floatT, anySrcIsZero, float0, - fragment.builder.createFMul(floatT, src0, src1)); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MADAK_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto constant = spirv::cast( - fragment.getScalarOperand(255, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFAdd( - floatT, fragment.builder.createFMul(floatT, src0, src1), constant); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_MADMK_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); - auto constant = spirv::cast( - fragment.getScalarOperand(255, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFAdd( - floatT, fragment.builder.createFMul(floatT, src0, constant), src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop2::Op::V_LSHL_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createShiftLeftLogical(uintT, src0, src1)}); - break; - } - - case Vop2::Op::V_LSHLREV_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createShiftLeftLogical(uintT, src1, src0)}); - break; - } - - case Vop2::Op::V_LSHR_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createShiftRightLogical(uintT, src0, src1)}); - break; - } - - case Vop2::Op::V_LSHRREV_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); - auto uintT = fragment.context->getType(TypeId::UInt32); - - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createShiftRightLogical(uintT, src1, src0)}); - break; - } - - case Vop2::Op::V_ASHR_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); - auto sintT = fragment.context->getType(TypeId::SInt32); - - fragment.setVectorOperand( - inst.vdst, {sintT, fragment.builder.createShiftRightArithmetic( - sintT, src0, src1)}); - break; - } - - case Vop2::Op::V_ASHRREV_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); - auto sintT = fragment.context->getType(TypeId::SInt32); - - fragment.setVectorOperand( - inst.vdst, {sintT, fragment.builder.createShiftRightArithmetic( - sintT, src1, src0)}); - break; - } - - case Vop2::Op::V_CNDMASK_B32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - auto vcc = fragment.getVccLo(); - - auto cmp = fragment.builder.createINotEqual(fragment.context->getBoolType(), - vcc.value, - fragment.context->getUInt32(0)); - - auto uint32T = fragment.context->getUInt32Type(); - auto result = fragment.builder.createSelect(uint32T, cmp, src1, src0); - fragment.setVectorOperand(inst.vdst, {uint32T, result}); - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} -void convertSop2(Fragment &fragment, Sop2 inst) { - fragment.registers->pc += Sop2::kMinInstSize * sizeof(std::uint32_t); - auto &builder = fragment.builder; - auto context = fragment.context; - auto sCarry = [&](spirv::SIntValue a, spirv::SIntValue b, - spirv::SIntValue result) { - auto boolT = context->getBoolType(); - auto uint32T = context->getUInt32Type(); - auto s0 = context->getSInt32(0); - auto u1 = context->getUInt32(1); - auto u0 = context->getUInt32(0); - auto aLtZero = builder.createSelect( - uint32T, builder.createSLessThan(boolT, a, s0), u1, u0); - auto bLtZero = builder.createSelect( - uint32T, builder.createSLessThan(boolT, b, s0), u1, u0); - auto resultLtZero = builder.createSelect( - uint32T, builder.createSLessThan(boolT, result, s0), u1, u0); - - auto argsSignEq = builder.createIEqual(boolT, aLtZero, bLtZero); - auto resSignNe = builder.createINotEqual(boolT, resultLtZero, aLtZero); - return Value{boolT, builder.createLogicalAnd(boolT, argsSignEq, resSignNe)}; - }; - - switch (inst.op) { - case Sop2::Op::S_ADD_U32: { - auto src0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value; - auto src1 = fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - auto resultStruct = - fragment.context->getStructType(std::array{uintT, uintT}); - auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); - fragment.setScalarOperand( - inst.sdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, {{static_cast(0)}})}); - fragment.setScc( - {uintT, fragment.builder.createCompositeExtract( - uintT, result, {{static_cast(1)}})}); - break; - } - case Sop2::Op::S_ADD_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); - auto resultT = fragment.context->getSint32Type(); - auto result = fragment.builder.createIAdd(resultT, src0, src1); - fragment.setScc(sCarry(src0, src1, result)); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_SUB_U32: { - auto src0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value; - auto src1 = fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - auto resultStruct = - fragment.context->getStructType(std::array{uintT, uintT}); - auto result = fragment.builder.createISubBorrow(resultStruct, src0, src1); - fragment.setScalarOperand( - inst.sdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, {{static_cast(0)}})}); - fragment.setScc( - {uintT, fragment.builder.createCompositeExtract( - uintT, result, {{static_cast(1)}})}); - break; - } - case Sop2::Op::S_SUB_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); - auto resultT = fragment.context->getSint32Type(); - auto result = fragment.builder.createISub(resultT, src0, src1); - fragment.setScc(sCarry(src0, src1, result)); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_ASHR_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getSint32Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x3f))); - - auto result = - fragment.builder.createShiftRightArithmetic(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_ASHR_I64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::SInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getSint64Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x3f))); - - auto result = - fragment.builder.createShiftRightArithmetic(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_LSHR_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getUInt32Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x1f))); - - auto result = fragment.builder.createShiftRightLogical(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_LSHR_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getUInt64Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x3f))); - - auto result = fragment.builder.createShiftRightLogical(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_LSHL_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getUInt32Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x1f))); - - auto result = fragment.builder.createShiftLeftLogical(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_LSHL_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - - auto resultT = fragment.context->getUInt64Type(); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - resultT, src1, fragment.context->getUInt32(0x3f))); - - auto result = fragment.builder.createShiftLeftLogical(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_CSELECT_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto resultT = fragment.context->getUInt32Type(); - auto result = - fragment.builder.createSelect(resultT, fragment.getScc(), src0, src1); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_CSELECT_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - - auto resultT = fragment.context->getUInt64Type(); - auto result = - fragment.builder.createSelect(resultT, fragment.getScc(), src0, src1); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_MUL_I32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); - auto resultT = fragment.context->getSint32Type(); - auto result = fragment.builder.createIMul(resultT, src0, src1); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_AND_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createBitwiseAnd(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_ANDN2_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createBitwiseAnd( - resultT, src0, fragment.builder.createNot(resultT, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_AND_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - auto resultT = fragment.context->getUInt64Type(); - auto result = fragment.builder.createBitwiseAnd(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_ANDN2_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - auto resultT = fragment.context->getUInt64Type(); - auto result = fragment.builder.createBitwiseAnd( - resultT, src0, fragment.builder.createNot(resultT, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_OR_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createBitwiseOr(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_OR_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - auto resultT = fragment.context->getUInt64Type(); - auto result = fragment.builder.createBitwiseOr(resultT, src0, src1); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_NAND_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createNot( - resultT, fragment.builder.createBitwiseAnd(resultT, src0, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_NAND_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - auto resultT = fragment.context->getUInt64Type(); - auto result = fragment.builder.createNot( - resultT, fragment.builder.createBitwiseAnd(resultT, src0, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_NOR_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createNot( - resultT, fragment.builder.createBitwiseOr(resultT, src0, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - case Sop2::Op::S_NOR_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); - auto resultT = fragment.context->getUInt64Type(); - auto result = fragment.builder.createNot( - resultT, fragment.builder.createBitwiseOr(resultT, src0, src1)); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - case Sop2::Op::S_BFE_U32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - - auto operandT = fragment.context->getUInt32Type(); - - auto offset = - spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x1f))); - auto size = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, - fragment.builder.createShiftRightLogical( - operandT, src1, fragment.context->getUInt32(16)), - fragment.context->getUInt32(0x7f))); - - auto field = - fragment.builder.createShiftRightLogical(operandT, src0, offset); - auto mask = fragment.builder.createISub( - operandT, - fragment.builder.createShiftLeftLogical( - operandT, fragment.context->getUInt32(1), size), - fragment.context->getUInt32(1)); - - auto result = fragment.builder.createBitwiseAnd(operandT, field, mask); - auto resultT = fragment.context->getUInt32Type(); - fragment.setScc({resultT, result}); - fragment.setScalarOperand(inst.sdst, {resultT, result}); - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} -void convertSopk(Fragment &fragment, Sopk inst) { - fragment.registers->pc += Sopk::kMinInstSize * sizeof(std::uint32_t); - switch (inst.op) { - case Sopk::Op::S_MOVK_I32: - fragment.setScalarOperand(inst.sdst, - {fragment.context->getSint32Type(), - fragment.context->getSInt32(inst.simm)}); - break; - default: - inst.dump(); - util::unreachable(); - } -} -void convertSmrd(Fragment &fragment, Smrd inst) { - fragment.registers->pc += Smrd::kMinInstSize * sizeof(std::uint32_t); - - auto getOffset = [&](std::int32_t adv = 0) -> spirv::IntValue { - if (inst.imm) { - return fragment.context->getUInt32(inst.offset + adv); - } - - auto resultT = fragment.context->getUInt32Type(); - auto resultV = fragment.getScalarOperand(inst.offset, TypeId::UInt32).value; - - if (auto constVal = fragment.context->findUint32Value(resultV)) { - return fragment.context->getUInt32(*constVal / 4 + adv); - } - - auto result = fragment.builder.createUDiv( - resultT, spirv::cast(resultV), - fragment.context->getUInt32(4)); - - if (adv != 0) { - result = fragment.builder.createIAdd(resultT, result, - fragment.context->getUInt32(adv)); - } - return result; - }; - - switch (inst.op) { - case Smrd::Op::S_BUFFER_LOAD_DWORD: - case Smrd::Op::S_BUFFER_LOAD_DWORDX2: - case Smrd::Op::S_BUFFER_LOAD_DWORDX4: - case Smrd::Op::S_BUFFER_LOAD_DWORDX8: - case Smrd::Op::S_BUFFER_LOAD_DWORDX16: { - std::uint32_t count = 1 - << (static_cast(inst.op) - - static_cast(Smrd::Op::S_BUFFER_LOAD_DWORD)); - auto vBuffer0 = - fragment.getScalarOperand((inst.sbase << 1) + 0, TypeId::UInt32); - auto vBuffer1 = - fragment.getScalarOperand((inst.sbase << 1) + 1, TypeId::UInt32); - auto vBuffer2 = - fragment.getScalarOperand((inst.sbase << 1) + 2, TypeId::UInt32); - auto vBuffer3 = - fragment.getScalarOperand((inst.sbase << 1) + 3, TypeId::UInt32); - - auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); - auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); - auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); - auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); - - if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && - optVBuffer3Value) { - std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, - *optVBuffer2Value, *optVBuffer3Value}; - auto vbuffer = reinterpret_cast(vBufferData); - // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); - - auto valueT = fragment.context->getFloat32Type(); - auto uniform = fragment.context->getOrCreateStorageBuffer( - vBufferData, TypeId::Float32); - uniform->accessOp |= AccessOp::Load; - auto storageBufferPointerType = fragment.context->getPointerType( - spv::StorageClass::StorageBuffer, TypeId::Float32); - - for (std::uint32_t i = 0; i < count; ++i) { - auto storageBufferPointerValue = fragment.builder.createAccessChain( - storageBufferPointerType, uniform->variable, - {{fragment.context->getUInt32(0), getOffset(i)}}); - - auto value = - fragment.builder.createLoad(valueT, storageBufferPointerValue); - fragment.setScalarOperand(inst.sdst + i, {valueT, value}); - } - } else { - // FIXME: implement runtime V# buffer fetching - util::unreachable(); - } - break; - } - - case Smrd::Op::S_LOAD_DWORD: - case Smrd::Op::S_LOAD_DWORDX2: - case Smrd::Op::S_LOAD_DWORDX4: - case Smrd::Op::S_LOAD_DWORDX8: - case Smrd::Op::S_LOAD_DWORDX16: { - std::uint32_t count = 1 << (static_cast(inst.op) - - static_cast(Smrd::Op::S_LOAD_DWORD)); - - auto uint32T = fragment.context->getUInt32Type(); - auto sgprLo = fragment.getScalarOperand(inst.sbase << 1, TypeId::UInt32); - auto sgprHi = - fragment.getScalarOperand((inst.sbase << 1) + 1, TypeId::UInt32); - auto optLoAddress = fragment.context->findUint32Value(sgprLo.value); - auto optHiAddress = fragment.context->findUint32Value(sgprHi.value); - - if (inst.imm && optLoAddress && optHiAddress) { - // if it is imm and address is known, read the values now - auto memory = fragment.context->getMemory(); - auto address = - *optLoAddress | (static_cast(*optHiAddress) << 32); - - fragment.context->dependencies->map(address + (inst.offset << 2), - address + (inst.offset << 2) + - sizeof(std::uint32_t) * count); - - auto data = - memory.getPointer(address + (inst.offset << 2)); - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setScalarOperand( - inst.sdst + i, {uint32T, fragment.context->getUInt32(data[i])}); - } - } else { - // FIXME: implement - // TODO: create uniform and do load from it - util::unreachable(); - } - - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} -void convertVop3(Fragment &fragment, Vop3 inst) { - fragment.registers->pc += Vop3::kMinInstSize * sizeof(std::uint32_t); - - auto applyOmod = [&](Value result) -> Value { - switch (inst.omod) { - case 1: - return {result.type, fragment.builder.createFMul( - spirv::cast(result.type), - spirv::cast(result.value), - fragment.context->getFloat32(2))}; - - case 2: - return {result.type, fragment.builder.createFMul( - spirv::cast(result.type), - spirv::cast(result.value), - fragment.context->getFloat32(4))}; - case 3: - return {result.type, fragment.builder.createFDiv( - spirv::cast(result.type), - spirv::cast(result.value), - fragment.context->getFloat32(2))}; - - default: - case 0: - return result; - } - }; - - auto applyClamp = [&](Value result) -> Value { - if (inst.clmp) { - auto glslStd450 = fragment.context->getGlslStd450(); - result.value = fragment.builder.createExtInst( - result.type, glslStd450, GLSLstd450FClamp, - {{result.value, fragment.context->getFloat32(0), - fragment.context->getFloat32(1)}}); - } - - return result; - }; - - auto getSrc = [&](int index, TypeId type) -> Value { - std::uint32_t src = - index == 0 ? inst.src0 : (index == 1 ? inst.src1 : inst.src2); - - auto result = fragment.getScalarOperand(src, type); - - if (inst.abs & (1 << index)) { - auto glslStd450 = fragment.context->getGlslStd450(); - result.value = fragment.builder.createExtInst( - result.type, glslStd450, GLSLstd450FAbs, {{result.value}}); - } - - if (inst.neg & (1 << index)) { - result.value = fragment.builder.createFNegate( - spirv::cast(result.type), - spirv::cast(result.value)); - } - - return result; - }; - - auto getSdstSrc = [&](int index, TypeId type) -> Value { - std::uint32_t src = - index == 0 ? inst.src0 : (index == 1 ? inst.src1 : inst.src2); - - auto result = fragment.getScalarOperand(src, type); - - if (inst.neg & (1 << index)) { - result.value = fragment.builder.createFNegate( - spirv::cast(result.type), - spirv::cast(result.value)); - } - - return result; - }; - - auto roundEven = [&](spirv::Type type, spirv::Value value) { - auto glslStd450 = fragment.context->getGlslStd450(); - return Value{type, fragment.builder.createExtInst( - type, glslStd450, GLSLstd450RoundEven, {{value}})}; - }; - - auto cmpOp = [&](TypeId type, CmpKind kind, CmpFlags flags = CmpFlags::None) { - auto src0 = fragment.getScalarOperand(inst.src0, type).value; - auto src1 = fragment.getScalarOperand(inst.src1, type).value; - - std::int8_t typeMask = 0; - if (kind == CmpKind::CLASS) { - auto value = fragment.context->findSint32Value( - fragment.getScalarOperand(inst.src2, type).value); - - if (!value) { - // util::unreachable(); - typeMask = 2; - } else { - typeMask = *value; - } - } - - auto result = doCmpOp(fragment, type, src0, src1, kind, flags, typeMask); - fragment.setScalarOperand(inst.vdst, result); - fragment.setScalarOperand(inst.vdst + 1, {fragment.context->getUInt32Type(), - fragment.context->getUInt32(0)}); - }; - - switch (inst.op) { - case Vop3::Op::V3_CMP_F_F32: - cmpOp(TypeId::Float32, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG); - break; - case Vop3::Op::V3_CMP_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_O_F32: - cmpOp(TypeId::Float32, CmpKind::O); - break; - case Vop3::Op::V3_CMP_U_F32: - cmpOp(TypeId::Float32, CmpKind::U); - break; - case Vop3::Op::V3_CMP_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE); - break; - case Vop3::Op::V3_CMP_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG); - break; - case Vop3::Op::V3_CMP_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT); - break; - case Vop3::Op::V3_CMP_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE); - break; - case Vop3::Op::V3_CMP_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ); - break; - case Vop3::Op::V3_CMP_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT); - break; - case Vop3::Op::V3_CMP_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU); - break; - case Vop3::Op::V3_CMPX_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::X); - break; - case Vop3::Op::V3_CMP_F_F64: - cmpOp(TypeId::Float64, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG); - break; - case Vop3::Op::V3_CMP_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_O_F64: - cmpOp(TypeId::Float64, CmpKind::O); - break; - case Vop3::Op::V3_CMP_U_F64: - cmpOp(TypeId::Float64, CmpKind::U); - break; - case Vop3::Op::V3_CMP_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE); - break; - case Vop3::Op::V3_CMP_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG); - break; - case Vop3::Op::V3_CMP_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT); - break; - case Vop3::Op::V3_CMP_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE); - break; - case Vop3::Op::V3_CMP_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ); - break; - case Vop3::Op::V3_CMP_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT); - break; - case Vop3::Op::V3_CMP_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU); - break; - case Vop3::Op::V3_CMPX_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::X); - break; - case Vop3::Op::V3_CMPS_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::S); - break; - case Vop3::Op::V3_CMPSX_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPS_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::S); - break; - case Vop3::Op::V3_CMPS_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::S); - break; - case Vop3::Op::V3_CMPSX_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::SX); - break; - case Vop3::Op::V3_CMPSX_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::SX); - break; - case Vop3::Op::V3_CMP_F_I32: - cmpOp(TypeId::SInt32, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_I32: - cmpOp(TypeId::SInt32, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_I32: - cmpOp(TypeId::SInt32, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_I32: - cmpOp(TypeId::SInt32, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_I32: - cmpOp(TypeId::SInt32, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_I32: - cmpOp(TypeId::SInt32, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_I32: - cmpOp(TypeId::SInt32, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_T_I32: - cmpOp(TypeId::SInt32, CmpKind::T); - break; - case Vop3::Op::V3_CMP_CLASS_F32: - cmpOp(TypeId::Float32, CmpKind::CLASS); - break; - case Vop3::Op::V3_CMP_LT_I16: - cmpOp(TypeId::SInt16, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_I16: - cmpOp(TypeId::SInt16, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_I16: - cmpOp(TypeId::SInt16, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_I16: - cmpOp(TypeId::SInt16, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_I16: - cmpOp(TypeId::SInt16, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_I16: - cmpOp(TypeId::SInt16, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_CLASS_F16: - cmpOp(TypeId::Float16, CmpKind::CLASS); - break; - case Vop3::Op::V3_CMPX_F_I32: - cmpOp(TypeId::SInt32, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_I32: - cmpOp(TypeId::SInt32, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_I32: - cmpOp(TypeId::SInt32, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_I32: - cmpOp(TypeId::SInt32, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_I32: - cmpOp(TypeId::SInt32, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_I32: - cmpOp(TypeId::SInt32, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_I32: - cmpOp(TypeId::SInt32, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_T_I32: - cmpOp(TypeId::SInt32, CmpKind::T, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_CLASS_F32: - cmpOp(TypeId::Float32, CmpKind::CLASS, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_I16: - cmpOp(TypeId::SInt16, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_I16: - cmpOp(TypeId::SInt16, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_I16: - cmpOp(TypeId::SInt16, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_I16: - cmpOp(TypeId::SInt16, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_I16: - cmpOp(TypeId::SInt16, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_I16: - cmpOp(TypeId::SInt16, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_CLASS_F16: - cmpOp(TypeId::Float16, CmpKind::CLASS, CmpFlags::X); - break; - case Vop3::Op::V3_CMP_F_I64: - cmpOp(TypeId::SInt64, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_I64: - cmpOp(TypeId::SInt64, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_I64: - cmpOp(TypeId::SInt64, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_I64: - cmpOp(TypeId::SInt64, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_I64: - cmpOp(TypeId::SInt64, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_I64: - cmpOp(TypeId::SInt64, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_I64: - cmpOp(TypeId::SInt64, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_T_I64: - cmpOp(TypeId::SInt64, CmpKind::T); - break; - case Vop3::Op::V3_CMP_CLASS_F64: - cmpOp(TypeId::Float64, CmpKind::CLASS); - break; - case Vop3::Op::V3_CMP_LT_U16: - cmpOp(TypeId::UInt16, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_U16: - cmpOp(TypeId::UInt16, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_U16: - cmpOp(TypeId::UInt16, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_U16: - cmpOp(TypeId::UInt16, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_U16: - cmpOp(TypeId::UInt16, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_U16: - cmpOp(TypeId::UInt16, CmpKind::GE); - break; - case Vop3::Op::V3_CMPX_F_I64: - cmpOp(TypeId::SInt64, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_I64: - cmpOp(TypeId::SInt64, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_I64: - cmpOp(TypeId::SInt64, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_I64: - cmpOp(TypeId::SInt64, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_I64: - cmpOp(TypeId::SInt64, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_I64: - cmpOp(TypeId::SInt64, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_I64: - cmpOp(TypeId::SInt64, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_T_I64: - cmpOp(TypeId::SInt64, CmpKind::T, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_CLASS_F64: - cmpOp(TypeId::Float64, CmpKind::CLASS, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_U16: - cmpOp(TypeId::UInt16, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_U16: - cmpOp(TypeId::UInt16, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_U16: - cmpOp(TypeId::UInt16, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_U16: - cmpOp(TypeId::UInt16, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_U16: - cmpOp(TypeId::UInt16, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_U16: - cmpOp(TypeId::UInt16, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMP_F_U32: - cmpOp(TypeId::UInt32, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_U32: - cmpOp(TypeId::UInt32, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_U32: - cmpOp(TypeId::UInt32, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_U32: - cmpOp(TypeId::UInt32, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_U32: - cmpOp(TypeId::UInt32, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_U32: - cmpOp(TypeId::UInt32, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_U32: - cmpOp(TypeId::UInt32, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_T_U32: - cmpOp(TypeId::UInt32, CmpKind::T); - break; - case Vop3::Op::V3_CMP_F_F16: - cmpOp(TypeId::Float16, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_F16: - cmpOp(TypeId::Float16, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_F16: - cmpOp(TypeId::Float16, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_F16: - cmpOp(TypeId::Float16, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_F16: - cmpOp(TypeId::Float16, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_LG_F16: - cmpOp(TypeId::Float16, CmpKind::LG); - break; - case Vop3::Op::V3_CMP_GE_F16: - cmpOp(TypeId::Float16, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_O_F16: - cmpOp(TypeId::Float16, CmpKind::O); - break; - case Vop3::Op::V3_CMPX_F_U32: - cmpOp(TypeId::UInt32, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_U32: - cmpOp(TypeId::UInt32, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_U32: - cmpOp(TypeId::UInt32, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_U32: - cmpOp(TypeId::UInt32, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_U32: - cmpOp(TypeId::UInt32, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_U32: - cmpOp(TypeId::UInt32, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_U32: - cmpOp(TypeId::UInt32, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_T_U32: - cmpOp(TypeId::UInt32, CmpKind::T, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_F_F16: - cmpOp(TypeId::Float16, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_F16: - cmpOp(TypeId::Float16, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_F16: - cmpOp(TypeId::Float16, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_F16: - cmpOp(TypeId::Float16, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_F16: - cmpOp(TypeId::Float16, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LG_F16: - cmpOp(TypeId::Float16, CmpKind::LG, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_F16: - cmpOp(TypeId::Float16, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_O_F16: - cmpOp(TypeId::Float16, CmpKind::O, CmpFlags::X); - break; - case Vop3::Op::V3_CMP_F_U64: - cmpOp(TypeId::UInt64, CmpKind::F); - break; - case Vop3::Op::V3_CMP_LT_U64: - cmpOp(TypeId::UInt64, CmpKind::LT); - break; - case Vop3::Op::V3_CMP_EQ_U64: - cmpOp(TypeId::UInt64, CmpKind::EQ); - break; - case Vop3::Op::V3_CMP_LE_U64: - cmpOp(TypeId::UInt64, CmpKind::LE); - break; - case Vop3::Op::V3_CMP_GT_U64: - cmpOp(TypeId::UInt64, CmpKind::GT); - break; - case Vop3::Op::V3_CMP_NE_U64: - cmpOp(TypeId::UInt64, CmpKind::NE); - break; - case Vop3::Op::V3_CMP_GE_U64: - cmpOp(TypeId::UInt64, CmpKind::GE); - break; - case Vop3::Op::V3_CMP_T_U64: - cmpOp(TypeId::UInt64, CmpKind::T); - break; - case Vop3::Op::V3_CMP_U_F16: - cmpOp(TypeId::Float16, CmpKind::U); - break; - case Vop3::Op::V3_CMP_NGE_F16: - cmpOp(TypeId::Float16, CmpKind::NGE); - break; - case Vop3::Op::V3_CMP_NLG_F16: - cmpOp(TypeId::Float16, CmpKind::NLG); - break; - case Vop3::Op::V3_CMP_NGT_F16: - cmpOp(TypeId::Float16, CmpKind::NGT); - break; - case Vop3::Op::V3_CMP_NLE_F16: - cmpOp(TypeId::Float16, CmpKind::NLE); - break; - case Vop3::Op::V3_CMP_NEQ_F16: - cmpOp(TypeId::Float16, CmpKind::NEQ); - break; - case Vop3::Op::V3_CMP_NLT_F16: - cmpOp(TypeId::Float16, CmpKind::NLT); - break; - case Vop3::Op::V3_CMP_TRU_F16: - cmpOp(TypeId::Float16, CmpKind::TRU); - break; - case Vop3::Op::V3_CMPX_F_U64: - cmpOp(TypeId::UInt64, CmpKind::F, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LT_U64: - cmpOp(TypeId::UInt64, CmpKind::LT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_EQ_U64: - cmpOp(TypeId::UInt64, CmpKind::EQ, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_LE_U64: - cmpOp(TypeId::UInt64, CmpKind::LE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GT_U64: - cmpOp(TypeId::UInt64, CmpKind::GT, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_NE_U64: - cmpOp(TypeId::UInt64, CmpKind::NE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_GE_U64: - cmpOp(TypeId::UInt64, CmpKind::GE, CmpFlags::X); - break; - case Vop3::Op::V3_CMPX_T_U64: - cmpOp(TypeId::UInt64, CmpKind::T, CmpFlags::X); - break; - - case Vop3::Op::V3_RCP_F32: { - auto src = getSrc(0, TypeId::Float32); - auto floatT = fragment.context->getFloat32Type(); - auto float1 = fragment.context->getFloat32(1); - auto resultValue = fragment.builder.createFDiv( - floatT, float1, spirv::cast(src.value)); - auto result = applyClamp(applyOmod({floatT, resultValue})); - - fragment.setVectorOperand(inst.vdst, roundEven(result.type, result.value)); - break; - } - - case Vop3::Op::V3_ADD_I32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getScalarOperand(inst.src1, TypeId::UInt32).value; - auto uintT = fragment.context->getType(TypeId::UInt32); - auto resultStruct = - fragment.context->getStructType(std::array{uintT, uintT}); - auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); - fragment.setVectorOperand( - inst.vdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(0)})}); - fragment.setScalarOperand( - inst.sdst, - {uintT, fragment.builder.createCompositeExtract( - uintT, result, std::array{static_cast(1)})}); - fragment.setScalarOperand(inst.sdst + 1, - {uintT, fragment.context->getUInt32(0)}); - break; - } - - case Vop3::Op::V3_MOV_B32: { - auto src0 = getSrc(0, TypeId::Float32); - - fragment.setVectorOperand(inst.vdst, src0); - break; - } - - case Vop3::Op::V3_ADD_F32: { - auto floatT = fragment.context->getFloat32Type(); - auto src0 = getSrc(0, TypeId::Float32); - auto src1 = getSrc(1, TypeId::Float32); - auto resultValue = fragment.builder.createFAdd( - floatT, spirv::cast(src0.value), - spirv::cast(src1.value)); - auto result = applyClamp(applyOmod({floatT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - - case Vop3::Op::V3_SUB_F32: { - auto floatT = fragment.context->getFloat32Type(); - auto src0 = getSrc(0, TypeId::Float32); - auto src1 = getSrc(1, TypeId::Float32); - auto resultValue = fragment.builder.createFSub( - floatT, spirv::cast(src0.value), - spirv::cast(src1.value)); - auto result = applyClamp(applyOmod({floatT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - - case Vop3::Op::V3_MUL_F32: { - auto floatT = fragment.context->getFloat32Type(); - auto src0 = getSrc(0, TypeId::Float32); - auto src1 = getSrc(1, TypeId::Float32); - auto resultValue = fragment.builder.createFMul( - floatT, spirv::cast(src0.value), - spirv::cast(src1.value)); - auto result = applyClamp(applyOmod({floatT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - case Vop3::Op::V3_MUL_LO_U32: { - auto resultT = fragment.context->getUInt32Type(); - auto src0 = getSrc(0, TypeId::UInt32); - auto src1 = getSrc(1, TypeId::UInt32); - auto resultValue = fragment.builder.createIMul( - resultT, spirv::cast(src0.value), - spirv::cast(src1.value)); - auto result = applyClamp(applyOmod({resultT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - case Vop3::Op::V3_MUL_LO_I32: { - auto resultT = fragment.context->getSint32Type(); - auto src0 = getSrc(0, TypeId::SInt32); - auto src1 = getSrc(1, TypeId::SInt32); - auto resultValue = fragment.builder.createIMul( - resultT, spirv::cast(src0.value), - spirv::cast(src1.value)); - auto result = applyClamp(applyOmod({resultT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - case Vop3::Op::V3_MUL_HI_I32: { - auto resultT = fragment.context->getSint32Type(); - auto src0 = getSrc(0, TypeId::SInt32); - auto src1 = getSrc(1, TypeId::SInt32); - - auto sint64T = fragment.context->getSint64Type(); - - auto src0_64 = fragment.builder.createSConvert( - sint64T, spirv::cast(src0.value)); - auto src1_64 = fragment.builder.createSConvert( - sint64T, spirv::cast(src1.value)); - - auto resultValue64 = fragment.builder.createIMul( - sint64T, spirv::cast(src0_64), - spirv::cast(src1_64)); - - resultValue64 = fragment.builder.createShiftRightLogical( - sint64T, resultValue64, fragment.context->getUInt32(32)); - auto resultValue = fragment.builder.createSConvert(resultT, resultValue64); - auto result = applyClamp(applyOmod({resultT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - case Vop3::Op::V3_MUL_HI_U32: { - auto resultT = fragment.context->getUInt32Type(); - auto src0 = spirv::cast(getSrc(0, TypeId::UInt32).value); - auto src1 = spirv::cast(getSrc(1, TypeId::UInt32).value); - - auto uint64T = fragment.context->getUInt64Type(); - - auto src0_64 = fragment.builder.createUConvert(uint64T, src0); - auto src1_64 = fragment.builder.createUConvert(uint64T, src1); - - auto resultValue64 = fragment.builder.createIMul(uint64T, src0_64, src1_64); - - resultValue64 = fragment.builder.createShiftRightLogical( - uint64T, resultValue64, fragment.context->getUInt32(32)); - auto resultValue = fragment.builder.createUConvert(resultT, resultValue64); - auto result = applyClamp(applyOmod({resultT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - - case Vop3::Op::V3_MAC_F32: { - auto floatT = fragment.context->getFloat32Type(); - auto src0 = getSrc(0, TypeId::Float32); - auto src1 = getSrc(1, TypeId::Float32); - - auto dst = spirv::cast( // FIXME: should use src2? - fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); - - auto resultValue = fragment.builder.createFAdd( - floatT, - fragment.builder.createFMul(floatT, - spirv::cast(src0.value), - spirv::cast(src1.value)), - dst); - - auto result = applyClamp(applyOmod({floatT, resultValue})); - - fragment.setVectorOperand(inst.vdst, result); - break; - } - case Vop3::Op::V3_MAD_U32_U24: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt32Type(); - - src0 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src0, fragment.context->getUInt32((1 << 24) - 1))); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32((1 << 24) - 1))); - - auto result = fragment.builder.createIAdd( - operandT, fragment.builder.createIMul(operandT, src0, src1), src2); - - fragment.setVectorOperand(inst.vdst, {operandT, result}); - break; - } - case Vop3::Op::V3_MAD_I32_I24: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::SInt32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::SInt32).value); - auto operandT = fragment.context->getSint32Type(); - - src0 = fragment.builder.createShiftLeftLogical( - operandT, src0, fragment.context->getUInt32(8)); - src0 = fragment.builder.createShiftRightArithmetic( - operandT, src0, fragment.context->getUInt32(8)); - src1 = fragment.builder.createShiftLeftLogical( - operandT, src1, fragment.context->getUInt32(8)); - src1 = fragment.builder.createShiftRightArithmetic( - operandT, src1, fragment.context->getUInt32(8)); - - auto result = fragment.builder.createIAdd( - operandT, fragment.builder.createIMul(operandT, src0, src1), src2); - - fragment.setVectorOperand(inst.vdst, {operandT, result}); - break; - } - case Vop3::Op::V3_MUL_U32_U24: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt32Type(); - - src0 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src0, fragment.context->getUInt32((1 << 24) - 1))); - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32((1 << 24) - 1))); - - auto result = fragment.builder.createIMul(operandT, src0, src1); - - fragment.setVectorOperand(inst.vdst, {operandT, result}); - break; - } - case Vop3::Op::V3_MUL_I32_I24: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::SInt32).value); - auto operandT = fragment.context->getSint32Type(); - - src0 = fragment.builder.createShiftLeftLogical( - operandT, src0, fragment.context->getUInt32(8)); - src0 = fragment.builder.createShiftRightArithmetic( - operandT, src0, fragment.context->getUInt32(8)); - src1 = fragment.builder.createShiftLeftLogical( - operandT, src1, fragment.context->getUInt32(8)); - src1 = fragment.builder.createShiftRightArithmetic( - operandT, src1, fragment.context->getUInt32(8)); - - auto result = fragment.builder.createIMul(operandT, src0, src1); - - fragment.setVectorOperand(inst.vdst, {operandT, result}); - break; - } - case Vop3::Op::V3_MAD_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto result = fragment.builder.createFAdd( - floatT, fragment.builder.createFMul(floatT, src0, src1), src2); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop3::Op::V3_MAX_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), - src0, src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop3::Op::V3_MAX3_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto max01 = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), - src0, src1); - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, max01, src2), - max01, src2); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop3::Op::V3_MIN_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, - src1); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop3::Op::V3_MIN3_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto boolT = fragment.context->getBoolType(); - - auto min01 = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, - src1); - auto result = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, min01, src2), min01, - src2); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop3::Op::V3_MED3_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::Float32).value); - auto boolT = fragment.context->getBoolType(); - auto floatT = fragment.context->getFloat32Type(); - auto glslStd450 = fragment.context->getGlslStd450(); - - auto min01 = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, - src1); - auto max01 = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdGreaterThan(boolT, src0, src1), src0, - src1); - auto minMax011 = fragment.builder.createSelect( - floatT, fragment.builder.createFOrdLessThan(boolT, max01, src2), max01, - src2); - - auto result = fragment.builder.createExtInst( - floatT, glslStd450, GLSLstd450NMax, {{min01, minMax011}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - } - case Vop3::Op::V3_FMA_F32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::Float32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto glslStd450 = fragment.context->getGlslStd450(); - - auto result = fragment.builder.createExtInst( - floatT, glslStd450, GLSLstd450Fma, {{src0, src1, src2}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop3::Op::V3_CNDMASK_B32: { - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto src1 = fragment.getScalarOperand(inst.src1, TypeId::UInt32).value; - auto src2 = fragment.getScalarOperand(inst.src2, TypeId::UInt32).value; - - auto cmp = fragment.builder.createINotEqual( - fragment.context->getBoolType(), src2, fragment.context->getUInt32(0)); - - auto uint32T = fragment.context->getUInt32Type(); - auto result = fragment.builder.createSelect(uint32T, cmp, src1, src0); - fragment.setVectorOperand(inst.vdst, {uint32T, result}); - break; - } - - case Vop3::Op::V3_BFE_U32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); - auto src2 = spirv::cast( - fragment.getScalarOperand(inst.src2, TypeId::UInt32).value); - - auto operandT = fragment.context->getUInt32Type(); - - auto voffset = - spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x1f))); - auto vsize = - spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src2, fragment.context->getUInt32(0x1f))); - auto field = - fragment.builder.createShiftRightLogical(operandT, src0, voffset); - auto mask = fragment.builder.createISub( - operandT, - fragment.builder.createShiftLeftLogical( - operandT, fragment.context->getUInt32(1), vsize), - fragment.context->getUInt32(1)); - - auto resultT = fragment.context->getUInt32Type(); - auto result = fragment.builder.createSelect( - operandT, - fragment.builder.createIEqual(fragment.context->getBoolType(), vsize, - fragment.context->getUInt32(0)), - fragment.context->getUInt32(0), - fragment.builder.createBitwiseAnd(operandT, field, mask)); - fragment.setVectorOperand(inst.vdst, {resultT, result}); - break; - } - - case Vop3::Op::V3_CVT_PKRTZ_F16_F32: { - auto float2T = fragment.context->getType(TypeId::Float32x2); - auto uintT = fragment.context->getType(TypeId::UInt32); - auto glslStd450 = fragment.context->getGlslStd450(); - - auto src0 = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; - auto src1 = fragment.getScalarOperand(inst.src1, TypeId::Float32).value; - - auto src = fragment.builder.createCompositeConstruct( - float2T, std::array{src0, src1}); - auto dst = fragment.builder.createExtInst( - uintT, glslStd450, GLSLstd450PackHalf2x16, std::array{src}); - - fragment.setVectorOperand(inst.vdst, {uintT, dst}); - break; - } - - case Vop3::Op::V3_SAD_U32: { - auto src0 = spirv::cast(getSrc(0, TypeId::UInt32).value); - auto src1 = spirv::cast(getSrc(1, TypeId::UInt32).value); - auto src2 = spirv::cast(getSrc(2, TypeId::UInt32).value); - - auto uint32T = fragment.context->getUInt32Type(); - auto sint32T = fragment.context->getSint32Type(); - - auto diff = fragment.builder.createISub(uint32T, src0, src1); - auto sdiff = fragment.builder.createBitcast(sint32T, diff); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto sabsdiff = fragment.builder.createExtInst(sint32T, glslStd450, - GLSLstd450SAbs, {{sdiff}}); - - auto absdiff = fragment.builder.createBitcast(uint32T, sabsdiff); - auto result = fragment.builder.createIAdd(uint32T, absdiff, src2); - fragment.setVectorOperand(inst.vdst, {uint32T, result}); - break; - } - case Vop3::Op::V3_RSQ_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst( - floatT, glslStd450, GLSLstd450InverseSqrt, {{src}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertMubuf(Fragment &fragment, Mubuf inst) { - fragment.registers->pc += Mubuf::kMinInstSize * sizeof(std::uint32_t); - /* - printMubufOpcode(op); - printf(" "); - printVectorOperand(vdata, inst + instSize); - printf(", "); - printScalarOperand(srsrc << 2, inst + instSize); - printf(", "); - printScalarOperand(soffset, inst + instSize); - */ - - auto getSOffset = [&](std::int32_t adv = 0) -> spirv::UIntValue { - auto resultT = fragment.context->getUInt32Type(); - auto resultV = - fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value; - auto result = spirv::cast(resultV); - - if (adv != 0) { - if (auto constVal = fragment.context->findSint32Value(result)) { - return fragment.context->getUInt32(*constVal + adv); - } - - result = fragment.builder.createIAdd(resultT, result, - fragment.context->getUInt32(adv)); - } - - return result; - }; - - auto getVBuffer = [&] { - auto vBuffer0 = - fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); - auto vBuffer1 = - fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); - auto vBuffer2 = - fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); - auto vBuffer3 = - fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); - - auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); - auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); - auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); - auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); - - if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && - optVBuffer3Value) { - // V# buffer value is known, read the buffer now - std::array vBufferData = { - *optVBuffer0Value, *optVBuffer1Value, *optVBuffer2Value, - *optVBuffer3Value}; - - GnmVBuffer result; - std::memcpy(&result, vBufferData.data(), sizeof(result)); - return result; - } - - util::unreachable(); - }; - - auto getAddress = [&](GnmVBuffer *vbuffer) { - auto &builder = fragment.builder; - auto uint32T = fragment.context->getUInt32Type(); - - spirv::UIntValue index; - if (inst.idxen) { - index = spirv::cast( - fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); - } - - // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); - - if (vbuffer->addtid_en) { - spirv::UIntValue threadId = - builder.createLoad(uint32T, fragment.context->getThreadId()); - - if (index) { - index = builder.createIAdd(uint32T, index, threadId); - } else { - index = threadId; - } - } - - auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) - : spirv::UIntValue{}; - - if (inst.offen) { - auto off = spirv::cast( - fragment - .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), - TypeId::UInt32) - .value); - - if (offset) { - offset = builder.createIAdd(uint32T, off, offset); - } else { - offset = off; - } - } - - spirv::UIntValue address = getSOffset(); - - if (vbuffer->swizzle_en == 0) { - if (vbuffer->stride == 0 || !index) { - return address; - } - - auto offset = builder.createIMul( - uint32T, index, fragment.context->getUInt32(vbuffer->stride)); - if (address == fragment.context->getUInt32(0)) { - return offset; - } - - return builder.createIAdd(uint32T, address, offset); - } - - if (!index && !offset) { - return address; - } - - if (index && offset) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - auto offsetMsb = builder.createIMul( - uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, - builder.createIAdd(uint32T, indexMsb, offsetMsb), - indexStride)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, index_lsb, elementSize)); - - return builder.createIAdd(uint32T, address, offset_lsb); - } - - if (index) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - - return builder.createIAdd( - uint32T, address, builder.createIMul(uint32T, indexMsb, indexStride)); - } - - if (!offset) { - util::unreachable(); - } - - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto offsetMsb = - builder.createIMul(uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, builder.createIMul(uint32T, offsetMsb, indexStride)); - - return builder.createIAdd(uint32T, address, offset_lsb); - }; - - switch (inst.op) { - case Mubuf::Op::BUFFER_LOAD_FORMAT_X: - case Mubuf::Op::BUFFER_LOAD_FORMAT_XY: - case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZ: - case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZW: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mubuf::Op::BUFFER_LOAD_FORMAT_X) + 1; - - auto vbuffer = getVBuffer(); - if (vbuffer.dfmt != kSurfaceFormatInvalid) { - auto address = getAddress(&vbuffer); - - spirv::Value result[4]; - auto resultType = convertFromFormat( - result, count, fragment, reinterpret_cast(&vbuffer), - address, vbuffer.dfmt, vbuffer.nfmt); - - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setVectorOperand(inst.vdata + i, {resultType, result[i]}); - } - } else { - auto floatT = fragment.context->getFloat32Type(); - auto zero = fragment.context->getFloat32(0); - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setVectorOperand(inst.vdata + i, {floatT, zero}); - } - } - break; - } - - case Mubuf::Op::BUFFER_STORE_FORMAT_X: - case Mubuf::Op::BUFFER_STORE_FORMAT_XY: - case Mubuf::Op::BUFFER_STORE_FORMAT_XYZ: - case Mubuf::Op::BUFFER_STORE_FORMAT_XYZW: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mubuf::Op::BUFFER_STORE_FORMAT_X) + - 1; - - auto vbuffer = getVBuffer(); - if (vbuffer.dfmt != kSurfaceFormatInvalid) { - auto address = getAddress(&vbuffer); - - convertToFormat(RegisterId::Vector(inst.vdata), count, fragment, - reinterpret_cast(&vbuffer), address, - vbuffer.dfmt, vbuffer.nfmt); - } - break; - } - - case Mubuf::Op::BUFFER_LOAD_UBYTE: - case Mubuf::Op::BUFFER_LOAD_USHORT: - case Mubuf::Op::BUFFER_LOAD_SSHORT: - case Mubuf::Op::BUFFER_LOAD_SBYTE: - inst.dump(); - util::unreachable(); - - case Mubuf::Op::BUFFER_LOAD_DWORD: - case Mubuf::Op::BUFFER_LOAD_DWORDX2: - case Mubuf::Op::BUFFER_LOAD_DWORDX4: - case Mubuf::Op::BUFFER_LOAD_DWORDX3: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mubuf::Op::BUFFER_LOAD_DWORD) + 1; - - auto vbuffer = getVBuffer(); - auto address = getAddress(&vbuffer); - auto loadType = fragment.context->getType(TypeId::UInt32); - auto uniform = fragment.context->getOrCreateStorageBuffer( - reinterpret_cast(&vbuffer), TypeId::UInt32); - uniform->accessOp |= AccessOp::Load; - - auto uniformPointerType = fragment.context->getPointerType( - spv::StorageClass::StorageBuffer, TypeId::UInt32); - address = - fragment.builder.createUDiv(fragment.context->getUInt32Type(), address, - fragment.context->getUInt32(4)); - - for (int i = 0; i < count; ++i) { - auto channelOffset = address; - - if (i != 0) { - channelOffset = fragment.builder.createIAdd( - fragment.context->getUInt32Type(), channelOffset, - fragment.context->getUInt32(i)); - } - - auto uniformPointerValue = fragment.builder.createAccessChain( - uniformPointerType, uniform->variable, - {{fragment.context->getUInt32(0), channelOffset}}); - - auto value = fragment.builder.createLoad(loadType, uniformPointerValue); - fragment.setVectorOperand(inst.vdata + i, {loadType, value}); - } - break; - } - - case Mubuf::Op::BUFFER_STORE_BYTE: - case Mubuf::Op::BUFFER_STORE_SHORT: - inst.dump(); - util::unreachable(); - - case Mubuf::Op::BUFFER_STORE_DWORD: - case Mubuf::Op::BUFFER_STORE_DWORDX2: - case Mubuf::Op::BUFFER_STORE_DWORDX4: - case Mubuf::Op::BUFFER_STORE_DWORDX3: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mubuf::Op::BUFFER_STORE_DWORD) + 1; - - auto vbuffer = getVBuffer(); - auto address = getAddress(&vbuffer); - auto uniform = fragment.context->getOrCreateStorageBuffer( - reinterpret_cast(&vbuffer), TypeId::UInt32); - uniform->accessOp |= AccessOp::Store; - - auto uniformPointerType = fragment.context->getPointerType( - spv::StorageClass::StorageBuffer, TypeId::UInt32); - address = - fragment.builder.createUDiv(fragment.context->getUInt32Type(), address, - fragment.context->getUInt32(4)); - - for (int i = 0; i < count; ++i) { - auto channelOffset = address; - - if (i != 0) { - channelOffset = fragment.builder.createIAdd( - fragment.context->getUInt32Type(), channelOffset, - fragment.context->getUInt32(i)); - } - - auto uniformPointerValue = fragment.builder.createAccessChain( - uniformPointerType, uniform->variable, - {{fragment.context->getUInt32(0), channelOffset}}); - - fragment.builder.createStore( - uniformPointerValue, - fragment.getVectorOperand(inst.vdata + i, TypeId::UInt32).value); - } - } - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertMtbuf(Fragment &fragment, Mtbuf inst) { - fragment.registers->pc += Mtbuf::kMinInstSize * sizeof(std::uint32_t); - - switch (inst.op) { - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_X: - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XY: - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZ: - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZW: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mtbuf::Op::TBUFFER_LOAD_FORMAT_X) + - 1; - - auto &builder = fragment.builder; - - auto vBuffer0 = - fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); - auto vBuffer1 = - fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); - auto vBuffer2 = - fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); - auto vBuffer3 = - fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); - - auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); - auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); - auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); - auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); - - if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && - optVBuffer3Value) { - // V# buffer value is known, read the buffer now - std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, - *optVBuffer2Value, *optVBuffer3Value}; - - auto vbuffer = reinterpret_cast(vBufferData); - auto base = spirv::cast( - fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value); - - auto uint32T = fragment.context->getUInt32Type(); - auto uint32_0 = fragment.context->getUInt32(0); - - if (inst.dfmt == kSurfaceFormatInvalid) { - util::unreachable("!! dfmt is invalid !!\n"); - - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setVectorOperand(inst.vdata + i, {uint32T, uint32_0}); - } - - return; - } - - spirv::UIntValue index; - if (inst.idxen) { - index = spirv::cast( - fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); - } - - // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); - - if (vbuffer->addtid_en) { - spirv::UIntValue threadId = - builder.createLoad(uint32T, fragment.context->getThreadId()); - - if (index) { - index = builder.createIAdd(uint32T, index, threadId); - } else { - index = threadId; - } - } - - auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) - : spirv::UIntValue{}; - - if (inst.offen) { - auto off = spirv::cast( - fragment - .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), - TypeId::UInt32) - .value); - - if (offset) { - offset = builder.createIAdd(uint32T, off, offset); - } else { - offset = off; - } - } - - spirv::UIntValue address = base; - if (vbuffer->swizzle_en == 0) { - if (vbuffer->stride != 0 && index) { - auto offset = builder.createIMul( - uint32T, index, fragment.context->getUInt32(vbuffer->stride)); - if (address == uint32_0) { - address = offset; - } else { - address = builder.createIAdd(uint32T, address, offset); - } - } - } else { - if (index && offset) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - auto offsetMsb = builder.createIMul( - uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul( - uint32T, builder.createIAdd(uint32T, indexMsb, offsetMsb), - indexStride)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, index_lsb, elementSize)); - - address = builder.createIAdd(uint32T, address, offset_lsb); - } else if (index) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - - auto indexLsb = builder.createIMul( - uint32T, index_lsb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, indexMsb, indexStride)); - - address = builder.createIAdd(uint32T, address, indexLsb); - } else if (offset) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto offsetMsb = builder.createIMul( - uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, offsetMsb, indexStride)); - - address = builder.createIAdd(uint32T, address, offset_lsb); - } - } - - spirv::Value result[4]; - auto resultType = convertFromFormat(result, count, fragment, vBufferData, - address, inst.dfmt, inst.nfmt); - - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setVectorOperand(inst.vdata + i, {resultType, result[i]}); - } - break; - } else { - util::unreachable(); - } - } - - case Mtbuf::Op::TBUFFER_STORE_FORMAT_X: - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XY: - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZ: - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZW: { - std::uint32_t count = static_cast(inst.op) - - static_cast(Mtbuf::Op::TBUFFER_STORE_FORMAT_X) + - 1; - auto &builder = fragment.builder; - - auto vBuffer0 = - fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); - auto vBuffer1 = - fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); - auto vBuffer2 = - fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); - auto vBuffer3 = - fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); - - auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); - auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); - auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); - auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); - - if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && - optVBuffer3Value) { - // V# buffer value is known, read the buffer now - std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, - *optVBuffer2Value, *optVBuffer3Value}; - - auto vbuffer = reinterpret_cast(vBufferData); - // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); - - auto base = spirv::cast( - fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value); - - auto uint32T = fragment.context->getUInt32Type(); - auto uint32_0 = fragment.context->getUInt32(0); - - if (inst.dfmt == kSurfaceFormatInvalid) { - util::unreachable("!! dfmt is invalid !!\n"); - - for (std::uint32_t i = 0; i < count; ++i) { - fragment.setVectorOperand(inst.vdata + i, {uint32T, uint32_0}); - } - - return; - } - - spirv::UIntValue index; - if (inst.idxen) { - index = spirv::cast( - fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); - } - - if (vbuffer->addtid_en) { - spirv::UIntValue threadId = - builder.createLoad(uint32T, fragment.context->getThreadId()); - - if (index) { - index = builder.createIAdd(uint32T, index, threadId); - } else { - index = threadId; - } - } - - auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) - : spirv::UIntValue{}; - - if (inst.offen) { - auto off = spirv::cast( - fragment - .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), - TypeId::UInt32) - .value); - - if (offset) { - offset = builder.createIAdd(uint32T, off, offset); - } else { - offset = off; - } - } - - spirv::UIntValue address = base; - if (vbuffer->swizzle_en == 0) { - if (vbuffer->stride != 0 && index) { - auto offset = builder.createIMul( - uint32T, index, fragment.context->getUInt32(vbuffer->stride)); - if (address == uint32_0) { - address = offset; - } else { - address = builder.createIAdd(uint32T, address, offset); - } - } - } else { - if (index && offset) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - auto offsetMsb = builder.createIMul( - uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul( - uint32T, builder.createIAdd(uint32T, indexMsb, offsetMsb), - indexStride)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, index_lsb, elementSize)); - - address = builder.createIAdd(uint32T, address, offset_lsb); - } else if (index) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto index_msb = builder.createUDiv(uint32T, index, indexStride); - auto index_lsb = builder.createUMod(uint32T, index, indexStride); - - auto indexMsb = builder.createIMul( - uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); - - auto indexLsb = builder.createIMul( - uint32T, index_lsb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, indexMsb, indexStride)); - - address = builder.createIAdd(uint32T, address, indexLsb); - } else if (offset) { - auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); - auto elementSize = fragment.context->getUInt32(vbuffer->element_size); - auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); - auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); - - auto offsetMsb = builder.createIMul( - uint32T, offset_msb, - fragment.context->getUInt32(vbuffer->element_size)); - - address = builder.createIAdd( - uint32T, address, - builder.createIMul(uint32T, offsetMsb, indexStride)); - - address = builder.createIAdd(uint32T, address, offset_lsb); - } - } - - convertToFormat(RegisterId::Vector(inst.vdata), count, fragment, - vBufferData, address, inst.dfmt, inst.nfmt); - } else { - util::unreachable(); - } - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} -void convertMimg(Fragment &fragment, Mimg inst) { - fragment.registers->pc += Mimg::kMinInstSize * sizeof(std::uint32_t); - switch (inst.op) { - case Mimg::Op::IMAGE_GET_RESINFO: { - auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), - inst.r128, true, // fixme, should be any - AccessOp::None); - spirv::Value values[4]; - auto uint32T = fragment.context->getUInt32Type(); - - if (inst.dmask & 3) { - // query whd - // TODO: support other than 2D textures - auto uint32x2T = fragment.context->getUint32x2Type(); - auto lod = fragment.getScalarOperand(inst.vaddr, TypeId::UInt32); - auto sizeResult = - fragment.builder.createImageQuerySizeLod(uint32x2T, image, lod.value); - - values[0] = - fragment.builder.createCompositeExtract(uint32T, sizeResult, {{0}}); - values[1] = - fragment.builder.createCompositeExtract(uint32T, sizeResult, {{1}}); - values[2] = fragment.context->getUInt32(1); - } - - if (inst.dmask & (1 << 3)) { - // query total mip count - values[3] = fragment.builder.createImageQueryLevels(uint32T, image); - } - - for (std::size_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - fragment.setVectorOperand(inst.vdata + dstOffset++, - {uint32T, values[i]}); - } - } - break; - } - - case Mimg::Op::IMAGE_SAMPLE_LZ: { - auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), - inst.r128, true, AccessOp::Load); - auto sampler = fragment.createSampler(RegisterId::Raw(inst.ssamp << 2)); - auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::Float32).value; - auto coord1 = - fragment.getVectorOperand(inst.vaddr + 1, TypeId::Float32).value; - auto coord2 = - fragment.getVectorOperand(inst.vaddr + 2, TypeId::Float32).value; - auto coords = fragment.builder.createCompositeConstruct( - fragment.context->getFloat32x3Type(), - {{coord0, coord1, coord2}}); // TODO - - auto sampledImage2dT = fragment.context->getSampledImage2DType(); - auto float4T = fragment.context->getFloat32x4Type(); - auto floatT = fragment.context->getFloat32Type(); - auto sampledImage = - fragment.builder.createSampledImage(sampledImage2dT, image, sampler); - auto value = fragment.builder.createImageSampleExplicitLod( - float4T, sampledImage, coords, spv::ImageOperandsMask::Lod, - {{fragment.context->getFloat32(0)}}); - - for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - fragment.setVectorOperand( - inst.vdata + dstOffset++, - {floatT, - fragment.builder.createCompositeExtract(floatT, value, {{i}})}); - } - } - break; - } - - case Mimg::Op::IMAGE_SAMPLE: { - auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), - inst.r128, true, AccessOp::Load); - auto sampler = fragment.createSampler(RegisterId::Raw(inst.ssamp << 2)); - auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::Float32).value; - auto coord1 = - fragment.getVectorOperand(inst.vaddr + 1, TypeId::Float32).value; - auto coord2 = - fragment.getVectorOperand(inst.vaddr + 2, TypeId::Float32).value; - auto coords = fragment.builder.createCompositeConstruct( - fragment.context->getFloat32x3Type(), - {{coord0, coord1, coord2}}); // TODO - - auto sampledImage2dT = fragment.context->getSampledImage2DType(); - auto float4T = fragment.context->getFloat32x4Type(); - auto floatT = fragment.context->getFloat32Type(); - auto sampledImage = - fragment.builder.createSampledImage(sampledImage2dT, image, sampler); - auto value = fragment.builder.createImageSampleImplicitLod( - float4T, sampledImage, coords); - - for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - fragment.setVectorOperand( - inst.vdata + dstOffset++, - {floatT, - fragment.builder.createCompositeExtract(floatT, value, {{i}})}); - } - } - break; - } - - case Mimg::Op::IMAGE_STORE: - case Mimg::Op::IMAGE_STORE_MIP: { - auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), - inst.r128, false, AccessOp::Store); - auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value; - auto coord1 = - fragment.getVectorOperand(inst.vaddr + 1, TypeId::UInt32).value; - auto coord2 = - fragment.getVectorOperand(inst.vaddr + 2, TypeId::UInt32).value; - auto coords = fragment.builder.createCompositeConstruct( - fragment.context->getUint32x3Type(), - {{coord0, coord1, coord2}}); // TODO - - auto float4T = fragment.context->getFloat32x4Type(); - spirv::Value values[4]; - - for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - values[i] = - fragment.getVectorOperand(inst.vdata + dstOffset++, TypeId::Float32) - .value; - } else { - values[i] = fragment.context->getFloat32(0); - } - } - - auto value = fragment.builder.createCompositeConstruct(float4T, values); - fragment.builder.createImageWrite(image, coords, value); - break; - } - - case Mimg::Op::IMAGE_LOAD: - case Mimg::Op::IMAGE_LOAD_MIP: { - auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), - inst.r128, false, AccessOp::Load); - auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value; - auto coord1 = - fragment.getVectorOperand(inst.vaddr + 1, TypeId::UInt32).value; - auto coord2 = - fragment.getVectorOperand(inst.vaddr + 2, TypeId::UInt32).value; - auto coords = fragment.builder.createCompositeConstruct( - fragment.context->getUint32x3Type(), - {{coord0, coord1, coord2}}); // TODO - - auto float4T = fragment.context->getFloat32x4Type(); - auto floatT = fragment.context->getFloat32Type(); - - auto value = fragment.builder.createImageRead(float4T, image, coords); - - for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - fragment.setVectorOperand( - inst.vdata + dstOffset++, - {floatT, - fragment.builder.createCompositeExtract(floatT, value, {{i}})}); - } - } - break; - } - - case Mimg::Op::IMAGE_GET_LOD: { - auto intT = fragment.context->getUInt32Type(); - for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) { - if (inst.dmask & (1 << i)) { - fragment.setVectorOperand(inst.vdata + dstOffset++, - {intT, fragment.context->getUInt32(0)}); - } - } - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} -void convertDs(Fragment &fragment, Ds inst) { - fragment.registers->pc += Ds::kMinInstSize * sizeof(std::uint32_t); - switch (inst.op) { - - default: - inst.dump(); - util::unreachable(); - } -} -void convertVintrp(Fragment &fragment, Vintrp inst) { - fragment.registers->pc += Vintrp::kMinInstSize * sizeof(std::uint32_t); - switch (inst.op) { - case Vintrp::Op::V_INTERP_P1_F32: - // TODO: operation should read from LDS - // TODO: accurate emulation - - // In current inaccurate emulation we just ignore phase 1 and vsrc argument - // interpolated value stored in attr# - break; - - case Vintrp::Op::V_INTERP_P2_F32: - case Vintrp::Op::V_INTERP_MOV_F32: { - // TODO: operation should read from LDS - // TODO: accurate emulation - - auto attr = fragment.getAttrOperand(inst.attr, TypeId::Float32x4); - auto channelType = fragment.context->getType(TypeId::Float32); - auto attrChan = fragment.builder.createCompositeExtract( - channelType, attr.value, - std::array{static_cast(inst.attrChan)}); - fragment.setVectorOperand(inst.vdst, {channelType, attrChan}); - break; - } - // { - // fragment.setVectorOperand( - // inst.vdst, fragment.getScalarOperand(inst.vsrc, - // TypeId::Float32x4)); - // break; - // } - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertExp(Fragment &fragment, Exp inst) { - fragment.registers->pc += Exp::kMinInstSize * sizeof(std::uint32_t); - - if (inst.en == 0) { - fragment.builder.createFunctionCall(fragment.context->getVoidType(), - fragment.context->getDiscardFn(), {}); - return; - } +namespace +{ + std::uint32_t getChannelsCount(SurfaceFormat format) + { + switch (format) + { + case kSurfaceFormat8: + return 1; + case kSurfaceFormat16: + return 1; + case kSurfaceFormat8_8: + return 2; + case kSurfaceFormat32: + return 1; + case kSurfaceFormat16_16: + return 2; + case kSurfaceFormat10_11_11: + return 3; + case kSurfaceFormat11_11_10: + return 3; + case kSurfaceFormat10_10_10_2: + return 4; + case kSurfaceFormat2_10_10_10: + return 4; + case kSurfaceFormat8_8_8_8: + return 4; + case kSurfaceFormat32_32: + return 2; + case kSurfaceFormat16_16_16_16: + return 4; + case kSurfaceFormat32_32_32: + return 3; + case kSurfaceFormat32_32_32_32: + return 4; + default: + util::unreachable(); + } + } + + std::uint32_t sizeOfFormat(SurfaceFormat format) + { + switch (format) + { + case kSurfaceFormat8: + return 8; + case kSurfaceFormat16: + return 16; + case kSurfaceFormat8_8: + return 16; + case kSurfaceFormat32: + return 32; + case kSurfaceFormat16_16: + return 32; + case kSurfaceFormat10_11_11: + return 32; + case kSurfaceFormat11_11_10: + return 32; + case kSurfaceFormat10_10_10_2: + return 32; + case kSurfaceFormat2_10_10_10: + return 32; + case kSurfaceFormat8_8_8_8: + return 32; + case kSurfaceFormat32_32: + return 64; + case kSurfaceFormat16_16_16_16: + return 64; + case kSurfaceFormat32_32_32: + return 96; + case kSurfaceFormat32_32_32_32: + return 128; + default: + util::unreachable("unsupported format %u", format); + } + } + + TypeId pickBufferType(SurfaceFormat surfaceFormat, + TextureChannelType channelType) + { + auto size = sizeOfFormat(surfaceFormat) / getChannelsCount(surfaceFormat); + + if (size == 8) + { + switch (channelType) + { + case kTextureChannelTypeUNorm: + case kTextureChannelTypeUScaled: + case kTextureChannelTypeUInt: + return TypeId::UInt8; + + default: + return TypeId::SInt8; + } + } + + if (size == 16) + { + switch (channelType) + { + case kTextureChannelTypeUNorm: + case kTextureChannelTypeUScaled: + case kTextureChannelTypeUInt: + return TypeId::UInt16; + + case kTextureChannelTypeFloat: + return TypeId::Float16; + + default: + return TypeId::SInt16; + } + } + + if (size == 32) + { + switch (channelType) + { + case kTextureChannelTypeUNorm: + case kTextureChannelTypeUScaled: + case kTextureChannelTypeUInt: + return TypeId::UInt32; + + case kTextureChannelTypeFloat: + return TypeId::Float32; + + default: + return TypeId::SInt32; + } + } + + if (size == 64) + { + switch (channelType) + { + case kTextureChannelTypeUNorm: + case kTextureChannelTypeUScaled: + case kTextureChannelTypeUInt: + return TypeId::UInt64; + + case kTextureChannelTypeFloat: + return TypeId::Float64; + + default: + return TypeId::SInt64; + } + } + + util::unreachable(); + } + + spirv::Type convertFromFormat(spirv::Value* result, int count, + Fragment& fragment, std::uint32_t* vBufferData, + spirv::UIntValue offset, + SurfaceFormat surfaceFormat, + TextureChannelType channelType) + { + auto loadType = pickBufferType(surfaceFormat, channelType); + + auto uniform = + fragment.context->getOrCreateStorageBuffer(vBufferData, loadType); + uniform->accessOp |= AccessOp::Load; + + auto storageBufferPointerType = fragment.context->getPointerType( + spv::StorageClass::StorageBuffer, loadType); + + auto& builder = fragment.builder; + + switch (surfaceFormat) + { + case kSurfaceFormat32: + case kSurfaceFormat32_32: + case kSurfaceFormat32_32_32: + case kSurfaceFormat32_32_32_32: + case kSurfaceFormat16: + case kSurfaceFormat16_16: + case kSurfaceFormat16_16_16_16: + case kSurfaceFormat8: + case kSurfaceFormat8_8: + case kSurfaceFormat8_8_8_8: + { + // format not requires bit fetching + auto totalChannelsCount = getChannelsCount(surfaceFormat); + auto channelSize = sizeOfFormat(surfaceFormat) / 8 / totalChannelsCount; + auto channelsCount = std::min(count, totalChannelsCount); + + if (channelSize != 1) + { + offset = builder.createUDiv(fragment.context->getUInt32Type(), offset, + fragment.context->getUInt32(channelSize)); + } + + int channel = 0; + auto resultType = fragment.context->getType(loadType); + for (; channel < channelsCount; ++channel) + { + auto channelOffset = offset; + + if (channel != 0) + { + channelOffset = + builder.createIAdd(fragment.context->getUInt32Type(), channelOffset, + fragment.context->getUInt32(channel)); + } + + auto uniformPointerValue = fragment.builder.createAccessChain( + storageBufferPointerType, uniform->variable, + {{fragment.context->getUInt32(0), channelOffset}}); + + auto channelValue = fragment.builder.createLoad( + fragment.context->getType(loadType), uniformPointerValue); + + switch (channelType) + { + case kTextureChannelTypeFloat: + { + if (loadType != TypeId::Float32) + { + channelValue = fragment.builder.createFConvert( + fragment.context->getFloat32Type(), channelValue); + + resultType = fragment.context->getFloat32Type(); + } + + result[channel] = channelValue; + break; + } + case kTextureChannelTypeSInt: + { + if (loadType != TypeId::SInt32) + { + channelValue = fragment.builder.createSConvert( + fragment.context->getSint32Type(), + spirv::cast(channelValue)); + + resultType = fragment.context->getSint32Type(); + } + + result[channel] = channelValue; + break; + } + case kTextureChannelTypeUInt: + if (loadType != TypeId::UInt32) + { + channelValue = fragment.builder.createUConvert( + fragment.context->getUInt32Type(), + spirv::cast(channelValue)); + + resultType = fragment.context->getUInt32Type(); + } + + result[channel] = channelValue; + break; + + case kTextureChannelTypeUNorm: + { + auto maxValue = + (static_cast(1) << (channelSize * 8)) - 1; + + auto uintChannelValue = spirv::cast(channelValue); + + if (loadType != TypeId::UInt32) + { + uintChannelValue = builder.createUConvert( + fragment.context->getUInt32Type(), uintChannelValue); + } + + auto floatChannelValue = builder.createConvertUToF( + fragment.context->getFloat32Type(), uintChannelValue); + floatChannelValue = builder.createFDiv( + fragment.context->getFloat32Type(), floatChannelValue, + fragment.context->getFloat32(maxValue)); + result[channel] = floatChannelValue; + resultType = fragment.context->getFloat32Type(); + break; + } + + case kTextureChannelTypeSNorm: + { + auto maxValue = + (static_cast(1) << (channelSize * 8 - 1)) - 1; + + auto uintChannelValue = spirv::cast(channelValue); + + if (loadType != TypeId::SInt32) + { + uintChannelValue = builder.createSConvert( + fragment.context->getSint32Type(), uintChannelValue); + } + + auto floatChannelValue = builder.createConvertSToF( + fragment.context->getFloat32Type(), uintChannelValue); + + floatChannelValue = builder.createFDiv( + fragment.context->getFloat32Type(), floatChannelValue, + fragment.context->getFloat32(maxValue)); + + auto glslStd450 = fragment.context->getGlslStd450(); + floatChannelValue = + spirv::cast(fragment.builder.createExtInst( + fragment.context->getFloat32Type(), glslStd450, + GLSLstd450FClamp, + {{floatChannelValue, fragment.context->getFloat32(-1), + fragment.context->getFloat32(1)}})); + result[channel] = floatChannelValue; + resultType = fragment.context->getFloat32Type(); + break; + } + + case kTextureChannelTypeUScaled: + { + auto uintChannelValue = spirv::cast(channelValue); + + if (loadType != TypeId::UInt32) + { + uintChannelValue = builder.createUConvert( + fragment.context->getUInt32Type(), uintChannelValue); + } + + auto floatChannelValue = builder.createConvertUToF( + fragment.context->getFloat32Type(), uintChannelValue); + + result[channel] = floatChannelValue; + resultType = fragment.context->getFloat32Type(); + break; + } + + case kTextureChannelTypeSScaled: + { + auto uintChannelValue = spirv::cast(channelValue); + + if (loadType != TypeId::SInt32) + { + uintChannelValue = builder.createSConvert( + fragment.context->getSint32Type(), uintChannelValue); + } + + auto floatChannelValue = builder.createConvertSToF( + fragment.context->getFloat32Type(), uintChannelValue); + + result[channel] = floatChannelValue; + resultType = fragment.context->getFloat32Type(); + break; + } + + case kTextureChannelTypeSNormNoZero: + { + auto maxValue = + (static_cast(1) << (channelSize * 8)) - 1; + + auto uintChannelValue = spirv::cast(channelValue); + + if (loadType != TypeId::SInt32) + { + uintChannelValue = builder.createSConvert( + fragment.context->getSint32Type(), uintChannelValue); + } + + auto floatChannelValue = builder.createConvertSToF( + fragment.context->getFloat32Type(), uintChannelValue); + + floatChannelValue = builder.createFMul( + fragment.context->getFloat32Type(), floatChannelValue, + fragment.context->getFloat32(2)); + floatChannelValue = builder.createFAdd( + fragment.context->getFloat32Type(), floatChannelValue, + fragment.context->getFloat32(1)); + + floatChannelValue = builder.createFDiv( + fragment.context->getFloat32Type(), floatChannelValue, + fragment.context->getFloat32(maxValue)); + + result[channel] = floatChannelValue; + resultType = fragment.context->getFloat32Type(); + break; + } + + default: + util::unreachable("unimplemented channel type %u", channelType); + } + } + + // for (; channel < count; ++channel) { + // result[channel] = fragment.createBitcast( + // resultType, fragment.context->getUInt32Type(), + // fragment.context->getUInt32(0)); + // } + return resultType; + } + + default: + break; + } + + util::unreachable("unimplemented conversion type. %u.%u", surfaceFormat, + channelType); + } + + void convertToFormat(RegisterId sourceRegister, int count, Fragment& fragment, + std::uint32_t* vBufferData, spirv::UIntValue offset, + SurfaceFormat surfaceFormat, + TextureChannelType channelType) + { + + auto storeType = pickBufferType(surfaceFormat, channelType); + + auto uniform = + fragment.context->getOrCreateStorageBuffer(vBufferData, storeType); + uniform->accessOp |= AccessOp::Store; + + auto uniformPointerType = fragment.context->getPointerType( + spv::StorageClass::StorageBuffer, storeType); + + auto& builder = fragment.builder; + switch (surfaceFormat) + { + case kSurfaceFormat8: + case kSurfaceFormat8_8: + case kSurfaceFormat8_8_8_8: + case kSurfaceFormat16: + case kSurfaceFormat16_16: + case kSurfaceFormat16_16_16_16: + case kSurfaceFormat32: + case kSurfaceFormat32_32: + case kSurfaceFormat32_32_32: + case kSurfaceFormat32_32_32_32: + { + // format not requires bit fetching + auto totalChannelsCount = getChannelsCount(surfaceFormat); + auto channelSize = sizeOfFormat(surfaceFormat) / 8 / totalChannelsCount; + auto channelsCount = std::min(count, totalChannelsCount); + + if (channelSize != 1) + { + offset = builder.createUDiv(fragment.context->getUInt32Type(), offset, + fragment.context->getUInt32(channelSize)); + } + + int channel = 0; + + for (; channel < channelsCount; ++channel) + { + auto channelOffset = offset; + + if (channel != 0) + { + channelOffset = + builder.createIAdd(fragment.context->getUInt32Type(), channelOffset, + fragment.context->getUInt32(channel)); + } + + auto uniformPointerValue = fragment.builder.createAccessChain( + uniformPointerType, uniform->variable, + {{fragment.context->getUInt32(0), channelOffset}}); + + spirv::Value channelValue; + + switch (channelType) + { + case kTextureChannelTypeUNorm: + { + channelValue = + fragment + .getOperand(RegisterId::Raw(sourceRegister + channel), + TypeId::Float32) + .value; + + auto maxValue = + (static_cast(1) << (channelSize * 8)) - 1; + + channelValue = + builder.createFMul(fragment.context->getFloat32Type(), + spirv::cast(channelValue), + fragment.context->getFloat32(maxValue)); + + channelValue = builder.createConvertFToU( + fragment.context->getType(TypeId::UInt32), channelValue); + + if (storeType != TypeId::UInt32) + { + channelValue = builder.createUConvert( + fragment.context->getType(storeType), + spirv::cast(channelValue)); + } + break; + } + case kTextureChannelTypeFloat: + channelValue = + fragment + .getOperand(RegisterId::Raw(sourceRegister + channel), + TypeId::Float32) + .value; + + if (storeType != TypeId::Float32) + { + channelValue = fragment.builder.createFConvert( + fragment.context->getType(storeType), channelValue); + } + break; + + case kTextureChannelTypeSInt: + channelValue = + fragment + .getOperand(RegisterId::Raw(sourceRegister + channel), + TypeId::SInt32) + .value; + + if (storeType != TypeId::SInt32) + { + channelValue = fragment.builder.createSConvert( + fragment.context->getType(storeType), + spirv::cast(channelValue)); + } + break; + case kTextureChannelTypeUInt: + channelValue = + fragment + .getOperand(RegisterId::Raw(sourceRegister + channel), + TypeId::UInt32) + .value; + + if (storeType != TypeId::UInt32) + { + channelValue = fragment.builder.createUConvert( + fragment.context->getType(storeType), + spirv::cast(channelValue)); + } + break; + + default: + util::unreachable("unimplemented channel type %u", channelType); + } + + fragment.builder.createStore(uniformPointerValue, channelValue); + } + + for (; channel < count; ++channel) + { + auto channelOffset = + builder.createIAdd(fragment.context->getUInt32Type(), offset, + fragment.context->getUInt32(channel)); + auto uniformPointerValue = fragment.builder.createAccessChain( + uniformPointerType, uniform->variable, + {{fragment.context->getUInt32(0), channelOffset}}); + + fragment.builder.createStore( + uniformPointerValue, + fragment.createBitcast(fragment.context->getType(storeType), + fragment.context->getUInt32Type(), + fragment.context->getUInt32(0))); + } + + return; + } + + default: + break; + } + + util::unreachable("unimplemented conversion type. %u.%u", surfaceFormat, + channelType); + } + + struct GnmVBuffer + { + uint64_t base : 44; + uint64_t mtype_L1s : 2; + uint64_t mtype_L2 : 2; + uint64_t stride : 14; + uint64_t cache_swizzle : 1; + uint64_t swizzle_en : 1; + + uint32_t num_records; + + uint32_t dst_sel_x : 3; + uint32_t dst_sel_y : 3; + uint32_t dst_sel_z : 3; + uint32_t dst_sel_w : 3; + + TextureChannelType nfmt : 3; + SurfaceFormat dfmt : 4; + uint32_t element_size : 2; + uint32_t index_stride : 2; + uint32_t addtid_en : 1; + uint32_t reserved0 : 1; + uint32_t hash_en : 1; + uint32_t reserved1 : 1; + uint32_t mtype : 3; + uint32_t type : 2; + + std::uint64_t getAddress() const { return base; } + + uint32_t getStride() const { return stride; } + + uint32_t getSize() const + { + uint32_t stride = getStride(); + uint32_t numElements = getNumRecords(); + return stride ? numElements * stride : numElements; + } + + uint32_t getNumRecords() const { return num_records; } + uint32_t getElementSize() const { return element_size; } + uint32_t getIndexStrideSize() const { return index_stride; } + SurfaceFormat getSurfaceFormat() const { return (SurfaceFormat)dfmt; } + TextureChannelType getChannelType() const { return (TextureChannelType)nfmt; } + }; + + static_assert(sizeof(GnmVBuffer) == sizeof(std::uint64_t) * 2); + + enum class TextureType + { + Dim1D = 8, + Dim2D, + Dim3D, + Cube, + Array1D, + Array2D, + Msaa2D, + MsaaArray2D, + }; + + struct GnmTBuffer + { + uint64_t baseaddr256 : 38; + uint64_t mtype_L2 : 2; + uint64_t min_lod : 12; + SurfaceFormat dfmt : 6; + TextureChannelType nfmt : 4; + uint64_t mtype01 : 2; + + uint64_t width : 14; + uint64_t height : 14; + uint64_t perfMod : 3; + uint64_t interlaced : 1; + uint64_t dst_sel_x : 3; + uint64_t dst_sel_y : 3; + uint64_t dst_sel_z : 3; + uint64_t dst_sel_w : 3; + uint64_t base_level : 4; + uint64_t last_level : 4; + uint64_t tiling_idx : 5; + uint64_t pow2pad : 1; + uint64_t mtype2 : 1; + uint64_t : 1; // reserved + TextureType type : 4; + + uint64_t depth : 13; + uint64_t pitch : 14; + uint64_t : 5; // reserved + uint64_t base_array : 13; + uint64_t last_array : 13; + uint64_t : 6; // reserved + + uint64_t min_lod_warn : 12; // fixed point 4.8 + uint64_t counter_bank_id : 8; + uint64_t LOD_hdw_cnt_en : 1; + uint64_t : 42; // reserved + + std::uint64_t getAddress() const + { + return static_cast(static_cast(baseaddr256)) + << 8; + } + }; + + static_assert(sizeof(GnmTBuffer) == sizeof(std::uint64_t) * 4); + + enum class CmpKind + { + F, + LT, + EQ, + LE, + GT, + LG, + GE, + O, + U, + NGE, + NLG, + NGT, + NLE, + NEQ, + NLT, + NE, + TRU, + T = TRU, + CLASS + }; + + enum class CmpFlags + { + None = 0, + X = 1 << 0, + S = 1 << 1, + SX = S | X + }; + inline CmpFlags operator&(CmpFlags a, CmpFlags b) + { + return static_cast(static_cast(a) & static_cast(b)); + } + + Value doCmpOp(Fragment& fragment, TypeId type, spirv::Value src0, + spirv::Value src1, CmpKind kind, CmpFlags flags, + std::uint8_t typeMask = 0) + { + spirv::BoolValue cmp; + auto boolT = fragment.context->getBoolType(); + + switch (kind) + { + case CmpKind::F: + cmp = fragment.context->getFalse(); + break; + case CmpKind::LT: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdLessThan(boolT, src0, src1); + } + else if (type.isSignedInt()) + { + cmp = fragment.builder.createSLessThan(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createULessThan(boolT, src0, src1); + } + break; + case CmpKind::EQ: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdEqual(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createIEqual(boolT, src0, src1); + } + break; + case CmpKind::LE: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdLessThanEqual(boolT, src0, src1); + } + else if (type.isSignedInt()) + { + cmp = fragment.builder.createSLessThanEqual(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createULessThanEqual(boolT, src0, src1); + } + break; + case CmpKind::GT: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdGreaterThan(boolT, src0, src1); + } + else if (type.isSignedInt()) + { + cmp = fragment.builder.createSGreaterThan(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createUGreaterThan(boolT, src0, src1); + } + break; + case CmpKind::LG: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdNotEqual(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createINotEqual(boolT, src0, src1); + } + break; + case CmpKind::GE: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1); + } + else if (type.isSignedInt()) + { + cmp = fragment.builder.createSGreaterThanEqual(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createUGreaterThanEqual(boolT, src0, src1); + } + break; + case CmpKind::O: + cmp = fragment.builder.createLogicalAnd( + boolT, fragment.builder.createFOrdEqual(boolT, src0, src0), + fragment.builder.createFOrdEqual(boolT, src1, src1)); + break; + case CmpKind::U: + cmp = fragment.builder.createLogicalAnd( + boolT, fragment.builder.createFUnordNotEqual(boolT, src0, src0), + fragment.builder.createFUnordNotEqual(boolT, src1, src1)); + break; + case CmpKind::NGE: + cmp = fragment.builder.createFUnordLessThan(boolT, src0, src1); + break; + case CmpKind::NLG: + cmp = fragment.builder.createFUnordGreaterThanEqual(boolT, src0, src1); + break; + case CmpKind::NGT: + cmp = fragment.builder.createFUnordLessThanEqual(boolT, src0, src1); + break; + case CmpKind::NLE: + cmp = fragment.builder.createFUnordGreaterThan(boolT, src0, src1); + break; + case CmpKind::NE: + case CmpKind::NEQ: + if (type.isFloatPoint()) + { + cmp = fragment.builder.createFUnordNotEqual(boolT, src0, src1); + } + else + { + cmp = fragment.builder.createINotEqual(boolT, src0, src1); + } + break; + case CmpKind::NLT: + cmp = fragment.builder.createFUnordGreaterThanEqual(boolT, src0, src1); + break; + case CmpKind::TRU: + cmp = fragment.context->getTrue(); + break; + + case CmpKind::CLASS: + { + enum class FloatClass + { + SNan = 0, + QNan = 1, + NInf = 2, + NNorm = 3, + NDenom = 4, + NZero = 5, + PZero = 6, + PDenom = 7, + PNorm = 8, + PInf = 9, + }; + + auto testCmpClass = [&](FloatClass fclass, + spirv::FloatValue val) -> spirv::BoolValue { + switch (fclass) + { + case FloatClass::SNan: + case FloatClass::QNan: + return fragment.builder.createIsNan(boolT, val); + + case FloatClass::NInf: + return fragment.builder.createLogicalAnd( + boolT, + fragment.builder.createFOrdLessThan( + boolT, val, fragment.context->getFloat32(0)), + fragment.builder.createIsInf(boolT, val)); + + case FloatClass::NZero: + case FloatClass::PZero: + return fragment.builder.createFOrdEqual( + boolT, val, fragment.context->getFloat32(0)); + + case FloatClass::NNorm: + case FloatClass::NDenom: + case FloatClass::PDenom: + case FloatClass::PNorm: + util::unreachable(); + + case FloatClass::PInf: + return fragment.builder.createLogicalAnd( + boolT, + fragment.builder.createFOrdGreaterThan( + boolT, val, fragment.context->getFloat32(0)), + fragment.builder.createIsInf(boolT, val)); + } + + util::unreachable(); + }; + + // we cannot differ signaling and quiet nan + if (typeMask & 3) + { + typeMask = (typeMask & ~3) | 2; + } + + // we cannot differ positive and negative zero + if (typeMask & 0x60) + { + typeMask = (typeMask & ~0x60) | 0x40; + } + + for (int i = 0; i < 10; ++i) + { + if (typeMask & (1 << i)) + { + auto lhs = + testCmpClass((FloatClass)i, spirv::cast(src0)); + auto rhs = + testCmpClass((FloatClass)i, spirv::cast(src1)); + + auto bitResult = fragment.builder.createLogicalAnd(boolT, lhs, rhs); + + if (cmp) + { + cmp = fragment.builder.createLogicalOr(boolT, cmp, bitResult); + } + else + { + cmp = bitResult; + } + } + } + + if (!cmp) + { + cmp = fragment.context->getFalse(); + } + break; + } + } + + if (!cmp) + { + util::unreachable(); + } + + auto uint32T = fragment.context->getUInt32Type(); + auto uint32_0 = fragment.context->getUInt32(0); + auto result = fragment.builder.createSelect( + uint32T, cmp, fragment.context->getUInt32(1), uint32_0); + + if ((flags & CmpFlags::X) == CmpFlags::X) + { + fragment.setOperand(RegisterId::ExecLo, {uint32T, result}); + fragment.setOperand(RegisterId::ExecHi, {uint32T, uint32_0}); + } + + // TODO: handle flags + return {uint32T, result}; + }; + + void convertVop2(Fragment& fragment, Vop2 inst) + { + fragment.registers->pc += Vop2::kMinInstSize * sizeof(std::uint32_t); + switch (inst.op) + { + case Vop2::Op::V_CVT_PKRTZ_F16_F32: + { + auto float2T = fragment.context->getType(TypeId::Float32x2); + auto uintT = fragment.context->getType(TypeId::UInt32); + auto glslStd450 = fragment.context->getGlslStd450(); + + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value; + + auto src = fragment.builder.createCompositeConstruct( + float2T, std::array{src0, src1}); + auto dst = fragment.builder.createExtInst( + uintT, glslStd450, GLSLstd450PackHalf2x16, std::array{src}); + + fragment.setVectorOperand(inst.vdst, {uintT, dst}); + break; + } + case Vop2::Op::V_AND_B32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createBitwiseAnd(uintT, src0, src1)}); + break; + } + + case Vop2::Op::V_OR_B32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createBitwiseOr(uintT, src0, src1)}); + break; + } + + case Vop2::Op::V_ADD_I32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + auto resultStruct = + fragment.context->getStructType(std::array{uintT, uintT}); + auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(0)})}); + fragment.setVcc( + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(1)})}); + // TODO: update vcc hi + break; + } + + case Vop2::Op::V_SUB_I32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + auto resultStruct = + fragment.context->getStructType(std::array{uintT, uintT}); + auto result = fragment.builder.createISubBorrow(resultStruct, src0, src1); + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(0)})}); + fragment.setVcc( + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(1)})}); + // TODO: update vcc hi + break; + } + + case Vop2::Op::V_MAC_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto dst = spirv::cast( + fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFAdd( + floatT, fragment.builder.createFMul(floatT, src0, src1), dst); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MAC_LEGACY_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto dst = spirv::cast( + fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + auto float0 = fragment.context->getFloat32(0); + + auto src0IsZero = fragment.builder.createFOrdEqual(boolT, src0, float0); + auto src1IsZero = fragment.builder.createFOrdEqual(boolT, src1, float0); + auto anySrcIsZero = + fragment.builder.createLogicalOr(boolT, src0IsZero, src1IsZero); + + auto result = fragment.builder.createFAdd( + floatT, + fragment.builder.createSelect( + floatT, anySrcIsZero, float0, + fragment.builder.createFMul(floatT, src0, src1)), + dst); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MUL_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFMul(floatT, src0, src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_ADD_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFAdd(floatT, src0, src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_SUB_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFSub(floatT, src0, src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop2::Op::V_SUBREV_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFSub(floatT, src1, src0); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop2::Op::V_SUBREV_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); + auto floatT = fragment.context->getSint32Type(); + + auto result = fragment.builder.createISub(floatT, src1, src0); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MIN_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, + src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MAX_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), + src0, src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MUL_LEGACY_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + auto float0 = fragment.context->getFloat32(0); + + auto src0IsZero = fragment.builder.createFOrdEqual(boolT, src0, float0); + auto src1IsZero = fragment.builder.createFOrdEqual(boolT, src1, float0); + auto anySrcIsZero = + fragment.builder.createLogicalOr(boolT, src0IsZero, src1IsZero); + + auto result = fragment.builder.createSelect( + floatT, anySrcIsZero, float0, + fragment.builder.createFMul(floatT, src0, src1)); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MADAK_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto constant = spirv::cast( + fragment.getScalarOperand(255, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFAdd( + floatT, fragment.builder.createFMul(floatT, src0, src1), constant); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_MADMK_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value); + auto constant = spirv::cast( + fragment.getScalarOperand(255, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFAdd( + floatT, fragment.builder.createFMul(floatT, src0, constant), src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop2::Op::V_LSHL_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createShiftLeftLogical(uintT, src0, src1)}); + break; + } + + case Vop2::Op::V_LSHLREV_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createShiftLeftLogical(uintT, src1, src0)}); + break; + } + + case Vop2::Op::V_LSHR_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createShiftRightLogical(uintT, src0, src1)}); + break; + } + + case Vop2::Op::V_LSHRREV_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value); + auto uintT = fragment.context->getType(TypeId::UInt32); + + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createShiftRightLogical(uintT, src1, src0)}); + break; + } + + case Vop2::Op::V_ASHR_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); + auto sintT = fragment.context->getType(TypeId::SInt32); + + fragment.setVectorOperand( + inst.vdst, {sintT, fragment.builder.createShiftRightArithmetic( + sintT, src0, src1)}); + break; + } + + case Vop2::Op::V_ASHRREV_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getVectorOperand(inst.vsrc1, TypeId::SInt32).value); + auto sintT = fragment.context->getType(TypeId::SInt32); + + fragment.setVectorOperand( + inst.vdst, {sintT, fragment.builder.createShiftRightArithmetic( + sintT, src1, src0)}); + break; + } + + case Vop2::Op::V_CNDMASK_B32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + auto vcc = fragment.getVccLo(); + + auto cmp = fragment.builder.createINotEqual(fragment.context->getBoolType(), + vcc.value, + fragment.context->getUInt32(0)); + + auto uint32T = fragment.context->getUInt32Type(); + auto result = fragment.builder.createSelect(uint32T, cmp, src1, src0); + fragment.setVectorOperand(inst.vdst, {uint32T, result}); + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + void convertSop2(Fragment& fragment, Sop2 inst) + { + fragment.registers->pc += Sop2::kMinInstSize * sizeof(std::uint32_t); + auto& builder = fragment.builder; + auto context = fragment.context; + auto sCarry = [&](spirv::SIntValue a, spirv::SIntValue b, + spirv::SIntValue result) { + auto boolT = context->getBoolType(); + auto uint32T = context->getUInt32Type(); + auto s0 = context->getSInt32(0); + auto u1 = context->getUInt32(1); + auto u0 = context->getUInt32(0); + auto aLtZero = builder.createSelect( + uint32T, builder.createSLessThan(boolT, a, s0), u1, u0); + auto bLtZero = builder.createSelect( + uint32T, builder.createSLessThan(boolT, b, s0), u1, u0); + auto resultLtZero = builder.createSelect( + uint32T, builder.createSLessThan(boolT, result, s0), u1, u0); + + auto argsSignEq = builder.createIEqual(boolT, aLtZero, bLtZero); + auto resSignNe = builder.createINotEqual(boolT, resultLtZero, aLtZero); + return Value{boolT, builder.createLogicalAnd(boolT, argsSignEq, resSignNe)}; + }; + + switch (inst.op) + { + case Sop2::Op::S_ADD_U32: + { + auto src0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value; + auto src1 = fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + auto resultStruct = + fragment.context->getStructType(std::array{uintT, uintT}); + auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); + fragment.setScalarOperand( + inst.sdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, {{static_cast(0)}})}); + fragment.setScc( + {uintT, fragment.builder.createCompositeExtract( + uintT, result, {{static_cast(1)}})}); + break; + } + case Sop2::Op::S_ADD_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); + auto resultT = fragment.context->getSint32Type(); + auto result = fragment.builder.createIAdd(resultT, src0, src1); + fragment.setScc(sCarry(src0, src1, result)); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_SUB_U32: + { + auto src0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value; + auto src1 = fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + auto resultStruct = + fragment.context->getStructType(std::array{uintT, uintT}); + auto result = fragment.builder.createISubBorrow(resultStruct, src0, src1); + fragment.setScalarOperand( + inst.sdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, {{static_cast(0)}})}); + fragment.setScc( + {uintT, fragment.builder.createCompositeExtract( + uintT, result, {{static_cast(1)}})}); + break; + } + case Sop2::Op::S_SUB_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); + auto resultT = fragment.context->getSint32Type(); + auto result = fragment.builder.createISub(resultT, src0, src1); + fragment.setScc(sCarry(src0, src1, result)); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_ASHR_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getSint32Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x3f))); + + auto result = + fragment.builder.createShiftRightArithmetic(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_ASHR_I64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::SInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getSint64Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x3f))); + + auto result = + fragment.builder.createShiftRightArithmetic(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_LSHR_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getUInt32Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x1f))); + + auto result = fragment.builder.createShiftRightLogical(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_LSHR_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getUInt64Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x3f))); + + auto result = fragment.builder.createShiftRightLogical(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_LSHL_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getUInt32Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x1f))); + + auto result = fragment.builder.createShiftLeftLogical(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_LSHL_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + + auto resultT = fragment.context->getUInt64Type(); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + resultT, src1, fragment.context->getUInt32(0x3f))); + + auto result = fragment.builder.createShiftLeftLogical(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_CSELECT_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto resultT = fragment.context->getUInt32Type(); + auto result = + fragment.builder.createSelect(resultT, fragment.getScc(), src0, src1); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_CSELECT_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + + auto resultT = fragment.context->getUInt64Type(); + auto result = + fragment.builder.createSelect(resultT, fragment.getScc(), src0, src1); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_MUL_I32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::SInt32).value); + auto resultT = fragment.context->getSint32Type(); + auto result = fragment.builder.createIMul(resultT, src0, src1); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_AND_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createBitwiseAnd(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_ANDN2_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createBitwiseAnd( + resultT, src0, fragment.builder.createNot(resultT, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_AND_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + auto resultT = fragment.context->getUInt64Type(); + auto result = fragment.builder.createBitwiseAnd(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_ANDN2_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + auto resultT = fragment.context->getUInt64Type(); + auto result = fragment.builder.createBitwiseAnd( + resultT, src0, fragment.builder.createNot(resultT, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_OR_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createBitwiseOr(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_OR_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + auto resultT = fragment.context->getUInt64Type(); + auto result = fragment.builder.createBitwiseOr(resultT, src0, src1); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_NAND_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createNot( + resultT, fragment.builder.createBitwiseAnd(resultT, src0, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_NAND_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + auto resultT = fragment.context->getUInt64Type(); + auto result = fragment.builder.createNot( + resultT, fragment.builder.createBitwiseAnd(resultT, src0, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_NOR_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createNot( + resultT, fragment.builder.createBitwiseOr(resultT, src0, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + case Sop2::Op::S_NOR_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt64).value); + auto resultT = fragment.context->getUInt64Type(); + auto result = fragment.builder.createNot( + resultT, fragment.builder.createBitwiseOr(resultT, src0, src1)); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + case Sop2::Op::S_BFE_U32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + + auto operandT = fragment.context->getUInt32Type(); + + auto offset = + spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x1f))); + auto size = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, + fragment.builder.createShiftRightLogical( + operandT, src1, fragment.context->getUInt32(16)), + fragment.context->getUInt32(0x7f))); + + auto field = + fragment.builder.createShiftRightLogical(operandT, src0, offset); + auto mask = fragment.builder.createISub( + operandT, + fragment.builder.createShiftLeftLogical( + operandT, fragment.context->getUInt32(1), size), + fragment.context->getUInt32(1)); + + auto result = fragment.builder.createBitwiseAnd(operandT, field, mask); + auto resultT = fragment.context->getUInt32Type(); + fragment.setScc({resultT, result}); + fragment.setScalarOperand(inst.sdst, {resultT, result}); + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + void convertSopk(Fragment& fragment, Sopk inst) + { + fragment.registers->pc += Sopk::kMinInstSize * sizeof(std::uint32_t); + switch (inst.op) + { + case Sopk::Op::S_MOVK_I32: + fragment.setScalarOperand(inst.sdst, + {fragment.context->getSint32Type(), + fragment.context->getSInt32(inst.simm)}); + break; + default: + inst.dump(); + util::unreachable(); + } + } + void convertSmrd(Fragment& fragment, Smrd inst) + { + fragment.registers->pc += Smrd::kMinInstSize * sizeof(std::uint32_t); + + auto getOffset = [&](std::int32_t adv = 0) -> spirv::IntValue { + if (inst.imm) + { + return fragment.context->getUInt32(inst.offset + adv); + } + + auto resultT = fragment.context->getUInt32Type(); + auto resultV = fragment.getScalarOperand(inst.offset, TypeId::UInt32).value; + + if (auto constVal = fragment.context->findUint32Value(resultV)) + { + return fragment.context->getUInt32(*constVal / 4 + adv); + } + + auto result = fragment.builder.createUDiv( + resultT, spirv::cast(resultV), + fragment.context->getUInt32(4)); + + if (adv != 0) + { + result = fragment.builder.createIAdd(resultT, result, + fragment.context->getUInt32(adv)); + } + return result; + }; + + switch (inst.op) + { + case Smrd::Op::S_BUFFER_LOAD_DWORD: + case Smrd::Op::S_BUFFER_LOAD_DWORDX2: + case Smrd::Op::S_BUFFER_LOAD_DWORDX4: + case Smrd::Op::S_BUFFER_LOAD_DWORDX8: + case Smrd::Op::S_BUFFER_LOAD_DWORDX16: + { + std::uint32_t count = 1 + << (static_cast(inst.op) - + static_cast(Smrd::Op::S_BUFFER_LOAD_DWORD)); + auto vBuffer0 = + fragment.getScalarOperand((inst.sbase << 1) + 0, TypeId::UInt32); + auto vBuffer1 = + fragment.getScalarOperand((inst.sbase << 1) + 1, TypeId::UInt32); + auto vBuffer2 = + fragment.getScalarOperand((inst.sbase << 1) + 2, TypeId::UInt32); + auto vBuffer3 = + fragment.getScalarOperand((inst.sbase << 1) + 3, TypeId::UInt32); + + auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); + auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); + auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); + auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); + + if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && + optVBuffer3Value) + { + std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, + *optVBuffer2Value, *optVBuffer3Value}; + auto vbuffer = reinterpret_cast(vBufferData); + // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); + + auto valueT = fragment.context->getFloat32Type(); + auto uniform = fragment.context->getOrCreateStorageBuffer( + vBufferData, TypeId::Float32); + uniform->accessOp |= AccessOp::Load; + auto storageBufferPointerType = fragment.context->getPointerType( + spv::StorageClass::StorageBuffer, TypeId::Float32); + + for (std::uint32_t i = 0; i < count; ++i) + { + auto storageBufferPointerValue = fragment.builder.createAccessChain( + storageBufferPointerType, uniform->variable, + {{fragment.context->getUInt32(0), getOffset(i)}}); + + auto value = + fragment.builder.createLoad(valueT, storageBufferPointerValue); + fragment.setScalarOperand(inst.sdst + i, {valueT, value}); + } + } + else + { + // FIXME: implement runtime V# buffer fetching + util::unreachable(); + } + break; + } + + case Smrd::Op::S_LOAD_DWORD: + case Smrd::Op::S_LOAD_DWORDX2: + case Smrd::Op::S_LOAD_DWORDX4: + case Smrd::Op::S_LOAD_DWORDX8: + case Smrd::Op::S_LOAD_DWORDX16: + { + std::uint32_t count = 1 << (static_cast(inst.op) - + static_cast(Smrd::Op::S_LOAD_DWORD)); + + auto uint32T = fragment.context->getUInt32Type(); + auto sgprLo = fragment.getScalarOperand(inst.sbase << 1, TypeId::UInt32); + auto sgprHi = + fragment.getScalarOperand((inst.sbase << 1) + 1, TypeId::UInt32); + auto optLoAddress = fragment.context->findUint32Value(sgprLo.value); + auto optHiAddress = fragment.context->findUint32Value(sgprHi.value); + + if (inst.imm && optLoAddress && optHiAddress) + { + // if it is imm and address is known, read the values now + auto memory = fragment.context->getMemory(); + auto address = + *optLoAddress | (static_cast(*optHiAddress) << 32); + + fragment.context->dependencies->map(address + (inst.offset << 2), + address + (inst.offset << 2) + + sizeof(std::uint32_t) * count); + + auto data = + memory.getPointer(address + (inst.offset << 2)); + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setScalarOperand( + inst.sdst + i, {uint32T, fragment.context->getUInt32(data[i])}); + } + } + else + { + // FIXME: implement + // TODO: create uniform and do load from it + util::unreachable(); + } + + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + void convertVop3(Fragment& fragment, Vop3 inst) + { + fragment.registers->pc += Vop3::kMinInstSize * sizeof(std::uint32_t); + + auto applyOmod = [&](Value result) -> Value { + switch (inst.omod) + { + case 1: + return {result.type, fragment.builder.createFMul( + spirv::cast(result.type), + spirv::cast(result.value), + fragment.context->getFloat32(2))}; + + case 2: + return {result.type, fragment.builder.createFMul( + spirv::cast(result.type), + spirv::cast(result.value), + fragment.context->getFloat32(4))}; + case 3: + return {result.type, fragment.builder.createFDiv( + spirv::cast(result.type), + spirv::cast(result.value), + fragment.context->getFloat32(2))}; + + default: + case 0: + return result; + } + }; + + auto applyClamp = [&](Value result) -> Value { + if (inst.clmp) + { + auto glslStd450 = fragment.context->getGlslStd450(); + result.value = fragment.builder.createExtInst( + result.type, glslStd450, GLSLstd450FClamp, + {{result.value, fragment.context->getFloat32(0), + fragment.context->getFloat32(1)}}); + } + + return result; + }; + + auto getSrc = [&](int index, TypeId type) -> Value { + std::uint32_t src = + index == 0 ? inst.src0 : (index == 1 ? inst.src1 : inst.src2); + + auto result = fragment.getScalarOperand(src, type); + + if (inst.abs & (1 << index)) + { + auto glslStd450 = fragment.context->getGlslStd450(); + result.value = fragment.builder.createExtInst( + result.type, glslStd450, GLSLstd450FAbs, {{result.value}}); + } + + if (inst.neg & (1 << index)) + { + result.value = fragment.builder.createFNegate( + spirv::cast(result.type), + spirv::cast(result.value)); + } + + return result; + }; + + auto getSdstSrc = [&](int index, TypeId type) -> Value { + std::uint32_t src = + index == 0 ? inst.src0 : (index == 1 ? inst.src1 : inst.src2); + + auto result = fragment.getScalarOperand(src, type); + + if (inst.neg & (1 << index)) + { + result.value = fragment.builder.createFNegate( + spirv::cast(result.type), + spirv::cast(result.value)); + } + + return result; + }; + + auto roundEven = [&](spirv::Type type, spirv::Value value) { + auto glslStd450 = fragment.context->getGlslStd450(); + return Value{type, fragment.builder.createExtInst( + type, glslStd450, GLSLstd450RoundEven, {{value}})}; + }; + + auto cmpOp = [&](TypeId type, CmpKind kind, CmpFlags flags = CmpFlags::None) { + auto src0 = fragment.getScalarOperand(inst.src0, type).value; + auto src1 = fragment.getScalarOperand(inst.src1, type).value; + + std::int8_t typeMask = 0; + if (kind == CmpKind::CLASS) + { + auto value = fragment.context->findSint32Value( + fragment.getScalarOperand(inst.src2, type).value); + + if (!value) + { + // util::unreachable(); + typeMask = 2; + } + else + { + typeMask = *value; + } + } + + auto result = doCmpOp(fragment, type, src0, src1, kind, flags, typeMask); + fragment.setScalarOperand(inst.vdst, result); + fragment.setScalarOperand(inst.vdst + 1, {fragment.context->getUInt32Type(), + fragment.context->getUInt32(0)}); + }; + + switch (inst.op) + { + case Vop3::Op::V3_CMP_F_F32: + cmpOp(TypeId::Float32, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG); + break; + case Vop3::Op::V3_CMP_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_O_F32: + cmpOp(TypeId::Float32, CmpKind::O); + break; + case Vop3::Op::V3_CMP_U_F32: + cmpOp(TypeId::Float32, CmpKind::U); + break; + case Vop3::Op::V3_CMP_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE); + break; + case Vop3::Op::V3_CMP_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG); + break; + case Vop3::Op::V3_CMP_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT); + break; + case Vop3::Op::V3_CMP_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE); + break; + case Vop3::Op::V3_CMP_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ); + break; + case Vop3::Op::V3_CMP_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT); + break; + case Vop3::Op::V3_CMP_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU); + break; + case Vop3::Op::V3_CMPX_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::X); + break; + case Vop3::Op::V3_CMP_F_F64: + cmpOp(TypeId::Float64, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG); + break; + case Vop3::Op::V3_CMP_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_O_F64: + cmpOp(TypeId::Float64, CmpKind::O); + break; + case Vop3::Op::V3_CMP_U_F64: + cmpOp(TypeId::Float64, CmpKind::U); + break; + case Vop3::Op::V3_CMP_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE); + break; + case Vop3::Op::V3_CMP_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG); + break; + case Vop3::Op::V3_CMP_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT); + break; + case Vop3::Op::V3_CMP_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE); + break; + case Vop3::Op::V3_CMP_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ); + break; + case Vop3::Op::V3_CMP_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT); + break; + case Vop3::Op::V3_CMP_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU); + break; + case Vop3::Op::V3_CMPX_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::X); + break; + case Vop3::Op::V3_CMPS_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::S); + break; + case Vop3::Op::V3_CMPSX_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPS_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::S); + break; + case Vop3::Op::V3_CMPS_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::S); + break; + case Vop3::Op::V3_CMPSX_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::SX); + break; + case Vop3::Op::V3_CMPSX_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::SX); + break; + case Vop3::Op::V3_CMP_F_I32: + cmpOp(TypeId::SInt32, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_I32: + cmpOp(TypeId::SInt32, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_I32: + cmpOp(TypeId::SInt32, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_I32: + cmpOp(TypeId::SInt32, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_I32: + cmpOp(TypeId::SInt32, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_I32: + cmpOp(TypeId::SInt32, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_I32: + cmpOp(TypeId::SInt32, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_T_I32: + cmpOp(TypeId::SInt32, CmpKind::T); + break; + case Vop3::Op::V3_CMP_CLASS_F32: + cmpOp(TypeId::Float32, CmpKind::CLASS); + break; + case Vop3::Op::V3_CMP_LT_I16: + cmpOp(TypeId::SInt16, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_I16: + cmpOp(TypeId::SInt16, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_I16: + cmpOp(TypeId::SInt16, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_I16: + cmpOp(TypeId::SInt16, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_I16: + cmpOp(TypeId::SInt16, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_I16: + cmpOp(TypeId::SInt16, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_CLASS_F16: + cmpOp(TypeId::Float16, CmpKind::CLASS); + break; + case Vop3::Op::V3_CMPX_F_I32: + cmpOp(TypeId::SInt32, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_I32: + cmpOp(TypeId::SInt32, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_I32: + cmpOp(TypeId::SInt32, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_I32: + cmpOp(TypeId::SInt32, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_I32: + cmpOp(TypeId::SInt32, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_I32: + cmpOp(TypeId::SInt32, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_I32: + cmpOp(TypeId::SInt32, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_T_I32: + cmpOp(TypeId::SInt32, CmpKind::T, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_CLASS_F32: + cmpOp(TypeId::Float32, CmpKind::CLASS, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_I16: + cmpOp(TypeId::SInt16, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_I16: + cmpOp(TypeId::SInt16, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_I16: + cmpOp(TypeId::SInt16, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_I16: + cmpOp(TypeId::SInt16, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_I16: + cmpOp(TypeId::SInt16, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_I16: + cmpOp(TypeId::SInt16, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_CLASS_F16: + cmpOp(TypeId::Float16, CmpKind::CLASS, CmpFlags::X); + break; + case Vop3::Op::V3_CMP_F_I64: + cmpOp(TypeId::SInt64, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_I64: + cmpOp(TypeId::SInt64, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_I64: + cmpOp(TypeId::SInt64, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_I64: + cmpOp(TypeId::SInt64, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_I64: + cmpOp(TypeId::SInt64, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_I64: + cmpOp(TypeId::SInt64, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_I64: + cmpOp(TypeId::SInt64, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_T_I64: + cmpOp(TypeId::SInt64, CmpKind::T); + break; + case Vop3::Op::V3_CMP_CLASS_F64: + cmpOp(TypeId::Float64, CmpKind::CLASS); + break; + case Vop3::Op::V3_CMP_LT_U16: + cmpOp(TypeId::UInt16, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_U16: + cmpOp(TypeId::UInt16, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_U16: + cmpOp(TypeId::UInt16, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_U16: + cmpOp(TypeId::UInt16, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_U16: + cmpOp(TypeId::UInt16, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_U16: + cmpOp(TypeId::UInt16, CmpKind::GE); + break; + case Vop3::Op::V3_CMPX_F_I64: + cmpOp(TypeId::SInt64, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_I64: + cmpOp(TypeId::SInt64, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_I64: + cmpOp(TypeId::SInt64, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_I64: + cmpOp(TypeId::SInt64, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_I64: + cmpOp(TypeId::SInt64, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_I64: + cmpOp(TypeId::SInt64, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_I64: + cmpOp(TypeId::SInt64, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_T_I64: + cmpOp(TypeId::SInt64, CmpKind::T, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_CLASS_F64: + cmpOp(TypeId::Float64, CmpKind::CLASS, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_U16: + cmpOp(TypeId::UInt16, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_U16: + cmpOp(TypeId::UInt16, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_U16: + cmpOp(TypeId::UInt16, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_U16: + cmpOp(TypeId::UInt16, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_U16: + cmpOp(TypeId::UInt16, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_U16: + cmpOp(TypeId::UInt16, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMP_F_U32: + cmpOp(TypeId::UInt32, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_U32: + cmpOp(TypeId::UInt32, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_U32: + cmpOp(TypeId::UInt32, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_U32: + cmpOp(TypeId::UInt32, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_U32: + cmpOp(TypeId::UInt32, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_U32: + cmpOp(TypeId::UInt32, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_U32: + cmpOp(TypeId::UInt32, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_T_U32: + cmpOp(TypeId::UInt32, CmpKind::T); + break; + case Vop3::Op::V3_CMP_F_F16: + cmpOp(TypeId::Float16, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_F16: + cmpOp(TypeId::Float16, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_F16: + cmpOp(TypeId::Float16, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_F16: + cmpOp(TypeId::Float16, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_F16: + cmpOp(TypeId::Float16, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_LG_F16: + cmpOp(TypeId::Float16, CmpKind::LG); + break; + case Vop3::Op::V3_CMP_GE_F16: + cmpOp(TypeId::Float16, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_O_F16: + cmpOp(TypeId::Float16, CmpKind::O); + break; + case Vop3::Op::V3_CMPX_F_U32: + cmpOp(TypeId::UInt32, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_U32: + cmpOp(TypeId::UInt32, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_U32: + cmpOp(TypeId::UInt32, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_U32: + cmpOp(TypeId::UInt32, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_U32: + cmpOp(TypeId::UInt32, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_U32: + cmpOp(TypeId::UInt32, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_U32: + cmpOp(TypeId::UInt32, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_T_U32: + cmpOp(TypeId::UInt32, CmpKind::T, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_F_F16: + cmpOp(TypeId::Float16, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_F16: + cmpOp(TypeId::Float16, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_F16: + cmpOp(TypeId::Float16, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_F16: + cmpOp(TypeId::Float16, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_F16: + cmpOp(TypeId::Float16, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LG_F16: + cmpOp(TypeId::Float16, CmpKind::LG, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_F16: + cmpOp(TypeId::Float16, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_O_F16: + cmpOp(TypeId::Float16, CmpKind::O, CmpFlags::X); + break; + case Vop3::Op::V3_CMP_F_U64: + cmpOp(TypeId::UInt64, CmpKind::F); + break; + case Vop3::Op::V3_CMP_LT_U64: + cmpOp(TypeId::UInt64, CmpKind::LT); + break; + case Vop3::Op::V3_CMP_EQ_U64: + cmpOp(TypeId::UInt64, CmpKind::EQ); + break; + case Vop3::Op::V3_CMP_LE_U64: + cmpOp(TypeId::UInt64, CmpKind::LE); + break; + case Vop3::Op::V3_CMP_GT_U64: + cmpOp(TypeId::UInt64, CmpKind::GT); + break; + case Vop3::Op::V3_CMP_NE_U64: + cmpOp(TypeId::UInt64, CmpKind::NE); + break; + case Vop3::Op::V3_CMP_GE_U64: + cmpOp(TypeId::UInt64, CmpKind::GE); + break; + case Vop3::Op::V3_CMP_T_U64: + cmpOp(TypeId::UInt64, CmpKind::T); + break; + case Vop3::Op::V3_CMP_U_F16: + cmpOp(TypeId::Float16, CmpKind::U); + break; + case Vop3::Op::V3_CMP_NGE_F16: + cmpOp(TypeId::Float16, CmpKind::NGE); + break; + case Vop3::Op::V3_CMP_NLG_F16: + cmpOp(TypeId::Float16, CmpKind::NLG); + break; + case Vop3::Op::V3_CMP_NGT_F16: + cmpOp(TypeId::Float16, CmpKind::NGT); + break; + case Vop3::Op::V3_CMP_NLE_F16: + cmpOp(TypeId::Float16, CmpKind::NLE); + break; + case Vop3::Op::V3_CMP_NEQ_F16: + cmpOp(TypeId::Float16, CmpKind::NEQ); + break; + case Vop3::Op::V3_CMP_NLT_F16: + cmpOp(TypeId::Float16, CmpKind::NLT); + break; + case Vop3::Op::V3_CMP_TRU_F16: + cmpOp(TypeId::Float16, CmpKind::TRU); + break; + case Vop3::Op::V3_CMPX_F_U64: + cmpOp(TypeId::UInt64, CmpKind::F, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LT_U64: + cmpOp(TypeId::UInt64, CmpKind::LT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_EQ_U64: + cmpOp(TypeId::UInt64, CmpKind::EQ, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_LE_U64: + cmpOp(TypeId::UInt64, CmpKind::LE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GT_U64: + cmpOp(TypeId::UInt64, CmpKind::GT, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_NE_U64: + cmpOp(TypeId::UInt64, CmpKind::NE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_GE_U64: + cmpOp(TypeId::UInt64, CmpKind::GE, CmpFlags::X); + break; + case Vop3::Op::V3_CMPX_T_U64: + cmpOp(TypeId::UInt64, CmpKind::T, CmpFlags::X); + break; + + case Vop3::Op::V3_RCP_F32: + { + auto src = getSrc(0, TypeId::Float32); + auto floatT = fragment.context->getFloat32Type(); + auto float1 = fragment.context->getFloat32(1); + auto resultValue = fragment.builder.createFDiv( + floatT, float1, spirv::cast(src.value)); + auto result = applyClamp(applyOmod({floatT, resultValue})); + + fragment.setVectorOperand(inst.vdst, roundEven(result.type, result.value)); + break; + } + + case Vop3::Op::V3_ADD_I32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getScalarOperand(inst.src1, TypeId::UInt32).value; + auto uintT = fragment.context->getType(TypeId::UInt32); + auto resultStruct = + fragment.context->getStructType(std::array{uintT, uintT}); + auto result = fragment.builder.createIAddCarry(resultStruct, src0, src1); + fragment.setVectorOperand( + inst.vdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(0)})}); + fragment.setScalarOperand( + inst.sdst, + {uintT, fragment.builder.createCompositeExtract( + uintT, result, std::array{static_cast(1)})}); + fragment.setScalarOperand(inst.sdst + 1, + {uintT, fragment.context->getUInt32(0)}); + break; + } + + case Vop3::Op::V3_MOV_B32: + { + auto src0 = getSrc(0, TypeId::Float32); + + fragment.setVectorOperand(inst.vdst, src0); + break; + } + + case Vop3::Op::V3_ADD_F32: + { + auto floatT = fragment.context->getFloat32Type(); + auto src0 = getSrc(0, TypeId::Float32); + auto src1 = getSrc(1, TypeId::Float32); + auto resultValue = fragment.builder.createFAdd( + floatT, spirv::cast(src0.value), + spirv::cast(src1.value)); + auto result = applyClamp(applyOmod({floatT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + + case Vop3::Op::V3_SUB_F32: + { + auto floatT = fragment.context->getFloat32Type(); + auto src0 = getSrc(0, TypeId::Float32); + auto src1 = getSrc(1, TypeId::Float32); + auto resultValue = fragment.builder.createFSub( + floatT, spirv::cast(src0.value), + spirv::cast(src1.value)); + auto result = applyClamp(applyOmod({floatT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + + case Vop3::Op::V3_MUL_F32: + { + auto floatT = fragment.context->getFloat32Type(); + auto src0 = getSrc(0, TypeId::Float32); + auto src1 = getSrc(1, TypeId::Float32); + auto resultValue = fragment.builder.createFMul( + floatT, spirv::cast(src0.value), + spirv::cast(src1.value)); + auto result = applyClamp(applyOmod({floatT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + case Vop3::Op::V3_MUL_LO_U32: + { + auto resultT = fragment.context->getUInt32Type(); + auto src0 = getSrc(0, TypeId::UInt32); + auto src1 = getSrc(1, TypeId::UInt32); + auto resultValue = fragment.builder.createIMul( + resultT, spirv::cast(src0.value), + spirv::cast(src1.value)); + auto result = applyClamp(applyOmod({resultT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + case Vop3::Op::V3_MUL_LO_I32: + { + auto resultT = fragment.context->getSint32Type(); + auto src0 = getSrc(0, TypeId::SInt32); + auto src1 = getSrc(1, TypeId::SInt32); + auto resultValue = fragment.builder.createIMul( + resultT, spirv::cast(src0.value), + spirv::cast(src1.value)); + auto result = applyClamp(applyOmod({resultT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + case Vop3::Op::V3_MUL_HI_I32: + { + auto resultT = fragment.context->getSint32Type(); + auto src0 = getSrc(0, TypeId::SInt32); + auto src1 = getSrc(1, TypeId::SInt32); + + auto sint64T = fragment.context->getSint64Type(); + + auto src0_64 = fragment.builder.createSConvert( + sint64T, spirv::cast(src0.value)); + auto src1_64 = fragment.builder.createSConvert( + sint64T, spirv::cast(src1.value)); + + auto resultValue64 = fragment.builder.createIMul( + sint64T, spirv::cast(src0_64), + spirv::cast(src1_64)); + + resultValue64 = fragment.builder.createShiftRightLogical( + sint64T, resultValue64, fragment.context->getUInt32(32)); + auto resultValue = fragment.builder.createSConvert(resultT, resultValue64); + auto result = applyClamp(applyOmod({resultT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + case Vop3::Op::V3_MUL_HI_U32: + { + auto resultT = fragment.context->getUInt32Type(); + auto src0 = spirv::cast(getSrc(0, TypeId::UInt32).value); + auto src1 = spirv::cast(getSrc(1, TypeId::UInt32).value); + + auto uint64T = fragment.context->getUInt64Type(); + + auto src0_64 = fragment.builder.createUConvert(uint64T, src0); + auto src1_64 = fragment.builder.createUConvert(uint64T, src1); + + auto resultValue64 = fragment.builder.createIMul(uint64T, src0_64, src1_64); + + resultValue64 = fragment.builder.createShiftRightLogical( + uint64T, resultValue64, fragment.context->getUInt32(32)); + auto resultValue = fragment.builder.createUConvert(resultT, resultValue64); + auto result = applyClamp(applyOmod({resultT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + + case Vop3::Op::V3_MAC_F32: + { + auto floatT = fragment.context->getFloat32Type(); + auto src0 = getSrc(0, TypeId::Float32); + auto src1 = getSrc(1, TypeId::Float32); + + auto dst = spirv::cast( // FIXME: should use src2? + fragment.getVectorOperand(inst.vdst, TypeId::Float32).value); + + auto resultValue = fragment.builder.createFAdd( + floatT, + fragment.builder.createFMul(floatT, + spirv::cast(src0.value), + spirv::cast(src1.value)), + dst); + + auto result = applyClamp(applyOmod({floatT, resultValue})); + + fragment.setVectorOperand(inst.vdst, result); + break; + } + case Vop3::Op::V3_MAD_U32_U24: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt32Type(); + + src0 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src0, fragment.context->getUInt32((1 << 24) - 1))); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32((1 << 24) - 1))); + + auto result = fragment.builder.createIAdd( + operandT, fragment.builder.createIMul(operandT, src0, src1), src2); + + fragment.setVectorOperand(inst.vdst, {operandT, result}); + break; + } + case Vop3::Op::V3_MAD_I32_I24: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::SInt32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::SInt32).value); + auto operandT = fragment.context->getSint32Type(); + + src0 = fragment.builder.createShiftLeftLogical( + operandT, src0, fragment.context->getUInt32(8)); + src0 = fragment.builder.createShiftRightArithmetic( + operandT, src0, fragment.context->getUInt32(8)); + src1 = fragment.builder.createShiftLeftLogical( + operandT, src1, fragment.context->getUInt32(8)); + src1 = fragment.builder.createShiftRightArithmetic( + operandT, src1, fragment.context->getUInt32(8)); + + auto result = fragment.builder.createIAdd( + operandT, fragment.builder.createIMul(operandT, src0, src1), src2); + + fragment.setVectorOperand(inst.vdst, {operandT, result}); + break; + } + case Vop3::Op::V3_MUL_U32_U24: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt32Type(); + + src0 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src0, fragment.context->getUInt32((1 << 24) - 1))); + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32((1 << 24) - 1))); + + auto result = fragment.builder.createIMul(operandT, src0, src1); + + fragment.setVectorOperand(inst.vdst, {operandT, result}); + break; + } + case Vop3::Op::V3_MUL_I32_I24: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::SInt32).value); + auto operandT = fragment.context->getSint32Type(); + + src0 = fragment.builder.createShiftLeftLogical( + operandT, src0, fragment.context->getUInt32(8)); + src0 = fragment.builder.createShiftRightArithmetic( + operandT, src0, fragment.context->getUInt32(8)); + src1 = fragment.builder.createShiftLeftLogical( + operandT, src1, fragment.context->getUInt32(8)); + src1 = fragment.builder.createShiftRightArithmetic( + operandT, src1, fragment.context->getUInt32(8)); + + auto result = fragment.builder.createIMul(operandT, src0, src1); + + fragment.setVectorOperand(inst.vdst, {operandT, result}); + break; + } + case Vop3::Op::V3_MAD_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto result = fragment.builder.createFAdd( + floatT, fragment.builder.createFMul(floatT, src0, src1), src2); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop3::Op::V3_MAX_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), + src0, src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop3::Op::V3_MAX3_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto max01 = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, src0, src1), + src0, src1); + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdGreaterThanEqual(boolT, max01, src2), + max01, src2); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop3::Op::V3_MIN_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, + src1); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop3::Op::V3_MIN3_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto boolT = fragment.context->getBoolType(); + + auto min01 = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, + src1); + auto result = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, min01, src2), min01, + src2); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop3::Op::V3_MED3_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::Float32).value); + auto boolT = fragment.context->getBoolType(); + auto floatT = fragment.context->getFloat32Type(); + auto glslStd450 = fragment.context->getGlslStd450(); + + auto min01 = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, src0, src1), src0, + src1); + auto max01 = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdGreaterThan(boolT, src0, src1), src0, + src1); + auto minMax011 = fragment.builder.createSelect( + floatT, fragment.builder.createFOrdLessThan(boolT, max01, src2), max01, + src2); + + auto result = fragment.builder.createExtInst( + floatT, glslStd450, GLSLstd450NMax, {{min01, minMax011}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + } + case Vop3::Op::V3_FMA_F32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::Float32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto glslStd450 = fragment.context->getGlslStd450(); + + auto result = fragment.builder.createExtInst( + floatT, glslStd450, GLSLstd450Fma, {{src0, src1, src2}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop3::Op::V3_CNDMASK_B32: + { + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto src1 = fragment.getScalarOperand(inst.src1, TypeId::UInt32).value; + auto src2 = fragment.getScalarOperand(inst.src2, TypeId::UInt32).value; + + auto cmp = fragment.builder.createINotEqual( + fragment.context->getBoolType(), src2, fragment.context->getUInt32(0)); + + auto uint32T = fragment.context->getUInt32Type(); + auto result = fragment.builder.createSelect(uint32T, cmp, src1, src0); + fragment.setVectorOperand(inst.vdst, {uint32T, result}); + break; + } + + case Vop3::Op::V3_BFE_U32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.src1, TypeId::UInt32).value); + auto src2 = spirv::cast( + fragment.getScalarOperand(inst.src2, TypeId::UInt32).value); + + auto operandT = fragment.context->getUInt32Type(); + + auto voffset = + spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x1f))); + auto vsize = + spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src2, fragment.context->getUInt32(0x1f))); + auto field = + fragment.builder.createShiftRightLogical(operandT, src0, voffset); + auto mask = fragment.builder.createISub( + operandT, + fragment.builder.createShiftLeftLogical( + operandT, fragment.context->getUInt32(1), vsize), + fragment.context->getUInt32(1)); + + auto resultT = fragment.context->getUInt32Type(); + auto result = fragment.builder.createSelect( + operandT, + fragment.builder.createIEqual(fragment.context->getBoolType(), vsize, + fragment.context->getUInt32(0)), + fragment.context->getUInt32(0), + fragment.builder.createBitwiseAnd(operandT, field, mask)); + fragment.setVectorOperand(inst.vdst, {resultT, result}); + break; + } + + case Vop3::Op::V3_CVT_PKRTZ_F16_F32: + { + auto float2T = fragment.context->getType(TypeId::Float32x2); + auto uintT = fragment.context->getType(TypeId::UInt32); + auto glslStd450 = fragment.context->getGlslStd450(); + + auto src0 = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; + auto src1 = fragment.getScalarOperand(inst.src1, TypeId::Float32).value; + + auto src = fragment.builder.createCompositeConstruct( + float2T, std::array{src0, src1}); + auto dst = fragment.builder.createExtInst( + uintT, glslStd450, GLSLstd450PackHalf2x16, std::array{src}); + + fragment.setVectorOperand(inst.vdst, {uintT, dst}); + break; + } + + case Vop3::Op::V3_SAD_U32: + { + auto src0 = spirv::cast(getSrc(0, TypeId::UInt32).value); + auto src1 = spirv::cast(getSrc(1, TypeId::UInt32).value); + auto src2 = spirv::cast(getSrc(2, TypeId::UInt32).value); + + auto uint32T = fragment.context->getUInt32Type(); + auto sint32T = fragment.context->getSint32Type(); + + auto diff = fragment.builder.createISub(uint32T, src0, src1); + auto sdiff = fragment.builder.createBitcast(sint32T, diff); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto sabsdiff = fragment.builder.createExtInst(sint32T, glslStd450, + GLSLstd450SAbs, {{sdiff}}); + + auto absdiff = fragment.builder.createBitcast(uint32T, sabsdiff); + auto result = fragment.builder.createIAdd(uint32T, absdiff, src2); + fragment.setVectorOperand(inst.vdst, {uint32T, result}); + break; + } + case Vop3::Op::V3_RSQ_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst( + floatT, glslStd450, GLSLstd450InverseSqrt, {{src}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertMubuf(Fragment& fragment, Mubuf inst) + { + fragment.registers->pc += Mubuf::kMinInstSize * sizeof(std::uint32_t); + /* + printMubufOpcode(op); + printf(" "); + printVectorOperand(vdata, inst + instSize); + printf(", "); + printScalarOperand(srsrc << 2, inst + instSize); + printf(", "); + printScalarOperand(soffset, inst + instSize); + */ - // spirv::Value value; - std::array exports; - - // TODO: handle vm - if (inst.compr) { - auto floatT = fragment.context->getType(TypeId::Float32); - auto float2T = fragment.context->getType(TypeId::Float32x2); - auto glslStd450 = fragment.context->getGlslStd450(); - - auto xyUint = fragment.getVectorOperand(inst.vsrc0, TypeId::UInt32).value; - auto zwUint = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; - - auto xy = fragment.builder.createExtInst( - float2T, glslStd450, GLSLstd450UnpackHalf2x16, std::array{xyUint}); - auto zw = fragment.builder.createExtInst( - float2T, glslStd450, GLSLstd450UnpackHalf2x16, std::array{zwUint}); - exports[0] = fragment.builder.createCompositeExtract( - floatT, xy, std::array{static_cast(0)}); - exports[1] = fragment.builder.createCompositeExtract( - floatT, xy, std::array{static_cast(1)}); - exports[2] = fragment.builder.createCompositeExtract( - floatT, zw, std::array{static_cast(0)}); - exports[3] = fragment.builder.createCompositeExtract( - floatT, zw, std::array{static_cast(1)}); - // value = fragment.builder.createCompositeConstruct(type, std::array{x, y, - // z, w}); - } else { - exports[0] = fragment.getVectorOperand(inst.vsrc0, TypeId::Float32).value; - exports[1] = fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value; - exports[2] = fragment.getVectorOperand(inst.vsrc2, TypeId::Float32).value; - exports[3] = fragment.getVectorOperand(inst.vsrc3, TypeId::Float32).value; - /* + auto getSOffset = [&](std::int32_t adv = 0) -> spirv::UIntValue { + auto resultT = fragment.context->getUInt32Type(); + auto resultV = + fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value; + auto result = spirv::cast(resultV); + + if (adv != 0) + { + if (auto constVal = fragment.context->findSint32Value(result)) + { + return fragment.context->getUInt32(*constVal + adv); + } + + result = fragment.builder.createIAdd(resultT, result, + fragment.context->getUInt32(adv)); + } + + return result; + }; + + auto getVBuffer = [&] { + auto vBuffer0 = + fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); + auto vBuffer1 = + fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); + auto vBuffer2 = + fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); + auto vBuffer3 = + fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); + + auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); + auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); + auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); + auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); + + if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && + optVBuffer3Value) + { + // V# buffer value is known, read the buffer now + std::array vBufferData = { + *optVBuffer0Value, *optVBuffer1Value, *optVBuffer2Value, + *optVBuffer3Value}; + + GnmVBuffer result; + std::memcpy(&result, vBufferData.data(), sizeof(result)); + return result; + } + + util::unreachable(); + }; + + auto getAddress = [&](GnmVBuffer* vbuffer) { + auto& builder = fragment.builder; + auto uint32T = fragment.context->getUInt32Type(); + + spirv::UIntValue index; + if (inst.idxen) + { + index = spirv::cast( + fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); + } + + // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); + + if (vbuffer->addtid_en) + { + spirv::UIntValue threadId = + builder.createLoad(uint32T, fragment.context->getThreadId()); + + if (index) + { + index = builder.createIAdd(uint32T, index, threadId); + } + else + { + index = threadId; + } + } + + auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) : spirv::UIntValue{}; + + if (inst.offen) + { + auto off = spirv::cast( + fragment + .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), + TypeId::UInt32) + .value); + + if (offset) + { + offset = builder.createIAdd(uint32T, off, offset); + } + else + { + offset = off; + } + } + + spirv::UIntValue address = getSOffset(); + + if (vbuffer->swizzle_en == 0) + { + if (vbuffer->stride == 0 || !index) + { + return address; + } + + auto offset = builder.createIMul( + uint32T, index, fragment.context->getUInt32(vbuffer->stride)); + if (address == fragment.context->getUInt32(0)) + { + return offset; + } + + return builder.createIAdd(uint32T, address, offset); + } + + if (!index && !offset) + { + return address; + } + + if (index && offset) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + auto offsetMsb = builder.createIMul( + uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, + builder.createIAdd(uint32T, indexMsb, offsetMsb), + indexStride)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, index_lsb, elementSize)); + + return builder.createIAdd(uint32T, address, offset_lsb); + } + + if (index) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + + return builder.createIAdd( + uint32T, address, builder.createIMul(uint32T, indexMsb, indexStride)); + } + + if (!offset) + { + util::unreachable(); + } + + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto offsetMsb = + builder.createIMul(uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, builder.createIMul(uint32T, offsetMsb, indexStride)); + + return builder.createIAdd(uint32T, address, offset_lsb); + }; + + switch (inst.op) + { + case Mubuf::Op::BUFFER_LOAD_FORMAT_X: + case Mubuf::Op::BUFFER_LOAD_FORMAT_XY: + case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZ: + case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZW: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mubuf::Op::BUFFER_LOAD_FORMAT_X) + 1; + + auto vbuffer = getVBuffer(); + if (vbuffer.dfmt != kSurfaceFormatInvalid) + { + auto address = getAddress(&vbuffer); + + spirv::Value result[4]; + auto resultType = convertFromFormat( + result, count, fragment, reinterpret_cast(&vbuffer), + address, vbuffer.dfmt, vbuffer.nfmt); + + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setVectorOperand(inst.vdata + i, {resultType, result[i]}); + } + } + else + { + auto floatT = fragment.context->getFloat32Type(); + auto zero = fragment.context->getFloat32(0); + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setVectorOperand(inst.vdata + i, {floatT, zero}); + } + } + break; + } + + case Mubuf::Op::BUFFER_STORE_FORMAT_X: + case Mubuf::Op::BUFFER_STORE_FORMAT_XY: + case Mubuf::Op::BUFFER_STORE_FORMAT_XYZ: + case Mubuf::Op::BUFFER_STORE_FORMAT_XYZW: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mubuf::Op::BUFFER_STORE_FORMAT_X) + + 1; + + auto vbuffer = getVBuffer(); + if (vbuffer.dfmt != kSurfaceFormatInvalid) + { + auto address = getAddress(&vbuffer); + + convertToFormat(RegisterId::Vector(inst.vdata), count, fragment, + reinterpret_cast(&vbuffer), address, + vbuffer.dfmt, vbuffer.nfmt); + } + break; + } + + case Mubuf::Op::BUFFER_LOAD_UBYTE: + case Mubuf::Op::BUFFER_LOAD_USHORT: + case Mubuf::Op::BUFFER_LOAD_SSHORT: + case Mubuf::Op::BUFFER_LOAD_SBYTE: + inst.dump(); + util::unreachable(); + + case Mubuf::Op::BUFFER_LOAD_DWORD: + case Mubuf::Op::BUFFER_LOAD_DWORDX2: + case Mubuf::Op::BUFFER_LOAD_DWORDX4: + case Mubuf::Op::BUFFER_LOAD_DWORDX3: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mubuf::Op::BUFFER_LOAD_DWORD) + 1; + + auto vbuffer = getVBuffer(); + auto address = getAddress(&vbuffer); + auto loadType = fragment.context->getType(TypeId::UInt32); + auto uniform = fragment.context->getOrCreateStorageBuffer( + reinterpret_cast(&vbuffer), TypeId::UInt32); + uniform->accessOp |= AccessOp::Load; + + auto uniformPointerType = fragment.context->getPointerType( + spv::StorageClass::StorageBuffer, TypeId::UInt32); + address = + fragment.builder.createUDiv(fragment.context->getUInt32Type(), address, + fragment.context->getUInt32(4)); + + for (int i = 0; i < count; ++i) + { + auto channelOffset = address; + + if (i != 0) + { + channelOffset = fragment.builder.createIAdd( + fragment.context->getUInt32Type(), channelOffset, + fragment.context->getUInt32(i)); + } + + auto uniformPointerValue = fragment.builder.createAccessChain( + uniformPointerType, uniform->variable, + {{fragment.context->getUInt32(0), channelOffset}}); + + auto value = fragment.builder.createLoad(loadType, uniformPointerValue); + fragment.setVectorOperand(inst.vdata + i, {loadType, value}); + } + break; + } + + case Mubuf::Op::BUFFER_STORE_BYTE: + case Mubuf::Op::BUFFER_STORE_SHORT: + inst.dump(); + util::unreachable(); + + case Mubuf::Op::BUFFER_STORE_DWORD: + case Mubuf::Op::BUFFER_STORE_DWORDX2: + case Mubuf::Op::BUFFER_STORE_DWORDX4: + case Mubuf::Op::BUFFER_STORE_DWORDX3: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mubuf::Op::BUFFER_STORE_DWORD) + 1; + + auto vbuffer = getVBuffer(); + auto address = getAddress(&vbuffer); + auto uniform = fragment.context->getOrCreateStorageBuffer( + reinterpret_cast(&vbuffer), TypeId::UInt32); + uniform->accessOp |= AccessOp::Store; + + auto uniformPointerType = fragment.context->getPointerType( + spv::StorageClass::StorageBuffer, TypeId::UInt32); + address = + fragment.builder.createUDiv(fragment.context->getUInt32Type(), address, + fragment.context->getUInt32(4)); + + for (int i = 0; i < count; ++i) + { + auto channelOffset = address; + + if (i != 0) + { + channelOffset = fragment.builder.createIAdd( + fragment.context->getUInt32Type(), channelOffset, + fragment.context->getUInt32(i)); + } + + auto uniformPointerValue = fragment.builder.createAccessChain( + uniformPointerType, uniform->variable, + {{fragment.context->getUInt32(0), channelOffset}}); + + fragment.builder.createStore( + uniformPointerValue, + fragment.getVectorOperand(inst.vdata + i, TypeId::UInt32).value); + } + } + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertMtbuf(Fragment& fragment, Mtbuf inst) + { + fragment.registers->pc += Mtbuf::kMinInstSize * sizeof(std::uint32_t); + + switch (inst.op) + { + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_X: + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XY: + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZ: + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZW: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mtbuf::Op::TBUFFER_LOAD_FORMAT_X) + + 1; + + auto& builder = fragment.builder; + + auto vBuffer0 = + fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); + auto vBuffer1 = + fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); + auto vBuffer2 = + fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); + auto vBuffer3 = + fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); + + auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); + auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); + auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); + auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); + + if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && + optVBuffer3Value) + { + // V# buffer value is known, read the buffer now + std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, + *optVBuffer2Value, *optVBuffer3Value}; + + auto vbuffer = reinterpret_cast(vBufferData); + auto base = spirv::cast( + fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value); + + auto uint32T = fragment.context->getUInt32Type(); + auto uint32_0 = fragment.context->getUInt32(0); + + if (inst.dfmt == kSurfaceFormatInvalid) + { + util::unreachable("!! dfmt is invalid !!\n"); + + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setVectorOperand(inst.vdata + i, {uint32T, uint32_0}); + } + + return; + } + + spirv::UIntValue index; + if (inst.idxen) + { + index = spirv::cast( + fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); + } + + // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); + + if (vbuffer->addtid_en) + { + spirv::UIntValue threadId = + builder.createLoad(uint32T, fragment.context->getThreadId()); + + if (index) + { + index = builder.createIAdd(uint32T, index, threadId); + } + else + { + index = threadId; + } + } + + auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) : spirv::UIntValue{}; + + if (inst.offen) + { + auto off = spirv::cast( + fragment + .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), + TypeId::UInt32) + .value); + + if (offset) + { + offset = builder.createIAdd(uint32T, off, offset); + } + else + { + offset = off; + } + } + + spirv::UIntValue address = base; + if (vbuffer->swizzle_en == 0) + { + if (vbuffer->stride != 0 && index) + { + auto offset = builder.createIMul( + uint32T, index, fragment.context->getUInt32(vbuffer->stride)); + if (address == uint32_0) + { + address = offset; + } + else + { + address = builder.createIAdd(uint32T, address, offset); + } + } + } + else + { + if (index && offset) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + auto offsetMsb = builder.createIMul( + uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul( + uint32T, builder.createIAdd(uint32T, indexMsb, offsetMsb), + indexStride)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, index_lsb, elementSize)); + + address = builder.createIAdd(uint32T, address, offset_lsb); + } + else if (index) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + + auto indexLsb = builder.createIMul( + uint32T, index_lsb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, indexMsb, indexStride)); + + address = builder.createIAdd(uint32T, address, indexLsb); + } + else if (offset) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto offsetMsb = builder.createIMul( + uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, offsetMsb, indexStride)); + + address = builder.createIAdd(uint32T, address, offset_lsb); + } + } + + spirv::Value result[4]; + auto resultType = convertFromFormat(result, count, fragment, vBufferData, + address, inst.dfmt, inst.nfmt); + + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setVectorOperand(inst.vdata + i, {resultType, result[i]}); + } + break; + } + else + { + util::unreachable(); + } + } + + case Mtbuf::Op::TBUFFER_STORE_FORMAT_X: + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XY: + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZ: + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZW: + { + std::uint32_t count = static_cast(inst.op) - + static_cast(Mtbuf::Op::TBUFFER_STORE_FORMAT_X) + + 1; + auto& builder = fragment.builder; + + auto vBuffer0 = + fragment.getScalarOperand((inst.srsrc << 2) + 0, TypeId::UInt32); + auto vBuffer1 = + fragment.getScalarOperand((inst.srsrc << 2) + 1, TypeId::UInt32); + auto vBuffer2 = + fragment.getScalarOperand((inst.srsrc << 2) + 2, TypeId::UInt32); + auto vBuffer3 = + fragment.getScalarOperand((inst.srsrc << 2) + 3, TypeId::UInt32); + + auto optVBuffer0Value = fragment.context->findUint32Value(vBuffer0.value); + auto optVBuffer1Value = fragment.context->findUint32Value(vBuffer1.value); + auto optVBuffer2Value = fragment.context->findUint32Value(vBuffer2.value); + auto optVBuffer3Value = fragment.context->findUint32Value(vBuffer3.value); + + if (optVBuffer0Value && optVBuffer1Value && optVBuffer2Value && + optVBuffer3Value) + { + // V# buffer value is known, read the buffer now + std::uint32_t vBufferData[] = {*optVBuffer0Value, *optVBuffer1Value, + *optVBuffer2Value, *optVBuffer3Value}; + + auto vbuffer = reinterpret_cast(vBufferData); + // std::printf("vBuffer address = %lx\n", vbuffer->getAddress()); + + auto base = spirv::cast( + fragment.getScalarOperand(inst.soffset, TypeId::UInt32).value); + + auto uint32T = fragment.context->getUInt32Type(); + auto uint32_0 = fragment.context->getUInt32(0); + + if (inst.dfmt == kSurfaceFormatInvalid) + { + util::unreachable("!! dfmt is invalid !!\n"); + + for (std::uint32_t i = 0; i < count; ++i) + { + fragment.setVectorOperand(inst.vdata + i, {uint32T, uint32_0}); + } + + return; + } + + spirv::UIntValue index; + if (inst.idxen) + { + index = spirv::cast( + fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value); + } + + if (vbuffer->addtid_en) + { + spirv::UIntValue threadId = + builder.createLoad(uint32T, fragment.context->getThreadId()); + + if (index) + { + index = builder.createIAdd(uint32T, index, threadId); + } + else + { + index = threadId; + } + } + + auto offset = inst.offset ? fragment.context->getUInt32(inst.offset) : spirv::UIntValue{}; + + if (inst.offen) + { + auto off = spirv::cast( + fragment + .getVectorOperand(inst.vaddr + (inst.idxen ? 1 : 0), + TypeId::UInt32) + .value); + + if (offset) + { + offset = builder.createIAdd(uint32T, off, offset); + } + else + { + offset = off; + } + } + + spirv::UIntValue address = base; + if (vbuffer->swizzle_en == 0) + { + if (vbuffer->stride != 0 && index) + { + auto offset = builder.createIMul( + uint32T, index, fragment.context->getUInt32(vbuffer->stride)); + if (address == uint32_0) + { + address = offset; + } + else + { + address = builder.createIAdd(uint32T, address, offset); + } + } + } + else + { + if (index && offset) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + auto offsetMsb = builder.createIMul( + uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul( + uint32T, builder.createIAdd(uint32T, indexMsb, offsetMsb), + indexStride)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, index_lsb, elementSize)); + + address = builder.createIAdd(uint32T, address, offset_lsb); + } + else if (index) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto index_msb = builder.createUDiv(uint32T, index, indexStride); + auto index_lsb = builder.createUMod(uint32T, index, indexStride); + + auto indexMsb = builder.createIMul( + uint32T, index_msb, fragment.context->getUInt32(vbuffer->stride)); + + auto indexLsb = builder.createIMul( + uint32T, index_lsb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, indexMsb, indexStride)); + + address = builder.createIAdd(uint32T, address, indexLsb); + } + else if (offset) + { + auto indexStride = fragment.context->getUInt32(vbuffer->index_stride); + auto elementSize = fragment.context->getUInt32(vbuffer->element_size); + auto offset_msb = builder.createUDiv(uint32T, offset, elementSize); + auto offset_lsb = builder.createUMod(uint32T, offset, elementSize); + + auto offsetMsb = builder.createIMul( + uint32T, offset_msb, + fragment.context->getUInt32(vbuffer->element_size)); + + address = builder.createIAdd( + uint32T, address, + builder.createIMul(uint32T, offsetMsb, indexStride)); + + address = builder.createIAdd(uint32T, address, offset_lsb); + } + } + + convertToFormat(RegisterId::Vector(inst.vdata), count, fragment, + vBufferData, address, inst.dfmt, inst.nfmt); + } + else + { + util::unreachable(); + } + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + void convertMimg(Fragment& fragment, Mimg inst) + { + fragment.registers->pc += Mimg::kMinInstSize * sizeof(std::uint32_t); + switch (inst.op) + { + case Mimg::Op::IMAGE_GET_RESINFO: + { + auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), + inst.r128, true, // fixme, should be any + AccessOp::None); + spirv::Value values[4]; + auto uint32T = fragment.context->getUInt32Type(); + + if (inst.dmask & 3) + { + // query whd + // TODO: support other than 2D textures + auto uint32x2T = fragment.context->getUint32x2Type(); + auto lod = fragment.getScalarOperand(inst.vaddr, TypeId::UInt32); + auto sizeResult = + fragment.builder.createImageQuerySizeLod(uint32x2T, image, lod.value); + + values[0] = + fragment.builder.createCompositeExtract(uint32T, sizeResult, {{0}}); + values[1] = + fragment.builder.createCompositeExtract(uint32T, sizeResult, {{1}}); + values[2] = fragment.context->getUInt32(1); + } + + if (inst.dmask & (1 << 3)) + { + // query total mip count + values[3] = fragment.builder.createImageQueryLevels(uint32T, image); + } + + for (std::size_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + fragment.setVectorOperand(inst.vdata + dstOffset++, + {uint32T, values[i]}); + } + } + break; + } + + case Mimg::Op::IMAGE_SAMPLE_LZ: + { + auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), + inst.r128, true, AccessOp::Load); + auto sampler = fragment.createSampler(RegisterId::Raw(inst.ssamp << 2)); + auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::Float32).value; + auto coord1 = + fragment.getVectorOperand(inst.vaddr + 1, TypeId::Float32).value; + auto coord2 = + fragment.getVectorOperand(inst.vaddr + 2, TypeId::Float32).value; + auto coords = fragment.builder.createCompositeConstruct( + fragment.context->getFloat32x3Type(), + {{coord0, coord1, coord2}}); // TODO + + auto sampledImage2dT = fragment.context->getSampledImage2DType(); + auto float4T = fragment.context->getFloat32x4Type(); + auto floatT = fragment.context->getFloat32Type(); + auto sampledImage = + fragment.builder.createSampledImage(sampledImage2dT, image, sampler); + auto value = fragment.builder.createImageSampleExplicitLod( + float4T, sampledImage, coords, spv::ImageOperandsMask::Lod, + {{fragment.context->getFloat32(0)}}); + + for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + fragment.setVectorOperand( + inst.vdata + dstOffset++, + {floatT, + fragment.builder.createCompositeExtract(floatT, value, {{i}})}); + } + } + break; + } + + case Mimg::Op::IMAGE_SAMPLE: + { + auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), + inst.r128, true, AccessOp::Load); + auto sampler = fragment.createSampler(RegisterId::Raw(inst.ssamp << 2)); + auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::Float32).value; + auto coord1 = + fragment.getVectorOperand(inst.vaddr + 1, TypeId::Float32).value; + auto coord2 = + fragment.getVectorOperand(inst.vaddr + 2, TypeId::Float32).value; + auto coords = fragment.builder.createCompositeConstruct( + fragment.context->getFloat32x3Type(), + {{coord0, coord1, coord2}}); // TODO + + auto sampledImage2dT = fragment.context->getSampledImage2DType(); + auto float4T = fragment.context->getFloat32x4Type(); + auto floatT = fragment.context->getFloat32Type(); + auto sampledImage = + fragment.builder.createSampledImage(sampledImage2dT, image, sampler); + auto value = fragment.builder.createImageSampleImplicitLod( + float4T, sampledImage, coords); + + for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + fragment.setVectorOperand( + inst.vdata + dstOffset++, + {floatT, + fragment.builder.createCompositeExtract(floatT, value, {{i}})}); + } + } + break; + } + + case Mimg::Op::IMAGE_STORE: + case Mimg::Op::IMAGE_STORE_MIP: + { + auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), + inst.r128, false, AccessOp::Store); + auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value; + auto coord1 = + fragment.getVectorOperand(inst.vaddr + 1, TypeId::UInt32).value; + auto coord2 = + fragment.getVectorOperand(inst.vaddr + 2, TypeId::UInt32).value; + auto coords = fragment.builder.createCompositeConstruct( + fragment.context->getUint32x3Type(), + {{coord0, coord1, coord2}}); // TODO + + auto float4T = fragment.context->getFloat32x4Type(); + spirv::Value values[4]; + + for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + values[i] = + fragment.getVectorOperand(inst.vdata + dstOffset++, TypeId::Float32) + .value; + } + else + { + values[i] = fragment.context->getFloat32(0); + } + } + + auto value = fragment.builder.createCompositeConstruct(float4T, values); + fragment.builder.createImageWrite(image, coords, value); + break; + } + + case Mimg::Op::IMAGE_LOAD: + case Mimg::Op::IMAGE_LOAD_MIP: + { + auto image = fragment.createImage(RegisterId::Raw(inst.srsrc << 2), + inst.r128, false, AccessOp::Load); + auto coord0 = fragment.getVectorOperand(inst.vaddr, TypeId::UInt32).value; + auto coord1 = + fragment.getVectorOperand(inst.vaddr + 1, TypeId::UInt32).value; + auto coord2 = + fragment.getVectorOperand(inst.vaddr + 2, TypeId::UInt32).value; + auto coords = fragment.builder.createCompositeConstruct( + fragment.context->getUint32x3Type(), + {{coord0, coord1, coord2}}); // TODO + + auto float4T = fragment.context->getFloat32x4Type(); + auto floatT = fragment.context->getFloat32Type(); + + auto value = fragment.builder.createImageRead(float4T, image, coords); + + for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + fragment.setVectorOperand( + inst.vdata + dstOffset++, + {floatT, + fragment.builder.createCompositeExtract(floatT, value, {{i}})}); + } + } + break; + } + + case Mimg::Op::IMAGE_GET_LOD: + { + auto intT = fragment.context->getUInt32Type(); + for (std::uint32_t dstOffset = 0, i = 0; i < 4; ++i) + { + if (inst.dmask & (1 << i)) + { + fragment.setVectorOperand(inst.vdata + dstOffset++, + {intT, fragment.context->getUInt32(0)}); + } + } + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + void convertDs(Fragment& fragment, Ds inst) + { + fragment.registers->pc += Ds::kMinInstSize * sizeof(std::uint32_t); + switch (inst.op) + { + + default: + inst.dump(); + util::unreachable(); + } + } + void convertVintrp(Fragment& fragment, Vintrp inst) + { + fragment.registers->pc += Vintrp::kMinInstSize * sizeof(std::uint32_t); + switch (inst.op) + { + case Vintrp::Op::V_INTERP_P1_F32: + // TODO: operation should read from LDS + // TODO: accurate emulation + + // In current inaccurate emulation we just ignore phase 1 and vsrc argument + // interpolated value stored in attr# + break; + + case Vintrp::Op::V_INTERP_P2_F32: + case Vintrp::Op::V_INTERP_MOV_F32: + { + // TODO: operation should read from LDS + // TODO: accurate emulation + + auto attr = fragment.getAttrOperand(inst.attr, TypeId::Float32x4); + auto channelType = fragment.context->getType(TypeId::Float32); + auto attrChan = fragment.builder.createCompositeExtract( + channelType, attr.value, + std::array{static_cast(inst.attrChan)}); + fragment.setVectorOperand(inst.vdst, {channelType, attrChan}); + break; + } + // { + // fragment.setVectorOperand( + // inst.vdst, fragment.getScalarOperand(inst.vsrc, + // TypeId::Float32x4)); + // break; + // } + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertExp(Fragment& fragment, Exp inst) + { + fragment.registers->pc += Exp::kMinInstSize * sizeof(std::uint32_t); + + if (inst.en == 0) + { + fragment.builder.createFunctionCall(fragment.context->getVoidType(), + fragment.context->getDiscardFn(), {}); + return; + } + + // spirv::Value value; + std::array exports; + + // TODO: handle vm + if (inst.compr) + { + auto floatT = fragment.context->getType(TypeId::Float32); + auto float2T = fragment.context->getType(TypeId::Float32x2); + auto glslStd450 = fragment.context->getGlslStd450(); + + auto xyUint = fragment.getVectorOperand(inst.vsrc0, TypeId::UInt32).value; + auto zwUint = fragment.getVectorOperand(inst.vsrc1, TypeId::UInt32).value; + + auto xy = fragment.builder.createExtInst( + float2T, glslStd450, GLSLstd450UnpackHalf2x16, std::array{xyUint}); + auto zw = fragment.builder.createExtInst( + float2T, glslStd450, GLSLstd450UnpackHalf2x16, std::array{zwUint}); + exports[0] = fragment.builder.createCompositeExtract( + floatT, xy, std::array{static_cast(0)}); + exports[1] = fragment.builder.createCompositeExtract( + floatT, xy, std::array{static_cast(1)}); + exports[2] = fragment.builder.createCompositeExtract( + floatT, zw, std::array{static_cast(0)}); + exports[3] = fragment.builder.createCompositeExtract( + floatT, zw, std::array{static_cast(1)}); + // value = fragment.builder.createCompositeConstruct(type, std::array{x, y, + // z, w}); + } + else + { + exports[0] = fragment.getVectorOperand(inst.vsrc0, TypeId::Float32).value; + exports[1] = fragment.getVectorOperand(inst.vsrc1, TypeId::Float32).value; + exports[2] = fragment.getVectorOperand(inst.vsrc2, TypeId::Float32).value; + exports[3] = fragment.getVectorOperand(inst.vsrc3, TypeId::Float32).value; + /* value = fragment.builder.createCompositeConstruct( type, std::array{ @@ -3988,11 +4324,11 @@ void convertExp(Fragment &fragment, Exp inst) { fragment.getVectorOperand(inst.vsrc2, TypeId::Float32).value, fragment.getVectorOperand(inst.vsrc3, TypeId::Float32).value}); */ - } + } - auto resultType = fragment.context->getFloat32x4Type(); - auto floatType = fragment.context->getFloat32Type(); - /* + auto resultType = fragment.context->getFloat32x4Type(); + auto floatType = fragment.context->getFloat32Type(); + /* if (inst.en != 0xf) { auto prevValue = fragment.getExportTarget(inst.target, TypeId::Float32x4); if (prevValue) { @@ -4006,1222 +4342,1261 @@ void convertExp(Fragment &fragment, Exp inst) { } */ - auto value = fragment.builder.createCompositeConstruct(resultType, exports); - fragment.setExportTarget(inst.target, {resultType, value}); -} - -void convertVop1(Fragment &fragment, Vop1 inst) { - fragment.registers->pc += Vop1::kMinInstSize * sizeof(std::uint32_t); - auto roundEven = [&](spirv::Type type, spirv::Value value) { - // auto glslStd450 = fragment.context->getGlslStd450(); - // return Value{type, fragment.builder.createExtInst( - // type, glslStd450, GLSLstd450RoundEven, - // {{value}})}; - return Value{type, value}; - }; - - switch (inst.op) { - case Vop1::Op::V_MOV_B32: - fragment.setVectorOperand( - inst.vdst, fragment.getScalarOperand(inst.src0, TypeId::UInt32, - OperandGetFlags::PreserveType)); - break; - - case Vop1::Op::V_RCP_IFLAG_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto isNotZero = fragment.builder.createFOrdNotEqual( - fragment.context->getBoolType(), src, fragment.context->getFloat32(0)); - - src = fragment.builder.createSelect( - floatT, isNotZero, src, fragment.context->getFloat32(0.0000001)); - auto float1 = fragment.context->getFloat32(1); - auto result = fragment.builder.createFDiv(floatT, float1, src); - - fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); - break; - } - case Vop1::Op::V_RCP_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto float1 = fragment.context->getFloat32(1); - auto result = fragment.builder.createFDiv(floatT, float1, src); - - fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); - break; - } - - case Vop1::Op::V_CVT_OFF_F32_I4: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto floatT = fragment.context->getFloat32Type(); - auto int32T = fragment.context->getSint32Type(); - src = spirv::cast(fragment.builder.createBitwiseAnd( - int32T, src, fragment.context->getSInt32(0b1111))); - src = fragment.builder.createISub(int32T, src, - fragment.context->getSInt32(8)); - - auto fsrc = fragment.builder.createConvertSToF(floatT, src); - auto result = fragment.builder.createFDiv(floatT, fsrc, - fragment.context->getFloat32(16)); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop1::Op::V_RSQ_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst( - floatT, glslStd450, GLSLstd450InverseSqrt, {{src}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop1::Op::V_SQRT_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Sqrt, {{src}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop1::Op::V_EXP_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Exp2, {{src}}); - - fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); - break; - } - - case Vop1::Op::V_FRACT_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Fract, {{src}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - - case Vop1::Op::V_CVT_I32_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto resultType = fragment.context->getType(TypeId::SInt32); - auto result = fragment.builder.createConvertFToS(resultType, src); - - fragment.setVectorOperand(inst.vdst, {resultType, result}); - break; - } - case Vop1::Op::V_CVT_F32_I32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); - auto resultType = fragment.context->getType(TypeId::Float32); - auto result = fragment.builder.createConvertSToF(resultType, src); - - fragment.setVectorOperand(inst.vdst, {resultType, result}); - break; - } - - case Vop1::Op::V_CVT_U32_F32: { - auto src = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; - auto resultType = fragment.context->getType(TypeId::UInt32); - auto result = fragment.builder.createConvertFToU(resultType, src); - - fragment.setVectorOperand(inst.vdst, {resultType, result}); - break; - } - case Vop1::Op::V_CVT_F32_U32: { - auto src = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; - auto resultType = fragment.context->getFloat32Type(); - auto result = fragment.builder.createConvertUToF( - resultType, spirv::cast(src)); - - fragment.setVectorOperand(inst.vdst, {resultType, result}); - break; - } - case Vop1::Op::V_FLOOR_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Floor, {{src}}); - - fragment.setVectorOperand(inst.vdst, {floatT, result}); - break; - } - case Vop1::Op::V_SIN_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto constant = fragment.context->getFloat32(M_PI * 2); // 2pi - src = fragment.builder.createFMul(floatT, src, constant); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Sin, {{src}}); - - fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); - break; - } - case Vop1::Op::V_COS_F32: { - auto src = spirv::cast( - fragment.getScalarOperand(inst.src0, TypeId::Float32).value); - auto floatT = fragment.context->getFloat32Type(); - auto constant = fragment.context->getFloat32(M_PI * 2); // 2pi - src = fragment.builder.createFMul(floatT, src, constant); - - auto glslStd450 = fragment.context->getGlslStd450(); - auto result = fragment.builder.createExtInst(floatT, glslStd450, - GLSLstd450Cos, {{src}}); - - fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); - break; - } - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertVopc(Fragment &fragment, Vopc inst) { - fragment.registers->pc += Vopc::kMinInstSize * sizeof(std::uint32_t); - - auto cmpOp = [&](TypeId type, CmpKind kind, CmpFlags flags = CmpFlags::None) { - auto src0 = fragment.getScalarOperand(inst.src0, type).value; - auto src1 = fragment.getVectorOperand(inst.vsrc1, type).value; - - auto result = doCmpOp(fragment, type, src0, src1, kind, flags); - fragment.setVcc(result); - }; - - switch (inst.op) { - case Vopc::Op::V_CMP_F_F32: - cmpOp(TypeId::Float32, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT); - break; - case Vopc::Op::V_CMP_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG); - break; - case Vopc::Op::V_CMP_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE); - break; - case Vopc::Op::V_CMP_O_F32: - cmpOp(TypeId::Float32, CmpKind::O); - break; - case Vopc::Op::V_CMP_U_F32: - cmpOp(TypeId::Float32, CmpKind::U); - break; - case Vopc::Op::V_CMP_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE); - break; - case Vopc::Op::V_CMP_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG); - break; - case Vopc::Op::V_CMP_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT); - break; - case Vopc::Op::V_CMP_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE); - break; - case Vopc::Op::V_CMP_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ); - break; - case Vopc::Op::V_CMP_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT); - break; - case Vopc::Op::V_CMP_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU); - break; - case Vopc::Op::V_CMPX_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::X); - break; - case Vopc::Op::V_CMP_F_F64: - cmpOp(TypeId::Float64, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT); - break; - case Vopc::Op::V_CMP_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG); - break; - case Vopc::Op::V_CMP_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE); - break; - case Vopc::Op::V_CMP_O_F64: - cmpOp(TypeId::Float64, CmpKind::O); - break; - case Vopc::Op::V_CMP_U_F64: - cmpOp(TypeId::Float64, CmpKind::U); - break; - case Vopc::Op::V_CMP_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE); - break; - case Vopc::Op::V_CMP_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG); - break; - case Vopc::Op::V_CMP_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT); - break; - case Vopc::Op::V_CMP_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE); - break; - case Vopc::Op::V_CMP_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ); - break; - case Vopc::Op::V_CMP_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT); - break; - case Vopc::Op::V_CMP_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU); - break; - case Vopc::Op::V_CMPX_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::X); - break; - case Vopc::Op::V_CMPS_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::S); - break; - case Vopc::Op::V_CMPSX_F_F32: - cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LT_F32: - cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_EQ_F32: - cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LE_F32: - cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_GT_F32: - cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LG_F32: - cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_GE_F32: - cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_O_F32: - cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_U_F32: - cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NGE_F32: - cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLG_F32: - cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NGT_F32: - cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLE_F32: - cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NEQ_F32: - cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLT_F32: - cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_TRU_F32: - cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::SX); - break; - case Vopc::Op::V_CMPS_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::S); - break; - case Vopc::Op::V_CMPS_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::S); - break; - case Vopc::Op::V_CMPSX_F_F64: - cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LT_F64: - cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_EQ_F64: - cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LE_F64: - cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_GT_F64: - cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_LG_F64: - cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_GE_F64: - cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_O_F64: - cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_U_F64: - cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NGE_F64: - cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLG_F64: - cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NGT_F64: - cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLE_F64: - cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NEQ_F64: - cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_NLT_F64: - cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::SX); - break; - case Vopc::Op::V_CMPSX_TRU_F64: - cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::SX); - break; - case Vopc::Op::V_CMP_F_I32: - cmpOp(TypeId::SInt32, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_I32: - cmpOp(TypeId::SInt32, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_I32: - cmpOp(TypeId::SInt32, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_I32: - cmpOp(TypeId::SInt32, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_I32: - cmpOp(TypeId::SInt32, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_I32: - cmpOp(TypeId::SInt32, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_I32: - cmpOp(TypeId::SInt32, CmpKind::GE); - break; - case Vopc::Op::V_CMP_T_I32: - cmpOp(TypeId::SInt32, CmpKind::T); - break; - // case Vopc::Op::V_CMP_CLASS_F32: cmpOp(TypeId::Float32, CmpKind::CLASS); - // break; - case Vopc::Op::V_CMP_LT_I16: - cmpOp(TypeId::SInt16, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_I16: - cmpOp(TypeId::SInt16, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_I16: - cmpOp(TypeId::SInt16, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_I16: - cmpOp(TypeId::SInt16, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_I16: - cmpOp(TypeId::SInt16, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_I16: - cmpOp(TypeId::SInt16, CmpKind::GE); - break; - // case Vopc::Op::V_CMP_CLASS_F16: cmpOp(TypeId::Float16, CmpKind::CLASS); - // break; - case Vopc::Op::V_CMPX_F_I32: - cmpOp(TypeId::SInt32, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_I32: - cmpOp(TypeId::SInt32, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_I32: - cmpOp(TypeId::SInt32, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_I32: - cmpOp(TypeId::SInt32, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_I32: - cmpOp(TypeId::SInt32, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_I32: - cmpOp(TypeId::SInt32, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_I32: - cmpOp(TypeId::SInt32, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_T_I32: - cmpOp(TypeId::SInt32, CmpKind::T, CmpFlags::X); - break; - // case Vopc::Op::V_CMPX_CLASS_F32: cmpOp(TypeId::Float32, CmpKind::CLASS, - // CmpFlags::X); break; - case Vopc::Op::V_CMPX_LT_I16: - cmpOp(TypeId::SInt16, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_I16: - cmpOp(TypeId::SInt16, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_I16: - cmpOp(TypeId::SInt16, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_I16: - cmpOp(TypeId::SInt16, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_I16: - cmpOp(TypeId::SInt16, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_I16: - cmpOp(TypeId::SInt16, CmpKind::GE, CmpFlags::X); - break; - // case Vopc::Op::V_CMPX_CLASS_F16: cmpOp(TypeId::Float16, CmpKind::CLASS, - // CmpFlags::X); break; - case Vopc::Op::V_CMP_F_I64: - cmpOp(TypeId::SInt64, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_I64: - cmpOp(TypeId::SInt64, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_I64: - cmpOp(TypeId::SInt64, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_I64: - cmpOp(TypeId::SInt64, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_I64: - cmpOp(TypeId::SInt64, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_I64: - cmpOp(TypeId::SInt64, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_I64: - cmpOp(TypeId::SInt64, CmpKind::GE); - break; - case Vopc::Op::V_CMP_T_I64: - cmpOp(TypeId::SInt64, CmpKind::T); - break; - // case Vopc::Op::V_CMP_CLASS_F64: cmpOp(TypeId::Float64, CmpKind::CLASS); - // break; - case Vopc::Op::V_CMP_LT_U16: - cmpOp(TypeId::UInt16, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_U16: - cmpOp(TypeId::UInt16, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_U16: - cmpOp(TypeId::UInt16, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_U16: - cmpOp(TypeId::UInt16, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_U16: - cmpOp(TypeId::UInt16, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_U16: - cmpOp(TypeId::UInt16, CmpKind::GE); - break; - case Vopc::Op::V_CMPX_F_I64: - cmpOp(TypeId::SInt64, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_I64: - cmpOp(TypeId::SInt64, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_I64: - cmpOp(TypeId::SInt64, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_I64: - cmpOp(TypeId::SInt64, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_I64: - cmpOp(TypeId::SInt64, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_I64: - cmpOp(TypeId::SInt64, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_I64: - cmpOp(TypeId::SInt64, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_T_I64: - cmpOp(TypeId::SInt64, CmpKind::T, CmpFlags::X); - break; - // case Vopc::Op::V_CMPX_CLASS_F64: cmpOp(TypeId::Float64, CmpKind::CLASS, - // CmpFlags::X); break; - case Vopc::Op::V_CMPX_LT_U16: - cmpOp(TypeId::UInt16, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_U16: - cmpOp(TypeId::UInt16, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_U16: - cmpOp(TypeId::UInt16, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_U16: - cmpOp(TypeId::UInt16, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_U16: - cmpOp(TypeId::UInt16, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_U16: - cmpOp(TypeId::UInt16, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMP_F_U32: - cmpOp(TypeId::UInt32, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_U32: - cmpOp(TypeId::UInt32, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_U32: - cmpOp(TypeId::UInt32, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_U32: - cmpOp(TypeId::UInt32, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_U32: - cmpOp(TypeId::UInt32, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_U32: - cmpOp(TypeId::UInt32, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_U32: - cmpOp(TypeId::UInt32, CmpKind::GE); - break; - case Vopc::Op::V_CMP_T_U32: - cmpOp(TypeId::UInt32, CmpKind::T); - break; - case Vopc::Op::V_CMP_F_F16: - cmpOp(TypeId::Float16, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_F16: - cmpOp(TypeId::Float16, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_F16: - cmpOp(TypeId::Float16, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_F16: - cmpOp(TypeId::Float16, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_F16: - cmpOp(TypeId::Float16, CmpKind::GT); - break; - case Vopc::Op::V_CMP_LG_F16: - cmpOp(TypeId::Float16, CmpKind::LG); - break; - case Vopc::Op::V_CMP_GE_F16: - cmpOp(TypeId::Float16, CmpKind::GE); - break; - case Vopc::Op::V_CMP_O_F16: - cmpOp(TypeId::Float16, CmpKind::O); - break; - case Vopc::Op::V_CMPX_F_U32: - cmpOp(TypeId::UInt32, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_U32: - cmpOp(TypeId::UInt32, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_U32: - cmpOp(TypeId::UInt32, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_U32: - cmpOp(TypeId::UInt32, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_U32: - cmpOp(TypeId::UInt32, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_U32: - cmpOp(TypeId::UInt32, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_U32: - cmpOp(TypeId::UInt32, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_T_U32: - cmpOp(TypeId::UInt32, CmpKind::T, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_F_F16: - cmpOp(TypeId::Float16, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_F16: - cmpOp(TypeId::Float16, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_F16: - cmpOp(TypeId::Float16, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_F16: - cmpOp(TypeId::Float16, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_F16: - cmpOp(TypeId::Float16, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LG_F16: - cmpOp(TypeId::Float16, CmpKind::LG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_F16: - cmpOp(TypeId::Float16, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_O_F16: - cmpOp(TypeId::Float16, CmpKind::O, CmpFlags::X); - break; - case Vopc::Op::V_CMP_F_U64: - cmpOp(TypeId::UInt64, CmpKind::F); - break; - case Vopc::Op::V_CMP_LT_U64: - cmpOp(TypeId::UInt64, CmpKind::LT); - break; - case Vopc::Op::V_CMP_EQ_U64: - cmpOp(TypeId::UInt64, CmpKind::EQ); - break; - case Vopc::Op::V_CMP_LE_U64: - cmpOp(TypeId::UInt64, CmpKind::LE); - break; - case Vopc::Op::V_CMP_GT_U64: - cmpOp(TypeId::UInt64, CmpKind::GT); - break; - case Vopc::Op::V_CMP_NE_U64: - cmpOp(TypeId::UInt64, CmpKind::NE); - break; - case Vopc::Op::V_CMP_GE_U64: - cmpOp(TypeId::UInt64, CmpKind::GE); - break; - case Vopc::Op::V_CMP_T_U64: - cmpOp(TypeId::UInt64, CmpKind::T); - break; - case Vopc::Op::V_CMP_U_F16: - cmpOp(TypeId::Float16, CmpKind::U); - break; - case Vopc::Op::V_CMP_NGE_F16: - cmpOp(TypeId::Float16, CmpKind::NGE); - break; - case Vopc::Op::V_CMP_NLG_F16: - cmpOp(TypeId::Float16, CmpKind::NLG); - break; - case Vopc::Op::V_CMP_NGT_F16: - cmpOp(TypeId::Float16, CmpKind::NGT); - break; - case Vopc::Op::V_CMP_NLE_F16: - cmpOp(TypeId::Float16, CmpKind::NLE); - break; - case Vopc::Op::V_CMP_NEQ_F16: - cmpOp(TypeId::Float16, CmpKind::NEQ); - break; - case Vopc::Op::V_CMP_NLT_F16: - cmpOp(TypeId::Float16, CmpKind::NLT); - break; - case Vopc::Op::V_CMP_TRU_F16: - cmpOp(TypeId::Float16, CmpKind::TRU); - break; - case Vopc::Op::V_CMPX_F_U64: - cmpOp(TypeId::UInt64, CmpKind::F, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LT_U64: - cmpOp(TypeId::UInt64, CmpKind::LT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_EQ_U64: - cmpOp(TypeId::UInt64, CmpKind::EQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_LE_U64: - cmpOp(TypeId::UInt64, CmpKind::LE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GT_U64: - cmpOp(TypeId::UInt64, CmpKind::GT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NE_U64: - cmpOp(TypeId::UInt64, CmpKind::NE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_GE_U64: - cmpOp(TypeId::UInt64, CmpKind::GE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_T_U64: - cmpOp(TypeId::UInt64, CmpKind::T, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_U_F16: - cmpOp(TypeId::Float16, CmpKind::U, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGE_F16: - cmpOp(TypeId::Float16, CmpKind::NGE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLG_F16: - cmpOp(TypeId::Float16, CmpKind::NLG, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NGT_F16: - cmpOp(TypeId::Float16, CmpKind::NGT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLE_F16: - cmpOp(TypeId::Float16, CmpKind::NLE, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NEQ_F16: - cmpOp(TypeId::Float16, CmpKind::NEQ, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_NLT_F16: - cmpOp(TypeId::Float16, CmpKind::NLT, CmpFlags::X); - break; - case Vopc::Op::V_CMPX_TRU_F16: - cmpOp(TypeId::Float16, CmpKind::TRU, CmpFlags::X); - break; - - default: - inst.dump(); - util::unreachable(); - } -} -void convertSop1(Fragment &fragment, Sop1 inst) { - fragment.registers->pc += Sop1::kMinInstSize * sizeof(std::uint32_t); - - switch (inst.op) { - case Sop1::Op::S_MOV_B32: - fragment.setScalarOperand( - inst.sdst, fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32)); - break; - - case Sop1::Op::S_MOV_B64: - fragment.setScalarOperand( - inst.sdst, fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32)); - fragment.setScalarOperand( - inst.sdst + 1, - fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32)); - break; - - case Sop1::Op::S_WQM_B32: { - // TODO: whole quad mode - break; - } - case Sop1::Op::S_WQM_B64: { - // TODO: whole quad mode - break; - } - case Sop1::Op::S_AND_SAVEEXEC_B64: { - auto execLo = fragment.getExecLo(); - auto execHi = fragment.getExecHi(); - - auto srcLo = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32); - auto srcHi = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); - - fragment.setOperand( - RegisterId::ExecLo, - {srcLo.type, fragment.builder.createBitwiseAnd(srcLo.type, srcLo.value, - execLo.value)}); - fragment.setOperand( - RegisterId::ExecHi, - {srcHi.type, fragment.builder.createBitwiseAnd(srcHi.type, srcHi.value, - execHi.value)}); - auto uint32_0 = fragment.context->getUInt32(0); - auto boolT = fragment.context->getBoolType(); - auto loIsNotZero = - fragment.builder.createINotEqual(boolT, execLo.value, uint32_0); - auto hiIsNotZero = - fragment.builder.createINotEqual(boolT, execHi.value, uint32_0); - fragment.setScc({boolT, fragment.builder.createLogicalAnd( - boolT, loIsNotZero, hiIsNotZero)}); - fragment.setScalarOperand(inst.sdst, execLo); - fragment.setScalarOperand(inst.sdst + 1, execHi); - break; - } - - case Sop1::Op::S_SETPC_B64: - if (auto ssrc0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32), - ssrc1 = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); - ssrc0 && ssrc1) { - auto ssrc0OptValue = fragment.context->findUint32Value(ssrc0.value); - auto ssrc1OptValue = fragment.context->findUint32Value(ssrc1.value); - - if (!ssrc0OptValue.has_value() || !ssrc1OptValue.has_value()) { - util::unreachable(); - } - - fragment.jumpAddress = - *ssrc0OptValue | (static_cast(*ssrc1OptValue) << 32); - } else { - util::unreachable(); - } - return; - - case Sop1::Op::S_SWAPPC_B64: { - if (auto ssrc0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32), - ssrc1 = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); - ssrc0 && ssrc1) { - auto ssrc0OptValue = fragment.context->findUint32Value(ssrc0.value); - auto ssrc1OptValue = fragment.context->findUint32Value(ssrc1.value); - - if (!ssrc0OptValue.has_value() || !ssrc1OptValue.has_value()) { - util::unreachable(); - } - - auto pc = fragment.registers->pc; - fragment.setScalarOperand(inst.sdst, {fragment.context->getUInt32Type(), - fragment.context->getUInt32(pc)}); - fragment.setScalarOperand(inst.sdst + 1, - {fragment.context->getUInt32Type(), - fragment.context->getUInt32(pc >> 32)}); - - fragment.jumpAddress = - *ssrc0OptValue | (static_cast(*ssrc1OptValue) << 32); - } else { - inst.dump(); - util::unreachable(); - } - return; - } - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertSopc(Fragment &fragment, Sopc inst) { - fragment.registers->pc += Sopc::kMinInstSize * sizeof(std::uint32_t); - - auto cmpOp = [&](CmpKind kind, TypeId type) { - auto src0 = fragment.getScalarOperand(inst.ssrc0, type).value; - auto src1 = fragment.getScalarOperand(inst.ssrc1, type).value; - - auto result = doCmpOp(fragment, type, src0, src1, kind, CmpFlags::None); - fragment.setScc(result); - }; - - switch (inst.op) { - case Sopc::Op::S_CMP_EQ_I32: - cmpOp(CmpKind::EQ, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_LG_I32: - cmpOp(CmpKind::LG, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_GT_I32: - cmpOp(CmpKind::GT, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_GE_I32: - cmpOp(CmpKind::GE, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_LT_I32: - cmpOp(CmpKind::LT, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_LE_I32: - cmpOp(CmpKind::LE, TypeId::SInt32); - break; - case Sopc::Op::S_CMP_EQ_U32: - cmpOp(CmpKind::EQ, TypeId::UInt32); - break; - case Sopc::Op::S_CMP_LG_U32: - cmpOp(CmpKind::LG, TypeId::UInt32); - break; - case Sopc::Op::S_CMP_GT_U32: - cmpOp(CmpKind::GT, TypeId::UInt32); - break; - case Sopc::Op::S_CMP_GE_U32: - cmpOp(CmpKind::GE, TypeId::UInt32); - break; - case Sopc::Op::S_CMP_LT_U32: - cmpOp(CmpKind::LT, TypeId::UInt32); - break; - case Sopc::Op::S_CMP_LE_U32: - cmpOp(CmpKind::LE, TypeId::UInt32); - break; - - case Sopc::Op::S_BITCMP0_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt32Type(); - - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x1f))); - auto bit = fragment.builder.createBitwiseAnd( - operandT, - fragment.builder.createShiftRightLogical(operandT, src0, src1), - fragment.context->getUInt32(1)); - - auto boolT = fragment.context->getBoolType(); - fragment.setScc({boolT, fragment.builder.createIEqual( - boolT, bit, fragment.context->getUInt32(0))}); - break; - } - case Sopc::Op::S_BITCMP1_B32: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt32Type(); - - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x1f))); - auto bit = fragment.builder.createBitwiseAnd( - operandT, - fragment.builder.createShiftRightLogical(operandT, src0, src1), - fragment.context->getUInt32(1)); - - auto boolT = fragment.context->getBoolType(); - fragment.setScc({boolT, fragment.builder.createIEqual( - boolT, bit, fragment.context->getUInt32(1))}); - break; - } - case Sopc::Op::S_BITCMP0_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt64Type(); - - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x3f))); - auto bit = fragment.builder.createBitwiseAnd( - operandT, - fragment.builder.createShiftRightLogical(operandT, src0, src1), - fragment.context->getUInt64(1)); - - auto boolT = fragment.context->getBoolType(); - fragment.setScc({boolT, fragment.builder.createIEqual( - boolT, bit, fragment.context->getUInt64(0))}); - break; - } - case Sopc::Op::S_BITCMP1_B64: { - auto src0 = spirv::cast( - fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); - auto src1 = spirv::cast( - fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); - auto operandT = fragment.context->getUInt64Type(); - - src1 = spirv::cast(fragment.builder.createBitwiseAnd( - operandT, src1, fragment.context->getUInt32(0x3f))); - auto bit = fragment.builder.createBitwiseAnd( - operandT, - fragment.builder.createShiftRightLogical(operandT, src0, src1), - fragment.context->getUInt64(1)); - - auto boolT = fragment.context->getBoolType(); - fragment.setScc({boolT, fragment.builder.createIEqual( - boolT, bit, fragment.context->getUInt64(1))}); - break; - } - default: - inst.dump(); - util::unreachable(); - } -} - -void convertSopp(Fragment &fragment, Sopp inst) { - fragment.registers->pc += Sopp::kMinInstSize * sizeof(std::uint32_t); - - auto createCondBranch = [&](spirv::BoolValue condition) { - fragment.branchCondition = condition; - /* + auto value = fragment.builder.createCompositeConstruct(resultType, exports); + fragment.setExportTarget(inst.target, {resultType, value}); + } + + void convertVop1(Fragment& fragment, Vop1 inst) + { + fragment.registers->pc += Vop1::kMinInstSize * sizeof(std::uint32_t); + auto roundEven = [&](spirv::Type type, spirv::Value value) { + // auto glslStd450 = fragment.context->getGlslStd450(); + // return Value{type, fragment.builder.createExtInst( + // type, glslStd450, GLSLstd450RoundEven, + // {{value}})}; + return Value{type, value}; + }; + + switch (inst.op) + { + case Vop1::Op::V_MOV_B32: + fragment.setVectorOperand( + inst.vdst, fragment.getScalarOperand(inst.src0, TypeId::UInt32, + OperandGetFlags::PreserveType)); + break; + + case Vop1::Op::V_RCP_IFLAG_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto isNotZero = fragment.builder.createFOrdNotEqual( + fragment.context->getBoolType(), src, fragment.context->getFloat32(0)); + + src = fragment.builder.createSelect( + floatT, isNotZero, src, fragment.context->getFloat32(0.0000001)); + auto float1 = fragment.context->getFloat32(1); + auto result = fragment.builder.createFDiv(floatT, float1, src); + + fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); + break; + } + case Vop1::Op::V_RCP_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto float1 = fragment.context->getFloat32(1); + auto result = fragment.builder.createFDiv(floatT, float1, src); + + fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); + break; + } + + case Vop1::Op::V_CVT_OFF_F32_I4: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto floatT = fragment.context->getFloat32Type(); + auto int32T = fragment.context->getSint32Type(); + src = spirv::cast(fragment.builder.createBitwiseAnd( + int32T, src, fragment.context->getSInt32(0b1111))); + src = fragment.builder.createISub(int32T, src, + fragment.context->getSInt32(8)); + + auto fsrc = fragment.builder.createConvertSToF(floatT, src); + auto result = fragment.builder.createFDiv(floatT, fsrc, + fragment.context->getFloat32(16)); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop1::Op::V_RSQ_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst( + floatT, glslStd450, GLSLstd450InverseSqrt, {{src}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop1::Op::V_SQRT_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Sqrt, {{src}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop1::Op::V_EXP_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Exp2, {{src}}); + + fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); + break; + } + + case Vop1::Op::V_FRACT_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Fract, {{src}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + + case Vop1::Op::V_CVT_I32_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto resultType = fragment.context->getType(TypeId::SInt32); + auto result = fragment.builder.createConvertFToS(resultType, src); + + fragment.setVectorOperand(inst.vdst, {resultType, result}); + break; + } + case Vop1::Op::V_CVT_F32_I32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::SInt32).value); + auto resultType = fragment.context->getType(TypeId::Float32); + auto result = fragment.builder.createConvertSToF(resultType, src); + + fragment.setVectorOperand(inst.vdst, {resultType, result}); + break; + } + + case Vop1::Op::V_CVT_U32_F32: + { + auto src = fragment.getScalarOperand(inst.src0, TypeId::Float32).value; + auto resultType = fragment.context->getType(TypeId::UInt32); + auto result = fragment.builder.createConvertFToU(resultType, src); + + fragment.setVectorOperand(inst.vdst, {resultType, result}); + break; + } + case Vop1::Op::V_CVT_F32_U32: + { + auto src = fragment.getScalarOperand(inst.src0, TypeId::UInt32).value; + auto resultType = fragment.context->getFloat32Type(); + auto result = fragment.builder.createConvertUToF( + resultType, spirv::cast(src)); + + fragment.setVectorOperand(inst.vdst, {resultType, result}); + break; + } + case Vop1::Op::V_FLOOR_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Floor, {{src}}); + + fragment.setVectorOperand(inst.vdst, {floatT, result}); + break; + } + case Vop1::Op::V_SIN_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto constant = fragment.context->getFloat32(M_PI * 2); // 2pi + src = fragment.builder.createFMul(floatT, src, constant); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Sin, {{src}}); + + fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); + break; + } + case Vop1::Op::V_COS_F32: + { + auto src = spirv::cast( + fragment.getScalarOperand(inst.src0, TypeId::Float32).value); + auto floatT = fragment.context->getFloat32Type(); + auto constant = fragment.context->getFloat32(M_PI * 2); // 2pi + src = fragment.builder.createFMul(floatT, src, constant); + + auto glslStd450 = fragment.context->getGlslStd450(); + auto result = fragment.builder.createExtInst(floatT, glslStd450, + GLSLstd450Cos, {{src}}); + + fragment.setVectorOperand(inst.vdst, roundEven(floatT, result)); + break; + } + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertVopc(Fragment& fragment, Vopc inst) + { + fragment.registers->pc += Vopc::kMinInstSize * sizeof(std::uint32_t); + + auto cmpOp = [&](TypeId type, CmpKind kind, CmpFlags flags = CmpFlags::None) { + auto src0 = fragment.getScalarOperand(inst.src0, type).value; + auto src1 = fragment.getVectorOperand(inst.vsrc1, type).value; + + auto result = doCmpOp(fragment, type, src0, src1, kind, flags); + fragment.setVcc(result); + }; + + switch (inst.op) + { + case Vopc::Op::V_CMP_F_F32: + cmpOp(TypeId::Float32, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT); + break; + case Vopc::Op::V_CMP_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG); + break; + case Vopc::Op::V_CMP_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE); + break; + case Vopc::Op::V_CMP_O_F32: + cmpOp(TypeId::Float32, CmpKind::O); + break; + case Vopc::Op::V_CMP_U_F32: + cmpOp(TypeId::Float32, CmpKind::U); + break; + case Vopc::Op::V_CMP_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE); + break; + case Vopc::Op::V_CMP_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG); + break; + case Vopc::Op::V_CMP_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT); + break; + case Vopc::Op::V_CMP_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE); + break; + case Vopc::Op::V_CMP_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ); + break; + case Vopc::Op::V_CMP_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT); + break; + case Vopc::Op::V_CMP_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU); + break; + case Vopc::Op::V_CMPX_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::X); + break; + case Vopc::Op::V_CMP_F_F64: + cmpOp(TypeId::Float64, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT); + break; + case Vopc::Op::V_CMP_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG); + break; + case Vopc::Op::V_CMP_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE); + break; + case Vopc::Op::V_CMP_O_F64: + cmpOp(TypeId::Float64, CmpKind::O); + break; + case Vopc::Op::V_CMP_U_F64: + cmpOp(TypeId::Float64, CmpKind::U); + break; + case Vopc::Op::V_CMP_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE); + break; + case Vopc::Op::V_CMP_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG); + break; + case Vopc::Op::V_CMP_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT); + break; + case Vopc::Op::V_CMP_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE); + break; + case Vopc::Op::V_CMP_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ); + break; + case Vopc::Op::V_CMP_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT); + break; + case Vopc::Op::V_CMP_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU); + break; + case Vopc::Op::V_CMPX_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::X); + break; + case Vopc::Op::V_CMPS_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::S); + break; + case Vopc::Op::V_CMPSX_F_F32: + cmpOp(TypeId::Float32, CmpKind::F, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LT_F32: + cmpOp(TypeId::Float32, CmpKind::LT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_EQ_F32: + cmpOp(TypeId::Float32, CmpKind::EQ, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LE_F32: + cmpOp(TypeId::Float32, CmpKind::LE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_GT_F32: + cmpOp(TypeId::Float32, CmpKind::GT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LG_F32: + cmpOp(TypeId::Float32, CmpKind::LG, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_GE_F32: + cmpOp(TypeId::Float32, CmpKind::GE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_O_F32: + cmpOp(TypeId::Float32, CmpKind::O, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_U_F32: + cmpOp(TypeId::Float32, CmpKind::U, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NGE_F32: + cmpOp(TypeId::Float32, CmpKind::NGE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLG_F32: + cmpOp(TypeId::Float32, CmpKind::NLG, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NGT_F32: + cmpOp(TypeId::Float32, CmpKind::NGT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLE_F32: + cmpOp(TypeId::Float32, CmpKind::NLE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NEQ_F32: + cmpOp(TypeId::Float32, CmpKind::NEQ, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLT_F32: + cmpOp(TypeId::Float32, CmpKind::NLT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_TRU_F32: + cmpOp(TypeId::Float32, CmpKind::TRU, CmpFlags::SX); + break; + case Vopc::Op::V_CMPS_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::S); + break; + case Vopc::Op::V_CMPS_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::S); + break; + case Vopc::Op::V_CMPSX_F_F64: + cmpOp(TypeId::Float64, CmpKind::F, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LT_F64: + cmpOp(TypeId::Float64, CmpKind::LT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_EQ_F64: + cmpOp(TypeId::Float64, CmpKind::EQ, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LE_F64: + cmpOp(TypeId::Float64, CmpKind::LE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_GT_F64: + cmpOp(TypeId::Float64, CmpKind::GT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_LG_F64: + cmpOp(TypeId::Float64, CmpKind::LG, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_GE_F64: + cmpOp(TypeId::Float64, CmpKind::GE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_O_F64: + cmpOp(TypeId::Float64, CmpKind::O, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_U_F64: + cmpOp(TypeId::Float64, CmpKind::U, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NGE_F64: + cmpOp(TypeId::Float64, CmpKind::NGE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLG_F64: + cmpOp(TypeId::Float64, CmpKind::NLG, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NGT_F64: + cmpOp(TypeId::Float64, CmpKind::NGT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLE_F64: + cmpOp(TypeId::Float64, CmpKind::NLE, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NEQ_F64: + cmpOp(TypeId::Float64, CmpKind::NEQ, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_NLT_F64: + cmpOp(TypeId::Float64, CmpKind::NLT, CmpFlags::SX); + break; + case Vopc::Op::V_CMPSX_TRU_F64: + cmpOp(TypeId::Float64, CmpKind::TRU, CmpFlags::SX); + break; + case Vopc::Op::V_CMP_F_I32: + cmpOp(TypeId::SInt32, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_I32: + cmpOp(TypeId::SInt32, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_I32: + cmpOp(TypeId::SInt32, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_I32: + cmpOp(TypeId::SInt32, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_I32: + cmpOp(TypeId::SInt32, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_I32: + cmpOp(TypeId::SInt32, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_I32: + cmpOp(TypeId::SInt32, CmpKind::GE); + break; + case Vopc::Op::V_CMP_T_I32: + cmpOp(TypeId::SInt32, CmpKind::T); + break; + // case Vopc::Op::V_CMP_CLASS_F32: cmpOp(TypeId::Float32, CmpKind::CLASS); + // break; + case Vopc::Op::V_CMP_LT_I16: + cmpOp(TypeId::SInt16, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_I16: + cmpOp(TypeId::SInt16, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_I16: + cmpOp(TypeId::SInt16, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_I16: + cmpOp(TypeId::SInt16, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_I16: + cmpOp(TypeId::SInt16, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_I16: + cmpOp(TypeId::SInt16, CmpKind::GE); + break; + // case Vopc::Op::V_CMP_CLASS_F16: cmpOp(TypeId::Float16, CmpKind::CLASS); + // break; + case Vopc::Op::V_CMPX_F_I32: + cmpOp(TypeId::SInt32, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_I32: + cmpOp(TypeId::SInt32, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_I32: + cmpOp(TypeId::SInt32, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_I32: + cmpOp(TypeId::SInt32, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_I32: + cmpOp(TypeId::SInt32, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_I32: + cmpOp(TypeId::SInt32, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_I32: + cmpOp(TypeId::SInt32, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_T_I32: + cmpOp(TypeId::SInt32, CmpKind::T, CmpFlags::X); + break; + // case Vopc::Op::V_CMPX_CLASS_F32: cmpOp(TypeId::Float32, CmpKind::CLASS, + // CmpFlags::X); break; + case Vopc::Op::V_CMPX_LT_I16: + cmpOp(TypeId::SInt16, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_I16: + cmpOp(TypeId::SInt16, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_I16: + cmpOp(TypeId::SInt16, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_I16: + cmpOp(TypeId::SInt16, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_I16: + cmpOp(TypeId::SInt16, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_I16: + cmpOp(TypeId::SInt16, CmpKind::GE, CmpFlags::X); + break; + // case Vopc::Op::V_CMPX_CLASS_F16: cmpOp(TypeId::Float16, CmpKind::CLASS, + // CmpFlags::X); break; + case Vopc::Op::V_CMP_F_I64: + cmpOp(TypeId::SInt64, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_I64: + cmpOp(TypeId::SInt64, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_I64: + cmpOp(TypeId::SInt64, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_I64: + cmpOp(TypeId::SInt64, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_I64: + cmpOp(TypeId::SInt64, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_I64: + cmpOp(TypeId::SInt64, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_I64: + cmpOp(TypeId::SInt64, CmpKind::GE); + break; + case Vopc::Op::V_CMP_T_I64: + cmpOp(TypeId::SInt64, CmpKind::T); + break; + // case Vopc::Op::V_CMP_CLASS_F64: cmpOp(TypeId::Float64, CmpKind::CLASS); + // break; + case Vopc::Op::V_CMP_LT_U16: + cmpOp(TypeId::UInt16, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_U16: + cmpOp(TypeId::UInt16, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_U16: + cmpOp(TypeId::UInt16, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_U16: + cmpOp(TypeId::UInt16, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_U16: + cmpOp(TypeId::UInt16, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_U16: + cmpOp(TypeId::UInt16, CmpKind::GE); + break; + case Vopc::Op::V_CMPX_F_I64: + cmpOp(TypeId::SInt64, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_I64: + cmpOp(TypeId::SInt64, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_I64: + cmpOp(TypeId::SInt64, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_I64: + cmpOp(TypeId::SInt64, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_I64: + cmpOp(TypeId::SInt64, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_I64: + cmpOp(TypeId::SInt64, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_I64: + cmpOp(TypeId::SInt64, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_T_I64: + cmpOp(TypeId::SInt64, CmpKind::T, CmpFlags::X); + break; + // case Vopc::Op::V_CMPX_CLASS_F64: cmpOp(TypeId::Float64, CmpKind::CLASS, + // CmpFlags::X); break; + case Vopc::Op::V_CMPX_LT_U16: + cmpOp(TypeId::UInt16, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_U16: + cmpOp(TypeId::UInt16, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_U16: + cmpOp(TypeId::UInt16, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_U16: + cmpOp(TypeId::UInt16, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_U16: + cmpOp(TypeId::UInt16, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_U16: + cmpOp(TypeId::UInt16, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMP_F_U32: + cmpOp(TypeId::UInt32, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_U32: + cmpOp(TypeId::UInt32, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_U32: + cmpOp(TypeId::UInt32, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_U32: + cmpOp(TypeId::UInt32, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_U32: + cmpOp(TypeId::UInt32, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_U32: + cmpOp(TypeId::UInt32, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_U32: + cmpOp(TypeId::UInt32, CmpKind::GE); + break; + case Vopc::Op::V_CMP_T_U32: + cmpOp(TypeId::UInt32, CmpKind::T); + break; + case Vopc::Op::V_CMP_F_F16: + cmpOp(TypeId::Float16, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_F16: + cmpOp(TypeId::Float16, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_F16: + cmpOp(TypeId::Float16, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_F16: + cmpOp(TypeId::Float16, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_F16: + cmpOp(TypeId::Float16, CmpKind::GT); + break; + case Vopc::Op::V_CMP_LG_F16: + cmpOp(TypeId::Float16, CmpKind::LG); + break; + case Vopc::Op::V_CMP_GE_F16: + cmpOp(TypeId::Float16, CmpKind::GE); + break; + case Vopc::Op::V_CMP_O_F16: + cmpOp(TypeId::Float16, CmpKind::O); + break; + case Vopc::Op::V_CMPX_F_U32: + cmpOp(TypeId::UInt32, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_U32: + cmpOp(TypeId::UInt32, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_U32: + cmpOp(TypeId::UInt32, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_U32: + cmpOp(TypeId::UInt32, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_U32: + cmpOp(TypeId::UInt32, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_U32: + cmpOp(TypeId::UInt32, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_U32: + cmpOp(TypeId::UInt32, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_T_U32: + cmpOp(TypeId::UInt32, CmpKind::T, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_F_F16: + cmpOp(TypeId::Float16, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_F16: + cmpOp(TypeId::Float16, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_F16: + cmpOp(TypeId::Float16, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_F16: + cmpOp(TypeId::Float16, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_F16: + cmpOp(TypeId::Float16, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LG_F16: + cmpOp(TypeId::Float16, CmpKind::LG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_F16: + cmpOp(TypeId::Float16, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_O_F16: + cmpOp(TypeId::Float16, CmpKind::O, CmpFlags::X); + break; + case Vopc::Op::V_CMP_F_U64: + cmpOp(TypeId::UInt64, CmpKind::F); + break; + case Vopc::Op::V_CMP_LT_U64: + cmpOp(TypeId::UInt64, CmpKind::LT); + break; + case Vopc::Op::V_CMP_EQ_U64: + cmpOp(TypeId::UInt64, CmpKind::EQ); + break; + case Vopc::Op::V_CMP_LE_U64: + cmpOp(TypeId::UInt64, CmpKind::LE); + break; + case Vopc::Op::V_CMP_GT_U64: + cmpOp(TypeId::UInt64, CmpKind::GT); + break; + case Vopc::Op::V_CMP_NE_U64: + cmpOp(TypeId::UInt64, CmpKind::NE); + break; + case Vopc::Op::V_CMP_GE_U64: + cmpOp(TypeId::UInt64, CmpKind::GE); + break; + case Vopc::Op::V_CMP_T_U64: + cmpOp(TypeId::UInt64, CmpKind::T); + break; + case Vopc::Op::V_CMP_U_F16: + cmpOp(TypeId::Float16, CmpKind::U); + break; + case Vopc::Op::V_CMP_NGE_F16: + cmpOp(TypeId::Float16, CmpKind::NGE); + break; + case Vopc::Op::V_CMP_NLG_F16: + cmpOp(TypeId::Float16, CmpKind::NLG); + break; + case Vopc::Op::V_CMP_NGT_F16: + cmpOp(TypeId::Float16, CmpKind::NGT); + break; + case Vopc::Op::V_CMP_NLE_F16: + cmpOp(TypeId::Float16, CmpKind::NLE); + break; + case Vopc::Op::V_CMP_NEQ_F16: + cmpOp(TypeId::Float16, CmpKind::NEQ); + break; + case Vopc::Op::V_CMP_NLT_F16: + cmpOp(TypeId::Float16, CmpKind::NLT); + break; + case Vopc::Op::V_CMP_TRU_F16: + cmpOp(TypeId::Float16, CmpKind::TRU); + break; + case Vopc::Op::V_CMPX_F_U64: + cmpOp(TypeId::UInt64, CmpKind::F, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LT_U64: + cmpOp(TypeId::UInt64, CmpKind::LT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_EQ_U64: + cmpOp(TypeId::UInt64, CmpKind::EQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_LE_U64: + cmpOp(TypeId::UInt64, CmpKind::LE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GT_U64: + cmpOp(TypeId::UInt64, CmpKind::GT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NE_U64: + cmpOp(TypeId::UInt64, CmpKind::NE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_GE_U64: + cmpOp(TypeId::UInt64, CmpKind::GE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_T_U64: + cmpOp(TypeId::UInt64, CmpKind::T, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_U_F16: + cmpOp(TypeId::Float16, CmpKind::U, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGE_F16: + cmpOp(TypeId::Float16, CmpKind::NGE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLG_F16: + cmpOp(TypeId::Float16, CmpKind::NLG, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NGT_F16: + cmpOp(TypeId::Float16, CmpKind::NGT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLE_F16: + cmpOp(TypeId::Float16, CmpKind::NLE, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NEQ_F16: + cmpOp(TypeId::Float16, CmpKind::NEQ, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_NLT_F16: + cmpOp(TypeId::Float16, CmpKind::NLT, CmpFlags::X); + break; + case Vopc::Op::V_CMPX_TRU_F16: + cmpOp(TypeId::Float16, CmpKind::TRU, CmpFlags::X); + break; + + default: + inst.dump(); + util::unreachable(); + } + } + void convertSop1(Fragment& fragment, Sop1 inst) + { + fragment.registers->pc += Sop1::kMinInstSize * sizeof(std::uint32_t); + + switch (inst.op) + { + case Sop1::Op::S_MOV_B32: + fragment.setScalarOperand( + inst.sdst, fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32)); + break; + + case Sop1::Op::S_MOV_B64: + fragment.setScalarOperand( + inst.sdst, fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32)); + fragment.setScalarOperand( + inst.sdst + 1, + fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32)); + break; + + case Sop1::Op::S_WQM_B32: + { + // TODO: whole quad mode + break; + } + case Sop1::Op::S_WQM_B64: + { + // TODO: whole quad mode + break; + } + case Sop1::Op::S_AND_SAVEEXEC_B64: + { + auto execLo = fragment.getExecLo(); + auto execHi = fragment.getExecHi(); + + auto srcLo = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32); + auto srcHi = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); + + fragment.setOperand( + RegisterId::ExecLo, + {srcLo.type, fragment.builder.createBitwiseAnd(srcLo.type, srcLo.value, + execLo.value)}); + fragment.setOperand( + RegisterId::ExecHi, + {srcHi.type, fragment.builder.createBitwiseAnd(srcHi.type, srcHi.value, + execHi.value)}); + auto uint32_0 = fragment.context->getUInt32(0); + auto boolT = fragment.context->getBoolType(); + auto loIsNotZero = + fragment.builder.createINotEqual(boolT, execLo.value, uint32_0); + auto hiIsNotZero = + fragment.builder.createINotEqual(boolT, execHi.value, uint32_0); + fragment.setScc({boolT, fragment.builder.createLogicalAnd( + boolT, loIsNotZero, hiIsNotZero)}); + fragment.setScalarOperand(inst.sdst, execLo); + fragment.setScalarOperand(inst.sdst + 1, execHi); + break; + } + + case Sop1::Op::S_SETPC_B64: + if (auto ssrc0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32), + ssrc1 = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); + ssrc0 && ssrc1) + { + auto ssrc0OptValue = fragment.context->findUint32Value(ssrc0.value); + auto ssrc1OptValue = fragment.context->findUint32Value(ssrc1.value); + + if (!ssrc0OptValue.has_value() || !ssrc1OptValue.has_value()) + { + util::unreachable(); + } + + fragment.jumpAddress = + *ssrc0OptValue | (static_cast(*ssrc1OptValue) << 32); + } + else + { + util::unreachable(); + } + return; + + case Sop1::Op::S_SWAPPC_B64: + { + if (auto ssrc0 = fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32), + ssrc1 = fragment.getScalarOperand(inst.ssrc0 + 1, TypeId::UInt32); + ssrc0 && ssrc1) + { + auto ssrc0OptValue = fragment.context->findUint32Value(ssrc0.value); + auto ssrc1OptValue = fragment.context->findUint32Value(ssrc1.value); + + if (!ssrc0OptValue.has_value() || !ssrc1OptValue.has_value()) + { + util::unreachable(); + } + + auto pc = fragment.registers->pc; + fragment.setScalarOperand(inst.sdst, {fragment.context->getUInt32Type(), + fragment.context->getUInt32(pc)}); + fragment.setScalarOperand(inst.sdst + 1, + {fragment.context->getUInt32Type(), + fragment.context->getUInt32(pc >> 32)}); + + fragment.jumpAddress = + *ssrc0OptValue | (static_cast(*ssrc1OptValue) << 32); + } + else + { + inst.dump(); + util::unreachable(); + } + return; + } + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertSopc(Fragment& fragment, Sopc inst) + { + fragment.registers->pc += Sopc::kMinInstSize * sizeof(std::uint32_t); + + auto cmpOp = [&](CmpKind kind, TypeId type) { + auto src0 = fragment.getScalarOperand(inst.ssrc0, type).value; + auto src1 = fragment.getScalarOperand(inst.ssrc1, type).value; + + auto result = doCmpOp(fragment, type, src0, src1, kind, CmpFlags::None); + fragment.setScc(result); + }; + + switch (inst.op) + { + case Sopc::Op::S_CMP_EQ_I32: + cmpOp(CmpKind::EQ, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_LG_I32: + cmpOp(CmpKind::LG, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_GT_I32: + cmpOp(CmpKind::GT, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_GE_I32: + cmpOp(CmpKind::GE, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_LT_I32: + cmpOp(CmpKind::LT, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_LE_I32: + cmpOp(CmpKind::LE, TypeId::SInt32); + break; + case Sopc::Op::S_CMP_EQ_U32: + cmpOp(CmpKind::EQ, TypeId::UInt32); + break; + case Sopc::Op::S_CMP_LG_U32: + cmpOp(CmpKind::LG, TypeId::UInt32); + break; + case Sopc::Op::S_CMP_GT_U32: + cmpOp(CmpKind::GT, TypeId::UInt32); + break; + case Sopc::Op::S_CMP_GE_U32: + cmpOp(CmpKind::GE, TypeId::UInt32); + break; + case Sopc::Op::S_CMP_LT_U32: + cmpOp(CmpKind::LT, TypeId::UInt32); + break; + case Sopc::Op::S_CMP_LE_U32: + cmpOp(CmpKind::LE, TypeId::UInt32); + break; + + case Sopc::Op::S_BITCMP0_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt32Type(); + + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x1f))); + auto bit = fragment.builder.createBitwiseAnd( + operandT, + fragment.builder.createShiftRightLogical(operandT, src0, src1), + fragment.context->getUInt32(1)); + + auto boolT = fragment.context->getBoolType(); + fragment.setScc({boolT, fragment.builder.createIEqual( + boolT, bit, fragment.context->getUInt32(0))}); + break; + } + case Sopc::Op::S_BITCMP1_B32: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt32).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt32Type(); + + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x1f))); + auto bit = fragment.builder.createBitwiseAnd( + operandT, + fragment.builder.createShiftRightLogical(operandT, src0, src1), + fragment.context->getUInt32(1)); + + auto boolT = fragment.context->getBoolType(); + fragment.setScc({boolT, fragment.builder.createIEqual( + boolT, bit, fragment.context->getUInt32(1))}); + break; + } + case Sopc::Op::S_BITCMP0_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt64Type(); + + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x3f))); + auto bit = fragment.builder.createBitwiseAnd( + operandT, + fragment.builder.createShiftRightLogical(operandT, src0, src1), + fragment.context->getUInt64(1)); + + auto boolT = fragment.context->getBoolType(); + fragment.setScc({boolT, fragment.builder.createIEqual( + boolT, bit, fragment.context->getUInt64(0))}); + break; + } + case Sopc::Op::S_BITCMP1_B64: + { + auto src0 = spirv::cast( + fragment.getScalarOperand(inst.ssrc0, TypeId::UInt64).value); + auto src1 = spirv::cast( + fragment.getScalarOperand(inst.ssrc1, TypeId::UInt32).value); + auto operandT = fragment.context->getUInt64Type(); + + src1 = spirv::cast(fragment.builder.createBitwiseAnd( + operandT, src1, fragment.context->getUInt32(0x3f))); + auto bit = fragment.builder.createBitwiseAnd( + operandT, + fragment.builder.createShiftRightLogical(operandT, src0, src1), + fragment.context->getUInt64(1)); + + auto boolT = fragment.context->getBoolType(); + fragment.setScc({boolT, fragment.builder.createIEqual( + boolT, bit, fragment.context->getUInt64(1))}); + break; + } + default: + inst.dump(); + util::unreachable(); + } + } + + void convertSopp(Fragment& fragment, Sopp inst) + { + fragment.registers->pc += Sopp::kMinInstSize * sizeof(std::uint32_t); + + auto createCondBranch = [&](spirv::BoolValue condition) { + fragment.branchCondition = condition; + /* auto address = fragment.registers->pc + (inst.simm << 2); Fragment *ifTrueTarget = @@ -5234,661 +5609,772 @@ void convertSopp(Fragment &fragment, Sopp inst) { fragment.builder.createBranchConditional(condition, ifTrueTarget->builder.id, ifFalseTarget->entryBlockId); */ - }; - - switch (inst.op) { - case Sopp::Op::S_WAITCNT: - // TODO - break; - - case Sopp::Op::S_BRANCH: { - fragment.jumpAddress = fragment.registers->pc + (inst.simm << 2); - // auto address = fragment.registers->pc + (inst.simm << 2); - // Fragment *target = fragment.context->getOrCreateFragment(address, 0x100); - - // fragment.builder.createBranch(target->entryBlockId); - // fragment.terminator = FragmentTerminator::Branch; - // target->predecessors.insert(&fragment); - // fragment.successors.insert(target); - break; - } - - case Sopp::Op::S_CBRANCH_SCC0: { - createCondBranch(fragment.builder.createLogicalNot( - fragment.context->getBoolType(), fragment.getScc())); - break; - } - - case Sopp::Op::S_CBRANCH_SCC1: { - createCondBranch(fragment.getScc()); - break; - } - - case Sopp::Op::S_CBRANCH_VCCZ: { - auto loIsZero = fragment.builder.createIEqual( - fragment.context->getBoolType(), fragment.getVccLo().value, - fragment.context->getUInt32(0)); - auto hiIsZero = fragment.builder.createIEqual( - fragment.context->getBoolType(), fragment.getVccHi().value, - fragment.context->getUInt32(0)); - createCondBranch(fragment.builder.createLogicalAnd( - fragment.context->getBoolType(), loIsZero, hiIsZero)); - break; - } - - case Sopp::Op::S_CBRANCH_VCCNZ: { - auto loIsNotZero = fragment.builder.createINotEqual( - fragment.context->getBoolType(), fragment.getVccLo().value, - fragment.context->getUInt32(0)); - auto hiIsNotZero = fragment.builder.createINotEqual( - fragment.context->getBoolType(), fragment.getVccHi().value, - fragment.context->getUInt32(0)); - - createCondBranch(fragment.builder.createLogicalOr( - fragment.context->getBoolType(), loIsNotZero, hiIsNotZero)); - break; - } - - case Sopp::Op::S_CBRANCH_EXECZ: { - auto loIsZero = fragment.builder.createIEqual( - fragment.context->getBoolType(), fragment.getExecLo().value, - fragment.context->getUInt32(0)); - auto hiIsZero = fragment.builder.createIEqual( - fragment.context->getBoolType(), fragment.getExecHi().value, - fragment.context->getUInt32(0)); - createCondBranch(fragment.builder.createLogicalAnd( - fragment.context->getBoolType(), loIsZero, hiIsZero)); - break; - } - - case Sopp::Op::S_CBRANCH_EXECNZ: { - auto loIsNotZero = fragment.builder.createINotEqual( - fragment.context->getBoolType(), fragment.getExecLo().value, - fragment.context->getUInt32(0)); - auto hiIsNotZero = fragment.builder.createINotEqual( - fragment.context->getBoolType(), fragment.getExecHi().value, - fragment.context->getUInt32(0)); - - createCondBranch(fragment.builder.createLogicalOr( - fragment.context->getBoolType(), loIsNotZero, hiIsNotZero)); - break; - } - - case Sopp::Op::S_ENDPGM: - // fragment.terminator = FragmentTerminator::EndProgram; - return; - - case Sopp::Op::S_NOP: - break; - - default: - inst.dump(); - util::unreachable(); - } -} - -void convertInstruction(Fragment &fragment, Instruction inst) { - switch (inst.instClass) { - case InstructionClass::Vop2: - return convertVop2(fragment, Vop2(inst.inst)); - case InstructionClass::Sop2: - return convertSop2(fragment, Sop2(inst.inst)); - case InstructionClass::Sopk: - return convertSopk(fragment, Sopk(inst.inst)); - case InstructionClass::Smrd: - return convertSmrd(fragment, Smrd(inst.inst)); - case InstructionClass::Vop3: - return convertVop3(fragment, Vop3(inst.inst)); - case InstructionClass::Mubuf: - return convertMubuf(fragment, Mubuf(inst.inst)); - case InstructionClass::Mtbuf: - return convertMtbuf(fragment, Mtbuf(inst.inst)); - case InstructionClass::Mimg: - return convertMimg(fragment, Mimg(inst.inst)); - case InstructionClass::Ds: - return convertDs(fragment, Ds(inst.inst)); - case InstructionClass::Vintrp: - return convertVintrp(fragment, Vintrp(inst.inst)); - case InstructionClass::Exp: - return convertExp(fragment, Exp(inst.inst)); - case InstructionClass::Vop1: - return convertVop1(fragment, Vop1(inst.inst)); - case InstructionClass::Vopc: - return convertVopc(fragment, Vopc(inst.inst)); - case InstructionClass::Sop1: - return convertSop1(fragment, Sop1(inst.inst)); - case InstructionClass::Sopc: - return convertSopc(fragment, Sopc(inst.inst)); - case InstructionClass::Sopp: - return convertSopp(fragment, Sopp(inst.inst)); - - case InstructionClass::Invalid: - break; - } - - inst.dump(); - util::unreachable(); -} + }; + + switch (inst.op) + { + case Sopp::Op::S_WAITCNT: + // TODO + break; + + case Sopp::Op::S_BRANCH: + { + fragment.jumpAddress = fragment.registers->pc + (inst.simm << 2); + // auto address = fragment.registers->pc + (inst.simm << 2); + // Fragment *target = fragment.context->getOrCreateFragment(address, 0x100); + + // fragment.builder.createBranch(target->entryBlockId); + // fragment.terminator = FragmentTerminator::Branch; + // target->predecessors.insert(&fragment); + // fragment.successors.insert(target); + break; + } + + case Sopp::Op::S_CBRANCH_SCC0: + { + createCondBranch(fragment.builder.createLogicalNot( + fragment.context->getBoolType(), fragment.getScc())); + break; + } + + case Sopp::Op::S_CBRANCH_SCC1: + { + createCondBranch(fragment.getScc()); + break; + } + + case Sopp::Op::S_CBRANCH_VCCZ: + { + auto loIsZero = fragment.builder.createIEqual( + fragment.context->getBoolType(), fragment.getVccLo().value, + fragment.context->getUInt32(0)); + auto hiIsZero = fragment.builder.createIEqual( + fragment.context->getBoolType(), fragment.getVccHi().value, + fragment.context->getUInt32(0)); + createCondBranch(fragment.builder.createLogicalAnd( + fragment.context->getBoolType(), loIsZero, hiIsZero)); + break; + } + + case Sopp::Op::S_CBRANCH_VCCNZ: + { + auto loIsNotZero = fragment.builder.createINotEqual( + fragment.context->getBoolType(), fragment.getVccLo().value, + fragment.context->getUInt32(0)); + auto hiIsNotZero = fragment.builder.createINotEqual( + fragment.context->getBoolType(), fragment.getVccHi().value, + fragment.context->getUInt32(0)); + + createCondBranch(fragment.builder.createLogicalOr( + fragment.context->getBoolType(), loIsNotZero, hiIsNotZero)); + break; + } + + case Sopp::Op::S_CBRANCH_EXECZ: + { + auto loIsZero = fragment.builder.createIEqual( + fragment.context->getBoolType(), fragment.getExecLo().value, + fragment.context->getUInt32(0)); + auto hiIsZero = fragment.builder.createIEqual( + fragment.context->getBoolType(), fragment.getExecHi().value, + fragment.context->getUInt32(0)); + createCondBranch(fragment.builder.createLogicalAnd( + fragment.context->getBoolType(), loIsZero, hiIsZero)); + break; + } + + case Sopp::Op::S_CBRANCH_EXECNZ: + { + auto loIsNotZero = fragment.builder.createINotEqual( + fragment.context->getBoolType(), fragment.getExecLo().value, + fragment.context->getUInt32(0)); + auto hiIsNotZero = fragment.builder.createINotEqual( + fragment.context->getBoolType(), fragment.getExecHi().value, + fragment.context->getUInt32(0)); + + createCondBranch(fragment.builder.createLogicalOr( + fragment.context->getBoolType(), loIsNotZero, hiIsNotZero)); + break; + } + + case Sopp::Op::S_ENDPGM: + // fragment.terminator = FragmentTerminator::EndProgram; + return; + + case Sopp::Op::S_NOP: + break; + + default: + inst.dump(); + util::unreachable(); + } + } + + void convertInstruction(Fragment& fragment, Instruction inst) + { + switch (inst.instClass) + { + case InstructionClass::Vop2: + return convertVop2(fragment, Vop2(inst.inst)); + case InstructionClass::Sop2: + return convertSop2(fragment, Sop2(inst.inst)); + case InstructionClass::Sopk: + return convertSopk(fragment, Sopk(inst.inst)); + case InstructionClass::Smrd: + return convertSmrd(fragment, Smrd(inst.inst)); + case InstructionClass::Vop3: + return convertVop3(fragment, Vop3(inst.inst)); + case InstructionClass::Mubuf: + return convertMubuf(fragment, Mubuf(inst.inst)); + case InstructionClass::Mtbuf: + return convertMtbuf(fragment, Mtbuf(inst.inst)); + case InstructionClass::Mimg: + return convertMimg(fragment, Mimg(inst.inst)); + case InstructionClass::Ds: + return convertDs(fragment, Ds(inst.inst)); + case InstructionClass::Vintrp: + return convertVintrp(fragment, Vintrp(inst.inst)); + case InstructionClass::Exp: + return convertExp(fragment, Exp(inst.inst)); + case InstructionClass::Vop1: + return convertVop1(fragment, Vop1(inst.inst)); + case InstructionClass::Vopc: + return convertVopc(fragment, Vopc(inst.inst)); + case InstructionClass::Sop1: + return convertSop1(fragment, Sop1(inst.inst)); + case InstructionClass::Sopc: + return convertSopc(fragment, Sopc(inst.inst)); + case InstructionClass::Sopp: + return convertSopp(fragment, Sopp(inst.inst)); + + case InstructionClass::Invalid: + break; + } + + inst.dump(); + util::unreachable(); + } } // namespace -void Fragment::injectValuesFromPreds() { - for (auto pred : predecessors) { - for (auto value : pred->values) { - values.insert(value); - } - - for (auto output : pred->outputs) { - outputs.insert(output); - } - } - - std::vector> predValues; - - // std::printf("injection values for bb%lx\n", registers->pc); - - // auto getRegName = [](RegisterId id) { - // if (id.isScalar()) { - // return "sgpr"; - // } - - // if (id.isVector()) { - // return "vgpr"; - // } - - // if (id.isExport()) { - // return "exp"; - // } - - // if (id.isAttr()) { - // return "attr"; - // } - - // return ""; - // }; - - auto setupRegisterValue = [&](RegisterId id) { - bool allSameValues = true; - predValues.clear(); - - spirv::Type type; - - for (auto pred : predecessors) { - Value value; - - if (type) { - value = pred->getRegister(id, type); - } else { - value = pred->getRegister(id); - type = value.type; - } - - if (allSameValues && !predValues.empty()) { - allSameValues = predValues.back().first == value.value; - } - - predValues.emplace_back(value.value, pred->builder.id); - } - - Value value; - - if (allSameValues) { - value = {type, predValues.back().first}; - // std::printf(" ** %s[%u] is value = %u\n", getRegName(id), - // id.getOffset(), - // predValues.back().first.id); - } else { - // std::printf(" ** %s[%u] is phi = { ", getRegName(id), id.getOffset()); - // for (bool isFirst = true; auto value : predValues) { - // if (isFirst) { - // isFirst = false; - // } else { - // std::printf(", "); - // } - // std::printf("%u", value.first.id); - // } - // std::printf(" }\n"); - value = {type, builder.createPhi(type, predValues)}; - } - - registers->setRegister(id, value); - }; - - for (auto id : values) { - setupRegisterValue(id); - } - for (auto id : outputs) { - setupRegisterValue(id); - } +void Fragment::injectValuesFromPreds() +{ + for (auto pred : predecessors) + { + for (auto value : pred->values) + { + values.insert(value); + } + + for (auto output : pred->outputs) + { + outputs.insert(output); + } + } + + std::vector> predValues; + + // std::printf("injection values for bb%lx\n", registers->pc); + + // auto getRegName = [](RegisterId id) { + // if (id.isScalar()) { + // return "sgpr"; + // } + + // if (id.isVector()) { + // return "vgpr"; + // } + + // if (id.isExport()) { + // return "exp"; + // } + + // if (id.isAttr()) { + // return "attr"; + // } + + // return ""; + // }; + + auto setupRegisterValue = [&](RegisterId id) { + bool allSameValues = true; + predValues.clear(); + + spirv::Type type; + + for (auto pred : predecessors) + { + Value value; + + if (type) + { + value = pred->getRegister(id, type); + } + else + { + value = pred->getRegister(id); + type = value.type; + } + + if (allSameValues && !predValues.empty()) + { + allSameValues = predValues.back().first == value.value; + } + + predValues.emplace_back(value.value, pred->builder.id); + } + + Value value; + + if (allSameValues) + { + value = {type, predValues.back().first}; + // std::printf(" ** %s[%u] is value = %u\n", getRegName(id), + // id.getOffset(), + // predValues.back().first.id); + } + else + { + // std::printf(" ** %s[%u] is phi = { ", getRegName(id), id.getOffset()); + // for (bool isFirst = true; auto value : predValues) { + // if (isFirst) { + // isFirst = false; + // } else { + // std::printf(", "); + // } + // std::printf("%u", value.first.id); + // } + // std::printf(" }\n"); + value = {type, builder.createPhi(type, predValues)}; + } + + registers->setRegister(id, value); + }; + + for (auto id : values) + { + setupRegisterValue(id); + } + for (auto id : outputs) + { + setupRegisterValue(id); + } } -spirv::SamplerValue Fragment::createSampler(RegisterId base) { - auto sBuffer0 = getOperand(RegisterId::Raw(base + 0), TypeId::UInt32); - auto sBuffer1 = getOperand(RegisterId::Raw(base + 1), TypeId::UInt32); - auto sBuffer2 = getOperand(RegisterId::Raw(base + 2), TypeId::UInt32); - auto sBuffer3 = getOperand(RegisterId::Raw(base + 3), TypeId::UInt32); - - auto optSBuffer0Value = context->findUint32Value(sBuffer0.value); - auto optSBuffer1Value = context->findUint32Value(sBuffer1.value); - auto optSBuffer2Value = context->findUint32Value(sBuffer2.value); - auto optSBuffer3Value = context->findUint32Value(sBuffer3.value); - - if (optSBuffer0Value && optSBuffer1Value && optSBuffer2Value && - optSBuffer3Value) { - std::uint32_t sbuffer[] = { - *optSBuffer0Value, - *optSBuffer1Value, - *optSBuffer2Value, - *optSBuffer3Value, - }; - - auto uniform = context->getOrCreateUniformConstant( - sbuffer, std::size(sbuffer), TypeId::Sampler); - return builder.createLoad(context->getSamplerType(), uniform->variable); - } else { - util::unreachable(); - } +spirv::SamplerValue Fragment::createSampler(RegisterId base) +{ + auto sBuffer0 = getOperand(RegisterId::Raw(base + 0), TypeId::UInt32); + auto sBuffer1 = getOperand(RegisterId::Raw(base + 1), TypeId::UInt32); + auto sBuffer2 = getOperand(RegisterId::Raw(base + 2), TypeId::UInt32); + auto sBuffer3 = getOperand(RegisterId::Raw(base + 3), TypeId::UInt32); + + auto optSBuffer0Value = context->findUint32Value(sBuffer0.value); + auto optSBuffer1Value = context->findUint32Value(sBuffer1.value); + auto optSBuffer2Value = context->findUint32Value(sBuffer2.value); + auto optSBuffer3Value = context->findUint32Value(sBuffer3.value); + + if (optSBuffer0Value && optSBuffer1Value && optSBuffer2Value && + optSBuffer3Value) + { + std::uint32_t sbuffer[] = { + *optSBuffer0Value, + *optSBuffer1Value, + *optSBuffer2Value, + *optSBuffer3Value, + }; + + auto uniform = context->getOrCreateUniformConstant( + sbuffer, std::size(sbuffer), TypeId::Sampler); + return builder.createLoad(context->getSamplerType(), uniform->variable); + } + else + { + util::unreachable(); + } } spirv::ImageValue Fragment::createImage(RegisterId base, bool r128, - bool sampled, AccessOp access) { - auto tBuffer0 = getOperand(RegisterId::Raw(base + 0), TypeId::UInt32); - auto tBuffer1 = getOperand(RegisterId::Raw(base + 1), TypeId::UInt32); - auto tBuffer2 = getOperand(RegisterId::Raw(base + 2), TypeId::UInt32); - auto tBuffer3 = getOperand(RegisterId::Raw(base + 3), TypeId::UInt32); - - auto optTBuffer0Value = context->findUint32Value(tBuffer0.value); - auto optTBuffer1Value = context->findUint32Value(tBuffer1.value); - auto optTBuffer2Value = context->findUint32Value(tBuffer2.value); - auto optTBuffer3Value = context->findUint32Value(tBuffer3.value); - - if (!optTBuffer0Value || !optTBuffer1Value || !optTBuffer2Value || - !optTBuffer3Value) { - util::unreachable(); - } - - auto imageTypeId = sampled ? TypeId::Image2D : TypeId::StorageImage2D; - auto imageType = - sampled ? context->getImage2DType() : context->getStorageImage2DType(); - - if (r128) { - std::uint32_t sbuffer[] = { - *optTBuffer0Value, - *optTBuffer1Value, - *optTBuffer2Value, - *optTBuffer3Value, - }; - - auto uniform = context->getOrCreateUniformConstant( - sbuffer, std::size(sbuffer), imageTypeId); - uniform->accessOp |= access; - return builder.createLoad(imageType, uniform->variable); - } - - auto tBuffer4 = getOperand(RegisterId::Raw(base + 4), TypeId::UInt32); - auto tBuffer5 = getOperand(RegisterId::Raw(base + 5), TypeId::UInt32); - auto tBuffer6 = getOperand(RegisterId::Raw(base + 6), TypeId::UInt32); - auto tBuffer7 = getOperand(RegisterId::Raw(base + 7), TypeId::UInt32); - - auto optTBuffer4Value = context->findUint32Value(tBuffer4.value); - auto optTBuffer5Value = context->findUint32Value(tBuffer5.value); - auto optTBuffer6Value = context->findUint32Value(tBuffer6.value); - auto optTBuffer7Value = context->findUint32Value(tBuffer7.value); - - if (!optTBuffer4Value || !optTBuffer5Value || !optTBuffer6Value || - !optTBuffer7Value) { - util::unreachable(); - } - - std::uint32_t sbuffer[] = { - *optTBuffer0Value, *optTBuffer1Value, *optTBuffer2Value, - *optTBuffer3Value, *optTBuffer4Value, *optTBuffer5Value, - *optTBuffer6Value, *optTBuffer7Value, - }; - - auto uniform = context->getOrCreateUniformConstant( - sbuffer, std::size(sbuffer), imageTypeId); - uniform->accessOp |= access; - return builder.createLoad(imageType, uniform->variable); + bool sampled, AccessOp access) +{ + auto tBuffer0 = getOperand(RegisterId::Raw(base + 0), TypeId::UInt32); + auto tBuffer1 = getOperand(RegisterId::Raw(base + 1), TypeId::UInt32); + auto tBuffer2 = getOperand(RegisterId::Raw(base + 2), TypeId::UInt32); + auto tBuffer3 = getOperand(RegisterId::Raw(base + 3), TypeId::UInt32); + + auto optTBuffer0Value = context->findUint32Value(tBuffer0.value); + auto optTBuffer1Value = context->findUint32Value(tBuffer1.value); + auto optTBuffer2Value = context->findUint32Value(tBuffer2.value); + auto optTBuffer3Value = context->findUint32Value(tBuffer3.value); + + if (!optTBuffer0Value || !optTBuffer1Value || !optTBuffer2Value || + !optTBuffer3Value) + { + util::unreachable(); + } + + auto imageTypeId = sampled ? TypeId::Image2D : TypeId::StorageImage2D; + auto imageType = + sampled ? context->getImage2DType() : context->getStorageImage2DType(); + + if (r128) + { + std::uint32_t sbuffer[] = { + *optTBuffer0Value, + *optTBuffer1Value, + *optTBuffer2Value, + *optTBuffer3Value, + }; + + auto uniform = context->getOrCreateUniformConstant( + sbuffer, std::size(sbuffer), imageTypeId); + uniform->accessOp |= access; + return builder.createLoad(imageType, uniform->variable); + } + + auto tBuffer4 = getOperand(RegisterId::Raw(base + 4), TypeId::UInt32); + auto tBuffer5 = getOperand(RegisterId::Raw(base + 5), TypeId::UInt32); + auto tBuffer6 = getOperand(RegisterId::Raw(base + 6), TypeId::UInt32); + auto tBuffer7 = getOperand(RegisterId::Raw(base + 7), TypeId::UInt32); + + auto optTBuffer4Value = context->findUint32Value(tBuffer4.value); + auto optTBuffer5Value = context->findUint32Value(tBuffer5.value); + auto optTBuffer6Value = context->findUint32Value(tBuffer6.value); + auto optTBuffer7Value = context->findUint32Value(tBuffer7.value); + + if (!optTBuffer4Value || !optTBuffer5Value || !optTBuffer6Value || + !optTBuffer7Value) + { + util::unreachable(); + } + + std::uint32_t sbuffer[] = { + *optTBuffer0Value, + *optTBuffer1Value, + *optTBuffer2Value, + *optTBuffer3Value, + *optTBuffer4Value, + *optTBuffer5Value, + *optTBuffer6Value, + *optTBuffer7Value, + }; + + auto uniform = context->getOrCreateUniformConstant( + sbuffer, std::size(sbuffer), imageTypeId); + uniform->accessOp |= access; + return builder.createLoad(imageType, uniform->variable); } -Value Fragment::createCompositeExtract(Value composite, std::uint32_t member) { - auto optCompositeType = context->getTypeIdOf(composite.type); - if (!optCompositeType.has_value()) { - util::unreachable(); - } - - auto compositeType = *optCompositeType; - - TypeId baseType = compositeType.getBaseType(); - std::uint32_t memberCount = compositeType.getElementsCount(); - - if (member >= memberCount) { - util::unreachable(); - } - - auto resultType = context->getType(baseType); - spirv::Value resultValue; - - if (memberCount > 4) { - // stored in array - auto row = member / 4; - auto column = member % 4; - - auto rowType = context->getType( - static_cast(static_cast(baseType) + 3)); - - auto rowValue = - builder.createCompositeExtract(rowType, composite.value, {{row}}); - resultValue = - builder.createCompositeExtract(resultType, rowValue, {{column}}); - } else { - resultValue = - builder.createCompositeExtract(resultType, composite.value, {{member}}); - } - - return {resultType, resultValue}; +Value Fragment::createCompositeExtract(Value composite, std::uint32_t member) +{ + auto optCompositeType = context->getTypeIdOf(composite.type); + if (!optCompositeType.has_value()) + { + util::unreachable(); + } + + auto compositeType = *optCompositeType; + + TypeId baseType = compositeType.getBaseType(); + std::uint32_t memberCount = compositeType.getElementsCount(); + + if (member >= memberCount) + { + util::unreachable(); + } + + auto resultType = context->getType(baseType); + spirv::Value resultValue; + + if (memberCount > 4) + { + // stored in array + auto row = member / 4; + auto column = member % 4; + + auto rowType = context->getType( + static_cast(static_cast(baseType) + 3)); + + auto rowValue = + builder.createCompositeExtract(rowType, composite.value, {{row}}); + resultValue = + builder.createCompositeExtract(resultType, rowValue, {{column}}); + } + else + { + resultValue = + builder.createCompositeExtract(resultType, composite.value, {{member}}); + } + + return {resultType, resultValue}; } spirv::Value Fragment::createBitcast(spirv::Type to, spirv::Type from, - spirv::Value value) { - if (from == to) { - return value; - } - - if (from == context->getUInt8Type()) - value = builder.createUConvert(to, spirv::cast(value)); - - if (from == context->getFloat32Type()) { - if (auto origValue = context->findFloat32Value(value)) { - if (to == context->getUInt32Type()) { - return context->getUInt32(std::bit_cast(*origValue)); - } - - if (to == context->getSint32Type()) { - return context->getSInt32(std::bit_cast(*origValue)); - } - } - } else if (from == context->getUInt32Type()) { - if (auto origValue = context->findUint32Value(value)) { - if (to == context->getFloat32Type()) { - return context->getFloat32(std::bit_cast(*origValue)); - } - - if (to == context->getSint32Type()) { - return context->getSInt32(std::bit_cast(*origValue)); - } - } - } else if (from == context->getSint32Type()) { - if (auto origValue = context->findSint32Value(value)) { - if (to == context->getFloat32Type()) { - return context->getFloat32(std::bit_cast(*origValue)); - } - - if (to == context->getUInt32Type()) { - return context->getUInt32(std::bit_cast(*origValue)); - } - } - } - - if (from == context->getUInt64Type() && to == context->getUInt32Type()) { - util::unreachable(); - } - return builder.createBitcast(to, value); + spirv::Value value) +{ + if (from == to) + { + return value; + } + + if (from == context->getUInt8Type()) + value = builder.createUConvert(to, spirv::cast(value)); + + if (from == context->getFloat32Type()) + { + if (auto origValue = context->findFloat32Value(value)) + { + if (to == context->getUInt32Type()) + { + return context->getUInt32(std::bit_cast(*origValue)); + } + + if (to == context->getSint32Type()) + { + return context->getSInt32(std::bit_cast(*origValue)); + } + } + } + else if (from == context->getUInt32Type()) + { + if (auto origValue = context->findUint32Value(value)) + { + if (to == context->getFloat32Type()) + { + return context->getFloat32(std::bit_cast(*origValue)); + } + + if (to == context->getSint32Type()) + { + return context->getSInt32(std::bit_cast(*origValue)); + } + } + } + else if (from == context->getSint32Type()) + { + if (auto origValue = context->findSint32Value(value)) + { + if (to == context->getFloat32Type()) + { + return context->getFloat32(std::bit_cast(*origValue)); + } + + if (to == context->getUInt32Type()) + { + return context->getUInt32(std::bit_cast(*origValue)); + } + } + } + + if (from == context->getUInt64Type() && to == context->getUInt32Type()) + { + util::unreachable(); + } + return builder.createBitcast(to, value); } -Value Fragment::getOperand(RegisterId id, TypeId type, OperandGetFlags flags) { - if (id == RegisterId::Scc) { - if (type != TypeId::Bool) { - util::unreachable(); - } - - return getRegister(id); - } - - auto elementsCount = type.getElementsCount(); - - if (elementsCount == 0) { - util::unreachable(); - } - - auto resultType = context->getType(type); - - auto baseTypeId = type.getBaseType(); - auto baseTypeSize = baseTypeId.getSize(); - auto registerCountPerElement = (baseTypeSize + 3) / 4; - auto registerElementsCount = elementsCount * registerCountPerElement; - - if (registerElementsCount == 1 || id.isExport() || id.isAttr()) { - if (flags == OperandGetFlags::PreserveType) { - return getRegister(id); - } else { - return getRegister(id, resultType); - } - } - - if (baseTypeSize < 4) { - util::unreachable(); - } - - auto baseType = context->getType(baseTypeId); - - if (registerCountPerElement == 1) { - std::vector members; - members.reserve(elementsCount); - spirv::Type preservedType; - - for (std::uint32_t i = 0; i < elementsCount; ++i) { - Value member; - - if (flags == OperandGetFlags::PreserveType) { - if (!preservedType) { - member = getRegister(RegisterId::Raw(id + i)); - preservedType = member.type; - } else { - member = getRegister(RegisterId::Raw(id + i), preservedType); - } - } else { - member = getRegister(RegisterId::Raw(id + i), baseType); - } - - members.push_back(member.value); - } - - return {resultType, builder.createCompositeConstruct(resultType, members)}; - } - - if (registerElementsCount != 2) { - util::unreachable(); - } - - TypeId registerType; - - switch (baseTypeId) { - case TypeId::UInt64: - registerType = TypeId::UInt32; - break; - case TypeId::SInt64: - registerType = TypeId::SInt32; - break; - case TypeId::Float64: - registerType = TypeId::Float32; - break; - - default: - util::unreachable(); - } - - if (registerCountPerElement != 2) { - util::unreachable(); - } - - auto uint64T = context->getUInt64Type(); - auto valueLo = builder.createUConvert( - uint64T, - spirv::cast(getOperand(id, TypeId::UInt32).value)); - auto valueHi = builder.createUConvert( - uint64T, spirv::cast( - getOperand(RegisterId::Raw(id + 1), TypeId::UInt32).value)); - valueHi = - builder.createShiftLeftLogical(uint64T, valueHi, context->getUInt32(32)); - auto value = builder.createBitwiseOr(uint64T, valueLo, valueHi); - - if (baseTypeId != TypeId::UInt64) { - value = createBitcast(baseType, context->getUInt64Type(), value); - } - - return {resultType, value}; +Value Fragment::getOperand(RegisterId id, TypeId type, OperandGetFlags flags) +{ + if (id == RegisterId::Scc) + { + if (type != TypeId::Bool) + { + util::unreachable(); + } + + return getRegister(id); + } + + auto elementsCount = type.getElementsCount(); + + if (elementsCount == 0) + { + util::unreachable(); + } + + auto resultType = context->getType(type); + + auto baseTypeId = type.getBaseType(); + auto baseTypeSize = baseTypeId.getSize(); + auto registerCountPerElement = (baseTypeSize + 3) / 4; + auto registerElementsCount = elementsCount * registerCountPerElement; + + if (registerElementsCount == 1 || id.isExport() || id.isAttr()) + { + if (flags == OperandGetFlags::PreserveType) + { + return getRegister(id); + } + else + { + return getRegister(id, resultType); + } + } + + if (baseTypeSize < 4) + { + util::unreachable(); + } + + auto baseType = context->getType(baseTypeId); + + if (registerCountPerElement == 1) + { + std::vector members; + members.reserve(elementsCount); + spirv::Type preservedType; + + for (std::uint32_t i = 0; i < elementsCount; ++i) + { + Value member; + + if (flags == OperandGetFlags::PreserveType) + { + if (!preservedType) + { + member = getRegister(RegisterId::Raw(id + i)); + preservedType = member.type; + } + else + { + member = getRegister(RegisterId::Raw(id + i), preservedType); + } + } + else + { + member = getRegister(RegisterId::Raw(id + i), baseType); + } + + members.push_back(member.value); + } + + return {resultType, builder.createCompositeConstruct(resultType, members)}; + } + + if (registerElementsCount != 2) + { + util::unreachable(); + } + + TypeId registerType; + + switch (baseTypeId) + { + case TypeId::UInt64: + registerType = TypeId::UInt32; + break; + case TypeId::SInt64: + registerType = TypeId::SInt32; + break; + case TypeId::Float64: + registerType = TypeId::Float32; + break; + + default: + util::unreachable(); + } + + if (registerCountPerElement != 2) + { + util::unreachable(); + } + + auto uint64T = context->getUInt64Type(); + auto valueLo = builder.createUConvert( + uint64T, + spirv::cast(getOperand(id, TypeId::UInt32).value)); + auto valueHi = builder.createUConvert( + uint64T, spirv::cast( + getOperand(RegisterId::Raw(id + 1), TypeId::UInt32).value)); + valueHi = + builder.createShiftLeftLogical(uint64T, valueHi, context->getUInt32(32)); + auto value = builder.createBitwiseOr(uint64T, valueLo, valueHi); + + if (baseTypeId != TypeId::UInt64) + { + value = createBitcast(baseType, context->getUInt64Type(), value); + } + + return {resultType, value}; } -void Fragment::setOperand(RegisterId id, Value value) { - if (id.isExport()) { - function->createExport(builder, id.getOffset(), value); - return; - } - - auto typeId = *context->getTypeIdOf(value.type); - auto elementsCount = typeId.getElementsCount(); - - if (elementsCount == 0) { - util::unreachable(); - } - - // if (id.isScalar()) { - // std::printf("update sgpr[%u]\n", id.getOffset()); - // } - - // TODO: handle half types - auto baseTypeId = typeId.getBaseType(); - auto baseTypeSize = baseTypeId.getSize(); - - auto registerCountPerElement = (baseTypeSize + 3) / 4; - auto registerElementsCount = elementsCount * registerCountPerElement; - - if (id == RegisterId::Scc) { - auto boolT = context->getBoolType(); - if (value.type != boolT) { - if (value.type == context->getUInt32Type()) { - value.value = - builder.createINotEqual(boolT, value.value, context->getUInt32(0)); - } else if (value.type == context->getSint32Type()) { - value.value = - builder.createINotEqual(boolT, value.value, context->getSInt32(0)); - } else if (value.type == context->getUInt64Type()) { - value.value = - builder.createINotEqual(boolT, value.value, context->getUInt64(0)); - } else { - util::unreachable(); - } - - value.type = boolT; - } - - setRegister(id, value); - return; - } - - if (registerElementsCount == 1 || id.isExport() || id.isAttr()) { - setRegister(id, value); - return; - } - - if (baseTypeSize < 4) { - util::unreachable(); - } - - if (registerCountPerElement == 1) { - for (std::uint32_t i = 0; i < elementsCount; ++i) { - auto element = createCompositeExtract(value, i); - auto regId = RegisterId::Raw(id + i); - setRegister(regId, element); - } - } else { - if (elementsCount != 1 || baseTypeId != typeId) { - util::unreachable(); - } - - TypeId registerType; - - switch (baseTypeId) { - case TypeId::UInt64: - registerType = TypeId::UInt32; - break; - case TypeId::SInt64: - registerType = TypeId::SInt32; - break; - case TypeId::Float64: - registerType = TypeId::Float32; - break; - - default: - util::unreachable(); - } - - if (registerCountPerElement != 2) { - util::unreachable(); - } - - auto uint64T = context->getUInt64Type(); - auto uint64_value = spirv::cast(value.value); - if (baseTypeId != TypeId::UInt64) { - uint64_value = spirv::cast( - createBitcast(uint64T, context->getType(baseTypeId), value.value)); - } - - auto uint32T = context->getUInt32Type(); - auto valueLo = builder.createUConvert(uint32T, uint64_value); - auto valueHi = builder.createUConvert( - uint32T, builder.createShiftRightLogical(uint64T, uint64_value, - context->getUInt32(32))); - - setOperand(id, {uint32T, valueLo}); - setOperand(RegisterId::Raw(id.raw + 1), {uint32T, valueHi}); - } +void Fragment::setOperand(RegisterId id, Value value) +{ + if (id.isExport()) + { + function->createExport(builder, id.getOffset(), value); + return; + } + + auto typeId = *context->getTypeIdOf(value.type); + auto elementsCount = typeId.getElementsCount(); + + if (elementsCount == 0) + { + util::unreachable(); + } + + // if (id.isScalar()) { + // std::printf("update sgpr[%u]\n", id.getOffset()); + // } + + // TODO: handle half types + auto baseTypeId = typeId.getBaseType(); + auto baseTypeSize = baseTypeId.getSize(); + + auto registerCountPerElement = (baseTypeSize + 3) / 4; + auto registerElementsCount = elementsCount * registerCountPerElement; + + if (id == RegisterId::Scc) + { + auto boolT = context->getBoolType(); + if (value.type != boolT) + { + if (value.type == context->getUInt32Type()) + { + value.value = + builder.createINotEqual(boolT, value.value, context->getUInt32(0)); + } + else if (value.type == context->getSint32Type()) + { + value.value = + builder.createINotEqual(boolT, value.value, context->getSInt32(0)); + } + else if (value.type == context->getUInt64Type()) + { + value.value = + builder.createINotEqual(boolT, value.value, context->getUInt64(0)); + } + else + { + util::unreachable(); + } + + value.type = boolT; + } + + setRegister(id, value); + return; + } + + if (registerElementsCount == 1 || id.isExport() || id.isAttr()) + { + setRegister(id, value); + return; + } + + if (baseTypeSize < 4) + { + util::unreachable(); + } + + if (registerCountPerElement == 1) + { + for (std::uint32_t i = 0; i < elementsCount; ++i) + { + auto element = createCompositeExtract(value, i); + auto regId = RegisterId::Raw(id + i); + setRegister(regId, element); + } + } + else + { + if (elementsCount != 1 || baseTypeId != typeId) + { + util::unreachable(); + } + + TypeId registerType; + + switch (baseTypeId) + { + case TypeId::UInt64: + registerType = TypeId::UInt32; + break; + case TypeId::SInt64: + registerType = TypeId::SInt32; + break; + case TypeId::Float64: + registerType = TypeId::Float32; + break; + + default: + util::unreachable(); + } + + if (registerCountPerElement != 2) + { + util::unreachable(); + } + + auto uint64T = context->getUInt64Type(); + auto uint64_value = spirv::cast(value.value); + if (baseTypeId != TypeId::UInt64) + { + uint64_value = spirv::cast( + createBitcast(uint64T, context->getType(baseTypeId), value.value)); + } + + auto uint32T = context->getUInt32Type(); + auto valueLo = builder.createUConvert(uint32T, uint64_value); + auto valueHi = builder.createUConvert( + uint32T, builder.createShiftRightLogical(uint64T, uint64_value, + context->getUInt32(32))); + + setOperand(id, {uint32T, valueLo}); + setOperand(RegisterId::Raw(id.raw + 1), {uint32T, valueHi}); + } } -void Fragment::setVcc(Value value) { - // TODO: update vcc hi if needed - // TODO: update vccz +void Fragment::setVcc(Value value) +{ + // TODO: update vcc hi if needed + // TODO: update vccz - setOperand(RegisterId::VccLo, value); - setOperand(RegisterId::VccHi, - {context->getUInt32Type(), context->getUInt32(0)}); + setOperand(RegisterId::VccLo, value); + setOperand(RegisterId::VccHi, + {context->getUInt32Type(), context->getUInt32(0)}); } -void Fragment::setScc(Value value) { - setOperand(RegisterId::Scc, value); - - if (value.type != context->getBoolType() && - value.type != context->getUInt32Type() && - value.type != context->getSint32Type() && - value.type != context->getUInt64Type()) { - util::unreachable(); - } +void Fragment::setScc(Value value) +{ + setOperand(RegisterId::Scc, value); + + if (value.type != context->getBoolType() && + value.type != context->getUInt32Type() && + value.type != context->getSint32Type() && + value.type != context->getUInt64Type()) + { + util::unreachable(); + } } -spirv::BoolValue Fragment::getScc() { - auto result = - getOperand(RegisterId::Scc, TypeId::Bool, OperandGetFlags::PreserveType); - - if (result.type == context->getBoolType()) { - return spirv::cast(result.value); - } - - if (result.type == context->getUInt32Type()) { - return builder.createINotEqual(context->getBoolType(), result.value, - context->getUInt32(0)); - } - if (result.type == context->getSint32Type()) { - return builder.createINotEqual(context->getBoolType(), result.value, - context->getSInt32(0)); - } - if (result.type == context->getUInt64Type()) { - return builder.createINotEqual(context->getBoolType(), result.value, - context->getUInt64(0)); - } - - util::unreachable(); +spirv::BoolValue Fragment::getScc() +{ + auto result = + getOperand(RegisterId::Scc, TypeId::Bool, OperandGetFlags::PreserveType); + + if (result.type == context->getBoolType()) + { + return spirv::cast(result.value); + } + + if (result.type == context->getUInt32Type()) + { + return builder.createINotEqual(context->getBoolType(), result.value, + context->getUInt32(0)); + } + if (result.type == context->getSint32Type()) + { + return builder.createINotEqual(context->getBoolType(), result.value, + context->getSInt32(0)); + } + if (result.type == context->getUInt64Type()) + { + return builder.createINotEqual(context->getBoolType(), result.value, + context->getUInt64(0)); + } + + util::unreachable(); } /* void Fragment::createCallTo(MaterializedFunction *materialized) { @@ -5933,102 +6419,115 @@ void Fragment::createCallTo(MaterializedFunction *materialized) { } } */ -void amdgpu::shader::Fragment::convert(std::uint64_t size) { - auto ptr = context->getMemory().getPointer(registers->pc); - auto endptr = ptr + size / sizeof(std::uint32_t); +void amdgpu::shader::Fragment::convert(std::uint64_t size) +{ + auto ptr = context->getMemory().getPointer(registers->pc); + auto endptr = ptr + size / sizeof(std::uint32_t); - context->dependencies->map(registers->pc, registers->pc + size); + context->dependencies->map(registers->pc, registers->pc + size); - while (ptr < endptr) { - Instruction inst(ptr); - auto startPoint = builder.bodyRegion.getCurrentPosition(); + while (ptr < endptr) + { + Instruction inst(ptr); + auto startPoint = builder.bodyRegion.getCurrentPosition(); - std::printf("===============\n"); - inst.dump(); - std::printf("\n"); - convertInstruction(*this, inst); + std::printf("===============\n"); + inst.dump(); + std::printf("\n"); + convertInstruction(*this, inst); - std::printf("-------------->\n"); - spirv::dump(builder.bodyRegion.getCurrentPosition() - startPoint); + std::printf("-------------->\n"); + spirv::dump(builder.bodyRegion.getCurrentPosition() - startPoint); - ptr += inst.size(); - } + ptr += inst.size(); + } } -Value amdgpu::shader::Fragment::getRegister(RegisterId id) { - if (id.isScalar()) { - switch (id.getOffset()) { - case 128 ... 192: - return {context->getSint32Type(), context->getSInt32(id - 128)}; - case 193 ... 208: - return {context->getSint32Type(), - context->getSInt32(-static_cast(id - 192))}; - case 240: - return {context->getFloat32Type(), context->getFloat32(0.5f)}; - case 241: - return {context->getFloat32Type(), context->getFloat32(-0.5f)}; - case 242: - return {context->getFloat32Type(), context->getFloat32(1.0f)}; - case 243: - return {context->getFloat32Type(), context->getFloat32(-1.0f)}; - case 244: - return {context->getFloat32Type(), context->getFloat32(2.0f)}; - case 245: - return {context->getFloat32Type(), context->getFloat32(-2.0f)}; - case 246: - return {context->getFloat32Type(), context->getFloat32(4.0f)}; - case 247: - return {context->getFloat32Type(), context->getFloat32(-4.0f)}; - // case 248: - // return {context->getFloat32Type(), context->getFloat32(1 / M_PI * 2)}; - case 255: { - context->dependencies->map(registers->pc, - registers->pc + sizeof(std::uint32_t)); - auto ptr = context->getMemory().getPointer(registers->pc); - registers->pc += sizeof(std::uint32_t); - return {context->getUInt32Type(), context->getUInt32(*ptr)}; - } - } - } - - if (auto result = registers->getRegister(id)) { - return result; - } - - if (id.isExport()) { - util::unreachable(); - } - - // std::printf("creation input %u\n", id.raw); - auto result = function->createInput(id); - assert(result); - values.insert(id); - registers->setRegister(id, result); - return result; +Value amdgpu::shader::Fragment::getRegister(RegisterId id) +{ + if (id.isScalar()) + { + switch (id.getOffset()) + { + case 128 ... 192: + return {context->getSint32Type(), context->getSInt32(id - 128)}; + case 193 ... 208: + return {context->getSint32Type(), + context->getSInt32(-static_cast(id - 192))}; + case 240: + return {context->getFloat32Type(), context->getFloat32(0.5f)}; + case 241: + return {context->getFloat32Type(), context->getFloat32(-0.5f)}; + case 242: + return {context->getFloat32Type(), context->getFloat32(1.0f)}; + case 243: + return {context->getFloat32Type(), context->getFloat32(-1.0f)}; + case 244: + return {context->getFloat32Type(), context->getFloat32(2.0f)}; + case 245: + return {context->getFloat32Type(), context->getFloat32(-2.0f)}; + case 246: + return {context->getFloat32Type(), context->getFloat32(4.0f)}; + case 247: + return {context->getFloat32Type(), context->getFloat32(-4.0f)}; + // case 248: + // return {context->getFloat32Type(), context->getFloat32(1 / M_PI * 2)}; + case 255: + { + context->dependencies->map(registers->pc, + registers->pc + sizeof(std::uint32_t)); + auto ptr = context->getMemory().getPointer(registers->pc); + registers->pc += sizeof(std::uint32_t); + return {context->getUInt32Type(), context->getUInt32(*ptr)}; + } + } + } + + if (auto result = registers->getRegister(id)) + { + return result; + } + + if (id.isExport()) + { + util::unreachable(); + } + + // std::printf("creation input %u\n", id.raw); + auto result = function->createInput(id); + assert(result); + values.insert(id); + registers->setRegister(id, result); + return result; } -Value amdgpu::shader::Fragment::getRegister(RegisterId id, spirv::Type type) { - auto result = getRegister(id); +Value amdgpu::shader::Fragment::getRegister(RegisterId id, spirv::Type type) +{ + auto result = getRegister(id); - if (!result) { - return result; - } + if (!result) + { + return result; + } - if (type == context->getUInt64Type()) { - util::unreachable("%u is ulong\n", id.raw); - } + if (type == context->getUInt64Type()) + { + util::unreachable("%u is ulong\n", id.raw); + } - return {type, createBitcast(type, result.type, result.value)}; + return {type, createBitcast(type, result.type, result.value)}; } -void amdgpu::shader::Fragment::setRegister(RegisterId id, Value value) { - if (registers->getRegister(id) == value) { - return; - } +void amdgpu::shader::Fragment::setRegister(RegisterId id, Value value) +{ + if (registers->getRegister(id) == value) + { + return; + } - assert(value); + assert(value); - registers->setRegister(id, value); - outputs.insert(id); - // std::printf("creation output %u\n", id.raw); + registers->setRegister(id, value); + outputs.insert(id); + // std::printf("creation output %u\n", id.raw); } diff --git a/hw/amdgpu/shader/src/Function.cpp b/hw/amdgpu/shader/src/Function.cpp index 096be614..c1f1d96a 100644 --- a/hw/amdgpu/shader/src/Function.cpp +++ b/hw/amdgpu/shader/src/Function.cpp @@ -4,271 +4,319 @@ using namespace amdgpu::shader; -Value Function::createInput(RegisterId id) { - auto [it, inserted] = inputs.try_emplace(id); - - if (!inserted) { - assert(it->second); - return it->second; - } - - auto offset = id.getOffset(); - - if (id.isScalar()) { - auto uint32T = context->getUInt32Type(); - - if (userSgprs.size() > offset) { - return ((it->second = {uint32T, context->getUInt32(userSgprs[offset])})); - } - - if (stage == Stage::None) { - return ((it->second = - Value{uint32T, builder.createFunctionParameter(uint32T)})); - } - - switch (id.raw) { - case RegisterId::ExecLo: - return ((it->second = {uint32T, context->getUInt32(1)})); - case RegisterId::ExecHi: - return ((it->second = {uint32T, context->getUInt32(0)})); - - case RegisterId::Scc: - return ((it->second = {context->getBoolType(), context->getFalse()})); - - default: - break; - } - - if (stage == Stage::Vertex) { - return ((it->second = {uint32T, context->getUInt32(0)})); - } else if (stage == Stage::Fragment) { - return ((it->second = {uint32T, context->getUInt32(0)})); - } else if (stage == Stage::Compute) { - std::uint32_t offsetAfterSgprs = offset - userSgprs.size(); - if (offsetAfterSgprs < 3) { - auto workgroupIdVar = context->getWorkgroupId(); - auto workgroupId = entryFragment.builder.createLoad( - context->getUint32x3Type(), workgroupIdVar); - for (uint32_t i = 0; i < 3; ++i) { - auto input = entryFragment.builder.createCompositeExtract( - uint32T, workgroupId, {{i}}); - - inputs[RegisterId::Scalar(userSgprs.size() + i)] = {uint32T, input}; - } - - return inputs[id]; - } - - return ((it->second = {uint32T, context->getUInt32(0)})); - } - - util::unreachable(); - } - - if (stage == Stage::None) { - auto float32T = context->getFloat32Type(); - return ( - (it->second = {float32T, builder.createFunctionParameter(float32T)})); - } - - if (stage == Stage::Vertex) { - if (id.isVector()) { - auto uint32T = context->getUInt32Type(); - - if (id.getOffset() == 0) { - auto input = - entryFragment.builder.createLoad(uint32T, context->getThreadId()); - - return ((it->second = {uint32T, input})); - } - - return ((it->second = {uint32T, context->getUInt32(0)})); - } - - util::unreachable("Unexpected vertex input %u. user sgprs count=%zu", - id.raw, userSgprs.size()); - } - - if (stage == Stage::Fragment) { - if (id.isAttr()) { - auto float4T = context->getFloat32x4Type(); - auto input = entryFragment.builder.createLoad( - float4T, context->getIn(id.getOffset())); - return ((it->second = {float4T, input})); - } - - if (id.isVector()) { - switch (offset) { - case 2: - case 3: - case 4: - case 5: { - auto float4T = context->getFloat32x4Type(); - auto floatT = context->getFloat32Type(); - auto fragCoord = - entryFragment.builder.createLoad(float4T, context->getFragCoord()); - return ( - (it->second = {floatT, entryFragment.builder.createCompositeExtract( - floatT, fragCoord, {{offset - 2}})})); - } - } - } - - return ((it->second = {context->getUInt32Type(), context->getUInt32(0)})); - } - - if (stage == Stage::Compute) { - if (id.isVector() && offset < 3) { - auto uint32T = context->getUInt32Type(); - auto localInvocationIdVar = context->getLocalInvocationId(); - auto localInvocationId = entryFragment.builder.createLoad( - context->getUint32x3Type(), localInvocationIdVar); - - for (uint32_t i = 0; i < 3; ++i) { - auto input = entryFragment.builder.createCompositeExtract( - uint32T, localInvocationId, {{i}}); - - inputs[RegisterId::Vector(i)] = {uint32T, input}; - } - - return inputs[id]; - } - - return ((it->second = {context->getUInt32Type(), context->getUInt32(0)})); - } - - util::unreachable(); +Value Function::createInput(RegisterId id) +{ + auto [it, inserted] = inputs.try_emplace(id); + + if (!inserted) + { + assert(it->second); + return it->second; + } + + auto offset = id.getOffset(); + + if (id.isScalar()) + { + auto uint32T = context->getUInt32Type(); + + if (userSgprs.size() > offset) + { + return ((it->second = {uint32T, context->getUInt32(userSgprs[offset])})); + } + + if (stage == Stage::None) + { + return ((it->second = + Value{uint32T, builder.createFunctionParameter(uint32T)})); + } + + switch (id.raw) + { + case RegisterId::ExecLo: + return ((it->second = {uint32T, context->getUInt32(1)})); + case RegisterId::ExecHi: + return ((it->second = {uint32T, context->getUInt32(0)})); + + case RegisterId::Scc: + return ((it->second = {context->getBoolType(), context->getFalse()})); + + default: + break; + } + + if (stage == Stage::Vertex) + { + return ((it->second = {uint32T, context->getUInt32(0)})); + } + else if (stage == Stage::Fragment) + { + return ((it->second = {uint32T, context->getUInt32(0)})); + } + else if (stage == Stage::Compute) + { + std::uint32_t offsetAfterSgprs = offset - userSgprs.size(); + if (offsetAfterSgprs < 3) + { + auto workgroupIdVar = context->getWorkgroupId(); + auto workgroupId = entryFragment.builder.createLoad( + context->getUint32x3Type(), workgroupIdVar); + for (uint32_t i = 0; i < 3; ++i) + { + auto input = entryFragment.builder.createCompositeExtract( + uint32T, workgroupId, {{i}}); + + inputs[RegisterId::Scalar(userSgprs.size() + i)] = {uint32T, input}; + } + + return inputs[id]; + } + + return ((it->second = {uint32T, context->getUInt32(0)})); + } + + util::unreachable(); + } + + if (stage == Stage::None) + { + auto float32T = context->getFloat32Type(); + return ( + (it->second = {float32T, builder.createFunctionParameter(float32T)})); + } + + if (stage == Stage::Vertex) + { + if (id.isVector()) + { + auto uint32T = context->getUInt32Type(); + + if (id.getOffset() == 0) + { + auto input = + entryFragment.builder.createLoad(uint32T, context->getThreadId()); + + return ((it->second = {uint32T, input})); + } + + return ((it->second = {uint32T, context->getUInt32(0)})); + } + + util::unreachable("Unexpected vertex input %u. user sgprs count=%zu", + id.raw, userSgprs.size()); + } + + if (stage == Stage::Fragment) + { + if (id.isAttr()) + { + auto float4T = context->getFloat32x4Type(); + auto input = entryFragment.builder.createLoad( + float4T, context->getIn(id.getOffset())); + return ((it->second = {float4T, input})); + } + + if (id.isVector()) + { + switch (offset) + { + case 2: + case 3: + case 4: + case 5: + { + auto float4T = context->getFloat32x4Type(); + auto floatT = context->getFloat32Type(); + auto fragCoord = + entryFragment.builder.createLoad(float4T, context->getFragCoord()); + return ( + (it->second = {floatT, entryFragment.builder.createCompositeExtract( + floatT, fragCoord, {{offset - 2}})})); + } + } + } + + return ((it->second = {context->getUInt32Type(), context->getUInt32(0)})); + } + + if (stage == Stage::Compute) + { + if (id.isVector() && offset < 3) + { + auto uint32T = context->getUInt32Type(); + auto localInvocationIdVar = context->getLocalInvocationId(); + auto localInvocationId = entryFragment.builder.createLoad( + context->getUint32x3Type(), localInvocationIdVar); + + for (uint32_t i = 0; i < 3; ++i) + { + auto input = entryFragment.builder.createCompositeExtract( + uint32T, localInvocationId, {{i}}); + + inputs[RegisterId::Vector(i)] = {uint32T, input}; + } + + return inputs[id]; + } + + return ((it->second = {context->getUInt32Type(), context->getUInt32(0)})); + } + + util::unreachable(); } -void Function::createExport(spirv::BlockBuilder &builder, unsigned index, - Value value) { - if (stage == Stage::Vertex) { - switch (index) { - case 12: { - auto float4OutPtrT = - context->getPointerType(spv::StorageClass::Output, TypeId::Float32x4); - - auto gl_PerVertexPosition = builder.createAccessChain( - float4OutPtrT, context->getPerVertex(), {{context->getSInt32(0)}}); - - if (value.type != context->getFloat32x4Type()) { - util::unreachable(); - } - - builder.createStore(gl_PerVertexPosition, value.value); - return; - } - - case 32 ... 64: { // paramN - if (value.type != context->getFloat32x4Type()) { - util::unreachable(); - } - - builder.createStore(context->getOut(index - 32), value.value); - return; - } - } - - util::unreachable("Unexpected vartex export target %u", index); - } - - if (stage == Stage::Fragment) { - switch (index) { - case 0 ... 7: { - if (value.type != context->getFloat32x4Type()) { - util::unreachable(); - } - - builder.createStore(context->getOut(index), value.value); - return; - } - } - - util::unreachable("Unexpected fragment export target %u", index); - } - - util::unreachable(); +void Function::createExport(spirv::BlockBuilder& builder, unsigned index, + Value value) +{ + if (stage == Stage::Vertex) + { + switch (index) + { + case 12: + { + auto float4OutPtrT = + context->getPointerType(spv::StorageClass::Output, TypeId::Float32x4); + + auto gl_PerVertexPosition = builder.createAccessChain( + float4OutPtrT, context->getPerVertex(), {{context->getSInt32(0)}}); + + if (value.type != context->getFloat32x4Type()) + { + util::unreachable(); + } + + builder.createStore(gl_PerVertexPosition, value.value); + return; + } + + case 32 ... 64: + { // paramN + if (value.type != context->getFloat32x4Type()) + { + util::unreachable(); + } + + builder.createStore(context->getOut(index - 32), value.value); + return; + } + } + + util::unreachable("Unexpected vartex export target %u", index); + } + + if (stage == Stage::Fragment) + { + switch (index) + { + case 0 ... 7: + { + if (value.type != context->getFloat32x4Type()) + { + util::unreachable(); + } + + builder.createStore(context->getOut(index), value.value); + return; + } + } + + util::unreachable("Unexpected fragment export target %u", index); + } + + util::unreachable(); } -spirv::Type Function::getResultType() { - if (exitFragment.outputs.empty()) { - return context->getVoidType(); - } +spirv::Type Function::getResultType() +{ + if (exitFragment.outputs.empty()) + { + return context->getVoidType(); + } - if (exitFragment.outputs.size() == 1) { - return exitFragment.registers->getRegister(*exitFragment.outputs.begin()) - .type; - } + if (exitFragment.outputs.size() == 1) + { + return exitFragment.registers->getRegister(*exitFragment.outputs.begin()) + .type; + } - std::vector members; - members.reserve(exitFragment.outputs.size()); + std::vector members; + members.reserve(exitFragment.outputs.size()); - for (auto id : exitFragment.outputs) { - members.push_back(exitFragment.registers->getRegister(id).type); - } + for (auto id : exitFragment.outputs) + { + members.push_back(exitFragment.registers->getRegister(id).type); + } - return context->getStructType(members); + return context->getStructType(members); } -spirv::FunctionType Function::getFunctionType() { - if (stage != Stage::None) { - return context->getFunctionType(getResultType(), {}); - } +spirv::FunctionType Function::getFunctionType() +{ + if (stage != Stage::None) + { + return context->getFunctionType(getResultType(), {}); + } - std::vector params; - params.reserve(inputs.size()); + std::vector params; + params.reserve(inputs.size()); - for (auto inp : inputs) { - params.push_back(inp.second.type); - } + for (auto inp : inputs) + { + params.push_back(inp.second.type); + } - return context->getFunctionType(getResultType(), params); + return context->getFunctionType(getResultType(), params); } -Fragment *Function::createDetachedFragment() { - auto result = context->createFragment(0); - result->function = this; - return result; +Fragment* Function::createDetachedFragment() +{ + auto result = context->createFragment(0); + result->function = this; + return result; } -void Function::insertReturn() { - if (exitFragment.outputs.empty()) { - exitFragment.builder.createReturn(); - return; - } - - if (exitFragment.outputs.size() == 1) { - auto value = - exitFragment.registers->getRegister(*exitFragment.outputs.begin()) - .value; - exitFragment.builder.createReturnValue(value); - return; - } - - auto resultType = getResultType(); - - auto resultTypePointer = context->getBuilder().createTypePointer( - spv::StorageClass::Function, resultType); - - auto resultVariable = entryFragment.builder.createVariable( - resultTypePointer, spv::StorageClass::Function); - - std::uint32_t member = 0; - for (auto regId : exitFragment.outputs) { - auto value = exitFragment.registers->getRegister(regId); - auto valueTypeId = context->getTypeIdOf(value.type); - - auto pointerType = - context->getPointerType(spv::StorageClass::Function, *valueTypeId); - auto valuePointer = exitFragment.builder.createAccessChain( - pointerType, resultVariable, - {{exitFragment.context->getUInt32(member++)}}); - - exitFragment.builder.createStore(valuePointer, value.value); - } - - auto resultValue = - exitFragment.builder.createLoad(resultType, resultVariable); - - exitFragment.builder.createReturnValue(resultValue); +void Function::insertReturn() +{ + if (exitFragment.outputs.empty()) + { + exitFragment.builder.createReturn(); + return; + } + + if (exitFragment.outputs.size() == 1) + { + auto value = + exitFragment.registers->getRegister(*exitFragment.outputs.begin()) + .value; + exitFragment.builder.createReturnValue(value); + return; + } + + auto resultType = getResultType(); + + auto resultTypePointer = context->getBuilder().createTypePointer( + spv::StorageClass::Function, resultType); + + auto resultVariable = entryFragment.builder.createVariable( + resultTypePointer, spv::StorageClass::Function); + + std::uint32_t member = 0; + for (auto regId : exitFragment.outputs) + { + auto value = exitFragment.registers->getRegister(regId); + auto valueTypeId = context->getTypeIdOf(value.type); + + auto pointerType = + context->getPointerType(spv::StorageClass::Function, *valueTypeId); + auto valuePointer = exitFragment.builder.createAccessChain( + pointerType, resultVariable, + {{exitFragment.context->getUInt32(member++)}}); + + exitFragment.builder.createStore(valuePointer, value.value); + } + + auto resultValue = + exitFragment.builder.createLoad(resultType, resultVariable); + + exitFragment.builder.createReturnValue(resultValue); } diff --git a/hw/amdgpu/shader/src/Instruction.cpp b/hw/amdgpu/shader/src/Instruction.cpp index f85f0618..818eeb5b 100644 --- a/hw/amdgpu/shader/src/Instruction.cpp +++ b/hw/amdgpu/shader/src/Instruction.cpp @@ -1,2935 +1,3042 @@ #include "Instruction.hpp" #include -namespace { -using namespace amdgpu::shader; - -int printScalarOperand(int id, const std::uint32_t *inst) { - switch (id) { - case 0 ... 103: - std::printf("sgpr[%d]", id); - return 0; - case 106: - std::printf("VCC_LO"); - return 0; - case 107: - std::printf("VCC_HI"); - return 0; - case 124: - std::printf("M0"); - return 0; - case 126: - std::printf("EXEC_LO"); - return 0; - case 127: - std::printf("EXEC_HI"); - return 0; - case 128 ... 192: - std::printf("%d", id - 128); - return 0; - case 193 ... 208: - std::printf("%d", -static_cast(id - 192)); - return 0; - case 240: - std::printf("0.5"); - return 0; - case 241: - std::printf("-0.5"); - return 0; - case 242: - std::printf("1.0"); - return 0; - case 243: - std::printf("-1.0"); - return 0; - case 244: - std::printf("2.0"); - return 0; - case 245: - std::printf("-2.0"); - return 0; - case 246: - std::printf("4.0"); - return 0; - case 247: - std::printf("-4.0"); - return 0; - case 251: - std::printf("VCCZ"); - return 0; - case 252: - std::printf("EXECZ"); - return 0; - case 253: - std::printf("SCC"); - return 0; - case 254: - std::printf("LDS_DIRECT"); - return 0; - case 255: - std::printf("%08x", *inst); - return 1; - case 256 ... 511: - std::printf("vgpr[%u]", id - 256); - return 0; - } - - std::printf("", id); - return 0; -} - -int printVectorOperand(int id, const std::uint32_t *inst) { - std::printf("vgpr[%u]", id); - return 0; -} - -void printExpTarget(int target) { - switch (target) { - case 0 ... 7: - std::printf("mrt%u", target); - break; - case 8: - std::printf("mrtz"); - break; - case 9: - std::printf("null"); - break; - case 12 ... 15: - std::printf("pos%u", target - 12); - break; - case 32 ... 63: - std::printf("param%u", target - 32); - break; - - default: - std::printf("", target); - break; - } -} - -void printSop1Opcode(Sop1::Op op) { - if (auto string = sop1OpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printSop2Opcode(Sop2::Op op) { - if (auto string = sop2OpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printSopkOpcode(Sopk::Op op) { - if (auto string = sopkOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printSopcOpcode(Sopc::Op op) { - if (auto string = sopcOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printSoppOpcode(Sopp::Op op) { - if (auto string = soppOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printVop2Opcode(Vop2::Op op) { - if (auto string = vop2OpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printVop1Opcode(Vop1::Op op) { - if (auto string = vop1OpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printVopcOpcode(Vopc::Op op) { - if (auto string = vopcOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printVop3Opcode(Vop3::Op op) { - if (auto string = vop3OpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printSmrdOpcode(Smrd::Op op) { - if (auto string = smrdOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printMubufOpcode(Mubuf::Op op) { - if (auto string = mubufOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printMtbufOpcode(Mtbuf::Op op) { - if (auto string = mtbufOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printMimgOpcode(Mimg::Op op) { - if (auto string = mimgOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printDsOpcode(Ds::Op op) { - if (auto string = dsOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} - -void printVintrpOpcode(Vintrp::Op op) { - if (auto string = vintrpOpcodeToString(op)) { - std::printf("%s", string); - } else { - std::printf("", static_cast(op)); - } -} +namespace +{ + using namespace amdgpu::shader; + + int printScalarOperand(int id, const std::uint32_t* inst) + { + switch (id) + { + case 0 ... 103: + std::printf("sgpr[%d]", id); + return 0; + case 106: + std::printf("VCC_LO"); + return 0; + case 107: + std::printf("VCC_HI"); + return 0; + case 124: + std::printf("M0"); + return 0; + case 126: + std::printf("EXEC_LO"); + return 0; + case 127: + std::printf("EXEC_HI"); + return 0; + case 128 ... 192: + std::printf("%d", id - 128); + return 0; + case 193 ... 208: + std::printf("%d", -static_cast(id - 192)); + return 0; + case 240: + std::printf("0.5"); + return 0; + case 241: + std::printf("-0.5"); + return 0; + case 242: + std::printf("1.0"); + return 0; + case 243: + std::printf("-1.0"); + return 0; + case 244: + std::printf("2.0"); + return 0; + case 245: + std::printf("-2.0"); + return 0; + case 246: + std::printf("4.0"); + return 0; + case 247: + std::printf("-4.0"); + return 0; + case 251: + std::printf("VCCZ"); + return 0; + case 252: + std::printf("EXECZ"); + return 0; + case 253: + std::printf("SCC"); + return 0; + case 254: + std::printf("LDS_DIRECT"); + return 0; + case 255: + std::printf("%08x", *inst); + return 1; + case 256 ... 511: + std::printf("vgpr[%u]", id - 256); + return 0; + } + + std::printf("", id); + return 0; + } + + int printVectorOperand(int id, const std::uint32_t* inst) + { + std::printf("vgpr[%u]", id); + return 0; + } + + void printExpTarget(int target) + { + switch (target) + { + case 0 ... 7: + std::printf("mrt%u", target); + break; + case 8: + std::printf("mrtz"); + break; + case 9: + std::printf("null"); + break; + case 12 ... 15: + std::printf("pos%u", target - 12); + break; + case 32 ... 63: + std::printf("param%u", target - 32); + break; + + default: + std::printf("", target); + break; + } + } + + void printSop1Opcode(Sop1::Op op) + { + if (auto string = sop1OpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printSop2Opcode(Sop2::Op op) + { + if (auto string = sop2OpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printSopkOpcode(Sopk::Op op) + { + if (auto string = sopkOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printSopcOpcode(Sopc::Op op) + { + if (auto string = sopcOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printSoppOpcode(Sopp::Op op) + { + if (auto string = soppOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printVop2Opcode(Vop2::Op op) + { + if (auto string = vop2OpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printVop1Opcode(Vop1::Op op) + { + if (auto string = vop1OpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printVopcOpcode(Vopc::Op op) + { + if (auto string = vopcOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printVop3Opcode(Vop3::Op op) + { + if (auto string = vop3OpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printSmrdOpcode(Smrd::Op op) + { + if (auto string = smrdOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printMubufOpcode(Mubuf::Op op) + { + if (auto string = mubufOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printMtbufOpcode(Mtbuf::Op op) + { + if (auto string = mtbufOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printMimgOpcode(Mimg::Op op) + { + if (auto string = mimgOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printDsOpcode(Ds::Op op) + { + if (auto string = dsOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } + + void printVintrpOpcode(Vintrp::Op op) + { + if (auto string = vintrpOpcodeToString(op)) + { + std::printf("%s", string); + } + else + { + std::printf("", static_cast(op)); + } + } } // namespace -const char *amdgpu::shader::sop1OpcodeToString(Sop1::Op op) { - switch (op) { - case Sop1::Op::S_MOV_B32: - return "s_mov_b32"; - case Sop1::Op::S_MOV_B64: - return "s_mov_b64"; - case Sop1::Op::S_CMOV_B32: - return "s_cmov_b32"; - case Sop1::Op::S_CMOV_B64: - return "s_cmov_b64"; - case Sop1::Op::S_NOT_B32: - return "s_not_b32"; - case Sop1::Op::S_NOT_B64: - return "s_not_b64"; - case Sop1::Op::S_WQM_B32: - return "s_wqm_b32"; - case Sop1::Op::S_WQM_B64: - return "s_wqm_b64"; - case Sop1::Op::S_BREV_B32: - return "s_brev_b32"; - case Sop1::Op::S_BREV_B64: - return "s_brev_b64"; - case Sop1::Op::S_BCNT0_I32_B32: - return "s_bcnt0_i32_b32"; - case Sop1::Op::S_BCNT0_I32_B64: - return "s_bcnt0_i32_b64"; - case Sop1::Op::S_BCNT1_I32_B32: - return "s_bcnt1_i32_b32"; - case Sop1::Op::S_BCNT1_I32_B64: - return "s_bcnt1_i32_b64"; - case Sop1::Op::S_FF0_I32_B32: - return "s_ff0_i32_b32"; - case Sop1::Op::S_FF0_I32_B64: - return "s_ff0_i32_b64"; - case Sop1::Op::S_FF1_I32_B32: - return "s_ff1_i32_b32"; - case Sop1::Op::S_FF1_I32_B64: - return "s_ff1_i32_b64"; - case Sop1::Op::S_FLBIT_I32_B32: - return "s_flbit_i32_b32"; - case Sop1::Op::S_FLBIT_I32_B64: - return "s_flbit_i32_b64"; - case Sop1::Op::S_FLBIT_I32: - return "s_flbit_i32"; - case Sop1::Op::S_FLBIT_I32_I64: - return "s_flbit_i32_i64"; - case Sop1::Op::S_SEXT_I32_I8: - return "s_sext_i32_i8"; - case Sop1::Op::S_SEXT_I32_I16: - return "s_sext_i32_i16"; - case Sop1::Op::S_BITSET0_B32: - return "s_bitset0_b32"; - case Sop1::Op::S_BITSET0_B64: - return "s_bitset0_b64"; - case Sop1::Op::S_BITSET1_B32: - return "s_bitset1_b32"; - case Sop1::Op::S_BITSET1_B64: - return "s_bitset1_b64"; - case Sop1::Op::S_GETPC_B64: - return "s_getpc_b64"; - case Sop1::Op::S_SETPC_B64: - return "s_setpc_b64"; - case Sop1::Op::S_SWAPPC_B64: - return "s_swappc_b64"; - case Sop1::Op::S_RFE_B64: - return "s_rfe_b64"; - case Sop1::Op::S_AND_SAVEEXEC_B64: - return "s_and_saveexec_b64"; - case Sop1::Op::S_OR_SAVEEXEC_B64: - return "s_or_saveexec_b64"; - case Sop1::Op::S_XOR_SAVEEXEC_B64: - return "s_xor_saveexec_b64"; - case Sop1::Op::S_ANDN2_SAVEEXEC_B64: - return "s_andn2_saveexec_b64"; - case Sop1::Op::S_ORN2_SAVEEXEC_B64: - return "s_orn2_saveexec_b64"; - case Sop1::Op::S_NAND_SAVEEXEC_B64: - return "s_nand_saveexec_b64"; - case Sop1::Op::S_NOR_SAVEEXEC_B64: - return "s_nor_saveexec_b64"; - case Sop1::Op::S_XNOR_SAVEEXEC_B64: - return "s_xnor_saveexec_b64"; - case Sop1::Op::S_QUADMASK_B32: - return "s_quadmask_b32"; - case Sop1::Op::S_QUADMASK_B64: - return "s_quadmask_b64"; - case Sop1::Op::S_MOVRELS_B32: - return "s_movrels_b32"; - case Sop1::Op::S_MOVRELS_B64: - return "s_movrels_b64"; - case Sop1::Op::S_MOVRELD_B32: - return "s_movreld_b32"; - case Sop1::Op::S_MOVRELD_B64: - return "s_movreld_b64"; - case Sop1::Op::S_CBRANCH_JOIN: - return "s_cbranch_join"; - case Sop1::Op::S_ABS_I32: - return "s_abs_i32"; - case Sop1::Op::S_MOV_FED_B32: - return "s_mov_fed_b32"; - default: - return nullptr; - } +const char* amdgpu::shader::sop1OpcodeToString(Sop1::Op op) +{ + switch (op) + { + case Sop1::Op::S_MOV_B32: + return "s_mov_b32"; + case Sop1::Op::S_MOV_B64: + return "s_mov_b64"; + case Sop1::Op::S_CMOV_B32: + return "s_cmov_b32"; + case Sop1::Op::S_CMOV_B64: + return "s_cmov_b64"; + case Sop1::Op::S_NOT_B32: + return "s_not_b32"; + case Sop1::Op::S_NOT_B64: + return "s_not_b64"; + case Sop1::Op::S_WQM_B32: + return "s_wqm_b32"; + case Sop1::Op::S_WQM_B64: + return "s_wqm_b64"; + case Sop1::Op::S_BREV_B32: + return "s_brev_b32"; + case Sop1::Op::S_BREV_B64: + return "s_brev_b64"; + case Sop1::Op::S_BCNT0_I32_B32: + return "s_bcnt0_i32_b32"; + case Sop1::Op::S_BCNT0_I32_B64: + return "s_bcnt0_i32_b64"; + case Sop1::Op::S_BCNT1_I32_B32: + return "s_bcnt1_i32_b32"; + case Sop1::Op::S_BCNT1_I32_B64: + return "s_bcnt1_i32_b64"; + case Sop1::Op::S_FF0_I32_B32: + return "s_ff0_i32_b32"; + case Sop1::Op::S_FF0_I32_B64: + return "s_ff0_i32_b64"; + case Sop1::Op::S_FF1_I32_B32: + return "s_ff1_i32_b32"; + case Sop1::Op::S_FF1_I32_B64: + return "s_ff1_i32_b64"; + case Sop1::Op::S_FLBIT_I32_B32: + return "s_flbit_i32_b32"; + case Sop1::Op::S_FLBIT_I32_B64: + return "s_flbit_i32_b64"; + case Sop1::Op::S_FLBIT_I32: + return "s_flbit_i32"; + case Sop1::Op::S_FLBIT_I32_I64: + return "s_flbit_i32_i64"; + case Sop1::Op::S_SEXT_I32_I8: + return "s_sext_i32_i8"; + case Sop1::Op::S_SEXT_I32_I16: + return "s_sext_i32_i16"; + case Sop1::Op::S_BITSET0_B32: + return "s_bitset0_b32"; + case Sop1::Op::S_BITSET0_B64: + return "s_bitset0_b64"; + case Sop1::Op::S_BITSET1_B32: + return "s_bitset1_b32"; + case Sop1::Op::S_BITSET1_B64: + return "s_bitset1_b64"; + case Sop1::Op::S_GETPC_B64: + return "s_getpc_b64"; + case Sop1::Op::S_SETPC_B64: + return "s_setpc_b64"; + case Sop1::Op::S_SWAPPC_B64: + return "s_swappc_b64"; + case Sop1::Op::S_RFE_B64: + return "s_rfe_b64"; + case Sop1::Op::S_AND_SAVEEXEC_B64: + return "s_and_saveexec_b64"; + case Sop1::Op::S_OR_SAVEEXEC_B64: + return "s_or_saveexec_b64"; + case Sop1::Op::S_XOR_SAVEEXEC_B64: + return "s_xor_saveexec_b64"; + case Sop1::Op::S_ANDN2_SAVEEXEC_B64: + return "s_andn2_saveexec_b64"; + case Sop1::Op::S_ORN2_SAVEEXEC_B64: + return "s_orn2_saveexec_b64"; + case Sop1::Op::S_NAND_SAVEEXEC_B64: + return "s_nand_saveexec_b64"; + case Sop1::Op::S_NOR_SAVEEXEC_B64: + return "s_nor_saveexec_b64"; + case Sop1::Op::S_XNOR_SAVEEXEC_B64: + return "s_xnor_saveexec_b64"; + case Sop1::Op::S_QUADMASK_B32: + return "s_quadmask_b32"; + case Sop1::Op::S_QUADMASK_B64: + return "s_quadmask_b64"; + case Sop1::Op::S_MOVRELS_B32: + return "s_movrels_b32"; + case Sop1::Op::S_MOVRELS_B64: + return "s_movrels_b64"; + case Sop1::Op::S_MOVRELD_B32: + return "s_movreld_b32"; + case Sop1::Op::S_MOVRELD_B64: + return "s_movreld_b64"; + case Sop1::Op::S_CBRANCH_JOIN: + return "s_cbranch_join"; + case Sop1::Op::S_ABS_I32: + return "s_abs_i32"; + case Sop1::Op::S_MOV_FED_B32: + return "s_mov_fed_b32"; + default: + return nullptr; + } } -const char *amdgpu::shader::sop2OpcodeToString(Sop2::Op op) { - switch (op) { - case Sop2::Op::S_ADD_U32: - return "s_add_u32"; - case Sop2::Op::S_SUB_U32: - return "s_sub_u32"; - case Sop2::Op::S_ADD_I32: - return "s_add_i32"; - case Sop2::Op::S_SUB_I32: - return "s_sub_i32"; - case Sop2::Op::S_ADDC_U32: - return "s_addc_u32"; - case Sop2::Op::S_SUBB_U32: - return "s_subb_u32"; - case Sop2::Op::S_MIN_I32: - return "s_min_i32"; - case Sop2::Op::S_MIN_U32: - return "s_min_u32"; - case Sop2::Op::S_MAX_I32: - return "s_max_i32"; - case Sop2::Op::S_MAX_U32: - return "s_max_u32"; - case Sop2::Op::S_CSELECT_B32: - return "s_cselect_b32"; - case Sop2::Op::S_CSELECT_B64: - return "s_cselect_b64"; - case Sop2::Op::S_AND_B32: - return "s_and_b32"; - case Sop2::Op::S_AND_B64: - return "s_and_b64"; - case Sop2::Op::S_OR_B32: - return "s_or_b32"; - case Sop2::Op::S_OR_B64: - return "s_or_b64"; - case Sop2::Op::S_XOR_B32: - return "s_xor_b32"; - case Sop2::Op::S_XOR_B64: - return "s_xor_b64"; - case Sop2::Op::S_ANDN2_B32: - return "s_andn2_b32"; - case Sop2::Op::S_ANDN2_B64: - return "s_andn2_b64"; - case Sop2::Op::S_ORN2_B32: - return "s_orn2_b32"; - case Sop2::Op::S_ORN2_B64: - return "s_orn2_b64"; - case Sop2::Op::S_NAND_B32: - return "s_nand_b32"; - case Sop2::Op::S_NAND_B64: - return "s_nand_b64"; - case Sop2::Op::S_NOR_B32: - return "s_nor_b32"; - case Sop2::Op::S_NOR_B64: - return "s_nor_b64"; - case Sop2::Op::S_XNOR_B32: - return "s_xnor_b32"; - case Sop2::Op::S_XNOR_B64: - return "s_xnor_b64"; - case Sop2::Op::S_LSHL_B32: - return "s_lshl_b32"; - case Sop2::Op::S_LSHL_B64: - return "s_lshl_b64"; - case Sop2::Op::S_LSHR_B32: - return "s_lshr_b32"; - case Sop2::Op::S_LSHR_B64: - return "s_lshr_b64"; - case Sop2::Op::S_ASHR_I32: - return "s_ashr_i32"; - case Sop2::Op::S_ASHR_I64: - return "s_ashr_i64"; - case Sop2::Op::S_BFM_B32: - return "s_bfm_b32"; - case Sop2::Op::S_BFM_B64: - return "s_bfm_b64"; - case Sop2::Op::S_MUL_I32: - return "s_mul_i32"; - case Sop2::Op::S_BFE_U32: - return "s_bfe_u32"; - case Sop2::Op::S_BFE_I32: - return "s_bfe_i32"; - case Sop2::Op::S_BFE_U64: - return "s_bfe_u64"; - case Sop2::Op::S_BFE_I64: - return "s_bfe_i64"; - case Sop2::Op::S_CBRANCH_G_FORK: - return "s_cbranch_g_fork"; - case Sop2::Op::S_ABSDIFF_I32: - return "s_absdiff_i32"; - default: - return nullptr; - } +const char* amdgpu::shader::sop2OpcodeToString(Sop2::Op op) +{ + switch (op) + { + case Sop2::Op::S_ADD_U32: + return "s_add_u32"; + case Sop2::Op::S_SUB_U32: + return "s_sub_u32"; + case Sop2::Op::S_ADD_I32: + return "s_add_i32"; + case Sop2::Op::S_SUB_I32: + return "s_sub_i32"; + case Sop2::Op::S_ADDC_U32: + return "s_addc_u32"; + case Sop2::Op::S_SUBB_U32: + return "s_subb_u32"; + case Sop2::Op::S_MIN_I32: + return "s_min_i32"; + case Sop2::Op::S_MIN_U32: + return "s_min_u32"; + case Sop2::Op::S_MAX_I32: + return "s_max_i32"; + case Sop2::Op::S_MAX_U32: + return "s_max_u32"; + case Sop2::Op::S_CSELECT_B32: + return "s_cselect_b32"; + case Sop2::Op::S_CSELECT_B64: + return "s_cselect_b64"; + case Sop2::Op::S_AND_B32: + return "s_and_b32"; + case Sop2::Op::S_AND_B64: + return "s_and_b64"; + case Sop2::Op::S_OR_B32: + return "s_or_b32"; + case Sop2::Op::S_OR_B64: + return "s_or_b64"; + case Sop2::Op::S_XOR_B32: + return "s_xor_b32"; + case Sop2::Op::S_XOR_B64: + return "s_xor_b64"; + case Sop2::Op::S_ANDN2_B32: + return "s_andn2_b32"; + case Sop2::Op::S_ANDN2_B64: + return "s_andn2_b64"; + case Sop2::Op::S_ORN2_B32: + return "s_orn2_b32"; + case Sop2::Op::S_ORN2_B64: + return "s_orn2_b64"; + case Sop2::Op::S_NAND_B32: + return "s_nand_b32"; + case Sop2::Op::S_NAND_B64: + return "s_nand_b64"; + case Sop2::Op::S_NOR_B32: + return "s_nor_b32"; + case Sop2::Op::S_NOR_B64: + return "s_nor_b64"; + case Sop2::Op::S_XNOR_B32: + return "s_xnor_b32"; + case Sop2::Op::S_XNOR_B64: + return "s_xnor_b64"; + case Sop2::Op::S_LSHL_B32: + return "s_lshl_b32"; + case Sop2::Op::S_LSHL_B64: + return "s_lshl_b64"; + case Sop2::Op::S_LSHR_B32: + return "s_lshr_b32"; + case Sop2::Op::S_LSHR_B64: + return "s_lshr_b64"; + case Sop2::Op::S_ASHR_I32: + return "s_ashr_i32"; + case Sop2::Op::S_ASHR_I64: + return "s_ashr_i64"; + case Sop2::Op::S_BFM_B32: + return "s_bfm_b32"; + case Sop2::Op::S_BFM_B64: + return "s_bfm_b64"; + case Sop2::Op::S_MUL_I32: + return "s_mul_i32"; + case Sop2::Op::S_BFE_U32: + return "s_bfe_u32"; + case Sop2::Op::S_BFE_I32: + return "s_bfe_i32"; + case Sop2::Op::S_BFE_U64: + return "s_bfe_u64"; + case Sop2::Op::S_BFE_I64: + return "s_bfe_i64"; + case Sop2::Op::S_CBRANCH_G_FORK: + return "s_cbranch_g_fork"; + case Sop2::Op::S_ABSDIFF_I32: + return "s_absdiff_i32"; + default: + return nullptr; + } } -const char *amdgpu::shader::sopkOpcodeToString(Sopk::Op op) { - switch (op) { - case Sopk::Op::S_MOVK_I32: - return "s_movk_i32"; - case Sopk::Op::S_CMOVK_I32: - return "s_cmovk_i32"; - case Sopk::Op::S_CMPK_EQ_I32: - return "s_cmpk_eq_i32"; - case Sopk::Op::S_CMPK_LG_I32: - return "s_cmpk_lg_i32"; - case Sopk::Op::S_CMPK_GT_I32: - return "s_cmpk_gt_i32"; - case Sopk::Op::S_CMPK_GE_I32: - return "s_cmpk_ge_i32"; - case Sopk::Op::S_CMPK_LT_I32: - return "s_cmpk_lt_i32"; - case Sopk::Op::S_CMPK_LE_I32: - return "s_cmpk_le_i32"; - case Sopk::Op::S_CMPK_EQ_U32: - return "s_cmpk_eq_u32"; - case Sopk::Op::S_CMPK_LG_U32: - return "s_cmpk_lg_u32"; - case Sopk::Op::S_CMPK_GT_U32: - return "s_cmpk_gt_u32"; - case Sopk::Op::S_CMPK_GE_U32: - return "s_cmpk_ge_u32"; - case Sopk::Op::S_CMPK_LT_U32: - return "s_cmpk_lt_u32"; - case Sopk::Op::S_CMPK_LE_U32: - return "s_cmpk_le_u32"; - case Sopk::Op::S_ADDK_I32: - return "s_addk_i32"; - case Sopk::Op::S_MULK_I32: - return "s_mulk_i32"; - case Sopk::Op::S_CBRANCH_I_FORK: - return "s_cbranch_i_fork"; - case Sopk::Op::S_GETREG_B32: - return "s_getreg_b32"; - case Sopk::Op::S_SETREG_B32: - return "s_setreg_b32"; - case Sopk::Op::S_SETREG_IMM: - return "s_setreg_imm"; - default: - return nullptr; - } +const char* amdgpu::shader::sopkOpcodeToString(Sopk::Op op) +{ + switch (op) + { + case Sopk::Op::S_MOVK_I32: + return "s_movk_i32"; + case Sopk::Op::S_CMOVK_I32: + return "s_cmovk_i32"; + case Sopk::Op::S_CMPK_EQ_I32: + return "s_cmpk_eq_i32"; + case Sopk::Op::S_CMPK_LG_I32: + return "s_cmpk_lg_i32"; + case Sopk::Op::S_CMPK_GT_I32: + return "s_cmpk_gt_i32"; + case Sopk::Op::S_CMPK_GE_I32: + return "s_cmpk_ge_i32"; + case Sopk::Op::S_CMPK_LT_I32: + return "s_cmpk_lt_i32"; + case Sopk::Op::S_CMPK_LE_I32: + return "s_cmpk_le_i32"; + case Sopk::Op::S_CMPK_EQ_U32: + return "s_cmpk_eq_u32"; + case Sopk::Op::S_CMPK_LG_U32: + return "s_cmpk_lg_u32"; + case Sopk::Op::S_CMPK_GT_U32: + return "s_cmpk_gt_u32"; + case Sopk::Op::S_CMPK_GE_U32: + return "s_cmpk_ge_u32"; + case Sopk::Op::S_CMPK_LT_U32: + return "s_cmpk_lt_u32"; + case Sopk::Op::S_CMPK_LE_U32: + return "s_cmpk_le_u32"; + case Sopk::Op::S_ADDK_I32: + return "s_addk_i32"; + case Sopk::Op::S_MULK_I32: + return "s_mulk_i32"; + case Sopk::Op::S_CBRANCH_I_FORK: + return "s_cbranch_i_fork"; + case Sopk::Op::S_GETREG_B32: + return "s_getreg_b32"; + case Sopk::Op::S_SETREG_B32: + return "s_setreg_b32"; + case Sopk::Op::S_SETREG_IMM: + return "s_setreg_imm"; + default: + return nullptr; + } } -const char *amdgpu::shader::sopcOpcodeToString(Sopc::Op op) { - switch (op) { - case Sopc::Op::S_CMP_EQ_I32: - return "s_cmp_eq_i32"; - case Sopc::Op::S_CMP_LG_I32: - return "s_cmp_lg_i32"; - case Sopc::Op::S_CMP_GT_I32: - return "s_cmp_gt_i32"; - case Sopc::Op::S_CMP_GE_I32: - return "s_cmp_ge_i32"; - case Sopc::Op::S_CMP_LT_I32: - return "s_cmp_lt_i32"; - case Sopc::Op::S_CMP_LE_I32: - return "s_cmp_le_i32"; - case Sopc::Op::S_CMP_EQ_U32: - return "s_cmp_eq_u32"; - case Sopc::Op::S_CMP_LG_U32: - return "s_cmp_lg_u32"; - case Sopc::Op::S_CMP_GT_U32: - return "s_cmp_gt_u32"; - case Sopc::Op::S_CMP_GE_U32: - return "s_cmp_ge_u32"; - case Sopc::Op::S_CMP_LT_U32: - return "s_cmp_lt_u32"; - case Sopc::Op::S_CMP_LE_U32: - return "s_cmp_le_u32"; - case Sopc::Op::S_BITCMP0_B32: - return "s_bitcmp0_b32"; - case Sopc::Op::S_BITCMP1_B32: - return "s_bitcmp1_b32"; - case Sopc::Op::S_BITCMP0_B64: - return "s_bitcmp0_b64"; - case Sopc::Op::S_BITCMP1_B64: - return "s_bitcmp1_b64"; - case Sopc::Op::S_SETVSKIP: - return "s_setvskip"; - default: - return nullptr; - } +const char* amdgpu::shader::sopcOpcodeToString(Sopc::Op op) +{ + switch (op) + { + case Sopc::Op::S_CMP_EQ_I32: + return "s_cmp_eq_i32"; + case Sopc::Op::S_CMP_LG_I32: + return "s_cmp_lg_i32"; + case Sopc::Op::S_CMP_GT_I32: + return "s_cmp_gt_i32"; + case Sopc::Op::S_CMP_GE_I32: + return "s_cmp_ge_i32"; + case Sopc::Op::S_CMP_LT_I32: + return "s_cmp_lt_i32"; + case Sopc::Op::S_CMP_LE_I32: + return "s_cmp_le_i32"; + case Sopc::Op::S_CMP_EQ_U32: + return "s_cmp_eq_u32"; + case Sopc::Op::S_CMP_LG_U32: + return "s_cmp_lg_u32"; + case Sopc::Op::S_CMP_GT_U32: + return "s_cmp_gt_u32"; + case Sopc::Op::S_CMP_GE_U32: + return "s_cmp_ge_u32"; + case Sopc::Op::S_CMP_LT_U32: + return "s_cmp_lt_u32"; + case Sopc::Op::S_CMP_LE_U32: + return "s_cmp_le_u32"; + case Sopc::Op::S_BITCMP0_B32: + return "s_bitcmp0_b32"; + case Sopc::Op::S_BITCMP1_B32: + return "s_bitcmp1_b32"; + case Sopc::Op::S_BITCMP0_B64: + return "s_bitcmp0_b64"; + case Sopc::Op::S_BITCMP1_B64: + return "s_bitcmp1_b64"; + case Sopc::Op::S_SETVSKIP: + return "s_setvskip"; + default: + return nullptr; + } } -const char *amdgpu::shader::soppOpcodeToString(Sopp::Op op) { - switch (op) { - case Sopp::Op::S_NOP: - return "s_nop"; - case Sopp::Op::S_ENDPGM: - return "s_endpgm"; - case Sopp::Op::S_BRANCH: - return "s_branch"; - case Sopp::Op::S_CBRANCH_SCC0: - return "s_cbranch_scc0"; - case Sopp::Op::S_CBRANCH_SCC1: - return "s_cbranch_scc1"; - case Sopp::Op::S_CBRANCH_VCCZ: - return "s_cbranch_vccz"; - case Sopp::Op::S_CBRANCH_VCCNZ: - return "s_cbranch_vccnz"; - case Sopp::Op::S_CBRANCH_EXECZ: - return "s_cbranch_execz"; - case Sopp::Op::S_CBRANCH_EXECNZ: - return "s_cbranch_execnz"; - case Sopp::Op::S_BARRIER: - return "s_barrier"; - case Sopp::Op::S_WAITCNT: - return "s_waitcnt"; - case Sopp::Op::S_SETHALT: - return "s_sethalt"; - case Sopp::Op::S_SLEEP: - return "s_sleep"; - case Sopp::Op::S_SETPRIO: - return "s_setprio"; - case Sopp::Op::S_SENDMSG: - return "s_sendmsg"; - case Sopp::Op::S_SENDMSGHALT: - return "s_sendmsghalt"; - case Sopp::Op::S_TRAP: - return "s_trap"; - case Sopp::Op::S_ICACHE_INV: - return "s_icache_inv"; - case Sopp::Op::S_INCPERFLEVEL: - return "s_incperflevel"; - case Sopp::Op::S_DECPERFLEVEL: - return "s_decperflevel"; - case Sopp::Op::S_TTRACEDATA: - return "s_ttracedata"; - case Sopp::Op::S_CBRANCH_CDBGSYS: - return "s_cbranch_cdbgsys"; - case Sopp::Op::S_CBRANCH_CDBGUSER: - return "s_cbranch_cdbguser"; - case Sopp::Op::S_CBRANCH_CDBGSYS_OR_USER: - return "s_cbranch_cdbgsys_or_user"; - case Sopp::Op::S_CBRANCH_CDBGSYS_AND_USER: - return "s_cbranch_cdbgsys_and_user"; - default: - return nullptr; - } +const char* amdgpu::shader::soppOpcodeToString(Sopp::Op op) +{ + switch (op) + { + case Sopp::Op::S_NOP: + return "s_nop"; + case Sopp::Op::S_ENDPGM: + return "s_endpgm"; + case Sopp::Op::S_BRANCH: + return "s_branch"; + case Sopp::Op::S_CBRANCH_SCC0: + return "s_cbranch_scc0"; + case Sopp::Op::S_CBRANCH_SCC1: + return "s_cbranch_scc1"; + case Sopp::Op::S_CBRANCH_VCCZ: + return "s_cbranch_vccz"; + case Sopp::Op::S_CBRANCH_VCCNZ: + return "s_cbranch_vccnz"; + case Sopp::Op::S_CBRANCH_EXECZ: + return "s_cbranch_execz"; + case Sopp::Op::S_CBRANCH_EXECNZ: + return "s_cbranch_execnz"; + case Sopp::Op::S_BARRIER: + return "s_barrier"; + case Sopp::Op::S_WAITCNT: + return "s_waitcnt"; + case Sopp::Op::S_SETHALT: + return "s_sethalt"; + case Sopp::Op::S_SLEEP: + return "s_sleep"; + case Sopp::Op::S_SETPRIO: + return "s_setprio"; + case Sopp::Op::S_SENDMSG: + return "s_sendmsg"; + case Sopp::Op::S_SENDMSGHALT: + return "s_sendmsghalt"; + case Sopp::Op::S_TRAP: + return "s_trap"; + case Sopp::Op::S_ICACHE_INV: + return "s_icache_inv"; + case Sopp::Op::S_INCPERFLEVEL: + return "s_incperflevel"; + case Sopp::Op::S_DECPERFLEVEL: + return "s_decperflevel"; + case Sopp::Op::S_TTRACEDATA: + return "s_ttracedata"; + case Sopp::Op::S_CBRANCH_CDBGSYS: + return "s_cbranch_cdbgsys"; + case Sopp::Op::S_CBRANCH_CDBGUSER: + return "s_cbranch_cdbguser"; + case Sopp::Op::S_CBRANCH_CDBGSYS_OR_USER: + return "s_cbranch_cdbgsys_or_user"; + case Sopp::Op::S_CBRANCH_CDBGSYS_AND_USER: + return "s_cbranch_cdbgsys_and_user"; + default: + return nullptr; + } } -const char *amdgpu::shader::vop2OpcodeToString(Vop2::Op op) { - switch (op) { - case Vop2::Op::V_CNDMASK_B32: - return "v_cndmask_b32"; - case Vop2::Op::V_READLANE_B32: - return "v_readlane_b32"; - case Vop2::Op::V_WRITELANE_B32: - return "v_writelane_b32"; - case Vop2::Op::V_ADD_F32: - return "v_add_f32"; - case Vop2::Op::V_SUB_F32: - return "v_sub_f32"; - case Vop2::Op::V_SUBREV_F32: - return "v_subrev_f32"; - case Vop2::Op::V_MAC_LEGACY_F32: - return "v_mac_legacy_f32"; - case Vop2::Op::V_MUL_LEGACY_F32: - return "v_mul_legacy_f32"; - case Vop2::Op::V_MUL_F32: - return "v_mul_f32"; - case Vop2::Op::V_MUL_I32_I24: - return "v_mul_i32_i24"; - case Vop2::Op::V_MUL_HI_I32_I24: - return "v_mul_hi_i32_i24"; - case Vop2::Op::V_MUL_U32_U24: - return "v_mul_u32_u24"; - case Vop2::Op::V_MUL_HI_U32_U24: - return "v_mul_hi_u32_u24"; - case Vop2::Op::V_MIN_LEGACY_F32: - return "v_min_legacy_f32"; - case Vop2::Op::V_MAX_LEGACY_F32: - return "v_max_legacy_f32"; - case Vop2::Op::V_MIN_F32: - return "v_min_f32"; - case Vop2::Op::V_MAX_F32: - return "v_max_f32"; - case Vop2::Op::V_MIN_I32: - return "v_min_i32"; - case Vop2::Op::V_MAX_I32: - return "v_max_i32"; - case Vop2::Op::V_MIN_U32: - return "v_min_u32"; - case Vop2::Op::V_MAX_U32: - return "v_max_u32"; - case Vop2::Op::V_LSHR_B32: - return "v_lshr_b32"; - case Vop2::Op::V_LSHRREV_B32: - return "v_lshrrev_b32"; - case Vop2::Op::V_ASHR_I32: - return "v_ashr_i32"; - case Vop2::Op::V_ASHRREV_I32: - return "v_ashrrev_i32"; - case Vop2::Op::V_LSHL_B32: - return "v_lshl_b32"; - case Vop2::Op::V_LSHLREV_B32: - return "v_lshlrev_b32"; - case Vop2::Op::V_AND_B32: - return "v_and_b32"; - case Vop2::Op::V_OR_B32: - return "v_or_b32"; - case Vop2::Op::V_XOR_B32: - return "v_xor_b32"; - case Vop2::Op::V_BFM_B32: - return "v_bfm_b32"; - case Vop2::Op::V_MAC_F32: - return "v_mac_f32"; - case Vop2::Op::V_MADMK_F32: - return "v_madmk_f32"; - case Vop2::Op::V_MADAK_F32: - return "v_madak_f32"; - case Vop2::Op::V_BCNT_U32_B32: - return "v_bcnt_u32_b32"; - case Vop2::Op::V_MBCNT_LO_U32_B32: - return "v_mbcnt_lo_u32_b32"; - case Vop2::Op::V_MBCNT_HI_U32_B32: - return "v_mbcnt_hi_u32_b32"; - case Vop2::Op::V_ADD_I32: - return "v_add_i32"; - case Vop2::Op::V_SUB_I32: - return "v_sub_i32"; - case Vop2::Op::V_SUBREV_I32: - return "v_subrev_i32"; - case Vop2::Op::V_ADDC_U32: - return "v_addc_u32"; - case Vop2::Op::V_SUBB_U32: - return "v_subb_u32"; - case Vop2::Op::V_SUBBREV_U32: - return "v_subbrev_u32"; - case Vop2::Op::V_LDEXP_F32: - return "v_ldexp_f32"; - case Vop2::Op::V_CVT_PKACCUM_U8_F32: - return "v_cvt_pkaccum_u8_f32"; - case Vop2::Op::V_CVT_PKNORM_I16_F32: - return "v_cvt_pknorm_i16_f32"; - case Vop2::Op::V_CVT_PKNORM_U16_F32: - return "v_cvt_pknorm_u16_f32"; - case Vop2::Op::V_CVT_PKRTZ_F16_F32: - return "v_cvt_pkrtz_f16_f32"; - case Vop2::Op::V_CVT_PK_U16_U32: - return "v_cvt_pk_u16_u32"; - case Vop2::Op::V_CVT_PK_I16_I32: - return "v_cvt_pk_i16_i32"; - default: - return nullptr; - } +const char* amdgpu::shader::vop2OpcodeToString(Vop2::Op op) +{ + switch (op) + { + case Vop2::Op::V_CNDMASK_B32: + return "v_cndmask_b32"; + case Vop2::Op::V_READLANE_B32: + return "v_readlane_b32"; + case Vop2::Op::V_WRITELANE_B32: + return "v_writelane_b32"; + case Vop2::Op::V_ADD_F32: + return "v_add_f32"; + case Vop2::Op::V_SUB_F32: + return "v_sub_f32"; + case Vop2::Op::V_SUBREV_F32: + return "v_subrev_f32"; + case Vop2::Op::V_MAC_LEGACY_F32: + return "v_mac_legacy_f32"; + case Vop2::Op::V_MUL_LEGACY_F32: + return "v_mul_legacy_f32"; + case Vop2::Op::V_MUL_F32: + return "v_mul_f32"; + case Vop2::Op::V_MUL_I32_I24: + return "v_mul_i32_i24"; + case Vop2::Op::V_MUL_HI_I32_I24: + return "v_mul_hi_i32_i24"; + case Vop2::Op::V_MUL_U32_U24: + return "v_mul_u32_u24"; + case Vop2::Op::V_MUL_HI_U32_U24: + return "v_mul_hi_u32_u24"; + case Vop2::Op::V_MIN_LEGACY_F32: + return "v_min_legacy_f32"; + case Vop2::Op::V_MAX_LEGACY_F32: + return "v_max_legacy_f32"; + case Vop2::Op::V_MIN_F32: + return "v_min_f32"; + case Vop2::Op::V_MAX_F32: + return "v_max_f32"; + case Vop2::Op::V_MIN_I32: + return "v_min_i32"; + case Vop2::Op::V_MAX_I32: + return "v_max_i32"; + case Vop2::Op::V_MIN_U32: + return "v_min_u32"; + case Vop2::Op::V_MAX_U32: + return "v_max_u32"; + case Vop2::Op::V_LSHR_B32: + return "v_lshr_b32"; + case Vop2::Op::V_LSHRREV_B32: + return "v_lshrrev_b32"; + case Vop2::Op::V_ASHR_I32: + return "v_ashr_i32"; + case Vop2::Op::V_ASHRREV_I32: + return "v_ashrrev_i32"; + case Vop2::Op::V_LSHL_B32: + return "v_lshl_b32"; + case Vop2::Op::V_LSHLREV_B32: + return "v_lshlrev_b32"; + case Vop2::Op::V_AND_B32: + return "v_and_b32"; + case Vop2::Op::V_OR_B32: + return "v_or_b32"; + case Vop2::Op::V_XOR_B32: + return "v_xor_b32"; + case Vop2::Op::V_BFM_B32: + return "v_bfm_b32"; + case Vop2::Op::V_MAC_F32: + return "v_mac_f32"; + case Vop2::Op::V_MADMK_F32: + return "v_madmk_f32"; + case Vop2::Op::V_MADAK_F32: + return "v_madak_f32"; + case Vop2::Op::V_BCNT_U32_B32: + return "v_bcnt_u32_b32"; + case Vop2::Op::V_MBCNT_LO_U32_B32: + return "v_mbcnt_lo_u32_b32"; + case Vop2::Op::V_MBCNT_HI_U32_B32: + return "v_mbcnt_hi_u32_b32"; + case Vop2::Op::V_ADD_I32: + return "v_add_i32"; + case Vop2::Op::V_SUB_I32: + return "v_sub_i32"; + case Vop2::Op::V_SUBREV_I32: + return "v_subrev_i32"; + case Vop2::Op::V_ADDC_U32: + return "v_addc_u32"; + case Vop2::Op::V_SUBB_U32: + return "v_subb_u32"; + case Vop2::Op::V_SUBBREV_U32: + return "v_subbrev_u32"; + case Vop2::Op::V_LDEXP_F32: + return "v_ldexp_f32"; + case Vop2::Op::V_CVT_PKACCUM_U8_F32: + return "v_cvt_pkaccum_u8_f32"; + case Vop2::Op::V_CVT_PKNORM_I16_F32: + return "v_cvt_pknorm_i16_f32"; + case Vop2::Op::V_CVT_PKNORM_U16_F32: + return "v_cvt_pknorm_u16_f32"; + case Vop2::Op::V_CVT_PKRTZ_F16_F32: + return "v_cvt_pkrtz_f16_f32"; + case Vop2::Op::V_CVT_PK_U16_U32: + return "v_cvt_pk_u16_u32"; + case Vop2::Op::V_CVT_PK_I16_I32: + return "v_cvt_pk_i16_i32"; + default: + return nullptr; + } } -const char *amdgpu::shader::vop1OpcodeToString(Vop1::Op op) { - switch (op) { - case Vop1::Op::V_NOP: - return "v_nop"; - case Vop1::Op::V_MOV_B32: - return "v_mov_b32"; - case Vop1::Op::V_READFIRSTLANE_B32: - return "v_readfirstlane_b32"; - case Vop1::Op::V_CVT_I32_F64: - return "v_cvt_i32_f64"; - case Vop1::Op::V_CVT_F64_I32: - return "v_cvt_f64_i32"; - case Vop1::Op::V_CVT_F32_I32: - return "v_cvt_f32_i32"; - case Vop1::Op::V_CVT_F32_U32: - return "v_cvt_f32_u32"; - case Vop1::Op::V_CVT_U32_F32: - return "v_cvt_u32_f32"; - case Vop1::Op::V_CVT_I32_F32: - return "v_cvt_i32_f32"; - case Vop1::Op::V_MOV_FED_B32: - return "v_mov_fed_b32"; - case Vop1::Op::V_CVT_F16_F32: - return "v_cvt_f16_f32"; - case Vop1::Op::V_CVT_F32_F16: - return "v_cvt_f32_f16"; - case Vop1::Op::V_CVT_RPI_I32_F32: - return "v_cvt_rpi_i32_f32"; - case Vop1::Op::V_CVT_FLR_I32_F32: - return "v_cvt_flr_i32_f32"; - case Vop1::Op::V_CVT_OFF_F32_I4: - return "v_cvt_off_f32_i4"; - case Vop1::Op::V_CVT_F32_F64: - return "v_cvt_f32_f64"; - case Vop1::Op::V_CVT_F64_F32: - return "v_cvt_f64_f32"; - case Vop1::Op::V_CVT_F32_UBYTE0: - return "v_cvt_f32_ubyte0"; - case Vop1::Op::V_CVT_F32_UBYTE1: - return "v_cvt_f32_ubyte1"; - case Vop1::Op::V_CVT_F32_UBYTE2: - return "v_cvt_f32_ubyte2"; - case Vop1::Op::V_CVT_F32_UBYTE3: - return "v_cvt_f32_ubyte3"; - case Vop1::Op::V_CVT_U32_F64: - return "v_cvt_u32_f64"; - case Vop1::Op::V_CVT_F64_U32: - return "v_cvt_f64_u32"; - case Vop1::Op::V_FRACT_F32: - return "v_fract_f32"; - case Vop1::Op::V_TRUNC_F32: - return "v_trunc_f32"; - case Vop1::Op::V_CEIL_F32: - return "v_ceil_f32"; - case Vop1::Op::V_RNDNE_F32: - return "v_rndne_f32"; - case Vop1::Op::V_FLOOR_F32: - return "v_floor_f32"; - case Vop1::Op::V_EXP_F32: - return "v_exp_f32"; - case Vop1::Op::V_LOG_CLAMP_F32: - return "v_log_clamp_f32"; - case Vop1::Op::V_LOG_F32: - return "v_log_f32"; - case Vop1::Op::V_RCP_CLAMP_F32: - return "v_rcp_clamp_f32"; - case Vop1::Op::V_RCP_LEGACY_F32: - return "v_rcp_legacy_f32"; - case Vop1::Op::V_RCP_F32: - return "v_rcp_f32"; - case Vop1::Op::V_RCP_IFLAG_F32: - return "v_rcp_iflag_f32"; - case Vop1::Op::V_RSQ_CLAMP_F32: - return "v_rsq_clamp_f32"; - case Vop1::Op::V_RSQ_LEGACY_F32: - return "v_rsq_legacy_f32"; - case Vop1::Op::V_RSQ_F32: - return "v_rsq_f32"; - case Vop1::Op::V_RCP_F64: - return "v_rcp_f64"; - case Vop1::Op::V_RCP_CLAMP_F64: - return "v_rcp_clamp_f64"; - case Vop1::Op::V_RSQ_F64: - return "v_rsq_f64"; - case Vop1::Op::V_RSQ_CLAMP_F64: - return "v_rsq_clamp_f64"; - case Vop1::Op::V_SQRT_F32: - return "v_sqrt_f32"; - case Vop1::Op::V_SQRT_F64: - return "v_sqrt_f64"; - case Vop1::Op::V_SIN_F32: - return "v_sin_f32"; - case Vop1::Op::V_COS_F32: - return "v_cos_f32"; - case Vop1::Op::V_NOT_B32: - return "v_not_b32"; - case Vop1::Op::V_BFREV_B32: - return "v_bfrev_b32"; - case Vop1::Op::V_FFBH_U32: - return "v_ffbh_u32"; - case Vop1::Op::V_FFBL_B32: - return "v_ffbl_b32"; - case Vop1::Op::V_FFBH_I32: - return "v_ffbh_i32"; - case Vop1::Op::V_FREXP_EXP_I32_F64: - return "v_frexp_exp_i32_f64"; - case Vop1::Op::V_FREXP_MANT_F64: - return "v_frexp_mant_f64"; - case Vop1::Op::V_FRACT_F64: - return "v_fract_f64"; - case Vop1::Op::V_FREXP_EXP_I32_F32: - return "v_frexp_exp_i32_f32"; - case Vop1::Op::V_FREXP_MANT_F32: - return "v_frexp_mant_f32"; - case Vop1::Op::V_CLREXCP: - return "v_clrexcp"; - case Vop1::Op::V_MOVRELD_B32: - return "v_movreld_b32"; - case Vop1::Op::V_MOVRELS_B32: - return "v_movrels_b32"; - case Vop1::Op::V_MOVRELSD_B32: - return "v_movrelsd_b32"; - default: - return nullptr; - } +const char* amdgpu::shader::vop1OpcodeToString(Vop1::Op op) +{ + switch (op) + { + case Vop1::Op::V_NOP: + return "v_nop"; + case Vop1::Op::V_MOV_B32: + return "v_mov_b32"; + case Vop1::Op::V_READFIRSTLANE_B32: + return "v_readfirstlane_b32"; + case Vop1::Op::V_CVT_I32_F64: + return "v_cvt_i32_f64"; + case Vop1::Op::V_CVT_F64_I32: + return "v_cvt_f64_i32"; + case Vop1::Op::V_CVT_F32_I32: + return "v_cvt_f32_i32"; + case Vop1::Op::V_CVT_F32_U32: + return "v_cvt_f32_u32"; + case Vop1::Op::V_CVT_U32_F32: + return "v_cvt_u32_f32"; + case Vop1::Op::V_CVT_I32_F32: + return "v_cvt_i32_f32"; + case Vop1::Op::V_MOV_FED_B32: + return "v_mov_fed_b32"; + case Vop1::Op::V_CVT_F16_F32: + return "v_cvt_f16_f32"; + case Vop1::Op::V_CVT_F32_F16: + return "v_cvt_f32_f16"; + case Vop1::Op::V_CVT_RPI_I32_F32: + return "v_cvt_rpi_i32_f32"; + case Vop1::Op::V_CVT_FLR_I32_F32: + return "v_cvt_flr_i32_f32"; + case Vop1::Op::V_CVT_OFF_F32_I4: + return "v_cvt_off_f32_i4"; + case Vop1::Op::V_CVT_F32_F64: + return "v_cvt_f32_f64"; + case Vop1::Op::V_CVT_F64_F32: + return "v_cvt_f64_f32"; + case Vop1::Op::V_CVT_F32_UBYTE0: + return "v_cvt_f32_ubyte0"; + case Vop1::Op::V_CVT_F32_UBYTE1: + return "v_cvt_f32_ubyte1"; + case Vop1::Op::V_CVT_F32_UBYTE2: + return "v_cvt_f32_ubyte2"; + case Vop1::Op::V_CVT_F32_UBYTE3: + return "v_cvt_f32_ubyte3"; + case Vop1::Op::V_CVT_U32_F64: + return "v_cvt_u32_f64"; + case Vop1::Op::V_CVT_F64_U32: + return "v_cvt_f64_u32"; + case Vop1::Op::V_FRACT_F32: + return "v_fract_f32"; + case Vop1::Op::V_TRUNC_F32: + return "v_trunc_f32"; + case Vop1::Op::V_CEIL_F32: + return "v_ceil_f32"; + case Vop1::Op::V_RNDNE_F32: + return "v_rndne_f32"; + case Vop1::Op::V_FLOOR_F32: + return "v_floor_f32"; + case Vop1::Op::V_EXP_F32: + return "v_exp_f32"; + case Vop1::Op::V_LOG_CLAMP_F32: + return "v_log_clamp_f32"; + case Vop1::Op::V_LOG_F32: + return "v_log_f32"; + case Vop1::Op::V_RCP_CLAMP_F32: + return "v_rcp_clamp_f32"; + case Vop1::Op::V_RCP_LEGACY_F32: + return "v_rcp_legacy_f32"; + case Vop1::Op::V_RCP_F32: + return "v_rcp_f32"; + case Vop1::Op::V_RCP_IFLAG_F32: + return "v_rcp_iflag_f32"; + case Vop1::Op::V_RSQ_CLAMP_F32: + return "v_rsq_clamp_f32"; + case Vop1::Op::V_RSQ_LEGACY_F32: + return "v_rsq_legacy_f32"; + case Vop1::Op::V_RSQ_F32: + return "v_rsq_f32"; + case Vop1::Op::V_RCP_F64: + return "v_rcp_f64"; + case Vop1::Op::V_RCP_CLAMP_F64: + return "v_rcp_clamp_f64"; + case Vop1::Op::V_RSQ_F64: + return "v_rsq_f64"; + case Vop1::Op::V_RSQ_CLAMP_F64: + return "v_rsq_clamp_f64"; + case Vop1::Op::V_SQRT_F32: + return "v_sqrt_f32"; + case Vop1::Op::V_SQRT_F64: + return "v_sqrt_f64"; + case Vop1::Op::V_SIN_F32: + return "v_sin_f32"; + case Vop1::Op::V_COS_F32: + return "v_cos_f32"; + case Vop1::Op::V_NOT_B32: + return "v_not_b32"; + case Vop1::Op::V_BFREV_B32: + return "v_bfrev_b32"; + case Vop1::Op::V_FFBH_U32: + return "v_ffbh_u32"; + case Vop1::Op::V_FFBL_B32: + return "v_ffbl_b32"; + case Vop1::Op::V_FFBH_I32: + return "v_ffbh_i32"; + case Vop1::Op::V_FREXP_EXP_I32_F64: + return "v_frexp_exp_i32_f64"; + case Vop1::Op::V_FREXP_MANT_F64: + return "v_frexp_mant_f64"; + case Vop1::Op::V_FRACT_F64: + return "v_fract_f64"; + case Vop1::Op::V_FREXP_EXP_I32_F32: + return "v_frexp_exp_i32_f32"; + case Vop1::Op::V_FREXP_MANT_F32: + return "v_frexp_mant_f32"; + case Vop1::Op::V_CLREXCP: + return "v_clrexcp"; + case Vop1::Op::V_MOVRELD_B32: + return "v_movreld_b32"; + case Vop1::Op::V_MOVRELS_B32: + return "v_movrels_b32"; + case Vop1::Op::V_MOVRELSD_B32: + return "v_movrelsd_b32"; + default: + return nullptr; + } } -const char *amdgpu::shader::vopcOpcodeToString(Vopc::Op op) { - switch (op) { - case Vopc::Op::V_CMP_F_F32: - return "v_cmp_f_f32"; - case Vopc::Op::V_CMP_LT_F32: - return "v_cmp_lt_f32"; - case Vopc::Op::V_CMP_EQ_F32: - return "v_cmp_eq_f32"; - case Vopc::Op::V_CMP_LE_F32: - return "v_cmp_le_f32"; - case Vopc::Op::V_CMP_GT_F32: - return "v_cmp_gt_f32"; - case Vopc::Op::V_CMP_LG_F32: - return "v_cmp_lg_f32"; - case Vopc::Op::V_CMP_GE_F32: - return "v_cmp_ge_f32"; - case Vopc::Op::V_CMP_O_F32: - return "v_cmp_o_f32"; - case Vopc::Op::V_CMP_U_F32: - return "v_cmp_u_f32"; - case Vopc::Op::V_CMP_NGE_F32: - return "v_cmp_nge_f32"; - case Vopc::Op::V_CMP_NLG_F32: - return "v_cmp_nlg_f32"; - case Vopc::Op::V_CMP_NGT_F32: - return "v_cmp_ngt_f32"; - case Vopc::Op::V_CMP_NLE_F32: - return "v_cmp_nle_f32"; - case Vopc::Op::V_CMP_NEQ_F32: - return "v_cmp_neq_f32"; - case Vopc::Op::V_CMP_NLT_F32: - return "v_cmp_nlt_f32"; - case Vopc::Op::V_CMP_TRU_F32: - return "v_cmp_tru_f32"; - case Vopc::Op::V_CMPX_F_F32: - return "v_cmpx_f_f32"; - case Vopc::Op::V_CMPX_LT_F32: - return "v_cmpx_lt_f32"; - case Vopc::Op::V_CMPX_EQ_F32: - return "v_cmpx_eq_f32"; - case Vopc::Op::V_CMPX_LE_F32: - return "v_cmpx_le_f32"; - case Vopc::Op::V_CMPX_GT_F32: - return "v_cmpx_gt_f32"; - case Vopc::Op::V_CMPX_LG_F32: - return "v_cmpx_lg_f32"; - case Vopc::Op::V_CMPX_GE_F32: - return "v_cmpx_ge_f32"; - case Vopc::Op::V_CMPX_O_F32: - return "v_cmpx_o_f32"; - case Vopc::Op::V_CMPX_U_F32: - return "v_cmpx_u_f32"; - case Vopc::Op::V_CMPX_NGE_F32: - return "v_cmpx_nge_f32"; - case Vopc::Op::V_CMPX_NLG_F32: - return "v_cmpx_nlg_f32"; - case Vopc::Op::V_CMPX_NGT_F32: - return "v_cmpx_ngt_f32"; - case Vopc::Op::V_CMPX_NLE_F32: - return "v_cmpx_nle_f32"; - case Vopc::Op::V_CMPX_NEQ_F32: - return "v_cmpx_neq_f32"; - case Vopc::Op::V_CMPX_NLT_F32: - return "v_cmpx_nlt_f32"; - case Vopc::Op::V_CMPX_TRU_F32: - return "v_cmpx_tru_f32"; - case Vopc::Op::V_CMP_F_F64: - return "v_cmp_f_f64"; - case Vopc::Op::V_CMP_LT_F64: - return "v_cmp_lt_f64"; - case Vopc::Op::V_CMP_EQ_F64: - return "v_cmp_eq_f64"; - case Vopc::Op::V_CMP_LE_F64: - return "v_cmp_le_f64"; - case Vopc::Op::V_CMP_GT_F64: - return "v_cmp_gt_f64"; - case Vopc::Op::V_CMP_LG_F64: - return "v_cmp_lg_f64"; - case Vopc::Op::V_CMP_GE_F64: - return "v_cmp_ge_f64"; - case Vopc::Op::V_CMP_O_F64: - return "v_cmp_o_f64"; - case Vopc::Op::V_CMP_U_F64: - return "v_cmp_u_f64"; - case Vopc::Op::V_CMP_NGE_F64: - return "v_cmp_nge_f64"; - case Vopc::Op::V_CMP_NLG_F64: - return "v_cmp_nlg_f64"; - case Vopc::Op::V_CMP_NGT_F64: - return "v_cmp_ngt_f64"; - case Vopc::Op::V_CMP_NLE_F64: - return "v_cmp_nle_f64"; - case Vopc::Op::V_CMP_NEQ_F64: - return "v_cmp_neq_f64"; - case Vopc::Op::V_CMP_NLT_F64: - return "v_cmp_nlt_f64"; - case Vopc::Op::V_CMP_TRU_F64: - return "v_cmp_tru_f64"; - case Vopc::Op::V_CMPX_F_F64: - return "v_cmpx_f_f64"; - case Vopc::Op::V_CMPX_LT_F64: - return "v_cmpx_lt_f64"; - case Vopc::Op::V_CMPX_EQ_F64: - return "v_cmpx_eq_f64"; - case Vopc::Op::V_CMPX_LE_F64: - return "v_cmpx_le_f64"; - case Vopc::Op::V_CMPX_GT_F64: - return "v_cmpx_gt_f64"; - case Vopc::Op::V_CMPX_LG_F64: - return "v_cmpx_lg_f64"; - case Vopc::Op::V_CMPX_GE_F64: - return "v_cmpx_ge_f64"; - case Vopc::Op::V_CMPX_O_F64: - return "v_cmpx_o_f64"; - case Vopc::Op::V_CMPX_U_F64: - return "v_cmpx_u_f64"; - case Vopc::Op::V_CMPX_NGE_F64: - return "v_cmpx_nge_f64"; - case Vopc::Op::V_CMPX_NLG_F64: - return "v_cmpx_nlg_f64"; - case Vopc::Op::V_CMPX_NGT_F64: - return "v_cmpx_ngt_f64"; - case Vopc::Op::V_CMPX_NLE_F64: - return "v_cmpx_nle_f64"; - case Vopc::Op::V_CMPX_NEQ_F64: - return "v_cmpx_neq_f64"; - case Vopc::Op::V_CMPX_NLT_F64: - return "v_cmpx_nlt_f64"; - case Vopc::Op::V_CMPX_TRU_F64: - return "v_cmpx_tru_f64"; - case Vopc::Op::V_CMPS_F_F32: - return "v_cmps_f_f32"; - case Vopc::Op::V_CMPS_LT_F32: - return "v_cmps_lt_f32"; - case Vopc::Op::V_CMPS_EQ_F32: - return "v_cmps_eq_f32"; - case Vopc::Op::V_CMPS_LE_F32: - return "v_cmps_le_f32"; - case Vopc::Op::V_CMPS_GT_F32: - return "v_cmps_gt_f32"; - case Vopc::Op::V_CMPS_LG_F32: - return "v_cmps_lg_f32"; - case Vopc::Op::V_CMPS_GE_F32: - return "v_cmps_ge_f32"; - case Vopc::Op::V_CMPS_O_F32: - return "v_cmps_o_f32"; - case Vopc::Op::V_CMPS_U_F32: - return "v_cmps_u_f32"; - case Vopc::Op::V_CMPS_NGE_F32: - return "v_cmps_nge_f32"; - case Vopc::Op::V_CMPS_NLG_F32: - return "v_cmps_nlg_f32"; - case Vopc::Op::V_CMPS_NGT_F32: - return "v_cmps_ngt_f32"; - case Vopc::Op::V_CMPS_NLE_F32: - return "v_cmps_nle_f32"; - case Vopc::Op::V_CMPS_NEQ_F32: - return "v_cmps_neq_f32"; - case Vopc::Op::V_CMPS_NLT_F32: - return "v_cmps_nlt_f32"; - case Vopc::Op::V_CMPS_TRU_F32: - return "v_cmps_tru_f32"; - case Vopc::Op::V_CMPSX_F_F32: - return "v_cmpsx_f_f32"; - case Vopc::Op::V_CMPSX_LT_F32: - return "v_cmpsx_lt_f32"; - case Vopc::Op::V_CMPSX_EQ_F32: - return "v_cmpsx_eq_f32"; - case Vopc::Op::V_CMPSX_LE_F32: - return "v_cmpsx_le_f32"; - case Vopc::Op::V_CMPSX_GT_F32: - return "v_cmpsx_gt_f32"; - case Vopc::Op::V_CMPSX_LG_F32: - return "v_cmpsx_lg_f32"; - case Vopc::Op::V_CMPSX_GE_F32: - return "v_cmpsx_ge_f32"; - case Vopc::Op::V_CMPSX_O_F32: - return "v_cmpsx_o_f32"; - case Vopc::Op::V_CMPSX_U_F32: - return "v_cmpsx_u_f32"; - case Vopc::Op::V_CMPSX_NGE_F32: - return "v_cmpsx_nge_f32"; - case Vopc::Op::V_CMPSX_NLG_F32: - return "v_cmpsx_nlg_f32"; - case Vopc::Op::V_CMPSX_NGT_F32: - return "v_cmpsx_ngt_f32"; - case Vopc::Op::V_CMPSX_NLE_F32: - return "v_cmpsx_nle_f32"; - case Vopc::Op::V_CMPSX_NEQ_F32: - return "v_cmpsx_neq_f32"; - case Vopc::Op::V_CMPSX_NLT_F32: - return "v_cmpsx_nlt_f32"; - case Vopc::Op::V_CMPSX_TRU_F32: - return "v_cmpsx_tru_f32"; - case Vopc::Op::V_CMPS_F_F64: - return "v_cmps_f_f64"; - case Vopc::Op::V_CMPS_LT_F64: - return "v_cmps_lt_f64"; - case Vopc::Op::V_CMPS_EQ_F64: - return "v_cmps_eq_f64"; - case Vopc::Op::V_CMPS_LE_F64: - return "v_cmps_le_f64"; - case Vopc::Op::V_CMPS_GT_F64: - return "v_cmps_gt_f64"; - case Vopc::Op::V_CMPS_LG_F64: - return "v_cmps_lg_f64"; - case Vopc::Op::V_CMPS_GE_F64: - return "v_cmps_ge_f64"; - case Vopc::Op::V_CMPS_O_F64: - return "v_cmps_o_f64"; - case Vopc::Op::V_CMPS_U_F64: - return "v_cmps_u_f64"; - case Vopc::Op::V_CMPS_NGE_F64: - return "v_cmps_nge_f64"; - case Vopc::Op::V_CMPS_NLG_F64: - return "v_cmps_nlg_f64"; - case Vopc::Op::V_CMPS_NGT_F64: - return "v_cmps_ngt_f64"; - case Vopc::Op::V_CMPS_NLE_F64: - return "v_cmps_nle_f64"; - case Vopc::Op::V_CMPS_NEQ_F64: - return "v_cmps_neq_f64"; - case Vopc::Op::V_CMPS_NLT_F64: - return "v_cmps_nlt_f64"; - case Vopc::Op::V_CMPS_TRU_F64: - return "v_cmps_tru_f64"; - case Vopc::Op::V_CMPSX_F_F64: - return "v_cmpsx_f_f64"; - case Vopc::Op::V_CMPSX_LT_F64: - return "v_cmpsx_lt_f64"; - case Vopc::Op::V_CMPSX_EQ_F64: - return "v_cmpsx_eq_f64"; - case Vopc::Op::V_CMPSX_LE_F64: - return "v_cmpsx_le_f64"; - case Vopc::Op::V_CMPSX_GT_F64: - return "v_cmpsx_gt_f64"; - case Vopc::Op::V_CMPSX_LG_F64: - return "v_cmpsx_lg_f64"; - case Vopc::Op::V_CMPSX_GE_F64: - return "v_cmpsx_ge_f64"; - case Vopc::Op::V_CMPSX_O_F64: - return "v_cmpsx_o_f64"; - case Vopc::Op::V_CMPSX_U_F64: - return "v_cmpsx_u_f64"; - case Vopc::Op::V_CMPSX_NGE_F64: - return "v_cmpsx_nge_f64"; - case Vopc::Op::V_CMPSX_NLG_F64: - return "v_cmpsx_nlg_f64"; - case Vopc::Op::V_CMPSX_NGT_F64: - return "v_cmpsx_ngt_f64"; - case Vopc::Op::V_CMPSX_NLE_F64: - return "v_cmpsx_nle_f64"; - case Vopc::Op::V_CMPSX_NEQ_F64: - return "v_cmpsx_neq_f64"; - case Vopc::Op::V_CMPSX_NLT_F64: - return "v_cmpsx_nlt_f64"; - case Vopc::Op::V_CMPSX_TRU_F64: - return "v_cmpsx_tru_f64"; - case Vopc::Op::V_CMP_F_I32: - return "v_cmp_f_i32"; - case Vopc::Op::V_CMP_LT_I32: - return "v_cmp_lt_i32"; - case Vopc::Op::V_CMP_EQ_I32: - return "v_cmp_eq_i32"; - case Vopc::Op::V_CMP_LE_I32: - return "v_cmp_le_i32"; - case Vopc::Op::V_CMP_GT_I32: - return "v_cmp_gt_i32"; - case Vopc::Op::V_CMP_NE_I32: - return "v_cmp_ne_i32"; - case Vopc::Op::V_CMP_GE_I32: - return "v_cmp_ge_i32"; - case Vopc::Op::V_CMP_T_I32: - return "v_cmp_t_i32"; - case Vopc::Op::V_CMP_CLASS_F32: - return "v_cmp_class_f32"; - case Vopc::Op::V_CMP_LT_I16: - return "v_cmp_lt_i16"; - case Vopc::Op::V_CMP_EQ_I16: - return "v_cmp_eq_i16"; - case Vopc::Op::V_CMP_LE_I16: - return "v_cmp_le_i16"; - case Vopc::Op::V_CMP_GT_I16: - return "v_cmp_gt_i16"; - case Vopc::Op::V_CMP_NE_I16: - return "v_cmp_ne_i16"; - case Vopc::Op::V_CMP_GE_I16: - return "v_cmp_ge_i16"; - case Vopc::Op::V_CMP_CLASS_F16: - return "v_cmp_class_f16"; - case Vopc::Op::V_CMPX_F_I32: - return "v_cmpx_f_i32"; - case Vopc::Op::V_CMPX_LT_I32: - return "v_cmpx_lt_i32"; - case Vopc::Op::V_CMPX_EQ_I32: - return "v_cmpx_eq_i32"; - case Vopc::Op::V_CMPX_LE_I32: - return "v_cmpx_le_i32"; - case Vopc::Op::V_CMPX_GT_I32: - return "v_cmpx_gt_i32"; - case Vopc::Op::V_CMPX_NE_I32: - return "v_cmpx_ne_i32"; - case Vopc::Op::V_CMPX_GE_I32: - return "v_cmpx_ge_i32"; - case Vopc::Op::V_CMPX_T_I32: - return "v_cmpx_t_i32"; - case Vopc::Op::V_CMPX_CLASS_F32: - return "v_cmpx_class_f32"; - case Vopc::Op::V_CMPX_LT_I16: - return "v_cmpx_lt_i16"; - case Vopc::Op::V_CMPX_EQ_I16: - return "v_cmpx_eq_i16"; - case Vopc::Op::V_CMPX_LE_I16: - return "v_cmpx_le_i16"; - case Vopc::Op::V_CMPX_GT_I16: - return "v_cmpx_gt_i16"; - case Vopc::Op::V_CMPX_NE_I16: - return "v_cmpx_ne_i16"; - case Vopc::Op::V_CMPX_GE_I16: - return "v_cmpx_ge_i16"; - case Vopc::Op::V_CMPX_CLASS_F16: - return "v_cmpx_class_f16"; - case Vopc::Op::V_CMP_F_I64: - return "v_cmp_f_i64"; - case Vopc::Op::V_CMP_LT_I64: - return "v_cmp_lt_i64"; - case Vopc::Op::V_CMP_EQ_I64: - return "v_cmp_eq_i64"; - case Vopc::Op::V_CMP_LE_I64: - return "v_cmp_le_i64"; - case Vopc::Op::V_CMP_GT_I64: - return "v_cmp_gt_i64"; - case Vopc::Op::V_CMP_NE_I64: - return "v_cmp_ne_i64"; - case Vopc::Op::V_CMP_GE_I64: - return "v_cmp_ge_i64"; - case Vopc::Op::V_CMP_T_I64: - return "v_cmp_t_i64"; - case Vopc::Op::V_CMP_CLASS_F64: - return "v_cmp_class_f64"; - case Vopc::Op::V_CMP_LT_U16: - return "v_cmp_lt_u16"; - case Vopc::Op::V_CMP_EQ_U16: - return "v_cmp_eq_u16"; - case Vopc::Op::V_CMP_LE_U16: - return "v_cmp_le_u16"; - case Vopc::Op::V_CMP_GT_U16: - return "v_cmp_gt_u16"; - case Vopc::Op::V_CMP_NE_U16: - return "v_cmp_ne_u16"; - case Vopc::Op::V_CMP_GE_U16: - return "v_cmp_ge_u16"; - case Vopc::Op::V_CMPX_F_I64: - return "v_cmpx_f_i64"; - case Vopc::Op::V_CMPX_LT_I64: - return "v_cmpx_lt_i64"; - case Vopc::Op::V_CMPX_EQ_I64: - return "v_cmpx_eq_i64"; - case Vopc::Op::V_CMPX_LE_I64: - return "v_cmpx_le_i64"; - case Vopc::Op::V_CMPX_GT_I64: - return "v_cmpx_gt_i64"; - case Vopc::Op::V_CMPX_NE_I64: - return "v_cmpx_ne_i64"; - case Vopc::Op::V_CMPX_GE_I64: - return "v_cmpx_ge_i64"; - case Vopc::Op::V_CMPX_T_I64: - return "v_cmpx_t_i64"; - case Vopc::Op::V_CMPX_CLASS_F64: - return "v_cmpx_class_f64"; - case Vopc::Op::V_CMPX_LT_U16: - return "v_cmpx_lt_u16"; - case Vopc::Op::V_CMPX_EQ_U16: - return "v_cmpx_eq_u16"; - case Vopc::Op::V_CMPX_LE_U16: - return "v_cmpx_le_u16"; - case Vopc::Op::V_CMPX_GT_U16: - return "v_cmpx_gt_u16"; - case Vopc::Op::V_CMPX_NE_U16: - return "v_cmpx_ne_u16"; - case Vopc::Op::V_CMPX_GE_U16: - return "v_cmpx_ge_u16"; - case Vopc::Op::V_CMP_F_U32: - return "v_cmp_f_u32"; - case Vopc::Op::V_CMP_LT_U32: - return "v_cmp_lt_u32"; - case Vopc::Op::V_CMP_EQ_U32: - return "v_cmp_eq_u32"; - case Vopc::Op::V_CMP_LE_U32: - return "v_cmp_le_u32"; - case Vopc::Op::V_CMP_GT_U32: - return "v_cmp_gt_u32"; - case Vopc::Op::V_CMP_NE_U32: - return "v_cmp_ne_u32"; - case Vopc::Op::V_CMP_GE_U32: - return "v_cmp_ge_u32"; - case Vopc::Op::V_CMP_T_U32: - return "v_cmp_t_u32"; - case Vopc::Op::V_CMP_F_F16: - return "v_cmp_f_f16"; - case Vopc::Op::V_CMP_LT_F16: - return "v_cmp_lt_f16"; - case Vopc::Op::V_CMP_EQ_F16: - return "v_cmp_eq_f16"; - case Vopc::Op::V_CMP_LE_F16: - return "v_cmp_le_f16"; - case Vopc::Op::V_CMP_GT_F16: - return "v_cmp_gt_f16"; - case Vopc::Op::V_CMP_LG_F16: - return "v_cmp_lg_f16"; - case Vopc::Op::V_CMP_GE_F16: - return "v_cmp_ge_f16"; - case Vopc::Op::V_CMP_O_F16: - return "v_cmp_o_f16"; - case Vopc::Op::V_CMPX_F_U32: - return "v_cmpx_f_u32"; - case Vopc::Op::V_CMPX_LT_U32: - return "v_cmpx_lt_u32"; - case Vopc::Op::V_CMPX_EQ_U32: - return "v_cmpx_eq_u32"; - case Vopc::Op::V_CMPX_LE_U32: - return "v_cmpx_le_u32"; - case Vopc::Op::V_CMPX_GT_U32: - return "v_cmpx_gt_u32"; - case Vopc::Op::V_CMPX_NE_U32: - return "v_cmpx_ne_u32"; - case Vopc::Op::V_CMPX_GE_U32: - return "v_cmpx_ge_u32"; - case Vopc::Op::V_CMPX_T_U32: - return "v_cmpx_t_u32"; - case Vopc::Op::V_CMPX_F_F16: - return "v_cmpx_f_f16"; - case Vopc::Op::V_CMPX_LT_F16: - return "v_cmpx_lt_f16"; - case Vopc::Op::V_CMPX_EQ_F16: - return "v_cmpx_eq_f16"; - case Vopc::Op::V_CMPX_LE_F16: - return "v_cmpx_le_f16"; - case Vopc::Op::V_CMPX_GT_F16: - return "v_cmpx_gt_f16"; - case Vopc::Op::V_CMPX_LG_F16: - return "v_cmpx_lg_f16"; - case Vopc::Op::V_CMPX_GE_F16: - return "v_cmpx_ge_f16"; - case Vopc::Op::V_CMPX_O_F16: - return "v_cmpx_o_f16"; - case Vopc::Op::V_CMP_F_U64: - return "v_cmp_f_u64"; - case Vopc::Op::V_CMP_LT_U64: - return "v_cmp_lt_u64"; - case Vopc::Op::V_CMP_EQ_U64: - return "v_cmp_eq_u64"; - case Vopc::Op::V_CMP_LE_U64: - return "v_cmp_le_u64"; - case Vopc::Op::V_CMP_GT_U64: - return "v_cmp_gt_u64"; - case Vopc::Op::V_CMP_NE_U64: - return "v_cmp_ne_u64"; - case Vopc::Op::V_CMP_GE_U64: - return "v_cmp_ge_u64"; - case Vopc::Op::V_CMP_T_U64: - return "v_cmp_t_u64"; - case Vopc::Op::V_CMP_U_F16: - return "v_cmp_u_f16"; - case Vopc::Op::V_CMP_NGE_F16: - return "v_cmp_nge_f16"; - case Vopc::Op::V_CMP_NLG_F16: - return "v_cmp_nlg_f16"; - case Vopc::Op::V_CMP_NGT_F16: - return "v_cmp_ngt_f16"; - case Vopc::Op::V_CMP_NLE_F16: - return "v_cmp_nle_f16"; - case Vopc::Op::V_CMP_NEQ_F16: - return "v_cmp_neq_f16"; - case Vopc::Op::V_CMP_NLT_F16: - return "v_cmp_nlt_f16"; - case Vopc::Op::V_CMP_TRU_F16: - return "v_cmp_tru_f16"; - case Vopc::Op::V_CMPX_F_U64: - return "v_cmpx_f_u64"; - case Vopc::Op::V_CMPX_LT_U64: - return "v_cmpx_lt_u64"; - case Vopc::Op::V_CMPX_EQ_U64: - return "v_cmpx_eq_u64"; - case Vopc::Op::V_CMPX_LE_U64: - return "v_cmpx_le_u64"; - case Vopc::Op::V_CMPX_GT_U64: - return "v_cmpx_gt_u64"; - case Vopc::Op::V_CMPX_NE_U64: - return "v_cmpx_ne_u64"; - case Vopc::Op::V_CMPX_GE_U64: - return "v_cmpx_ge_u64"; - case Vopc::Op::V_CMPX_T_U64: - return "v_cmpx_t_u64"; - case Vopc::Op::V_CMPX_U_F16: - return "v_cmpx_u_f16"; - case Vopc::Op::V_CMPX_NGE_F16: - return "v_cmpx_nge_f16"; - case Vopc::Op::V_CMPX_NLG_F16: - return "v_cmpx_nlg_f16"; - case Vopc::Op::V_CMPX_NGT_F16: - return "v_cmpx_ngt_f16"; - case Vopc::Op::V_CMPX_NLE_F16: - return "v_cmpx_nle_f16"; - case Vopc::Op::V_CMPX_NEQ_F16: - return "v_cmpx_neq_f16"; - case Vopc::Op::V_CMPX_NLT_F16: - return "v_cmpx_nlt_f16"; - case Vopc::Op::V_CMPX_TRU_F16: - return "v_cmpx_tru_f16"; - - default: - return nullptr; - } +const char* amdgpu::shader::vopcOpcodeToString(Vopc::Op op) +{ + switch (op) + { + case Vopc::Op::V_CMP_F_F32: + return "v_cmp_f_f32"; + case Vopc::Op::V_CMP_LT_F32: + return "v_cmp_lt_f32"; + case Vopc::Op::V_CMP_EQ_F32: + return "v_cmp_eq_f32"; + case Vopc::Op::V_CMP_LE_F32: + return "v_cmp_le_f32"; + case Vopc::Op::V_CMP_GT_F32: + return "v_cmp_gt_f32"; + case Vopc::Op::V_CMP_LG_F32: + return "v_cmp_lg_f32"; + case Vopc::Op::V_CMP_GE_F32: + return "v_cmp_ge_f32"; + case Vopc::Op::V_CMP_O_F32: + return "v_cmp_o_f32"; + case Vopc::Op::V_CMP_U_F32: + return "v_cmp_u_f32"; + case Vopc::Op::V_CMP_NGE_F32: + return "v_cmp_nge_f32"; + case Vopc::Op::V_CMP_NLG_F32: + return "v_cmp_nlg_f32"; + case Vopc::Op::V_CMP_NGT_F32: + return "v_cmp_ngt_f32"; + case Vopc::Op::V_CMP_NLE_F32: + return "v_cmp_nle_f32"; + case Vopc::Op::V_CMP_NEQ_F32: + return "v_cmp_neq_f32"; + case Vopc::Op::V_CMP_NLT_F32: + return "v_cmp_nlt_f32"; + case Vopc::Op::V_CMP_TRU_F32: + return "v_cmp_tru_f32"; + case Vopc::Op::V_CMPX_F_F32: + return "v_cmpx_f_f32"; + case Vopc::Op::V_CMPX_LT_F32: + return "v_cmpx_lt_f32"; + case Vopc::Op::V_CMPX_EQ_F32: + return "v_cmpx_eq_f32"; + case Vopc::Op::V_CMPX_LE_F32: + return "v_cmpx_le_f32"; + case Vopc::Op::V_CMPX_GT_F32: + return "v_cmpx_gt_f32"; + case Vopc::Op::V_CMPX_LG_F32: + return "v_cmpx_lg_f32"; + case Vopc::Op::V_CMPX_GE_F32: + return "v_cmpx_ge_f32"; + case Vopc::Op::V_CMPX_O_F32: + return "v_cmpx_o_f32"; + case Vopc::Op::V_CMPX_U_F32: + return "v_cmpx_u_f32"; + case Vopc::Op::V_CMPX_NGE_F32: + return "v_cmpx_nge_f32"; + case Vopc::Op::V_CMPX_NLG_F32: + return "v_cmpx_nlg_f32"; + case Vopc::Op::V_CMPX_NGT_F32: + return "v_cmpx_ngt_f32"; + case Vopc::Op::V_CMPX_NLE_F32: + return "v_cmpx_nle_f32"; + case Vopc::Op::V_CMPX_NEQ_F32: + return "v_cmpx_neq_f32"; + case Vopc::Op::V_CMPX_NLT_F32: + return "v_cmpx_nlt_f32"; + case Vopc::Op::V_CMPX_TRU_F32: + return "v_cmpx_tru_f32"; + case Vopc::Op::V_CMP_F_F64: + return "v_cmp_f_f64"; + case Vopc::Op::V_CMP_LT_F64: + return "v_cmp_lt_f64"; + case Vopc::Op::V_CMP_EQ_F64: + return "v_cmp_eq_f64"; + case Vopc::Op::V_CMP_LE_F64: + return "v_cmp_le_f64"; + case Vopc::Op::V_CMP_GT_F64: + return "v_cmp_gt_f64"; + case Vopc::Op::V_CMP_LG_F64: + return "v_cmp_lg_f64"; + case Vopc::Op::V_CMP_GE_F64: + return "v_cmp_ge_f64"; + case Vopc::Op::V_CMP_O_F64: + return "v_cmp_o_f64"; + case Vopc::Op::V_CMP_U_F64: + return "v_cmp_u_f64"; + case Vopc::Op::V_CMP_NGE_F64: + return "v_cmp_nge_f64"; + case Vopc::Op::V_CMP_NLG_F64: + return "v_cmp_nlg_f64"; + case Vopc::Op::V_CMP_NGT_F64: + return "v_cmp_ngt_f64"; + case Vopc::Op::V_CMP_NLE_F64: + return "v_cmp_nle_f64"; + case Vopc::Op::V_CMP_NEQ_F64: + return "v_cmp_neq_f64"; + case Vopc::Op::V_CMP_NLT_F64: + return "v_cmp_nlt_f64"; + case Vopc::Op::V_CMP_TRU_F64: + return "v_cmp_tru_f64"; + case Vopc::Op::V_CMPX_F_F64: + return "v_cmpx_f_f64"; + case Vopc::Op::V_CMPX_LT_F64: + return "v_cmpx_lt_f64"; + case Vopc::Op::V_CMPX_EQ_F64: + return "v_cmpx_eq_f64"; + case Vopc::Op::V_CMPX_LE_F64: + return "v_cmpx_le_f64"; + case Vopc::Op::V_CMPX_GT_F64: + return "v_cmpx_gt_f64"; + case Vopc::Op::V_CMPX_LG_F64: + return "v_cmpx_lg_f64"; + case Vopc::Op::V_CMPX_GE_F64: + return "v_cmpx_ge_f64"; + case Vopc::Op::V_CMPX_O_F64: + return "v_cmpx_o_f64"; + case Vopc::Op::V_CMPX_U_F64: + return "v_cmpx_u_f64"; + case Vopc::Op::V_CMPX_NGE_F64: + return "v_cmpx_nge_f64"; + case Vopc::Op::V_CMPX_NLG_F64: + return "v_cmpx_nlg_f64"; + case Vopc::Op::V_CMPX_NGT_F64: + return "v_cmpx_ngt_f64"; + case Vopc::Op::V_CMPX_NLE_F64: + return "v_cmpx_nle_f64"; + case Vopc::Op::V_CMPX_NEQ_F64: + return "v_cmpx_neq_f64"; + case Vopc::Op::V_CMPX_NLT_F64: + return "v_cmpx_nlt_f64"; + case Vopc::Op::V_CMPX_TRU_F64: + return "v_cmpx_tru_f64"; + case Vopc::Op::V_CMPS_F_F32: + return "v_cmps_f_f32"; + case Vopc::Op::V_CMPS_LT_F32: + return "v_cmps_lt_f32"; + case Vopc::Op::V_CMPS_EQ_F32: + return "v_cmps_eq_f32"; + case Vopc::Op::V_CMPS_LE_F32: + return "v_cmps_le_f32"; + case Vopc::Op::V_CMPS_GT_F32: + return "v_cmps_gt_f32"; + case Vopc::Op::V_CMPS_LG_F32: + return "v_cmps_lg_f32"; + case Vopc::Op::V_CMPS_GE_F32: + return "v_cmps_ge_f32"; + case Vopc::Op::V_CMPS_O_F32: + return "v_cmps_o_f32"; + case Vopc::Op::V_CMPS_U_F32: + return "v_cmps_u_f32"; + case Vopc::Op::V_CMPS_NGE_F32: + return "v_cmps_nge_f32"; + case Vopc::Op::V_CMPS_NLG_F32: + return "v_cmps_nlg_f32"; + case Vopc::Op::V_CMPS_NGT_F32: + return "v_cmps_ngt_f32"; + case Vopc::Op::V_CMPS_NLE_F32: + return "v_cmps_nle_f32"; + case Vopc::Op::V_CMPS_NEQ_F32: + return "v_cmps_neq_f32"; + case Vopc::Op::V_CMPS_NLT_F32: + return "v_cmps_nlt_f32"; + case Vopc::Op::V_CMPS_TRU_F32: + return "v_cmps_tru_f32"; + case Vopc::Op::V_CMPSX_F_F32: + return "v_cmpsx_f_f32"; + case Vopc::Op::V_CMPSX_LT_F32: + return "v_cmpsx_lt_f32"; + case Vopc::Op::V_CMPSX_EQ_F32: + return "v_cmpsx_eq_f32"; + case Vopc::Op::V_CMPSX_LE_F32: + return "v_cmpsx_le_f32"; + case Vopc::Op::V_CMPSX_GT_F32: + return "v_cmpsx_gt_f32"; + case Vopc::Op::V_CMPSX_LG_F32: + return "v_cmpsx_lg_f32"; + case Vopc::Op::V_CMPSX_GE_F32: + return "v_cmpsx_ge_f32"; + case Vopc::Op::V_CMPSX_O_F32: + return "v_cmpsx_o_f32"; + case Vopc::Op::V_CMPSX_U_F32: + return "v_cmpsx_u_f32"; + case Vopc::Op::V_CMPSX_NGE_F32: + return "v_cmpsx_nge_f32"; + case Vopc::Op::V_CMPSX_NLG_F32: + return "v_cmpsx_nlg_f32"; + case Vopc::Op::V_CMPSX_NGT_F32: + return "v_cmpsx_ngt_f32"; + case Vopc::Op::V_CMPSX_NLE_F32: + return "v_cmpsx_nle_f32"; + case Vopc::Op::V_CMPSX_NEQ_F32: + return "v_cmpsx_neq_f32"; + case Vopc::Op::V_CMPSX_NLT_F32: + return "v_cmpsx_nlt_f32"; + case Vopc::Op::V_CMPSX_TRU_F32: + return "v_cmpsx_tru_f32"; + case Vopc::Op::V_CMPS_F_F64: + return "v_cmps_f_f64"; + case Vopc::Op::V_CMPS_LT_F64: + return "v_cmps_lt_f64"; + case Vopc::Op::V_CMPS_EQ_F64: + return "v_cmps_eq_f64"; + case Vopc::Op::V_CMPS_LE_F64: + return "v_cmps_le_f64"; + case Vopc::Op::V_CMPS_GT_F64: + return "v_cmps_gt_f64"; + case Vopc::Op::V_CMPS_LG_F64: + return "v_cmps_lg_f64"; + case Vopc::Op::V_CMPS_GE_F64: + return "v_cmps_ge_f64"; + case Vopc::Op::V_CMPS_O_F64: + return "v_cmps_o_f64"; + case Vopc::Op::V_CMPS_U_F64: + return "v_cmps_u_f64"; + case Vopc::Op::V_CMPS_NGE_F64: + return "v_cmps_nge_f64"; + case Vopc::Op::V_CMPS_NLG_F64: + return "v_cmps_nlg_f64"; + case Vopc::Op::V_CMPS_NGT_F64: + return "v_cmps_ngt_f64"; + case Vopc::Op::V_CMPS_NLE_F64: + return "v_cmps_nle_f64"; + case Vopc::Op::V_CMPS_NEQ_F64: + return "v_cmps_neq_f64"; + case Vopc::Op::V_CMPS_NLT_F64: + return "v_cmps_nlt_f64"; + case Vopc::Op::V_CMPS_TRU_F64: + return "v_cmps_tru_f64"; + case Vopc::Op::V_CMPSX_F_F64: + return "v_cmpsx_f_f64"; + case Vopc::Op::V_CMPSX_LT_F64: + return "v_cmpsx_lt_f64"; + case Vopc::Op::V_CMPSX_EQ_F64: + return "v_cmpsx_eq_f64"; + case Vopc::Op::V_CMPSX_LE_F64: + return "v_cmpsx_le_f64"; + case Vopc::Op::V_CMPSX_GT_F64: + return "v_cmpsx_gt_f64"; + case Vopc::Op::V_CMPSX_LG_F64: + return "v_cmpsx_lg_f64"; + case Vopc::Op::V_CMPSX_GE_F64: + return "v_cmpsx_ge_f64"; + case Vopc::Op::V_CMPSX_O_F64: + return "v_cmpsx_o_f64"; + case Vopc::Op::V_CMPSX_U_F64: + return "v_cmpsx_u_f64"; + case Vopc::Op::V_CMPSX_NGE_F64: + return "v_cmpsx_nge_f64"; + case Vopc::Op::V_CMPSX_NLG_F64: + return "v_cmpsx_nlg_f64"; + case Vopc::Op::V_CMPSX_NGT_F64: + return "v_cmpsx_ngt_f64"; + case Vopc::Op::V_CMPSX_NLE_F64: + return "v_cmpsx_nle_f64"; + case Vopc::Op::V_CMPSX_NEQ_F64: + return "v_cmpsx_neq_f64"; + case Vopc::Op::V_CMPSX_NLT_F64: + return "v_cmpsx_nlt_f64"; + case Vopc::Op::V_CMPSX_TRU_F64: + return "v_cmpsx_tru_f64"; + case Vopc::Op::V_CMP_F_I32: + return "v_cmp_f_i32"; + case Vopc::Op::V_CMP_LT_I32: + return "v_cmp_lt_i32"; + case Vopc::Op::V_CMP_EQ_I32: + return "v_cmp_eq_i32"; + case Vopc::Op::V_CMP_LE_I32: + return "v_cmp_le_i32"; + case Vopc::Op::V_CMP_GT_I32: + return "v_cmp_gt_i32"; + case Vopc::Op::V_CMP_NE_I32: + return "v_cmp_ne_i32"; + case Vopc::Op::V_CMP_GE_I32: + return "v_cmp_ge_i32"; + case Vopc::Op::V_CMP_T_I32: + return "v_cmp_t_i32"; + case Vopc::Op::V_CMP_CLASS_F32: + return "v_cmp_class_f32"; + case Vopc::Op::V_CMP_LT_I16: + return "v_cmp_lt_i16"; + case Vopc::Op::V_CMP_EQ_I16: + return "v_cmp_eq_i16"; + case Vopc::Op::V_CMP_LE_I16: + return "v_cmp_le_i16"; + case Vopc::Op::V_CMP_GT_I16: + return "v_cmp_gt_i16"; + case Vopc::Op::V_CMP_NE_I16: + return "v_cmp_ne_i16"; + case Vopc::Op::V_CMP_GE_I16: + return "v_cmp_ge_i16"; + case Vopc::Op::V_CMP_CLASS_F16: + return "v_cmp_class_f16"; + case Vopc::Op::V_CMPX_F_I32: + return "v_cmpx_f_i32"; + case Vopc::Op::V_CMPX_LT_I32: + return "v_cmpx_lt_i32"; + case Vopc::Op::V_CMPX_EQ_I32: + return "v_cmpx_eq_i32"; + case Vopc::Op::V_CMPX_LE_I32: + return "v_cmpx_le_i32"; + case Vopc::Op::V_CMPX_GT_I32: + return "v_cmpx_gt_i32"; + case Vopc::Op::V_CMPX_NE_I32: + return "v_cmpx_ne_i32"; + case Vopc::Op::V_CMPX_GE_I32: + return "v_cmpx_ge_i32"; + case Vopc::Op::V_CMPX_T_I32: + return "v_cmpx_t_i32"; + case Vopc::Op::V_CMPX_CLASS_F32: + return "v_cmpx_class_f32"; + case Vopc::Op::V_CMPX_LT_I16: + return "v_cmpx_lt_i16"; + case Vopc::Op::V_CMPX_EQ_I16: + return "v_cmpx_eq_i16"; + case Vopc::Op::V_CMPX_LE_I16: + return "v_cmpx_le_i16"; + case Vopc::Op::V_CMPX_GT_I16: + return "v_cmpx_gt_i16"; + case Vopc::Op::V_CMPX_NE_I16: + return "v_cmpx_ne_i16"; + case Vopc::Op::V_CMPX_GE_I16: + return "v_cmpx_ge_i16"; + case Vopc::Op::V_CMPX_CLASS_F16: + return "v_cmpx_class_f16"; + case Vopc::Op::V_CMP_F_I64: + return "v_cmp_f_i64"; + case Vopc::Op::V_CMP_LT_I64: + return "v_cmp_lt_i64"; + case Vopc::Op::V_CMP_EQ_I64: + return "v_cmp_eq_i64"; + case Vopc::Op::V_CMP_LE_I64: + return "v_cmp_le_i64"; + case Vopc::Op::V_CMP_GT_I64: + return "v_cmp_gt_i64"; + case Vopc::Op::V_CMP_NE_I64: + return "v_cmp_ne_i64"; + case Vopc::Op::V_CMP_GE_I64: + return "v_cmp_ge_i64"; + case Vopc::Op::V_CMP_T_I64: + return "v_cmp_t_i64"; + case Vopc::Op::V_CMP_CLASS_F64: + return "v_cmp_class_f64"; + case Vopc::Op::V_CMP_LT_U16: + return "v_cmp_lt_u16"; + case Vopc::Op::V_CMP_EQ_U16: + return "v_cmp_eq_u16"; + case Vopc::Op::V_CMP_LE_U16: + return "v_cmp_le_u16"; + case Vopc::Op::V_CMP_GT_U16: + return "v_cmp_gt_u16"; + case Vopc::Op::V_CMP_NE_U16: + return "v_cmp_ne_u16"; + case Vopc::Op::V_CMP_GE_U16: + return "v_cmp_ge_u16"; + case Vopc::Op::V_CMPX_F_I64: + return "v_cmpx_f_i64"; + case Vopc::Op::V_CMPX_LT_I64: + return "v_cmpx_lt_i64"; + case Vopc::Op::V_CMPX_EQ_I64: + return "v_cmpx_eq_i64"; + case Vopc::Op::V_CMPX_LE_I64: + return "v_cmpx_le_i64"; + case Vopc::Op::V_CMPX_GT_I64: + return "v_cmpx_gt_i64"; + case Vopc::Op::V_CMPX_NE_I64: + return "v_cmpx_ne_i64"; + case Vopc::Op::V_CMPX_GE_I64: + return "v_cmpx_ge_i64"; + case Vopc::Op::V_CMPX_T_I64: + return "v_cmpx_t_i64"; + case Vopc::Op::V_CMPX_CLASS_F64: + return "v_cmpx_class_f64"; + case Vopc::Op::V_CMPX_LT_U16: + return "v_cmpx_lt_u16"; + case Vopc::Op::V_CMPX_EQ_U16: + return "v_cmpx_eq_u16"; + case Vopc::Op::V_CMPX_LE_U16: + return "v_cmpx_le_u16"; + case Vopc::Op::V_CMPX_GT_U16: + return "v_cmpx_gt_u16"; + case Vopc::Op::V_CMPX_NE_U16: + return "v_cmpx_ne_u16"; + case Vopc::Op::V_CMPX_GE_U16: + return "v_cmpx_ge_u16"; + case Vopc::Op::V_CMP_F_U32: + return "v_cmp_f_u32"; + case Vopc::Op::V_CMP_LT_U32: + return "v_cmp_lt_u32"; + case Vopc::Op::V_CMP_EQ_U32: + return "v_cmp_eq_u32"; + case Vopc::Op::V_CMP_LE_U32: + return "v_cmp_le_u32"; + case Vopc::Op::V_CMP_GT_U32: + return "v_cmp_gt_u32"; + case Vopc::Op::V_CMP_NE_U32: + return "v_cmp_ne_u32"; + case Vopc::Op::V_CMP_GE_U32: + return "v_cmp_ge_u32"; + case Vopc::Op::V_CMP_T_U32: + return "v_cmp_t_u32"; + case Vopc::Op::V_CMP_F_F16: + return "v_cmp_f_f16"; + case Vopc::Op::V_CMP_LT_F16: + return "v_cmp_lt_f16"; + case Vopc::Op::V_CMP_EQ_F16: + return "v_cmp_eq_f16"; + case Vopc::Op::V_CMP_LE_F16: + return "v_cmp_le_f16"; + case Vopc::Op::V_CMP_GT_F16: + return "v_cmp_gt_f16"; + case Vopc::Op::V_CMP_LG_F16: + return "v_cmp_lg_f16"; + case Vopc::Op::V_CMP_GE_F16: + return "v_cmp_ge_f16"; + case Vopc::Op::V_CMP_O_F16: + return "v_cmp_o_f16"; + case Vopc::Op::V_CMPX_F_U32: + return "v_cmpx_f_u32"; + case Vopc::Op::V_CMPX_LT_U32: + return "v_cmpx_lt_u32"; + case Vopc::Op::V_CMPX_EQ_U32: + return "v_cmpx_eq_u32"; + case Vopc::Op::V_CMPX_LE_U32: + return "v_cmpx_le_u32"; + case Vopc::Op::V_CMPX_GT_U32: + return "v_cmpx_gt_u32"; + case Vopc::Op::V_CMPX_NE_U32: + return "v_cmpx_ne_u32"; + case Vopc::Op::V_CMPX_GE_U32: + return "v_cmpx_ge_u32"; + case Vopc::Op::V_CMPX_T_U32: + return "v_cmpx_t_u32"; + case Vopc::Op::V_CMPX_F_F16: + return "v_cmpx_f_f16"; + case Vopc::Op::V_CMPX_LT_F16: + return "v_cmpx_lt_f16"; + case Vopc::Op::V_CMPX_EQ_F16: + return "v_cmpx_eq_f16"; + case Vopc::Op::V_CMPX_LE_F16: + return "v_cmpx_le_f16"; + case Vopc::Op::V_CMPX_GT_F16: + return "v_cmpx_gt_f16"; + case Vopc::Op::V_CMPX_LG_F16: + return "v_cmpx_lg_f16"; + case Vopc::Op::V_CMPX_GE_F16: + return "v_cmpx_ge_f16"; + case Vopc::Op::V_CMPX_O_F16: + return "v_cmpx_o_f16"; + case Vopc::Op::V_CMP_F_U64: + return "v_cmp_f_u64"; + case Vopc::Op::V_CMP_LT_U64: + return "v_cmp_lt_u64"; + case Vopc::Op::V_CMP_EQ_U64: + return "v_cmp_eq_u64"; + case Vopc::Op::V_CMP_LE_U64: + return "v_cmp_le_u64"; + case Vopc::Op::V_CMP_GT_U64: + return "v_cmp_gt_u64"; + case Vopc::Op::V_CMP_NE_U64: + return "v_cmp_ne_u64"; + case Vopc::Op::V_CMP_GE_U64: + return "v_cmp_ge_u64"; + case Vopc::Op::V_CMP_T_U64: + return "v_cmp_t_u64"; + case Vopc::Op::V_CMP_U_F16: + return "v_cmp_u_f16"; + case Vopc::Op::V_CMP_NGE_F16: + return "v_cmp_nge_f16"; + case Vopc::Op::V_CMP_NLG_F16: + return "v_cmp_nlg_f16"; + case Vopc::Op::V_CMP_NGT_F16: + return "v_cmp_ngt_f16"; + case Vopc::Op::V_CMP_NLE_F16: + return "v_cmp_nle_f16"; + case Vopc::Op::V_CMP_NEQ_F16: + return "v_cmp_neq_f16"; + case Vopc::Op::V_CMP_NLT_F16: + return "v_cmp_nlt_f16"; + case Vopc::Op::V_CMP_TRU_F16: + return "v_cmp_tru_f16"; + case Vopc::Op::V_CMPX_F_U64: + return "v_cmpx_f_u64"; + case Vopc::Op::V_CMPX_LT_U64: + return "v_cmpx_lt_u64"; + case Vopc::Op::V_CMPX_EQ_U64: + return "v_cmpx_eq_u64"; + case Vopc::Op::V_CMPX_LE_U64: + return "v_cmpx_le_u64"; + case Vopc::Op::V_CMPX_GT_U64: + return "v_cmpx_gt_u64"; + case Vopc::Op::V_CMPX_NE_U64: + return "v_cmpx_ne_u64"; + case Vopc::Op::V_CMPX_GE_U64: + return "v_cmpx_ge_u64"; + case Vopc::Op::V_CMPX_T_U64: + return "v_cmpx_t_u64"; + case Vopc::Op::V_CMPX_U_F16: + return "v_cmpx_u_f16"; + case Vopc::Op::V_CMPX_NGE_F16: + return "v_cmpx_nge_f16"; + case Vopc::Op::V_CMPX_NLG_F16: + return "v_cmpx_nlg_f16"; + case Vopc::Op::V_CMPX_NGT_F16: + return "v_cmpx_ngt_f16"; + case Vopc::Op::V_CMPX_NLE_F16: + return "v_cmpx_nle_f16"; + case Vopc::Op::V_CMPX_NEQ_F16: + return "v_cmpx_neq_f16"; + case Vopc::Op::V_CMPX_NLT_F16: + return "v_cmpx_nlt_f16"; + case Vopc::Op::V_CMPX_TRU_F16: + return "v_cmpx_tru_f16"; + + default: + return nullptr; + } } -const char *amdgpu::shader::vop3OpcodeToString(Vop3::Op op) { - switch (op) { - case Vop3::Op::V3_CMP_F_F32: - return "v3_cmp_f_f32"; - case Vop3::Op::V3_CMP_LT_F32: - return "v3_cmp_lt_f32"; - case Vop3::Op::V3_CMP_EQ_F32: - return "v3_cmp_eq_f32"; - case Vop3::Op::V3_CMP_LE_F32: - return "v3_cmp_le_f32"; - case Vop3::Op::V3_CMP_GT_F32: - return "v3_cmp_gt_f32"; - case Vop3::Op::V3_CMP_LG_F32: - return "v3_cmp_lg_f32"; - case Vop3::Op::V3_CMP_GE_F32: - return "v3_cmp_ge_f32"; - case Vop3::Op::V3_CMP_O_F32: - return "v3_cmp_o_f32"; - case Vop3::Op::V3_CMP_U_F32: - return "v3_cmp_u_f32"; - case Vop3::Op::V3_CMP_NGE_F32: - return "v3_cmp_nge_f32"; - case Vop3::Op::V3_CMP_NLG_F32: - return "v3_cmp_nlg_f32"; - case Vop3::Op::V3_CMP_NGT_F32: - return "v3_cmp_ngt_f32"; - case Vop3::Op::V3_CMP_NLE_F32: - return "v3_cmp_nle_f32"; - case Vop3::Op::V3_CMP_NEQ_F32: - return "v3_cmp_neq_f32"; - case Vop3::Op::V3_CMP_NLT_F32: - return "v3_cmp_nlt_f32"; - case Vop3::Op::V3_CMP_TRU_F32: - return "v3_cmp_tru_f32"; - case Vop3::Op::V3_CMPX_F_F32: - return "v3_cmpx_f_f32"; - case Vop3::Op::V3_CMPX_LT_F32: - return "v3_cmpx_lt_f32"; - case Vop3::Op::V3_CMPX_EQ_F32: - return "v3_cmpx_eq_f32"; - case Vop3::Op::V3_CMPX_LE_F32: - return "v3_cmpx_le_f32"; - case Vop3::Op::V3_CMPX_GT_F32: - return "v3_cmpx_gt_f32"; - case Vop3::Op::V3_CMPX_LG_F32: - return "v3_cmpx_lg_f32"; - case Vop3::Op::V3_CMPX_GE_F32: - return "v3_cmpx_ge_f32"; - case Vop3::Op::V3_CMPX_O_F32: - return "v3_cmpx_o_f32"; - case Vop3::Op::V3_CMPX_U_F32: - return "v3_cmpx_u_f32"; - case Vop3::Op::V3_CMPX_NGE_F32: - return "v3_cmpx_nge_f32"; - case Vop3::Op::V3_CMPX_NLG_F32: - return "v3_cmpx_nlg_f32"; - case Vop3::Op::V3_CMPX_NGT_F32: - return "v3_cmpx_ngt_f32"; - case Vop3::Op::V3_CMPX_NLE_F32: - return "v3_cmpx_nle_f32"; - case Vop3::Op::V3_CMPX_NEQ_F32: - return "v3_cmpx_neq_f32"; - case Vop3::Op::V3_CMPX_NLT_F32: - return "v3_cmpx_nlt_f32"; - case Vop3::Op::V3_CMPX_TRU_F32: - return "v3_cmpx_tru_f32"; - case Vop3::Op::V3_CMP_F_F64: - return "v3_cmp_f_f64"; - case Vop3::Op::V3_CMP_LT_F64: - return "v3_cmp_lt_f64"; - case Vop3::Op::V3_CMP_EQ_F64: - return "v3_cmp_eq_f64"; - case Vop3::Op::V3_CMP_LE_F64: - return "v3_cmp_le_f64"; - case Vop3::Op::V3_CMP_GT_F64: - return "v3_cmp_gt_f64"; - case Vop3::Op::V3_CMP_LG_F64: - return "v3_cmp_lg_f64"; - case Vop3::Op::V3_CMP_GE_F64: - return "v3_cmp_ge_f64"; - case Vop3::Op::V3_CMP_O_F64: - return "v3_cmp_o_f64"; - case Vop3::Op::V3_CMP_U_F64: - return "v3_cmp_u_f64"; - case Vop3::Op::V3_CMP_NGE_F64: - return "v3_cmp_nge_f64"; - case Vop3::Op::V3_CMP_NLG_F64: - return "v3_cmp_nlg_f64"; - case Vop3::Op::V3_CMP_NGT_F64: - return "v3_cmp_ngt_f64"; - case Vop3::Op::V3_CMP_NLE_F64: - return "v3_cmp_nle_f64"; - case Vop3::Op::V3_CMP_NEQ_F64: - return "v3_cmp_neq_f64"; - case Vop3::Op::V3_CMP_NLT_F64: - return "v3_cmp_nlt_f64"; - case Vop3::Op::V3_CMP_TRU_F64: - return "v3_cmp_tru_f64"; - case Vop3::Op::V3_CMPX_F_F64: - return "v3_cmpx_f_f64"; - case Vop3::Op::V3_CMPX_LT_F64: - return "v3_cmpx_lt_f64"; - case Vop3::Op::V3_CMPX_EQ_F64: - return "v3_cmpx_eq_f64"; - case Vop3::Op::V3_CMPX_LE_F64: - return "v3_cmpx_le_f64"; - case Vop3::Op::V3_CMPX_GT_F64: - return "v3_cmpx_gt_f64"; - case Vop3::Op::V3_CMPX_LG_F64: - return "v3_cmpx_lg_f64"; - case Vop3::Op::V3_CMPX_GE_F64: - return "v3_cmpx_ge_f64"; - case Vop3::Op::V3_CMPX_O_F64: - return "v3_cmpx_o_f64"; - case Vop3::Op::V3_CMPX_U_F64: - return "v3_cmpx_u_f64"; - case Vop3::Op::V3_CMPX_NGE_F64: - return "v3_cmpx_nge_f64"; - case Vop3::Op::V3_CMPX_NLG_F64: - return "v3_cmpx_nlg_f64"; - case Vop3::Op::V3_CMPX_NGT_F64: - return "v3_cmpx_ngt_f64"; - case Vop3::Op::V3_CMPX_NLE_F64: - return "v3_cmpx_nle_f64"; - case Vop3::Op::V3_CMPX_NEQ_F64: - return "v3_cmpx_neq_f64"; - case Vop3::Op::V3_CMPX_NLT_F64: - return "v3_cmpx_nlt_f64"; - case Vop3::Op::V3_CMPX_TRU_F64: - return "v3_cmpx_tru_f64"; - case Vop3::Op::V3_CMPS_F_F32: - return "v3_cmps_f_f32"; - case Vop3::Op::V3_CMPS_LT_F32: - return "v3_cmps_lt_f32"; - case Vop3::Op::V3_CMPS_EQ_F32: - return "v3_cmps_eq_f32"; - case Vop3::Op::V3_CMPS_LE_F32: - return "v3_cmps_le_f32"; - case Vop3::Op::V3_CMPS_GT_F32: - return "v3_cmps_gt_f32"; - case Vop3::Op::V3_CMPS_LG_F32: - return "v3_cmps_lg_f32"; - case Vop3::Op::V3_CMPS_GE_F32: - return "v3_cmps_ge_f32"; - case Vop3::Op::V3_CMPS_O_F32: - return "v3_cmps_o_f32"; - case Vop3::Op::V3_CMPS_U_F32: - return "v3_cmps_u_f32"; - case Vop3::Op::V3_CMPS_NGE_F32: - return "v3_cmps_nge_f32"; - case Vop3::Op::V3_CMPS_NLG_F32: - return "v3_cmps_nlg_f32"; - case Vop3::Op::V3_CMPS_NGT_F32: - return "v3_cmps_ngt_f32"; - case Vop3::Op::V3_CMPS_NLE_F32: - return "v3_cmps_nle_f32"; - case Vop3::Op::V3_CMPS_NEQ_F32: - return "v3_cmps_neq_f32"; - case Vop3::Op::V3_CMPS_NLT_F32: - return "v3_cmps_nlt_f32"; - case Vop3::Op::V3_CMPS_TRU_F32: - return "v3_cmps_tru_f32"; - case Vop3::Op::V3_CMPSX_F_F32: - return "v3_cmpsx_f_f32"; - case Vop3::Op::V3_CMPSX_LT_F32: - return "v3_cmpsx_lt_f32"; - case Vop3::Op::V3_CMPSX_EQ_F32: - return "v3_cmpsx_eq_f32"; - case Vop3::Op::V3_CMPSX_LE_F32: - return "v3_cmpsx_le_f32"; - case Vop3::Op::V3_CMPSX_GT_F32: - return "v3_cmpsx_gt_f32"; - case Vop3::Op::V3_CMPSX_LG_F32: - return "v3_cmpsx_lg_f32"; - case Vop3::Op::V3_CMPSX_GE_F32: - return "v3_cmpsx_ge_f32"; - case Vop3::Op::V3_CMPSX_O_F32: - return "v3_cmpsx_o_f32"; - case Vop3::Op::V3_CMPSX_U_F32: - return "v3_cmpsx_u_f32"; - case Vop3::Op::V3_CMPSX_NGE_F32: - return "v3_cmpsx_nge_f32"; - case Vop3::Op::V3_CMPSX_NLG_F32: - return "v3_cmpsx_nlg_f32"; - case Vop3::Op::V3_CMPSX_NGT_F32: - return "v3_cmpsx_ngt_f32"; - case Vop3::Op::V3_CMPSX_NLE_F32: - return "v3_cmpsx_nle_f32"; - case Vop3::Op::V3_CMPSX_NEQ_F32: - return "v3_cmpsx_neq_f32"; - case Vop3::Op::V3_CMPSX_NLT_F32: - return "v3_cmpsx_nlt_f32"; - case Vop3::Op::V3_CMPSX_TRU_F32: - return "v3_cmpsx_tru_f32"; - case Vop3::Op::V3_CMPS_F_F64: - return "v3_cmps_f_f64"; - case Vop3::Op::V3_CMPS_LT_F64: - return "v3_cmps_lt_f64"; - case Vop3::Op::V3_CMPS_EQ_F64: - return "v3_cmps_eq_f64"; - case Vop3::Op::V3_CMPS_LE_F64: - return "v3_cmps_le_f64"; - case Vop3::Op::V3_CMPS_GT_F64: - return "v3_cmps_gt_f64"; - case Vop3::Op::V3_CMPS_LG_F64: - return "v3_cmps_lg_f64"; - case Vop3::Op::V3_CMPS_GE_F64: - return "v3_cmps_ge_f64"; - case Vop3::Op::V3_CMPS_O_F64: - return "v3_cmps_o_f64"; - case Vop3::Op::V3_CMPS_U_F64: - return "v3_cmps_u_f64"; - case Vop3::Op::V3_CMPS_NGE_F64: - return "v3_cmps_nge_f64"; - case Vop3::Op::V3_CMPS_NLG_F64: - return "v3_cmps_nlg_f64"; - case Vop3::Op::V3_CMPS_NGT_F64: - return "v3_cmps_ngt_f64"; - case Vop3::Op::V3_CMPS_NLE_F64: - return "v3_cmps_nle_f64"; - case Vop3::Op::V3_CMPS_NEQ_F64: - return "v3_cmps_neq_f64"; - case Vop3::Op::V3_CMPS_NLT_F64: - return "v3_cmps_nlt_f64"; - case Vop3::Op::V3_CMPS_TRU_F64: - return "v3_cmps_tru_f64"; - case Vop3::Op::V3_CMPSX_F_F64: - return "v3_cmpsx_f_f64"; - case Vop3::Op::V3_CMPSX_LT_F64: - return "v3_cmpsx_lt_f64"; - case Vop3::Op::V3_CMPSX_EQ_F64: - return "v3_cmpsx_eq_f64"; - case Vop3::Op::V3_CMPSX_LE_F64: - return "v3_cmpsx_le_f64"; - case Vop3::Op::V3_CMPSX_GT_F64: - return "v3_cmpsx_gt_f64"; - case Vop3::Op::V3_CMPSX_LG_F64: - return "v3_cmpsx_lg_f64"; - case Vop3::Op::V3_CMPSX_GE_F64: - return "v3_cmpsx_ge_f64"; - case Vop3::Op::V3_CMPSX_O_F64: - return "v3_cmpsx_o_f64"; - case Vop3::Op::V3_CMPSX_U_F64: - return "v3_cmpsx_u_f64"; - case Vop3::Op::V3_CMPSX_NGE_F64: - return "v3_cmpsx_nge_f64"; - case Vop3::Op::V3_CMPSX_NLG_F64: - return "v3_cmpsx_nlg_f64"; - case Vop3::Op::V3_CMPSX_NGT_F64: - return "v3_cmpsx_ngt_f64"; - case Vop3::Op::V3_CMPSX_NLE_F64: - return "v3_cmpsx_nle_f64"; - case Vop3::Op::V3_CMPSX_NEQ_F64: - return "v3_cmpsx_neq_f64"; - case Vop3::Op::V3_CMPSX_NLT_F64: - return "v3_cmpsx_nlt_f64"; - case Vop3::Op::V3_CMPSX_TRU_F64: - return "v3_cmpsx_tru_f64"; - case Vop3::Op::V3_CMP_F_I32: - return "v3_cmp_f_i32"; - case Vop3::Op::V3_CMP_LT_I32: - return "v3_cmp_lt_i32"; - case Vop3::Op::V3_CMP_EQ_I32: - return "v3_cmp_eq_i32"; - case Vop3::Op::V3_CMP_LE_I32: - return "v3_cmp_le_i32"; - case Vop3::Op::V3_CMP_GT_I32: - return "v3_cmp_gt_i32"; - case Vop3::Op::V3_CMP_NE_I32: - return "v3_cmp_ne_i32"; - case Vop3::Op::V3_CMP_GE_I32: - return "v3_cmp_ge_i32"; - case Vop3::Op::V3_CMP_T_I32: - return "v3_cmp_t_i32"; - case Vop3::Op::V3_CMP_CLASS_F32: - return "v3_cmp_class_f32"; - case Vop3::Op::V3_CMP_LT_I16: - return "v3_cmp_lt_i16"; - case Vop3::Op::V3_CMP_EQ_I16: - return "v3_cmp_eq_i16"; - case Vop3::Op::V3_CMP_LE_I16: - return "v3_cmp_le_i16"; - case Vop3::Op::V3_CMP_GT_I16: - return "v3_cmp_gt_i16"; - case Vop3::Op::V3_CMP_NE_I16: - return "v3_cmp_ne_i16"; - case Vop3::Op::V3_CMP_GE_I16: - return "v3_cmp_ge_i16"; - case Vop3::Op::V3_CMP_CLASS_F16: - return "v3_cmp_class_f16"; - case Vop3::Op::V3_CMPX_F_I32: - return "v3_cmpx_f_i32"; - case Vop3::Op::V3_CMPX_LT_I32: - return "v3_cmpx_lt_i32"; - case Vop3::Op::V3_CMPX_EQ_I32: - return "v3_cmpx_eq_i32"; - case Vop3::Op::V3_CMPX_LE_I32: - return "v3_cmpx_le_i32"; - case Vop3::Op::V3_CMPX_GT_I32: - return "v3_cmpx_gt_i32"; - case Vop3::Op::V3_CMPX_NE_I32: - return "v3_cmpx_ne_i32"; - case Vop3::Op::V3_CMPX_GE_I32: - return "v3_cmpx_ge_i32"; - case Vop3::Op::V3_CMPX_T_I32: - return "v3_cmpx_t_i32"; - case Vop3::Op::V3_CMPX_CLASS_F32: - return "v3_cmpx_class_f32"; - case Vop3::Op::V3_CMPX_LT_I16: - return "v3_cmpx_lt_i16"; - case Vop3::Op::V3_CMPX_EQ_I16: - return "v3_cmpx_eq_i16"; - case Vop3::Op::V3_CMPX_LE_I16: - return "v3_cmpx_le_i16"; - case Vop3::Op::V3_CMPX_GT_I16: - return "v3_cmpx_gt_i16"; - case Vop3::Op::V3_CMPX_NE_I16: - return "v3_cmpx_ne_i16"; - case Vop3::Op::V3_CMPX_GE_I16: - return "v3_cmpx_ge_i16"; - case Vop3::Op::V3_CMPX_CLASS_F16: - return "v3_cmpx_class_f16"; - case Vop3::Op::V3_CMP_F_I64: - return "v3_cmp_f_i64"; - case Vop3::Op::V3_CMP_LT_I64: - return "v3_cmp_lt_i64"; - case Vop3::Op::V3_CMP_EQ_I64: - return "v3_cmp_eq_i64"; - case Vop3::Op::V3_CMP_LE_I64: - return "v3_cmp_le_i64"; - case Vop3::Op::V3_CMP_GT_I64: - return "v3_cmp_gt_i64"; - case Vop3::Op::V3_CMP_NE_I64: - return "v3_cmp_ne_i64"; - case Vop3::Op::V3_CMP_GE_I64: - return "v3_cmp_ge_i64"; - case Vop3::Op::V3_CMP_T_I64: - return "v3_cmp_t_i64"; - case Vop3::Op::V3_CMP_CLASS_F64: - return "v3_cmp_class_f64"; - case Vop3::Op::V3_CMP_LT_U16: - return "v3_cmp_lt_u16"; - case Vop3::Op::V3_CMP_EQ_U16: - return "v3_cmp_eq_u16"; - case Vop3::Op::V3_CMP_LE_U16: - return "v3_cmp_le_u16"; - case Vop3::Op::V3_CMP_GT_U16: - return "v3_cmp_gt_u16"; - case Vop3::Op::V3_CMP_NE_U16: - return "v3_cmp_ne_u16"; - case Vop3::Op::V3_CMP_GE_U16: - return "v3_cmp_ge_u16"; - case Vop3::Op::V3_CMPX_F_I64: - return "v3_cmpx_f_i64"; - case Vop3::Op::V3_CMPX_LT_I64: - return "v3_cmpx_lt_i64"; - case Vop3::Op::V3_CMPX_EQ_I64: - return "v3_cmpx_eq_i64"; - case Vop3::Op::V3_CMPX_LE_I64: - return "v3_cmpx_le_i64"; - case Vop3::Op::V3_CMPX_GT_I64: - return "v3_cmpx_gt_i64"; - case Vop3::Op::V3_CMPX_NE_I64: - return "v3_cmpx_ne_i64"; - case Vop3::Op::V3_CMPX_GE_I64: - return "v3_cmpx_ge_i64"; - case Vop3::Op::V3_CMPX_T_I64: - return "v3_cmpx_t_i64"; - case Vop3::Op::V3_CMPX_CLASS_F64: - return "v3_cmpx_class_f64"; - case Vop3::Op::V3_CMPX_LT_U16: - return "v3_cmpx_lt_u16"; - case Vop3::Op::V3_CMPX_EQ_U16: - return "v3_cmpx_eq_u16"; - case Vop3::Op::V3_CMPX_LE_U16: - return "v3_cmpx_le_u16"; - case Vop3::Op::V3_CMPX_GT_U16: - return "v3_cmpx_gt_u16"; - case Vop3::Op::V3_CMPX_NE_U16: - return "v3_cmpx_ne_u16"; - case Vop3::Op::V3_CMPX_GE_U16: - return "v3_cmpx_ge_u16"; - case Vop3::Op::V3_CMP_F_U32: - return "v3_cmp_f_u32"; - case Vop3::Op::V3_CMP_LT_U32: - return "v3_cmp_lt_u32"; - case Vop3::Op::V3_CMP_EQ_U32: - return "v3_cmp_eq_u32"; - case Vop3::Op::V3_CMP_LE_U32: - return "v3_cmp_le_u32"; - case Vop3::Op::V3_CMP_GT_U32: - return "v3_cmp_gt_u32"; - case Vop3::Op::V3_CMP_NE_U32: - return "v3_cmp_ne_u32"; - case Vop3::Op::V3_CMP_GE_U32: - return "v3_cmp_ge_u32"; - case Vop3::Op::V3_CMP_T_U32: - return "v3_cmp_t_u32"; - case Vop3::Op::V3_CMP_F_F16: - return "v3_cmp_f_f16"; - case Vop3::Op::V3_CMP_LT_F16: - return "v3_cmp_lt_f16"; - case Vop3::Op::V3_CMP_EQ_F16: - return "v3_cmp_eq_f16"; - case Vop3::Op::V3_CMP_LE_F16: - return "v3_cmp_le_f16"; - case Vop3::Op::V3_CMP_GT_F16: - return "v3_cmp_gt_f16"; - case Vop3::Op::V3_CMP_LG_F16: - return "v3_cmp_lg_f16"; - case Vop3::Op::V3_CMP_GE_F16: - return "v3_cmp_ge_f16"; - case Vop3::Op::V3_CMP_O_F16: - return "v3_cmp_o_f16"; - case Vop3::Op::V3_CMPX_F_U32: - return "v3_cmpx_f_u32"; - case Vop3::Op::V3_CMPX_LT_U32: - return "v3_cmpx_lt_u32"; - case Vop3::Op::V3_CMPX_EQ_U32: - return "v3_cmpx_eq_u32"; - case Vop3::Op::V3_CMPX_LE_U32: - return "v3_cmpx_le_u32"; - case Vop3::Op::V3_CMPX_GT_U32: - return "v3_cmpx_gt_u32"; - case Vop3::Op::V3_CMPX_NE_U32: - return "v3_cmpx_ne_u32"; - case Vop3::Op::V3_CMPX_GE_U32: - return "v3_cmpx_ge_u32"; - case Vop3::Op::V3_CMPX_T_U32: - return "v3_cmpx_t_u32"; - case Vop3::Op::V3_CMPX_F_F16: - return "v3_cmpx_f_f16"; - case Vop3::Op::V3_CMPX_LT_F16: - return "v3_cmpx_lt_f16"; - case Vop3::Op::V3_CMPX_EQ_F16: - return "v3_cmpx_eq_f16"; - case Vop3::Op::V3_CMPX_LE_F16: - return "v3_cmpx_le_f16"; - case Vop3::Op::V3_CMPX_GT_F16: - return "v3_cmpx_gt_f16"; - case Vop3::Op::V3_CMPX_LG_F16: - return "v3_cmpx_lg_f16"; - case Vop3::Op::V3_CMPX_GE_F16: - return "v3_cmpx_ge_f16"; - case Vop3::Op::V3_CMPX_O_F16: - return "v3_cmpx_o_f16"; - case Vop3::Op::V3_CMP_F_U64: - return "v3_cmp_f_u64"; - case Vop3::Op::V3_CMP_LT_U64: - return "v3_cmp_lt_u64"; - case Vop3::Op::V3_CMP_EQ_U64: - return "v3_cmp_eq_u64"; - case Vop3::Op::V3_CMP_LE_U64: - return "v3_cmp_le_u64"; - case Vop3::Op::V3_CMP_GT_U64: - return "v3_cmp_gt_u64"; - case Vop3::Op::V3_CMP_NE_U64: - return "v3_cmp_ne_u64"; - case Vop3::Op::V3_CMP_GE_U64: - return "v3_cmp_ge_u64"; - case Vop3::Op::V3_CMP_T_U64: - return "v3_cmp_t_u64"; - case Vop3::Op::V3_CMP_U_F16: - return "v3_cmp_u_f16"; - case Vop3::Op::V3_CMP_NGE_F16: - return "v3_cmp_nge_f16"; - case Vop3::Op::V3_CMP_NLG_F16: - return "v3_cmp_nlg_f16"; - case Vop3::Op::V3_CMP_NGT_F16: - return "v3_cmp_ngt_f16"; - case Vop3::Op::V3_CMP_NLE_F16: - return "v3_cmp_nle_f16"; - case Vop3::Op::V3_CMP_NEQ_F16: - return "v3_cmp_neq_f16"; - case Vop3::Op::V3_CMP_NLT_F16: - return "v3_cmp_nlt_f16"; - case Vop3::Op::V3_CMP_TRU_F16: - return "v3_cmp_tru_f16"; - case Vop3::Op::V3_CMPX_F_U64: - return "v3_cmpx_f_u64"; - case Vop3::Op::V3_CMPX_LT_U64: - return "v3_cmpx_lt_u64"; - case Vop3::Op::V3_CMPX_EQ_U64: - return "v3_cmpx_eq_u64"; - case Vop3::Op::V3_CMPX_LE_U64: - return "v3_cmpx_le_u64"; - case Vop3::Op::V3_CMPX_GT_U64: - return "v3_cmpx_gt_u64"; - case Vop3::Op::V3_CMPX_NE_U64: - return "v3_cmpx_ne_u64"; - case Vop3::Op::V3_CMPX_GE_U64: - return "v3_cmpx_ge_u64"; - case Vop3::Op::V3_CMPX_T_U64: - return "v3_cmpx_t_u64"; - case Vop3::Op::V3_CNDMASK_B32: - return "v3_cndmask_b32"; - case Vop3::Op::V3_READLANE_B32: - return "v3_readlane_b32"; - case Vop3::Op::V3_WRITELANE_B32: - return "v3_writelane_b32"; - case Vop3::Op::V3_ADD_F32: - return "v3_add_f32"; - case Vop3::Op::V3_SUB_F32: - return "v3_sub_f32"; - case Vop3::Op::V3_SUBREV_F32: - return "v3_subrev_f32"; - case Vop3::Op::V3_MAC_LEGACY_F32: - return "v3_mac_legacy_f32"; - case Vop3::Op::V3_MUL_LEGACY_F32: - return "v3_mul_legacy_f32"; - case Vop3::Op::V3_MUL_F32: - return "v3_mul_f32"; - case Vop3::Op::V3_MUL_I32_I24: - return "v3_mul_i32_i24"; - case Vop3::Op::V3_MUL_HI_I32_I24: - return "v3_mul_hi_i32_i24"; - case Vop3::Op::V3_MUL_U32_U24: - return "v3_mul_u32_u24"; - case Vop3::Op::V3_MUL_HI_U32_U24: - return "v3_mul_hi_u32_u24"; - case Vop3::Op::V3_MIN_LEGACY_F32: - return "v3_min_legacy_f32"; - case Vop3::Op::V3_MAX_LEGACY_F32: - return "v3_max_legacy_f32"; - case Vop3::Op::V3_MIN_F32: - return "v3_min_f32"; - case Vop3::Op::V3_MAX_F32: - return "v3_max_f32"; - case Vop3::Op::V3_MIN_I32: - return "v3_min_i32"; - case Vop3::Op::V3_MAX_I32: - return "v3_max_i32"; - case Vop3::Op::V3_MIN_U32: - return "v3_min_u32"; - case Vop3::Op::V3_MAX_U32: - return "v3_max_u32"; - case Vop3::Op::V3_LSHR_B32: - return "v3_lshr_b32"; - case Vop3::Op::V3_LSHRREV_B32: - return "v3_lshrrev_b32"; - case Vop3::Op::V3_ASHR_I32: - return "v3_ashr_i32"; - case Vop3::Op::V3_ASHRREV_I32: - return "v3_ashrrev_i32"; - case Vop3::Op::V3_LSHL_B32: - return "v3_lshl_b32"; - case Vop3::Op::V3_LSHLREV_B32: - return "v3_lshlrev_b32"; - case Vop3::Op::V3_AND_B32: - return "v3_and_b32"; - case Vop3::Op::V3_OR_B32: - return "v3_or_b32"; - case Vop3::Op::V3_XOR_B32: - return "v3_xor_b32"; - case Vop3::Op::V3_BFM_B32: - return "v3_bfm_b32"; - case Vop3::Op::V3_MAC_F32: - return "v3_mac_f32"; - case Vop3::Op::V3_MADMK_F32: - return "v3_madmk_f32"; - case Vop3::Op::V3_MADAK_F32: - return "v3_madak_f32"; - case Vop3::Op::V3_BCNT_U32_B32: - return "v3_bcnt_u32_b32"; - case Vop3::Op::V3_MBCNT_LO_U32_B32: - return "v3_mbcnt_lo_u32_b32"; - case Vop3::Op::V3_MBCNT_HI_U32_B32: - return "v3_mbcnt_hi_u32_b32"; - case Vop3::Op::V3_ADD_I32: - return "v3_add_i32"; - case Vop3::Op::V3_SUB_I32: - return "v3_sub_i32"; - case Vop3::Op::V3_SUBREV_I32: - return "v3_subrev_i32"; - case Vop3::Op::V3_ADDC_U32: - return "v3_addc_u32"; - case Vop3::Op::V3_SUBB_U32: - return "v3_subb_u32"; - case Vop3::Op::V3_SUBBREV_U32: - return "v3_subbrev_u32"; - case Vop3::Op::V3_LDEXP_F32: - return "v3_ldexp_f32"; - case Vop3::Op::V3_CVT_PKACCUM_U8_F32: - return "v3_cvt_pkaccum_u8_f32"; - case Vop3::Op::V3_CVT_PKNORM_I16_F32: - return "v3_cvt_pknorm_i16_f32"; - case Vop3::Op::V3_CVT_PKNORM_U16_F32: - return "v3_cvt_pknorm_u16_f32"; - case Vop3::Op::V3_CVT_PKRTZ_F16_F32: - return "v3_cvt_pkrtz_f16_f32"; - case Vop3::Op::V3_CVT_PK_U16_U32: - return "v3_cvt_pk_u16_u32"; - case Vop3::Op::V3_CVT_PK_I16_I32: - return "v3_cvt_pk_i16_i32"; - case Vop3::Op::V3_MAD_LEGACY_F32: - return "v3_mad_legacy_f32"; - case Vop3::Op::V3_MAD_F32: - return "v3_mad_f32"; - case Vop3::Op::V3_MAD_I32_I24: - return "v3_mad_i32_i24"; - case Vop3::Op::V3_MAD_U32_U24: - return "v3_mad_u32_u24"; - case Vop3::Op::V3_CUBEID_F32: - return "v3_cubeid_f32"; - case Vop3::Op::V3_CUBESC_F32: - return "v3_cubesc_f32"; - case Vop3::Op::V3_CUBETC_F32: - return "v3_cubetc_f32"; - case Vop3::Op::V3_CUBEMA_F32: - return "v3_cubema_f32"; - case Vop3::Op::V3_BFE_U32: - return "v3_bfe_u32"; - case Vop3::Op::V3_BFE_I32: - return "v3_bfe_i32"; - case Vop3::Op::V3_BFI_B32: - return "v3_bfi_b32"; - case Vop3::Op::V3_FMA_F32: - return "v3_fma_f32"; - case Vop3::Op::V3_FMA_F64: - return "v3_fma_f64"; - case Vop3::Op::V3_LERP_U8: - return "v3_lerp_u8"; - case Vop3::Op::V3_ALIGNBIT_B32: - return "v3_alignbit_b32"; - case Vop3::Op::V3_ALIGNBYTE_B32: - return "v3_alignbyte_b32"; - case Vop3::Op::V3_MULLIT_F32: - return "v3_mullit_f32"; - case Vop3::Op::V3_MIN3_F32: - return "v3_min3_f32"; - case Vop3::Op::V3_MIN3_I32: - return "v3_min3_i32"; - case Vop3::Op::V3_MIN3_U32: - return "v3_min3_u32"; - case Vop3::Op::V3_MAX3_F32: - return "v3_max3_f32"; - case Vop3::Op::V3_MAX3_I32: - return "v3_max3_i32"; - case Vop3::Op::V3_MAX3_U32: - return "v3_max3_u32"; - case Vop3::Op::V3_MED3_F32: - return "v3_med3_f32"; - case Vop3::Op::V3_MED3_I32: - return "v3_med3_i32"; - case Vop3::Op::V3_MED3_U32: - return "v3_med3_u32"; - case Vop3::Op::V3_SAD_U8: - return "v3_sad_u8"; - case Vop3::Op::V3_SAD_HI_U8: - return "v3_sad_hi_u8"; - case Vop3::Op::V3_SAD_U16: - return "v3_sad_u16"; - case Vop3::Op::V3_SAD_U32: - return "v3_sad_u32"; - case Vop3::Op::V3_CVT_PK_U8_F32: - return "v3_cvt_pk_u8_f32"; - case Vop3::Op::V3_DIV_FIXUP_F32: - return "v3_div_fixup_f32"; - case Vop3::Op::V3_DIV_FIXUP_F64: - return "v3_div_fixup_f64"; - case Vop3::Op::V3_LSHL_B64: - return "v3_lshl_b64"; - case Vop3::Op::V3_LSHR_B64: - return "v3_lshr_b64"; - case Vop3::Op::V3_ASHR_I64: - return "v3_ashr_i64"; - case Vop3::Op::V3_ADD_F64: - return "v3_add_f64"; - case Vop3::Op::V3_MUL_F64: - return "v3_mul_f64"; - case Vop3::Op::V3_MIN_F64: - return "v3_min_f64"; - case Vop3::Op::V3_MAX_F64: - return "v3_max_f64"; - case Vop3::Op::V3_LDEXP_F64: - return "v3_ldexp_f64"; - case Vop3::Op::V3_MUL_LO_U32: - return "v3_mul_lo_u32"; - case Vop3::Op::V3_MUL_HI_U32: - return "v3_mul_hi_u32"; - case Vop3::Op::V3_MUL_LO_I32: - return "v3_mul_lo_i32"; - case Vop3::Op::V3_MUL_HI_I32: - return "v3_mul_hi_i32"; - case Vop3::Op::V3_DIV_SCALE_F32: - return "v3_div_scale_f32"; - case Vop3::Op::V3_DIV_SCALE_F64: - return "v3_div_scale_f64"; - case Vop3::Op::V3_DIV_FMAS_F32: - return "v3_div_fmas_f32"; - case Vop3::Op::V3_DIV_FMAS_F64: - return "v3_div_fmas_f64"; - case Vop3::Op::V3_MSAD_U8: - return "v3_msad_u8"; - case Vop3::Op::V3_QSAD_U8: - return "v3_qsad_u8"; - case Vop3::Op::V3_MQSAD_U8: - return "v3_mqsad_u8"; - case Vop3::Op::V3_TRIG_PREOP_F64: - return "v3_trig_preop_f64"; - case Vop3::Op::V3_NOP: - return "v3_nop"; - case Vop3::Op::V3_MOV_B32: - return "v3_mov_b32"; - case Vop3::Op::V3_READFIRSTLANE_B32: - return "v3_readfirstlane_b32"; - case Vop3::Op::V3_CVT_I32_F64: - return "v3_cvt_i32_f64"; - case Vop3::Op::V3_CVT_F64_I32: - return "v3_cvt_f64_i32"; - case Vop3::Op::V3_CVT_F32_I32: - return "v3_cvt_f32_i32"; - case Vop3::Op::V3_CVT_F32_U32: - return "v3_cvt_f32_u32"; - case Vop3::Op::V3_CVT_U32_F32: - return "v3_cvt_u32_f32"; - case Vop3::Op::V3_CVT_I32_F32: - return "v3_cvt_i32_f32"; - case Vop3::Op::V3_MOV_FED_B32: - return "v3_mov_fed_b32"; - case Vop3::Op::V3_CVT_F16_F32: - return "v3_cvt_f16_f32"; - case Vop3::Op::V3_CVT_F32_F16: - return "v3_cvt_f32_f16"; - case Vop3::Op::V3_CVT_RPI_I32_F32: - return "v3_cvt_rpi_i32_f32"; - case Vop3::Op::V3_CVT_FLR_I32_F32: - return "v3_cvt_flr_i32_f32"; - case Vop3::Op::V3_CVT_OFF_F32_I4: - return "v3_cvt_off_f32_i4"; - case Vop3::Op::V3_CVT_F32_F64: - return "v3_cvt_f32_f64"; - case Vop3::Op::V3_CVT_F64_F32: - return "v3_cvt_f64_f32"; - case Vop3::Op::V3_CVT_F32_UBYTE0: - return "v3_cvt_f32_ubyte0"; - case Vop3::Op::V3_CVT_F32_UBYTE1: - return "v3_cvt_f32_ubyte1"; - case Vop3::Op::V3_CVT_F32_UBYTE2: - return "v3_cvt_f32_ubyte2"; - case Vop3::Op::V3_CVT_F32_UBYTE3: - return "v3_cvt_f32_ubyte3"; - case Vop3::Op::V3_CVT_U32_F64: - return "v3_cvt_u32_f64"; - case Vop3::Op::V3_CVT_F64_U32: - return "v3_cvt_f64_u32"; - case Vop3::Op::V3_FRACT_F32: - return "v3_fract_f32"; - case Vop3::Op::V3_TRUNC_F32: - return "v3_trunc_f32"; - case Vop3::Op::V3_CEIL_F32: - return "v3_ceil_f32"; - case Vop3::Op::V3_RNDNE_F32: - return "v3_rndne_f32"; - case Vop3::Op::V3_FLOOR_F32: - return "v3_floor_f32"; - case Vop3::Op::V3_EXP_F32: - return "v3_exp_f32"; - case Vop3::Op::V3_LOG_CLAMP_F32: - return "v3_log_clamp_f32"; - case Vop3::Op::V3_LOG_F32: - return "v3_log_f32"; - case Vop3::Op::V3_RCP_CLAMP_F32: - return "v3_rcp_clamp_f32"; - case Vop3::Op::V3_RCP_LEGACY_F32: - return "v3_rcp_legacy_f32"; - case Vop3::Op::V3_RCP_F32: - return "v3_rcp_f32"; - case Vop3::Op::V3_RCP_IFLAG_F32: - return "v3_rcp_iflag_f32"; - case Vop3::Op::V3_RSQ_CLAMP_F32: - return "v3_rsq_clamp_f32"; - case Vop3::Op::V3_RSQ_LEGACY_F32: - return "v3_rsq_legacy_f32"; - case Vop3::Op::V3_RSQ_F32: - return "v3_rsq_f32"; - case Vop3::Op::V3_RCP_F64: - return "v3_rcp_f64"; - case Vop3::Op::V3_RCP_CLAMP_F64: - return "v3_rcp_clamp_f64"; - case Vop3::Op::V3_RSQ_F64: - return "v3_rsq_f64"; - case Vop3::Op::V3_RSQ_CLAMP_F64: - return "v3_rsq_clamp_f64"; - case Vop3::Op::V3_SQRT_F32: - return "v3_sqrt_f32"; - case Vop3::Op::V3_SQRT_F64: - return "v3_sqrt_f64"; - case Vop3::Op::V3_SIN_F32: - return "v3_sin_f32"; - case Vop3::Op::V3_COS_F32: - return "v3_cos_f32"; - case Vop3::Op::V3_NOT_B32: - return "v3_not_b32"; - case Vop3::Op::V3_BFREV_B32: - return "v3_bfrev_b32"; - case Vop3::Op::V3_FFBH_U32: - return "v3_ffbh_u32"; - case Vop3::Op::V3_FFBL_B32: - return "v3_ffbl_b32"; - case Vop3::Op::V3_FFBH_I32: - return "v3_ffbh_i32"; - case Vop3::Op::V3_FREXP_EXP_I32_F64: - return "v3_frexp_exp_i32_f64"; - case Vop3::Op::V3_FREXP_MANT_F64: - return "v3_frexp_mant_f64"; - case Vop3::Op::V3_FRACT_F64: - return "v3_fract_f64"; - case Vop3::Op::V3_FREXP_EXP_I32_F32: - return "v3_frexp_exp_i32_f32"; - case Vop3::Op::V3_FREXP_MANT_F32: - return "v3_frexp_mant_f32"; - case Vop3::Op::V3_CLREXCP: - return "v3_clrexcp"; - case Vop3::Op::V3_MOVRELD_B32: - return "v3_movreld_b32"; - case Vop3::Op::V3_MOVRELS_B32: - return "v3_movrels_b32"; - case Vop3::Op::V3_MOVRELSD_B32: - return "v3_movrelsd_b32"; - default: - return nullptr; - } +const char* amdgpu::shader::vop3OpcodeToString(Vop3::Op op) +{ + switch (op) + { + case Vop3::Op::V3_CMP_F_F32: + return "v3_cmp_f_f32"; + case Vop3::Op::V3_CMP_LT_F32: + return "v3_cmp_lt_f32"; + case Vop3::Op::V3_CMP_EQ_F32: + return "v3_cmp_eq_f32"; + case Vop3::Op::V3_CMP_LE_F32: + return "v3_cmp_le_f32"; + case Vop3::Op::V3_CMP_GT_F32: + return "v3_cmp_gt_f32"; + case Vop3::Op::V3_CMP_LG_F32: + return "v3_cmp_lg_f32"; + case Vop3::Op::V3_CMP_GE_F32: + return "v3_cmp_ge_f32"; + case Vop3::Op::V3_CMP_O_F32: + return "v3_cmp_o_f32"; + case Vop3::Op::V3_CMP_U_F32: + return "v3_cmp_u_f32"; + case Vop3::Op::V3_CMP_NGE_F32: + return "v3_cmp_nge_f32"; + case Vop3::Op::V3_CMP_NLG_F32: + return "v3_cmp_nlg_f32"; + case Vop3::Op::V3_CMP_NGT_F32: + return "v3_cmp_ngt_f32"; + case Vop3::Op::V3_CMP_NLE_F32: + return "v3_cmp_nle_f32"; + case Vop3::Op::V3_CMP_NEQ_F32: + return "v3_cmp_neq_f32"; + case Vop3::Op::V3_CMP_NLT_F32: + return "v3_cmp_nlt_f32"; + case Vop3::Op::V3_CMP_TRU_F32: + return "v3_cmp_tru_f32"; + case Vop3::Op::V3_CMPX_F_F32: + return "v3_cmpx_f_f32"; + case Vop3::Op::V3_CMPX_LT_F32: + return "v3_cmpx_lt_f32"; + case Vop3::Op::V3_CMPX_EQ_F32: + return "v3_cmpx_eq_f32"; + case Vop3::Op::V3_CMPX_LE_F32: + return "v3_cmpx_le_f32"; + case Vop3::Op::V3_CMPX_GT_F32: + return "v3_cmpx_gt_f32"; + case Vop3::Op::V3_CMPX_LG_F32: + return "v3_cmpx_lg_f32"; + case Vop3::Op::V3_CMPX_GE_F32: + return "v3_cmpx_ge_f32"; + case Vop3::Op::V3_CMPX_O_F32: + return "v3_cmpx_o_f32"; + case Vop3::Op::V3_CMPX_U_F32: + return "v3_cmpx_u_f32"; + case Vop3::Op::V3_CMPX_NGE_F32: + return "v3_cmpx_nge_f32"; + case Vop3::Op::V3_CMPX_NLG_F32: + return "v3_cmpx_nlg_f32"; + case Vop3::Op::V3_CMPX_NGT_F32: + return "v3_cmpx_ngt_f32"; + case Vop3::Op::V3_CMPX_NLE_F32: + return "v3_cmpx_nle_f32"; + case Vop3::Op::V3_CMPX_NEQ_F32: + return "v3_cmpx_neq_f32"; + case Vop3::Op::V3_CMPX_NLT_F32: + return "v3_cmpx_nlt_f32"; + case Vop3::Op::V3_CMPX_TRU_F32: + return "v3_cmpx_tru_f32"; + case Vop3::Op::V3_CMP_F_F64: + return "v3_cmp_f_f64"; + case Vop3::Op::V3_CMP_LT_F64: + return "v3_cmp_lt_f64"; + case Vop3::Op::V3_CMP_EQ_F64: + return "v3_cmp_eq_f64"; + case Vop3::Op::V3_CMP_LE_F64: + return "v3_cmp_le_f64"; + case Vop3::Op::V3_CMP_GT_F64: + return "v3_cmp_gt_f64"; + case Vop3::Op::V3_CMP_LG_F64: + return "v3_cmp_lg_f64"; + case Vop3::Op::V3_CMP_GE_F64: + return "v3_cmp_ge_f64"; + case Vop3::Op::V3_CMP_O_F64: + return "v3_cmp_o_f64"; + case Vop3::Op::V3_CMP_U_F64: + return "v3_cmp_u_f64"; + case Vop3::Op::V3_CMP_NGE_F64: + return "v3_cmp_nge_f64"; + case Vop3::Op::V3_CMP_NLG_F64: + return "v3_cmp_nlg_f64"; + case Vop3::Op::V3_CMP_NGT_F64: + return "v3_cmp_ngt_f64"; + case Vop3::Op::V3_CMP_NLE_F64: + return "v3_cmp_nle_f64"; + case Vop3::Op::V3_CMP_NEQ_F64: + return "v3_cmp_neq_f64"; + case Vop3::Op::V3_CMP_NLT_F64: + return "v3_cmp_nlt_f64"; + case Vop3::Op::V3_CMP_TRU_F64: + return "v3_cmp_tru_f64"; + case Vop3::Op::V3_CMPX_F_F64: + return "v3_cmpx_f_f64"; + case Vop3::Op::V3_CMPX_LT_F64: + return "v3_cmpx_lt_f64"; + case Vop3::Op::V3_CMPX_EQ_F64: + return "v3_cmpx_eq_f64"; + case Vop3::Op::V3_CMPX_LE_F64: + return "v3_cmpx_le_f64"; + case Vop3::Op::V3_CMPX_GT_F64: + return "v3_cmpx_gt_f64"; + case Vop3::Op::V3_CMPX_LG_F64: + return "v3_cmpx_lg_f64"; + case Vop3::Op::V3_CMPX_GE_F64: + return "v3_cmpx_ge_f64"; + case Vop3::Op::V3_CMPX_O_F64: + return "v3_cmpx_o_f64"; + case Vop3::Op::V3_CMPX_U_F64: + return "v3_cmpx_u_f64"; + case Vop3::Op::V3_CMPX_NGE_F64: + return "v3_cmpx_nge_f64"; + case Vop3::Op::V3_CMPX_NLG_F64: + return "v3_cmpx_nlg_f64"; + case Vop3::Op::V3_CMPX_NGT_F64: + return "v3_cmpx_ngt_f64"; + case Vop3::Op::V3_CMPX_NLE_F64: + return "v3_cmpx_nle_f64"; + case Vop3::Op::V3_CMPX_NEQ_F64: + return "v3_cmpx_neq_f64"; + case Vop3::Op::V3_CMPX_NLT_F64: + return "v3_cmpx_nlt_f64"; + case Vop3::Op::V3_CMPX_TRU_F64: + return "v3_cmpx_tru_f64"; + case Vop3::Op::V3_CMPS_F_F32: + return "v3_cmps_f_f32"; + case Vop3::Op::V3_CMPS_LT_F32: + return "v3_cmps_lt_f32"; + case Vop3::Op::V3_CMPS_EQ_F32: + return "v3_cmps_eq_f32"; + case Vop3::Op::V3_CMPS_LE_F32: + return "v3_cmps_le_f32"; + case Vop3::Op::V3_CMPS_GT_F32: + return "v3_cmps_gt_f32"; + case Vop3::Op::V3_CMPS_LG_F32: + return "v3_cmps_lg_f32"; + case Vop3::Op::V3_CMPS_GE_F32: + return "v3_cmps_ge_f32"; + case Vop3::Op::V3_CMPS_O_F32: + return "v3_cmps_o_f32"; + case Vop3::Op::V3_CMPS_U_F32: + return "v3_cmps_u_f32"; + case Vop3::Op::V3_CMPS_NGE_F32: + return "v3_cmps_nge_f32"; + case Vop3::Op::V3_CMPS_NLG_F32: + return "v3_cmps_nlg_f32"; + case Vop3::Op::V3_CMPS_NGT_F32: + return "v3_cmps_ngt_f32"; + case Vop3::Op::V3_CMPS_NLE_F32: + return "v3_cmps_nle_f32"; + case Vop3::Op::V3_CMPS_NEQ_F32: + return "v3_cmps_neq_f32"; + case Vop3::Op::V3_CMPS_NLT_F32: + return "v3_cmps_nlt_f32"; + case Vop3::Op::V3_CMPS_TRU_F32: + return "v3_cmps_tru_f32"; + case Vop3::Op::V3_CMPSX_F_F32: + return "v3_cmpsx_f_f32"; + case Vop3::Op::V3_CMPSX_LT_F32: + return "v3_cmpsx_lt_f32"; + case Vop3::Op::V3_CMPSX_EQ_F32: + return "v3_cmpsx_eq_f32"; + case Vop3::Op::V3_CMPSX_LE_F32: + return "v3_cmpsx_le_f32"; + case Vop3::Op::V3_CMPSX_GT_F32: + return "v3_cmpsx_gt_f32"; + case Vop3::Op::V3_CMPSX_LG_F32: + return "v3_cmpsx_lg_f32"; + case Vop3::Op::V3_CMPSX_GE_F32: + return "v3_cmpsx_ge_f32"; + case Vop3::Op::V3_CMPSX_O_F32: + return "v3_cmpsx_o_f32"; + case Vop3::Op::V3_CMPSX_U_F32: + return "v3_cmpsx_u_f32"; + case Vop3::Op::V3_CMPSX_NGE_F32: + return "v3_cmpsx_nge_f32"; + case Vop3::Op::V3_CMPSX_NLG_F32: + return "v3_cmpsx_nlg_f32"; + case Vop3::Op::V3_CMPSX_NGT_F32: + return "v3_cmpsx_ngt_f32"; + case Vop3::Op::V3_CMPSX_NLE_F32: + return "v3_cmpsx_nle_f32"; + case Vop3::Op::V3_CMPSX_NEQ_F32: + return "v3_cmpsx_neq_f32"; + case Vop3::Op::V3_CMPSX_NLT_F32: + return "v3_cmpsx_nlt_f32"; + case Vop3::Op::V3_CMPSX_TRU_F32: + return "v3_cmpsx_tru_f32"; + case Vop3::Op::V3_CMPS_F_F64: + return "v3_cmps_f_f64"; + case Vop3::Op::V3_CMPS_LT_F64: + return "v3_cmps_lt_f64"; + case Vop3::Op::V3_CMPS_EQ_F64: + return "v3_cmps_eq_f64"; + case Vop3::Op::V3_CMPS_LE_F64: + return "v3_cmps_le_f64"; + case Vop3::Op::V3_CMPS_GT_F64: + return "v3_cmps_gt_f64"; + case Vop3::Op::V3_CMPS_LG_F64: + return "v3_cmps_lg_f64"; + case Vop3::Op::V3_CMPS_GE_F64: + return "v3_cmps_ge_f64"; + case Vop3::Op::V3_CMPS_O_F64: + return "v3_cmps_o_f64"; + case Vop3::Op::V3_CMPS_U_F64: + return "v3_cmps_u_f64"; + case Vop3::Op::V3_CMPS_NGE_F64: + return "v3_cmps_nge_f64"; + case Vop3::Op::V3_CMPS_NLG_F64: + return "v3_cmps_nlg_f64"; + case Vop3::Op::V3_CMPS_NGT_F64: + return "v3_cmps_ngt_f64"; + case Vop3::Op::V3_CMPS_NLE_F64: + return "v3_cmps_nle_f64"; + case Vop3::Op::V3_CMPS_NEQ_F64: + return "v3_cmps_neq_f64"; + case Vop3::Op::V3_CMPS_NLT_F64: + return "v3_cmps_nlt_f64"; + case Vop3::Op::V3_CMPS_TRU_F64: + return "v3_cmps_tru_f64"; + case Vop3::Op::V3_CMPSX_F_F64: + return "v3_cmpsx_f_f64"; + case Vop3::Op::V3_CMPSX_LT_F64: + return "v3_cmpsx_lt_f64"; + case Vop3::Op::V3_CMPSX_EQ_F64: + return "v3_cmpsx_eq_f64"; + case Vop3::Op::V3_CMPSX_LE_F64: + return "v3_cmpsx_le_f64"; + case Vop3::Op::V3_CMPSX_GT_F64: + return "v3_cmpsx_gt_f64"; + case Vop3::Op::V3_CMPSX_LG_F64: + return "v3_cmpsx_lg_f64"; + case Vop3::Op::V3_CMPSX_GE_F64: + return "v3_cmpsx_ge_f64"; + case Vop3::Op::V3_CMPSX_O_F64: + return "v3_cmpsx_o_f64"; + case Vop3::Op::V3_CMPSX_U_F64: + return "v3_cmpsx_u_f64"; + case Vop3::Op::V3_CMPSX_NGE_F64: + return "v3_cmpsx_nge_f64"; + case Vop3::Op::V3_CMPSX_NLG_F64: + return "v3_cmpsx_nlg_f64"; + case Vop3::Op::V3_CMPSX_NGT_F64: + return "v3_cmpsx_ngt_f64"; + case Vop3::Op::V3_CMPSX_NLE_F64: + return "v3_cmpsx_nle_f64"; + case Vop3::Op::V3_CMPSX_NEQ_F64: + return "v3_cmpsx_neq_f64"; + case Vop3::Op::V3_CMPSX_NLT_F64: + return "v3_cmpsx_nlt_f64"; + case Vop3::Op::V3_CMPSX_TRU_F64: + return "v3_cmpsx_tru_f64"; + case Vop3::Op::V3_CMP_F_I32: + return "v3_cmp_f_i32"; + case Vop3::Op::V3_CMP_LT_I32: + return "v3_cmp_lt_i32"; + case Vop3::Op::V3_CMP_EQ_I32: + return "v3_cmp_eq_i32"; + case Vop3::Op::V3_CMP_LE_I32: + return "v3_cmp_le_i32"; + case Vop3::Op::V3_CMP_GT_I32: + return "v3_cmp_gt_i32"; + case Vop3::Op::V3_CMP_NE_I32: + return "v3_cmp_ne_i32"; + case Vop3::Op::V3_CMP_GE_I32: + return "v3_cmp_ge_i32"; + case Vop3::Op::V3_CMP_T_I32: + return "v3_cmp_t_i32"; + case Vop3::Op::V3_CMP_CLASS_F32: + return "v3_cmp_class_f32"; + case Vop3::Op::V3_CMP_LT_I16: + return "v3_cmp_lt_i16"; + case Vop3::Op::V3_CMP_EQ_I16: + return "v3_cmp_eq_i16"; + case Vop3::Op::V3_CMP_LE_I16: + return "v3_cmp_le_i16"; + case Vop3::Op::V3_CMP_GT_I16: + return "v3_cmp_gt_i16"; + case Vop3::Op::V3_CMP_NE_I16: + return "v3_cmp_ne_i16"; + case Vop3::Op::V3_CMP_GE_I16: + return "v3_cmp_ge_i16"; + case Vop3::Op::V3_CMP_CLASS_F16: + return "v3_cmp_class_f16"; + case Vop3::Op::V3_CMPX_F_I32: + return "v3_cmpx_f_i32"; + case Vop3::Op::V3_CMPX_LT_I32: + return "v3_cmpx_lt_i32"; + case Vop3::Op::V3_CMPX_EQ_I32: + return "v3_cmpx_eq_i32"; + case Vop3::Op::V3_CMPX_LE_I32: + return "v3_cmpx_le_i32"; + case Vop3::Op::V3_CMPX_GT_I32: + return "v3_cmpx_gt_i32"; + case Vop3::Op::V3_CMPX_NE_I32: + return "v3_cmpx_ne_i32"; + case Vop3::Op::V3_CMPX_GE_I32: + return "v3_cmpx_ge_i32"; + case Vop3::Op::V3_CMPX_T_I32: + return "v3_cmpx_t_i32"; + case Vop3::Op::V3_CMPX_CLASS_F32: + return "v3_cmpx_class_f32"; + case Vop3::Op::V3_CMPX_LT_I16: + return "v3_cmpx_lt_i16"; + case Vop3::Op::V3_CMPX_EQ_I16: + return "v3_cmpx_eq_i16"; + case Vop3::Op::V3_CMPX_LE_I16: + return "v3_cmpx_le_i16"; + case Vop3::Op::V3_CMPX_GT_I16: + return "v3_cmpx_gt_i16"; + case Vop3::Op::V3_CMPX_NE_I16: + return "v3_cmpx_ne_i16"; + case Vop3::Op::V3_CMPX_GE_I16: + return "v3_cmpx_ge_i16"; + case Vop3::Op::V3_CMPX_CLASS_F16: + return "v3_cmpx_class_f16"; + case Vop3::Op::V3_CMP_F_I64: + return "v3_cmp_f_i64"; + case Vop3::Op::V3_CMP_LT_I64: + return "v3_cmp_lt_i64"; + case Vop3::Op::V3_CMP_EQ_I64: + return "v3_cmp_eq_i64"; + case Vop3::Op::V3_CMP_LE_I64: + return "v3_cmp_le_i64"; + case Vop3::Op::V3_CMP_GT_I64: + return "v3_cmp_gt_i64"; + case Vop3::Op::V3_CMP_NE_I64: + return "v3_cmp_ne_i64"; + case Vop3::Op::V3_CMP_GE_I64: + return "v3_cmp_ge_i64"; + case Vop3::Op::V3_CMP_T_I64: + return "v3_cmp_t_i64"; + case Vop3::Op::V3_CMP_CLASS_F64: + return "v3_cmp_class_f64"; + case Vop3::Op::V3_CMP_LT_U16: + return "v3_cmp_lt_u16"; + case Vop3::Op::V3_CMP_EQ_U16: + return "v3_cmp_eq_u16"; + case Vop3::Op::V3_CMP_LE_U16: + return "v3_cmp_le_u16"; + case Vop3::Op::V3_CMP_GT_U16: + return "v3_cmp_gt_u16"; + case Vop3::Op::V3_CMP_NE_U16: + return "v3_cmp_ne_u16"; + case Vop3::Op::V3_CMP_GE_U16: + return "v3_cmp_ge_u16"; + case Vop3::Op::V3_CMPX_F_I64: + return "v3_cmpx_f_i64"; + case Vop3::Op::V3_CMPX_LT_I64: + return "v3_cmpx_lt_i64"; + case Vop3::Op::V3_CMPX_EQ_I64: + return "v3_cmpx_eq_i64"; + case Vop3::Op::V3_CMPX_LE_I64: + return "v3_cmpx_le_i64"; + case Vop3::Op::V3_CMPX_GT_I64: + return "v3_cmpx_gt_i64"; + case Vop3::Op::V3_CMPX_NE_I64: + return "v3_cmpx_ne_i64"; + case Vop3::Op::V3_CMPX_GE_I64: + return "v3_cmpx_ge_i64"; + case Vop3::Op::V3_CMPX_T_I64: + return "v3_cmpx_t_i64"; + case Vop3::Op::V3_CMPX_CLASS_F64: + return "v3_cmpx_class_f64"; + case Vop3::Op::V3_CMPX_LT_U16: + return "v3_cmpx_lt_u16"; + case Vop3::Op::V3_CMPX_EQ_U16: + return "v3_cmpx_eq_u16"; + case Vop3::Op::V3_CMPX_LE_U16: + return "v3_cmpx_le_u16"; + case Vop3::Op::V3_CMPX_GT_U16: + return "v3_cmpx_gt_u16"; + case Vop3::Op::V3_CMPX_NE_U16: + return "v3_cmpx_ne_u16"; + case Vop3::Op::V3_CMPX_GE_U16: + return "v3_cmpx_ge_u16"; + case Vop3::Op::V3_CMP_F_U32: + return "v3_cmp_f_u32"; + case Vop3::Op::V3_CMP_LT_U32: + return "v3_cmp_lt_u32"; + case Vop3::Op::V3_CMP_EQ_U32: + return "v3_cmp_eq_u32"; + case Vop3::Op::V3_CMP_LE_U32: + return "v3_cmp_le_u32"; + case Vop3::Op::V3_CMP_GT_U32: + return "v3_cmp_gt_u32"; + case Vop3::Op::V3_CMP_NE_U32: + return "v3_cmp_ne_u32"; + case Vop3::Op::V3_CMP_GE_U32: + return "v3_cmp_ge_u32"; + case Vop3::Op::V3_CMP_T_U32: + return "v3_cmp_t_u32"; + case Vop3::Op::V3_CMP_F_F16: + return "v3_cmp_f_f16"; + case Vop3::Op::V3_CMP_LT_F16: + return "v3_cmp_lt_f16"; + case Vop3::Op::V3_CMP_EQ_F16: + return "v3_cmp_eq_f16"; + case Vop3::Op::V3_CMP_LE_F16: + return "v3_cmp_le_f16"; + case Vop3::Op::V3_CMP_GT_F16: + return "v3_cmp_gt_f16"; + case Vop3::Op::V3_CMP_LG_F16: + return "v3_cmp_lg_f16"; + case Vop3::Op::V3_CMP_GE_F16: + return "v3_cmp_ge_f16"; + case Vop3::Op::V3_CMP_O_F16: + return "v3_cmp_o_f16"; + case Vop3::Op::V3_CMPX_F_U32: + return "v3_cmpx_f_u32"; + case Vop3::Op::V3_CMPX_LT_U32: + return "v3_cmpx_lt_u32"; + case Vop3::Op::V3_CMPX_EQ_U32: + return "v3_cmpx_eq_u32"; + case Vop3::Op::V3_CMPX_LE_U32: + return "v3_cmpx_le_u32"; + case Vop3::Op::V3_CMPX_GT_U32: + return "v3_cmpx_gt_u32"; + case Vop3::Op::V3_CMPX_NE_U32: + return "v3_cmpx_ne_u32"; + case Vop3::Op::V3_CMPX_GE_U32: + return "v3_cmpx_ge_u32"; + case Vop3::Op::V3_CMPX_T_U32: + return "v3_cmpx_t_u32"; + case Vop3::Op::V3_CMPX_F_F16: + return "v3_cmpx_f_f16"; + case Vop3::Op::V3_CMPX_LT_F16: + return "v3_cmpx_lt_f16"; + case Vop3::Op::V3_CMPX_EQ_F16: + return "v3_cmpx_eq_f16"; + case Vop3::Op::V3_CMPX_LE_F16: + return "v3_cmpx_le_f16"; + case Vop3::Op::V3_CMPX_GT_F16: + return "v3_cmpx_gt_f16"; + case Vop3::Op::V3_CMPX_LG_F16: + return "v3_cmpx_lg_f16"; + case Vop3::Op::V3_CMPX_GE_F16: + return "v3_cmpx_ge_f16"; + case Vop3::Op::V3_CMPX_O_F16: + return "v3_cmpx_o_f16"; + case Vop3::Op::V3_CMP_F_U64: + return "v3_cmp_f_u64"; + case Vop3::Op::V3_CMP_LT_U64: + return "v3_cmp_lt_u64"; + case Vop3::Op::V3_CMP_EQ_U64: + return "v3_cmp_eq_u64"; + case Vop3::Op::V3_CMP_LE_U64: + return "v3_cmp_le_u64"; + case Vop3::Op::V3_CMP_GT_U64: + return "v3_cmp_gt_u64"; + case Vop3::Op::V3_CMP_NE_U64: + return "v3_cmp_ne_u64"; + case Vop3::Op::V3_CMP_GE_U64: + return "v3_cmp_ge_u64"; + case Vop3::Op::V3_CMP_T_U64: + return "v3_cmp_t_u64"; + case Vop3::Op::V3_CMP_U_F16: + return "v3_cmp_u_f16"; + case Vop3::Op::V3_CMP_NGE_F16: + return "v3_cmp_nge_f16"; + case Vop3::Op::V3_CMP_NLG_F16: + return "v3_cmp_nlg_f16"; + case Vop3::Op::V3_CMP_NGT_F16: + return "v3_cmp_ngt_f16"; + case Vop3::Op::V3_CMP_NLE_F16: + return "v3_cmp_nle_f16"; + case Vop3::Op::V3_CMP_NEQ_F16: + return "v3_cmp_neq_f16"; + case Vop3::Op::V3_CMP_NLT_F16: + return "v3_cmp_nlt_f16"; + case Vop3::Op::V3_CMP_TRU_F16: + return "v3_cmp_tru_f16"; + case Vop3::Op::V3_CMPX_F_U64: + return "v3_cmpx_f_u64"; + case Vop3::Op::V3_CMPX_LT_U64: + return "v3_cmpx_lt_u64"; + case Vop3::Op::V3_CMPX_EQ_U64: + return "v3_cmpx_eq_u64"; + case Vop3::Op::V3_CMPX_LE_U64: + return "v3_cmpx_le_u64"; + case Vop3::Op::V3_CMPX_GT_U64: + return "v3_cmpx_gt_u64"; + case Vop3::Op::V3_CMPX_NE_U64: + return "v3_cmpx_ne_u64"; + case Vop3::Op::V3_CMPX_GE_U64: + return "v3_cmpx_ge_u64"; + case Vop3::Op::V3_CMPX_T_U64: + return "v3_cmpx_t_u64"; + case Vop3::Op::V3_CNDMASK_B32: + return "v3_cndmask_b32"; + case Vop3::Op::V3_READLANE_B32: + return "v3_readlane_b32"; + case Vop3::Op::V3_WRITELANE_B32: + return "v3_writelane_b32"; + case Vop3::Op::V3_ADD_F32: + return "v3_add_f32"; + case Vop3::Op::V3_SUB_F32: + return "v3_sub_f32"; + case Vop3::Op::V3_SUBREV_F32: + return "v3_subrev_f32"; + case Vop3::Op::V3_MAC_LEGACY_F32: + return "v3_mac_legacy_f32"; + case Vop3::Op::V3_MUL_LEGACY_F32: + return "v3_mul_legacy_f32"; + case Vop3::Op::V3_MUL_F32: + return "v3_mul_f32"; + case Vop3::Op::V3_MUL_I32_I24: + return "v3_mul_i32_i24"; + case Vop3::Op::V3_MUL_HI_I32_I24: + return "v3_mul_hi_i32_i24"; + case Vop3::Op::V3_MUL_U32_U24: + return "v3_mul_u32_u24"; + case Vop3::Op::V3_MUL_HI_U32_U24: + return "v3_mul_hi_u32_u24"; + case Vop3::Op::V3_MIN_LEGACY_F32: + return "v3_min_legacy_f32"; + case Vop3::Op::V3_MAX_LEGACY_F32: + return "v3_max_legacy_f32"; + case Vop3::Op::V3_MIN_F32: + return "v3_min_f32"; + case Vop3::Op::V3_MAX_F32: + return "v3_max_f32"; + case Vop3::Op::V3_MIN_I32: + return "v3_min_i32"; + case Vop3::Op::V3_MAX_I32: + return "v3_max_i32"; + case Vop3::Op::V3_MIN_U32: + return "v3_min_u32"; + case Vop3::Op::V3_MAX_U32: + return "v3_max_u32"; + case Vop3::Op::V3_LSHR_B32: + return "v3_lshr_b32"; + case Vop3::Op::V3_LSHRREV_B32: + return "v3_lshrrev_b32"; + case Vop3::Op::V3_ASHR_I32: + return "v3_ashr_i32"; + case Vop3::Op::V3_ASHRREV_I32: + return "v3_ashrrev_i32"; + case Vop3::Op::V3_LSHL_B32: + return "v3_lshl_b32"; + case Vop3::Op::V3_LSHLREV_B32: + return "v3_lshlrev_b32"; + case Vop3::Op::V3_AND_B32: + return "v3_and_b32"; + case Vop3::Op::V3_OR_B32: + return "v3_or_b32"; + case Vop3::Op::V3_XOR_B32: + return "v3_xor_b32"; + case Vop3::Op::V3_BFM_B32: + return "v3_bfm_b32"; + case Vop3::Op::V3_MAC_F32: + return "v3_mac_f32"; + case Vop3::Op::V3_MADMK_F32: + return "v3_madmk_f32"; + case Vop3::Op::V3_MADAK_F32: + return "v3_madak_f32"; + case Vop3::Op::V3_BCNT_U32_B32: + return "v3_bcnt_u32_b32"; + case Vop3::Op::V3_MBCNT_LO_U32_B32: + return "v3_mbcnt_lo_u32_b32"; + case Vop3::Op::V3_MBCNT_HI_U32_B32: + return "v3_mbcnt_hi_u32_b32"; + case Vop3::Op::V3_ADD_I32: + return "v3_add_i32"; + case Vop3::Op::V3_SUB_I32: + return "v3_sub_i32"; + case Vop3::Op::V3_SUBREV_I32: + return "v3_subrev_i32"; + case Vop3::Op::V3_ADDC_U32: + return "v3_addc_u32"; + case Vop3::Op::V3_SUBB_U32: + return "v3_subb_u32"; + case Vop3::Op::V3_SUBBREV_U32: + return "v3_subbrev_u32"; + case Vop3::Op::V3_LDEXP_F32: + return "v3_ldexp_f32"; + case Vop3::Op::V3_CVT_PKACCUM_U8_F32: + return "v3_cvt_pkaccum_u8_f32"; + case Vop3::Op::V3_CVT_PKNORM_I16_F32: + return "v3_cvt_pknorm_i16_f32"; + case Vop3::Op::V3_CVT_PKNORM_U16_F32: + return "v3_cvt_pknorm_u16_f32"; + case Vop3::Op::V3_CVT_PKRTZ_F16_F32: + return "v3_cvt_pkrtz_f16_f32"; + case Vop3::Op::V3_CVT_PK_U16_U32: + return "v3_cvt_pk_u16_u32"; + case Vop3::Op::V3_CVT_PK_I16_I32: + return "v3_cvt_pk_i16_i32"; + case Vop3::Op::V3_MAD_LEGACY_F32: + return "v3_mad_legacy_f32"; + case Vop3::Op::V3_MAD_F32: + return "v3_mad_f32"; + case Vop3::Op::V3_MAD_I32_I24: + return "v3_mad_i32_i24"; + case Vop3::Op::V3_MAD_U32_U24: + return "v3_mad_u32_u24"; + case Vop3::Op::V3_CUBEID_F32: + return "v3_cubeid_f32"; + case Vop3::Op::V3_CUBESC_F32: + return "v3_cubesc_f32"; + case Vop3::Op::V3_CUBETC_F32: + return "v3_cubetc_f32"; + case Vop3::Op::V3_CUBEMA_F32: + return "v3_cubema_f32"; + case Vop3::Op::V3_BFE_U32: + return "v3_bfe_u32"; + case Vop3::Op::V3_BFE_I32: + return "v3_bfe_i32"; + case Vop3::Op::V3_BFI_B32: + return "v3_bfi_b32"; + case Vop3::Op::V3_FMA_F32: + return "v3_fma_f32"; + case Vop3::Op::V3_FMA_F64: + return "v3_fma_f64"; + case Vop3::Op::V3_LERP_U8: + return "v3_lerp_u8"; + case Vop3::Op::V3_ALIGNBIT_B32: + return "v3_alignbit_b32"; + case Vop3::Op::V3_ALIGNBYTE_B32: + return "v3_alignbyte_b32"; + case Vop3::Op::V3_MULLIT_F32: + return "v3_mullit_f32"; + case Vop3::Op::V3_MIN3_F32: + return "v3_min3_f32"; + case Vop3::Op::V3_MIN3_I32: + return "v3_min3_i32"; + case Vop3::Op::V3_MIN3_U32: + return "v3_min3_u32"; + case Vop3::Op::V3_MAX3_F32: + return "v3_max3_f32"; + case Vop3::Op::V3_MAX3_I32: + return "v3_max3_i32"; + case Vop3::Op::V3_MAX3_U32: + return "v3_max3_u32"; + case Vop3::Op::V3_MED3_F32: + return "v3_med3_f32"; + case Vop3::Op::V3_MED3_I32: + return "v3_med3_i32"; + case Vop3::Op::V3_MED3_U32: + return "v3_med3_u32"; + case Vop3::Op::V3_SAD_U8: + return "v3_sad_u8"; + case Vop3::Op::V3_SAD_HI_U8: + return "v3_sad_hi_u8"; + case Vop3::Op::V3_SAD_U16: + return "v3_sad_u16"; + case Vop3::Op::V3_SAD_U32: + return "v3_sad_u32"; + case Vop3::Op::V3_CVT_PK_U8_F32: + return "v3_cvt_pk_u8_f32"; + case Vop3::Op::V3_DIV_FIXUP_F32: + return "v3_div_fixup_f32"; + case Vop3::Op::V3_DIV_FIXUP_F64: + return "v3_div_fixup_f64"; + case Vop3::Op::V3_LSHL_B64: + return "v3_lshl_b64"; + case Vop3::Op::V3_LSHR_B64: + return "v3_lshr_b64"; + case Vop3::Op::V3_ASHR_I64: + return "v3_ashr_i64"; + case Vop3::Op::V3_ADD_F64: + return "v3_add_f64"; + case Vop3::Op::V3_MUL_F64: + return "v3_mul_f64"; + case Vop3::Op::V3_MIN_F64: + return "v3_min_f64"; + case Vop3::Op::V3_MAX_F64: + return "v3_max_f64"; + case Vop3::Op::V3_LDEXP_F64: + return "v3_ldexp_f64"; + case Vop3::Op::V3_MUL_LO_U32: + return "v3_mul_lo_u32"; + case Vop3::Op::V3_MUL_HI_U32: + return "v3_mul_hi_u32"; + case Vop3::Op::V3_MUL_LO_I32: + return "v3_mul_lo_i32"; + case Vop3::Op::V3_MUL_HI_I32: + return "v3_mul_hi_i32"; + case Vop3::Op::V3_DIV_SCALE_F32: + return "v3_div_scale_f32"; + case Vop3::Op::V3_DIV_SCALE_F64: + return "v3_div_scale_f64"; + case Vop3::Op::V3_DIV_FMAS_F32: + return "v3_div_fmas_f32"; + case Vop3::Op::V3_DIV_FMAS_F64: + return "v3_div_fmas_f64"; + case Vop3::Op::V3_MSAD_U8: + return "v3_msad_u8"; + case Vop3::Op::V3_QSAD_U8: + return "v3_qsad_u8"; + case Vop3::Op::V3_MQSAD_U8: + return "v3_mqsad_u8"; + case Vop3::Op::V3_TRIG_PREOP_F64: + return "v3_trig_preop_f64"; + case Vop3::Op::V3_NOP: + return "v3_nop"; + case Vop3::Op::V3_MOV_B32: + return "v3_mov_b32"; + case Vop3::Op::V3_READFIRSTLANE_B32: + return "v3_readfirstlane_b32"; + case Vop3::Op::V3_CVT_I32_F64: + return "v3_cvt_i32_f64"; + case Vop3::Op::V3_CVT_F64_I32: + return "v3_cvt_f64_i32"; + case Vop3::Op::V3_CVT_F32_I32: + return "v3_cvt_f32_i32"; + case Vop3::Op::V3_CVT_F32_U32: + return "v3_cvt_f32_u32"; + case Vop3::Op::V3_CVT_U32_F32: + return "v3_cvt_u32_f32"; + case Vop3::Op::V3_CVT_I32_F32: + return "v3_cvt_i32_f32"; + case Vop3::Op::V3_MOV_FED_B32: + return "v3_mov_fed_b32"; + case Vop3::Op::V3_CVT_F16_F32: + return "v3_cvt_f16_f32"; + case Vop3::Op::V3_CVT_F32_F16: + return "v3_cvt_f32_f16"; + case Vop3::Op::V3_CVT_RPI_I32_F32: + return "v3_cvt_rpi_i32_f32"; + case Vop3::Op::V3_CVT_FLR_I32_F32: + return "v3_cvt_flr_i32_f32"; + case Vop3::Op::V3_CVT_OFF_F32_I4: + return "v3_cvt_off_f32_i4"; + case Vop3::Op::V3_CVT_F32_F64: + return "v3_cvt_f32_f64"; + case Vop3::Op::V3_CVT_F64_F32: + return "v3_cvt_f64_f32"; + case Vop3::Op::V3_CVT_F32_UBYTE0: + return "v3_cvt_f32_ubyte0"; + case Vop3::Op::V3_CVT_F32_UBYTE1: + return "v3_cvt_f32_ubyte1"; + case Vop3::Op::V3_CVT_F32_UBYTE2: + return "v3_cvt_f32_ubyte2"; + case Vop3::Op::V3_CVT_F32_UBYTE3: + return "v3_cvt_f32_ubyte3"; + case Vop3::Op::V3_CVT_U32_F64: + return "v3_cvt_u32_f64"; + case Vop3::Op::V3_CVT_F64_U32: + return "v3_cvt_f64_u32"; + case Vop3::Op::V3_FRACT_F32: + return "v3_fract_f32"; + case Vop3::Op::V3_TRUNC_F32: + return "v3_trunc_f32"; + case Vop3::Op::V3_CEIL_F32: + return "v3_ceil_f32"; + case Vop3::Op::V3_RNDNE_F32: + return "v3_rndne_f32"; + case Vop3::Op::V3_FLOOR_F32: + return "v3_floor_f32"; + case Vop3::Op::V3_EXP_F32: + return "v3_exp_f32"; + case Vop3::Op::V3_LOG_CLAMP_F32: + return "v3_log_clamp_f32"; + case Vop3::Op::V3_LOG_F32: + return "v3_log_f32"; + case Vop3::Op::V3_RCP_CLAMP_F32: + return "v3_rcp_clamp_f32"; + case Vop3::Op::V3_RCP_LEGACY_F32: + return "v3_rcp_legacy_f32"; + case Vop3::Op::V3_RCP_F32: + return "v3_rcp_f32"; + case Vop3::Op::V3_RCP_IFLAG_F32: + return "v3_rcp_iflag_f32"; + case Vop3::Op::V3_RSQ_CLAMP_F32: + return "v3_rsq_clamp_f32"; + case Vop3::Op::V3_RSQ_LEGACY_F32: + return "v3_rsq_legacy_f32"; + case Vop3::Op::V3_RSQ_F32: + return "v3_rsq_f32"; + case Vop3::Op::V3_RCP_F64: + return "v3_rcp_f64"; + case Vop3::Op::V3_RCP_CLAMP_F64: + return "v3_rcp_clamp_f64"; + case Vop3::Op::V3_RSQ_F64: + return "v3_rsq_f64"; + case Vop3::Op::V3_RSQ_CLAMP_F64: + return "v3_rsq_clamp_f64"; + case Vop3::Op::V3_SQRT_F32: + return "v3_sqrt_f32"; + case Vop3::Op::V3_SQRT_F64: + return "v3_sqrt_f64"; + case Vop3::Op::V3_SIN_F32: + return "v3_sin_f32"; + case Vop3::Op::V3_COS_F32: + return "v3_cos_f32"; + case Vop3::Op::V3_NOT_B32: + return "v3_not_b32"; + case Vop3::Op::V3_BFREV_B32: + return "v3_bfrev_b32"; + case Vop3::Op::V3_FFBH_U32: + return "v3_ffbh_u32"; + case Vop3::Op::V3_FFBL_B32: + return "v3_ffbl_b32"; + case Vop3::Op::V3_FFBH_I32: + return "v3_ffbh_i32"; + case Vop3::Op::V3_FREXP_EXP_I32_F64: + return "v3_frexp_exp_i32_f64"; + case Vop3::Op::V3_FREXP_MANT_F64: + return "v3_frexp_mant_f64"; + case Vop3::Op::V3_FRACT_F64: + return "v3_fract_f64"; + case Vop3::Op::V3_FREXP_EXP_I32_F32: + return "v3_frexp_exp_i32_f32"; + case Vop3::Op::V3_FREXP_MANT_F32: + return "v3_frexp_mant_f32"; + case Vop3::Op::V3_CLREXCP: + return "v3_clrexcp"; + case Vop3::Op::V3_MOVRELD_B32: + return "v3_movreld_b32"; + case Vop3::Op::V3_MOVRELS_B32: + return "v3_movrels_b32"; + case Vop3::Op::V3_MOVRELSD_B32: + return "v3_movrelsd_b32"; + default: + return nullptr; + } } -const char *amdgpu::shader::smrdOpcodeToString(Smrd::Op op) { - switch (op) { - case Smrd::Op::S_LOAD_DWORD: - return "s_load_dword"; - case Smrd::Op::S_LOAD_DWORDX2: - return "s_load_dwordx2"; - case Smrd::Op::S_LOAD_DWORDX4: - return "s_load_dwordx4"; - case Smrd::Op::S_LOAD_DWORDX8: - return "s_load_dwordx8"; - case Smrd::Op::S_LOAD_DWORDX16: - return "s_load_dwordx16"; - case Smrd::Op::S_BUFFER_LOAD_DWORD: - return "s_buffer_load_dword"; - case Smrd::Op::S_BUFFER_LOAD_DWORDX2: - return "s_buffer_load_dwordx2"; - case Smrd::Op::S_BUFFER_LOAD_DWORDX4: - return "s_buffer_load_dwordx4"; - case Smrd::Op::S_BUFFER_LOAD_DWORDX8: - return "s_buffer_load_dwordx8"; - case Smrd::Op::S_BUFFER_LOAD_DWORDX16: - return "s_buffer_load_dwordx16"; - case Smrd::Op::S_DCACHE_INV_VOL: - return "s_dcache_inv_vol"; - case Smrd::Op::S_MEMTIME: - return "s_memtime"; - case Smrd::Op::S_DCACHE_INV: - return "s_dcache_inv"; - default: - return nullptr; - } +const char* amdgpu::shader::smrdOpcodeToString(Smrd::Op op) +{ + switch (op) + { + case Smrd::Op::S_LOAD_DWORD: + return "s_load_dword"; + case Smrd::Op::S_LOAD_DWORDX2: + return "s_load_dwordx2"; + case Smrd::Op::S_LOAD_DWORDX4: + return "s_load_dwordx4"; + case Smrd::Op::S_LOAD_DWORDX8: + return "s_load_dwordx8"; + case Smrd::Op::S_LOAD_DWORDX16: + return "s_load_dwordx16"; + case Smrd::Op::S_BUFFER_LOAD_DWORD: + return "s_buffer_load_dword"; + case Smrd::Op::S_BUFFER_LOAD_DWORDX2: + return "s_buffer_load_dwordx2"; + case Smrd::Op::S_BUFFER_LOAD_DWORDX4: + return "s_buffer_load_dwordx4"; + case Smrd::Op::S_BUFFER_LOAD_DWORDX8: + return "s_buffer_load_dwordx8"; + case Smrd::Op::S_BUFFER_LOAD_DWORDX16: + return "s_buffer_load_dwordx16"; + case Smrd::Op::S_DCACHE_INV_VOL: + return "s_dcache_inv_vol"; + case Smrd::Op::S_MEMTIME: + return "s_memtime"; + case Smrd::Op::S_DCACHE_INV: + return "s_dcache_inv"; + default: + return nullptr; + } } -const char *amdgpu::shader::mubufOpcodeToString(Mubuf::Op op) { - switch (op) { - case Mubuf::Op::BUFFER_LOAD_FORMAT_X: - return "buffer_load_format_x"; - case Mubuf::Op::BUFFER_LOAD_FORMAT_XY: - return "buffer_load_format_xy"; - case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZ: - return "buffer_load_format_xyz"; - case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZW: - return "buffer_load_format_xyzw"; - case Mubuf::Op::BUFFER_STORE_FORMAT_X: - return "buffer_store_format_x"; - case Mubuf::Op::BUFFER_STORE_FORMAT_XY: - return "buffer_store_format_xy"; - case Mubuf::Op::BUFFER_STORE_FORMAT_XYZ: - return "buffer_store_format_xyz"; - case Mubuf::Op::BUFFER_STORE_FORMAT_XYZW: - return "buffer_store_format_xyzw"; - case Mubuf::Op::BUFFER_LOAD_UBYTE: - return "buffer_load_ubyte"; - case Mubuf::Op::BUFFER_LOAD_SBYTE: - return "buffer_load_sbyte"; - case Mubuf::Op::BUFFER_LOAD_USHORT: - return "buffer_load_ushort"; - case Mubuf::Op::BUFFER_LOAD_SSHORT: - return "buffer_load_sshort"; - case Mubuf::Op::BUFFER_LOAD_DWORD: - return "buffer_load_dword"; - case Mubuf::Op::BUFFER_LOAD_DWORDX2: - return "buffer_load_dwordx2"; - case Mubuf::Op::BUFFER_LOAD_DWORDX4: - return "buffer_load_dwordx4"; - case Mubuf::Op::BUFFER_LOAD_DWORDX3: - return "buffer_load_dwordx3"; - case Mubuf::Op::BUFFER_STORE_BYTE: - return "buffer_store_byte"; - case Mubuf::Op::BUFFER_STORE_SHORT: - return "buffer_store_short"; - case Mubuf::Op::BUFFER_STORE_DWORD: - return "buffer_store_dword"; - case Mubuf::Op::BUFFER_STORE_DWORDX2: - return "buffer_store_dwordx2"; - case Mubuf::Op::BUFFER_STORE_DWORDX4: - return "buffer_store_dwordx4"; - case Mubuf::Op::BUFFER_STORE_DWORDX3: - return "buffer_store_dwordx3"; - case Mubuf::Op::BUFFER_ATOMIC_SWAP: - return "buffer_atomic_swap"; - case Mubuf::Op::BUFFER_ATOMIC_CMPSWAP: - return "buffer_atomic_cmpswap"; - case Mubuf::Op::BUFFER_ATOMIC_ADD: - return "buffer_atomic_add"; - case Mubuf::Op::BUFFER_ATOMIC_SUB: - return "buffer_atomic_sub"; - case Mubuf::Op::BUFFER_ATOMIC_RSUB: - return "buffer_atomic_rsub"; - case Mubuf::Op::BUFFER_ATOMIC_SMIN: - return "buffer_atomic_smin"; - case Mubuf::Op::BUFFER_ATOMIC_UMIN: - return "buffer_atomic_umin"; - case Mubuf::Op::BUFFER_ATOMIC_SMAX: - return "buffer_atomic_smax"; - case Mubuf::Op::BUFFER_ATOMIC_UMAX: - return "buffer_atomic_umax"; - case Mubuf::Op::BUFFER_ATOMIC_AND: - return "buffer_atomic_and"; - case Mubuf::Op::BUFFER_ATOMIC_OR: - return "buffer_atomic_or"; - case Mubuf::Op::BUFFER_ATOMIC_XOR: - return "buffer_atomic_xor"; - case Mubuf::Op::BUFFER_ATOMIC_INC: - return "buffer_atomic_inc"; - case Mubuf::Op::BUFFER_ATOMIC_DEC: - return "buffer_atomic_dec"; - case Mubuf::Op::BUFFER_ATOMIC_FCMPSWAP: - return "buffer_atomic_fcmpswap"; - case Mubuf::Op::BUFFER_ATOMIC_FMIN: - return "buffer_atomic_fmin"; - case Mubuf::Op::BUFFER_ATOMIC_FMAX: - return "buffer_atomic_fmax"; - case Mubuf::Op::BUFFER_ATOMIC_SWAP_X2: - return "buffer_atomic_swap_x2"; - case Mubuf::Op::BUFFER_ATOMIC_CMPSWAP_X2: - return "buffer_atomic_cmpswap_x2"; - case Mubuf::Op::BUFFER_ATOMIC_ADD_X2: - return "buffer_atomic_add_x2"; - case Mubuf::Op::BUFFER_ATOMIC_SUB_X2: - return "buffer_atomic_sub_x2"; - case Mubuf::Op::BUFFER_ATOMIC_RSUB_X2: - return "buffer_atomic_rsub_x2"; - case Mubuf::Op::BUFFER_ATOMIC_SMIN_X2: - return "buffer_atomic_smin_x2"; - case Mubuf::Op::BUFFER_ATOMIC_UMIN_X2: - return "buffer_atomic_umin_x2"; - case Mubuf::Op::BUFFER_ATOMIC_SMAX_X2: - return "buffer_atomic_smax_x2"; - case Mubuf::Op::BUFFER_ATOMIC_UMAX_X2: - return "buffer_atomic_umax_x2"; - case Mubuf::Op::BUFFER_ATOMIC_AND_X2: - return "buffer_atomic_and_x2"; - case Mubuf::Op::BUFFER_ATOMIC_OR_X2: - return "buffer_atomic_or_x2"; - case Mubuf::Op::BUFFER_ATOMIC_XOR_X2: - return "buffer_atomic_xor_x2"; - case Mubuf::Op::BUFFER_ATOMIC_INC_X2: - return "buffer_atomic_inc_x2"; - case Mubuf::Op::BUFFER_ATOMIC_DEC_X2: - return "buffer_atomic_dec_x2"; - case Mubuf::Op::BUFFER_ATOMIC_FCMPSWAP_X2: - return "buffer_atomic_fcmpswap_x2"; - case Mubuf::Op::BUFFER_ATOMIC_FMIN_X2: - return "buffer_atomic_fmin_x2"; - case Mubuf::Op::BUFFER_ATOMIC_FMAX_X2: - return "buffer_atomic_fmax_x2"; - case Mubuf::Op::BUFFER_WBINVL1_SC_VOL: - return "buffer_wbinvl1_sc/vol"; - case Mubuf::Op::BUFFER_WBINVL1: - return "buffer_wbinvl1"; - default: - return nullptr; - } +const char* amdgpu::shader::mubufOpcodeToString(Mubuf::Op op) +{ + switch (op) + { + case Mubuf::Op::BUFFER_LOAD_FORMAT_X: + return "buffer_load_format_x"; + case Mubuf::Op::BUFFER_LOAD_FORMAT_XY: + return "buffer_load_format_xy"; + case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZ: + return "buffer_load_format_xyz"; + case Mubuf::Op::BUFFER_LOAD_FORMAT_XYZW: + return "buffer_load_format_xyzw"; + case Mubuf::Op::BUFFER_STORE_FORMAT_X: + return "buffer_store_format_x"; + case Mubuf::Op::BUFFER_STORE_FORMAT_XY: + return "buffer_store_format_xy"; + case Mubuf::Op::BUFFER_STORE_FORMAT_XYZ: + return "buffer_store_format_xyz"; + case Mubuf::Op::BUFFER_STORE_FORMAT_XYZW: + return "buffer_store_format_xyzw"; + case Mubuf::Op::BUFFER_LOAD_UBYTE: + return "buffer_load_ubyte"; + case Mubuf::Op::BUFFER_LOAD_SBYTE: + return "buffer_load_sbyte"; + case Mubuf::Op::BUFFER_LOAD_USHORT: + return "buffer_load_ushort"; + case Mubuf::Op::BUFFER_LOAD_SSHORT: + return "buffer_load_sshort"; + case Mubuf::Op::BUFFER_LOAD_DWORD: + return "buffer_load_dword"; + case Mubuf::Op::BUFFER_LOAD_DWORDX2: + return "buffer_load_dwordx2"; + case Mubuf::Op::BUFFER_LOAD_DWORDX4: + return "buffer_load_dwordx4"; + case Mubuf::Op::BUFFER_LOAD_DWORDX3: + return "buffer_load_dwordx3"; + case Mubuf::Op::BUFFER_STORE_BYTE: + return "buffer_store_byte"; + case Mubuf::Op::BUFFER_STORE_SHORT: + return "buffer_store_short"; + case Mubuf::Op::BUFFER_STORE_DWORD: + return "buffer_store_dword"; + case Mubuf::Op::BUFFER_STORE_DWORDX2: + return "buffer_store_dwordx2"; + case Mubuf::Op::BUFFER_STORE_DWORDX4: + return "buffer_store_dwordx4"; + case Mubuf::Op::BUFFER_STORE_DWORDX3: + return "buffer_store_dwordx3"; + case Mubuf::Op::BUFFER_ATOMIC_SWAP: + return "buffer_atomic_swap"; + case Mubuf::Op::BUFFER_ATOMIC_CMPSWAP: + return "buffer_atomic_cmpswap"; + case Mubuf::Op::BUFFER_ATOMIC_ADD: + return "buffer_atomic_add"; + case Mubuf::Op::BUFFER_ATOMIC_SUB: + return "buffer_atomic_sub"; + case Mubuf::Op::BUFFER_ATOMIC_RSUB: + return "buffer_atomic_rsub"; + case Mubuf::Op::BUFFER_ATOMIC_SMIN: + return "buffer_atomic_smin"; + case Mubuf::Op::BUFFER_ATOMIC_UMIN: + return "buffer_atomic_umin"; + case Mubuf::Op::BUFFER_ATOMIC_SMAX: + return "buffer_atomic_smax"; + case Mubuf::Op::BUFFER_ATOMIC_UMAX: + return "buffer_atomic_umax"; + case Mubuf::Op::BUFFER_ATOMIC_AND: + return "buffer_atomic_and"; + case Mubuf::Op::BUFFER_ATOMIC_OR: + return "buffer_atomic_or"; + case Mubuf::Op::BUFFER_ATOMIC_XOR: + return "buffer_atomic_xor"; + case Mubuf::Op::BUFFER_ATOMIC_INC: + return "buffer_atomic_inc"; + case Mubuf::Op::BUFFER_ATOMIC_DEC: + return "buffer_atomic_dec"; + case Mubuf::Op::BUFFER_ATOMIC_FCMPSWAP: + return "buffer_atomic_fcmpswap"; + case Mubuf::Op::BUFFER_ATOMIC_FMIN: + return "buffer_atomic_fmin"; + case Mubuf::Op::BUFFER_ATOMIC_FMAX: + return "buffer_atomic_fmax"; + case Mubuf::Op::BUFFER_ATOMIC_SWAP_X2: + return "buffer_atomic_swap_x2"; + case Mubuf::Op::BUFFER_ATOMIC_CMPSWAP_X2: + return "buffer_atomic_cmpswap_x2"; + case Mubuf::Op::BUFFER_ATOMIC_ADD_X2: + return "buffer_atomic_add_x2"; + case Mubuf::Op::BUFFER_ATOMIC_SUB_X2: + return "buffer_atomic_sub_x2"; + case Mubuf::Op::BUFFER_ATOMIC_RSUB_X2: + return "buffer_atomic_rsub_x2"; + case Mubuf::Op::BUFFER_ATOMIC_SMIN_X2: + return "buffer_atomic_smin_x2"; + case Mubuf::Op::BUFFER_ATOMIC_UMIN_X2: + return "buffer_atomic_umin_x2"; + case Mubuf::Op::BUFFER_ATOMIC_SMAX_X2: + return "buffer_atomic_smax_x2"; + case Mubuf::Op::BUFFER_ATOMIC_UMAX_X2: + return "buffer_atomic_umax_x2"; + case Mubuf::Op::BUFFER_ATOMIC_AND_X2: + return "buffer_atomic_and_x2"; + case Mubuf::Op::BUFFER_ATOMIC_OR_X2: + return "buffer_atomic_or_x2"; + case Mubuf::Op::BUFFER_ATOMIC_XOR_X2: + return "buffer_atomic_xor_x2"; + case Mubuf::Op::BUFFER_ATOMIC_INC_X2: + return "buffer_atomic_inc_x2"; + case Mubuf::Op::BUFFER_ATOMIC_DEC_X2: + return "buffer_atomic_dec_x2"; + case Mubuf::Op::BUFFER_ATOMIC_FCMPSWAP_X2: + return "buffer_atomic_fcmpswap_x2"; + case Mubuf::Op::BUFFER_ATOMIC_FMIN_X2: + return "buffer_atomic_fmin_x2"; + case Mubuf::Op::BUFFER_ATOMIC_FMAX_X2: + return "buffer_atomic_fmax_x2"; + case Mubuf::Op::BUFFER_WBINVL1_SC_VOL: + return "buffer_wbinvl1_sc/vol"; + case Mubuf::Op::BUFFER_WBINVL1: + return "buffer_wbinvl1"; + default: + return nullptr; + } } -const char *amdgpu::shader::mtbufOpcodeToString(Mtbuf::Op op) { - switch (op) { - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_X: - return "tbuffer_load_format_x"; - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XY: - return "tbuffer_load_format_xy"; - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZ: - return "tbuffer_load_format_xyz"; - case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZW: - return "tbuffer_load_format_xyzw"; - case Mtbuf::Op::TBUFFER_STORE_FORMAT_X: - return "tbuffer_store_format_x"; - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XY: - return "tbuffer_store_format_xy"; - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZ: - return "tbuffer_store_format_xyz"; - case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZW: - return "tbuffer_store_format_xyzw"; - default: - return nullptr; - } +const char* amdgpu::shader::mtbufOpcodeToString(Mtbuf::Op op) +{ + switch (op) + { + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_X: + return "tbuffer_load_format_x"; + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XY: + return "tbuffer_load_format_xy"; + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZ: + return "tbuffer_load_format_xyz"; + case Mtbuf::Op::TBUFFER_LOAD_FORMAT_XYZW: + return "tbuffer_load_format_xyzw"; + case Mtbuf::Op::TBUFFER_STORE_FORMAT_X: + return "tbuffer_store_format_x"; + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XY: + return "tbuffer_store_format_xy"; + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZ: + return "tbuffer_store_format_xyz"; + case Mtbuf::Op::TBUFFER_STORE_FORMAT_XYZW: + return "tbuffer_store_format_xyzw"; + default: + return nullptr; + } } -const char *amdgpu::shader::mimgOpcodeToString(Mimg::Op op) { - switch (op) { - case Mimg::Op::IMAGE_LOAD: - return "image_load"; - case Mimg::Op::IMAGE_LOAD_MIP: - return "image_load_mip"; - case Mimg::Op::IMAGE_LOAD_PCK: - return "image_load_pck"; - case Mimg::Op::IMAGE_LOAD_PCK_SGN: - return "image_load_pck_sgn"; - case Mimg::Op::IMAGE_LOAD_MIP_PCK: - return "image_load_mip_pck"; - case Mimg::Op::IMAGE_LOAD_MIP_PCK_SGN: - return "image_load_mip_pck_sgn"; - case Mimg::Op::IMAGE_STORE: - return "image_store"; - case Mimg::Op::IMAGE_STORE_MIP: - return "image_store_mip"; - case Mimg::Op::IMAGE_STORE_PCK: - return "image_store_pck"; - case Mimg::Op::IMAGE_STORE_MIP_PCK: - return "image_store_mip_pck"; - case Mimg::Op::IMAGE_GET_RESINFO: - return "image_get_resinfo"; - case Mimg::Op::IMAGE_ATOMIC_SWAP: - return "image_atomic_swap"; - case Mimg::Op::IMAGE_ATOMIC_CMPSWAP: - return "image_atomic_cmpswap"; - case Mimg::Op::IMAGE_ATOMIC_ADD: - return "image_atomic_add"; - case Mimg::Op::IMAGE_ATOMIC_SUB: - return "image_atomic_sub"; - case Mimg::Op::IMAGE_ATOMIC_RSUB: - return "image_atomic_rsub"; - case Mimg::Op::IMAGE_ATOMIC_SMIN: - return "image_atomic_smin"; - case Mimg::Op::IMAGE_ATOMIC_UMIN: - return "image_atomic_umin"; - case Mimg::Op::IMAGE_ATOMIC_SMAX: - return "image_atomic_smax"; - case Mimg::Op::IMAGE_ATOMIC_UMAX: - return "image_atomic_umax"; - case Mimg::Op::IMAGE_ATOMIC_AND: - return "image_atomic_and"; - case Mimg::Op::IMAGE_ATOMIC_OR: - return "image_atomic_or"; - case Mimg::Op::IMAGE_ATOMIC_XOR: - return "image_atomic_xor"; - case Mimg::Op::IMAGE_ATOMIC_INC: - return "image_atomic_inc"; - case Mimg::Op::IMAGE_ATOMIC_DEC: - return "image_atomic_dec"; - case Mimg::Op::IMAGE_ATOMIC_FCMPSWAP: - return "image_atomic_fcmpswap"; - case Mimg::Op::IMAGE_ATOMIC_FMIN: - return "image_atomic_fmin"; - case Mimg::Op::IMAGE_ATOMIC_FMAX: - return "image_atomic_fmax"; - case Mimg::Op::IMAGE_SAMPLE: - return "image_sample"; - case Mimg::Op::IMAGE_SAMPLE_CL: - return "image_sample_cl"; - case Mimg::Op::IMAGE_SAMPLE_D: - return "image_sample_d"; - case Mimg::Op::IMAGE_SAMPLE_D_CL: - return "image_sample_d_cl"; - case Mimg::Op::IMAGE_SAMPLE_L: - return "image_sample_l"; - case Mimg::Op::IMAGE_SAMPLE_B: - return "image_sample_b"; - case Mimg::Op::IMAGE_SAMPLE_B_CL: - return "image_sample_b_cl"; - case Mimg::Op::IMAGE_SAMPLE_LZ: - return "image_sample_lz"; - case Mimg::Op::IMAGE_SAMPLE_C: - return "image_sample_c"; - case Mimg::Op::IMAGE_SAMPLE_C_CL: - return "image_sample_c_cl"; - case Mimg::Op::IMAGE_SAMPLE_C_D: - return "image_sample_c_d"; - case Mimg::Op::IMAGE_SAMPLE_C_D_CL: - return "image_sample_c_d_cl"; - case Mimg::Op::IMAGE_SAMPLE_C_L: - return "image_sample_c_l"; - case Mimg::Op::IMAGE_SAMPLE_C_B: - return "image_sample_c_b"; - case Mimg::Op::IMAGE_SAMPLE_C_B_CL: - return "image_sample_c_b_cl"; - case Mimg::Op::IMAGE_SAMPLE_C_LZ: - return "image_sample_c_lz"; - case Mimg::Op::IMAGE_SAMPLE_O: - return "image_sample_o"; - case Mimg::Op::IMAGE_SAMPLE_CL_O: - return "image_sample_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_D_O: - return "image_sample_d_o"; - case Mimg::Op::IMAGE_SAMPLE_D_CL_O: - return "image_sample_d_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_L_O: - return "image_sample_l_o"; - case Mimg::Op::IMAGE_SAMPLE_B_O: - return "image_sample_b_o"; - case Mimg::Op::IMAGE_SAMPLE_B_CL_O: - return "image_sample_b_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_LZ_O: - return "image_sample_lz_o"; - case Mimg::Op::IMAGE_SAMPLE_C_O: - return "image_sample_c_o"; - case Mimg::Op::IMAGE_SAMPLE_C_CL_O: - return "image_sample_c_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_C_D_O: - return "image_sample_c_d_o"; - case Mimg::Op::IMAGE_SAMPLE_C_D_CL_O: - return "image_sample_c_d_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_C_L_O: - return "image_sample_c_l_o"; - case Mimg::Op::IMAGE_SAMPLE_C_B_O: - return "image_sample_c_b_o"; - case Mimg::Op::IMAGE_SAMPLE_C_B_CL_O: - return "image_sample_c_b_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_C_LZ_O: - return "image_sample_c_lz_o"; - case Mimg::Op::IMAGE_GATHER4: - return "image_gather4"; - case Mimg::Op::IMAGE_GATHER4_CL: - return "image_gather4_cl"; - case Mimg::Op::IMAGE_GATHER4_L: - return "image_gather4_l"; - case Mimg::Op::IMAGE_GATHER4_B: - return "image_gather4_b"; - case Mimg::Op::IMAGE_GATHER4_B_CL: - return "image_gather4_b_cl"; - case Mimg::Op::IMAGE_GATHER4_LZ: - return "image_gather4_lz"; - case Mimg::Op::IMAGE_GATHER4_C: - return "image_gather4_c"; - case Mimg::Op::IMAGE_GATHER4_C_CL: - return "image_gather4_c_cl"; - case Mimg::Op::IMAGE_GATHER4_C_L: - return "image_gather4_c_l"; - case Mimg::Op::IMAGE_GATHER4_C_B: - return "image_gather4_c_b"; - case Mimg::Op::IMAGE_GATHER4_C_B_CL: - return "image_gather4_c_b_cl"; - case Mimg::Op::IMAGE_GATHER4_C_LZ: - return "image_gather4_c_lz"; - case Mimg::Op::IMAGE_GATHER4_O: - return "image_gather4_o"; - case Mimg::Op::IMAGE_GATHER4_CL_O: - return "image_gather4_cl_o"; - case Mimg::Op::IMAGE_GATHER4_L_O: - return "image_gather4_l_o"; - case Mimg::Op::IMAGE_GATHER4_B_O: - return "image_gather4_b_o"; - case Mimg::Op::IMAGE_GATHER4_B_CL_O: - return "image_gather4_b_cl_o"; - case Mimg::Op::IMAGE_GATHER4_LZ_O: - return "image_gather4_lz_o"; - case Mimg::Op::IMAGE_GATHER4_C_O: - return "image_gather4_c_o"; - case Mimg::Op::IMAGE_GATHER4_C_CL_O: - return "image_gather4_c_cl_o"; - case Mimg::Op::IMAGE_GATHER4_C_L_O: - return "image_gather4_c_l_o"; - case Mimg::Op::IMAGE_GATHER4_C_B_O: - return "image_gather4_c_b_o"; - case Mimg::Op::IMAGE_GATHER4_C_B_CL_O: - return "image_gather4_c_b_cl_o"; - case Mimg::Op::IMAGE_GATHER4_C_LZ_O: - return "image_gather4_c_lz_o"; - case Mimg::Op::IMAGE_GET_LOD: - return "image_get_lod"; - case Mimg::Op::IMAGE_SAMPLE_CD: - return "image_sample_cd"; - case Mimg::Op::IMAGE_SAMPLE_CD_CL: - return "image_sample_cd_cl"; - case Mimg::Op::IMAGE_SAMPLE_C_CD: - return "image_sample_c_cd"; - case Mimg::Op::IMAGE_SAMPLE_C_CD_CL: - return "image_sample_c_cd_cl"; - case Mimg::Op::IMAGE_SAMPLE_CD_O: - return "image_sample_cd_o"; - case Mimg::Op::IMAGE_SAMPLE_CD_CL_O: - return "image_sample_cd_cl_o"; - case Mimg::Op::IMAGE_SAMPLE_C_CD_O: - return "image_sample_c_cd_o"; - case Mimg::Op::IMAGE_SAMPLE_C_CD_CL_O: - return "image_sample_c_cd_cl_o"; - default: - return nullptr; - } +const char* amdgpu::shader::mimgOpcodeToString(Mimg::Op op) +{ + switch (op) + { + case Mimg::Op::IMAGE_LOAD: + return "image_load"; + case Mimg::Op::IMAGE_LOAD_MIP: + return "image_load_mip"; + case Mimg::Op::IMAGE_LOAD_PCK: + return "image_load_pck"; + case Mimg::Op::IMAGE_LOAD_PCK_SGN: + return "image_load_pck_sgn"; + case Mimg::Op::IMAGE_LOAD_MIP_PCK: + return "image_load_mip_pck"; + case Mimg::Op::IMAGE_LOAD_MIP_PCK_SGN: + return "image_load_mip_pck_sgn"; + case Mimg::Op::IMAGE_STORE: + return "image_store"; + case Mimg::Op::IMAGE_STORE_MIP: + return "image_store_mip"; + case Mimg::Op::IMAGE_STORE_PCK: + return "image_store_pck"; + case Mimg::Op::IMAGE_STORE_MIP_PCK: + return "image_store_mip_pck"; + case Mimg::Op::IMAGE_GET_RESINFO: + return "image_get_resinfo"; + case Mimg::Op::IMAGE_ATOMIC_SWAP: + return "image_atomic_swap"; + case Mimg::Op::IMAGE_ATOMIC_CMPSWAP: + return "image_atomic_cmpswap"; + case Mimg::Op::IMAGE_ATOMIC_ADD: + return "image_atomic_add"; + case Mimg::Op::IMAGE_ATOMIC_SUB: + return "image_atomic_sub"; + case Mimg::Op::IMAGE_ATOMIC_RSUB: + return "image_atomic_rsub"; + case Mimg::Op::IMAGE_ATOMIC_SMIN: + return "image_atomic_smin"; + case Mimg::Op::IMAGE_ATOMIC_UMIN: + return "image_atomic_umin"; + case Mimg::Op::IMAGE_ATOMIC_SMAX: + return "image_atomic_smax"; + case Mimg::Op::IMAGE_ATOMIC_UMAX: + return "image_atomic_umax"; + case Mimg::Op::IMAGE_ATOMIC_AND: + return "image_atomic_and"; + case Mimg::Op::IMAGE_ATOMIC_OR: + return "image_atomic_or"; + case Mimg::Op::IMAGE_ATOMIC_XOR: + return "image_atomic_xor"; + case Mimg::Op::IMAGE_ATOMIC_INC: + return "image_atomic_inc"; + case Mimg::Op::IMAGE_ATOMIC_DEC: + return "image_atomic_dec"; + case Mimg::Op::IMAGE_ATOMIC_FCMPSWAP: + return "image_atomic_fcmpswap"; + case Mimg::Op::IMAGE_ATOMIC_FMIN: + return "image_atomic_fmin"; + case Mimg::Op::IMAGE_ATOMIC_FMAX: + return "image_atomic_fmax"; + case Mimg::Op::IMAGE_SAMPLE: + return "image_sample"; + case Mimg::Op::IMAGE_SAMPLE_CL: + return "image_sample_cl"; + case Mimg::Op::IMAGE_SAMPLE_D: + return "image_sample_d"; + case Mimg::Op::IMAGE_SAMPLE_D_CL: + return "image_sample_d_cl"; + case Mimg::Op::IMAGE_SAMPLE_L: + return "image_sample_l"; + case Mimg::Op::IMAGE_SAMPLE_B: + return "image_sample_b"; + case Mimg::Op::IMAGE_SAMPLE_B_CL: + return "image_sample_b_cl"; + case Mimg::Op::IMAGE_SAMPLE_LZ: + return "image_sample_lz"; + case Mimg::Op::IMAGE_SAMPLE_C: + return "image_sample_c"; + case Mimg::Op::IMAGE_SAMPLE_C_CL: + return "image_sample_c_cl"; + case Mimg::Op::IMAGE_SAMPLE_C_D: + return "image_sample_c_d"; + case Mimg::Op::IMAGE_SAMPLE_C_D_CL: + return "image_sample_c_d_cl"; + case Mimg::Op::IMAGE_SAMPLE_C_L: + return "image_sample_c_l"; + case Mimg::Op::IMAGE_SAMPLE_C_B: + return "image_sample_c_b"; + case Mimg::Op::IMAGE_SAMPLE_C_B_CL: + return "image_sample_c_b_cl"; + case Mimg::Op::IMAGE_SAMPLE_C_LZ: + return "image_sample_c_lz"; + case Mimg::Op::IMAGE_SAMPLE_O: + return "image_sample_o"; + case Mimg::Op::IMAGE_SAMPLE_CL_O: + return "image_sample_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_D_O: + return "image_sample_d_o"; + case Mimg::Op::IMAGE_SAMPLE_D_CL_O: + return "image_sample_d_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_L_O: + return "image_sample_l_o"; + case Mimg::Op::IMAGE_SAMPLE_B_O: + return "image_sample_b_o"; + case Mimg::Op::IMAGE_SAMPLE_B_CL_O: + return "image_sample_b_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_LZ_O: + return "image_sample_lz_o"; + case Mimg::Op::IMAGE_SAMPLE_C_O: + return "image_sample_c_o"; + case Mimg::Op::IMAGE_SAMPLE_C_CL_O: + return "image_sample_c_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_C_D_O: + return "image_sample_c_d_o"; + case Mimg::Op::IMAGE_SAMPLE_C_D_CL_O: + return "image_sample_c_d_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_C_L_O: + return "image_sample_c_l_o"; + case Mimg::Op::IMAGE_SAMPLE_C_B_O: + return "image_sample_c_b_o"; + case Mimg::Op::IMAGE_SAMPLE_C_B_CL_O: + return "image_sample_c_b_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_C_LZ_O: + return "image_sample_c_lz_o"; + case Mimg::Op::IMAGE_GATHER4: + return "image_gather4"; + case Mimg::Op::IMAGE_GATHER4_CL: + return "image_gather4_cl"; + case Mimg::Op::IMAGE_GATHER4_L: + return "image_gather4_l"; + case Mimg::Op::IMAGE_GATHER4_B: + return "image_gather4_b"; + case Mimg::Op::IMAGE_GATHER4_B_CL: + return "image_gather4_b_cl"; + case Mimg::Op::IMAGE_GATHER4_LZ: + return "image_gather4_lz"; + case Mimg::Op::IMAGE_GATHER4_C: + return "image_gather4_c"; + case Mimg::Op::IMAGE_GATHER4_C_CL: + return "image_gather4_c_cl"; + case Mimg::Op::IMAGE_GATHER4_C_L: + return "image_gather4_c_l"; + case Mimg::Op::IMAGE_GATHER4_C_B: + return "image_gather4_c_b"; + case Mimg::Op::IMAGE_GATHER4_C_B_CL: + return "image_gather4_c_b_cl"; + case Mimg::Op::IMAGE_GATHER4_C_LZ: + return "image_gather4_c_lz"; + case Mimg::Op::IMAGE_GATHER4_O: + return "image_gather4_o"; + case Mimg::Op::IMAGE_GATHER4_CL_O: + return "image_gather4_cl_o"; + case Mimg::Op::IMAGE_GATHER4_L_O: + return "image_gather4_l_o"; + case Mimg::Op::IMAGE_GATHER4_B_O: + return "image_gather4_b_o"; + case Mimg::Op::IMAGE_GATHER4_B_CL_O: + return "image_gather4_b_cl_o"; + case Mimg::Op::IMAGE_GATHER4_LZ_O: + return "image_gather4_lz_o"; + case Mimg::Op::IMAGE_GATHER4_C_O: + return "image_gather4_c_o"; + case Mimg::Op::IMAGE_GATHER4_C_CL_O: + return "image_gather4_c_cl_o"; + case Mimg::Op::IMAGE_GATHER4_C_L_O: + return "image_gather4_c_l_o"; + case Mimg::Op::IMAGE_GATHER4_C_B_O: + return "image_gather4_c_b_o"; + case Mimg::Op::IMAGE_GATHER4_C_B_CL_O: + return "image_gather4_c_b_cl_o"; + case Mimg::Op::IMAGE_GATHER4_C_LZ_O: + return "image_gather4_c_lz_o"; + case Mimg::Op::IMAGE_GET_LOD: + return "image_get_lod"; + case Mimg::Op::IMAGE_SAMPLE_CD: + return "image_sample_cd"; + case Mimg::Op::IMAGE_SAMPLE_CD_CL: + return "image_sample_cd_cl"; + case Mimg::Op::IMAGE_SAMPLE_C_CD: + return "image_sample_c_cd"; + case Mimg::Op::IMAGE_SAMPLE_C_CD_CL: + return "image_sample_c_cd_cl"; + case Mimg::Op::IMAGE_SAMPLE_CD_O: + return "image_sample_cd_o"; + case Mimg::Op::IMAGE_SAMPLE_CD_CL_O: + return "image_sample_cd_cl_o"; + case Mimg::Op::IMAGE_SAMPLE_C_CD_O: + return "image_sample_c_cd_o"; + case Mimg::Op::IMAGE_SAMPLE_C_CD_CL_O: + return "image_sample_c_cd_cl_o"; + default: + return nullptr; + } } -const char *amdgpu::shader::dsOpcodeToString(Ds::Op op) { - switch (op) { - case Ds::Op::DS_ADD_U32: - return "ds_add_u32"; - case Ds::Op::DS_SUB_U32: - return "ds_sub_u32"; - case Ds::Op::DS_RSUB_U32: - return "ds_rsub_u32"; - case Ds::Op::DS_INC_U32: - return "ds_inc_u32"; - case Ds::Op::DS_DEC_U32: - return "ds_dec_u32"; - case Ds::Op::DS_MIN_I32: - return "ds_min_i32"; - case Ds::Op::DS_MAX_I32: - return "ds_max_i32"; - case Ds::Op::DS_MIN_U32: - return "ds_min_u32"; - case Ds::Op::DS_MAX_U32: - return "ds_max_u32"; - case Ds::Op::DS_AND_B32: - return "ds_and_b32"; - case Ds::Op::DS_OR_B32: - return "ds_or_b32"; - case Ds::Op::DS_XOR_B32: - return "ds_xor_b32"; - case Ds::Op::DS_MSKOR_B32: - return "ds_mskor_b32"; - case Ds::Op::DS_WRITE_B32: - return "ds_write_b32"; - case Ds::Op::DS_WRITE2_B32: - return "ds_write2_b32"; - case Ds::Op::DS_WRITE2ST64_B32: - return "ds_write2st64_b32"; - case Ds::Op::DS_CMPST_B32: - return "ds_cmpst_b32"; - case Ds::Op::DS_CMPST_F32: - return "ds_cmpst_f32"; - case Ds::Op::DS_MIN_F32: - return "ds_min_f32"; - case Ds::Op::DS_MAX_F32: - return "ds_max_f32"; - case Ds::Op::DS_NOP: - return "ds_nop"; - case Ds::Op::DS_GWS_SEMA_RELEASE_ALL: - return "ds_gws_sema_release_all"; - case Ds::Op::DS_GWS_INIT: - return "ds_gws_init"; - case Ds::Op::DS_GWS_SEMA_V: - return "ds_gws_sema_v"; - case Ds::Op::DS_GWS_SEMA_BR: - return "ds_gws_sema_br"; - case Ds::Op::DS_GWS_SEMA_P: - return "ds_gws_sema_p"; - case Ds::Op::DS_GWS_BARRIER: - return "ds_gws_barrier"; - case Ds::Op::DS_WRITE_B8: - return "ds_write_b8"; - case Ds::Op::DS_WRITE_B16: - return "ds_write_b16"; - case Ds::Op::DS_ADD_RTN_U32: - return "ds_add_rtn_u32"; - case Ds::Op::DS_SUB_RTN_U32: - return "ds_sub_rtn_u32"; - case Ds::Op::DS_RSUB_RTN_U32: - return "ds_rsub_rtn_u32"; - case Ds::Op::DS_INC_RTN_U32: - return "ds_inc_rtn_u32"; - case Ds::Op::DS_DEC_RTN_U32: - return "ds_dec_rtn_u32"; - case Ds::Op::DS_MIN_RTN_I32: - return "ds_min_rtn_i32"; - case Ds::Op::DS_MAX_RTN_I32: - return "ds_max_rtn_i32"; - case Ds::Op::DS_MIN_RTN_U32: - return "ds_min_rtn_u32"; - case Ds::Op::DS_MAX_RTN_U32: - return "ds_max_rtn_u32"; - case Ds::Op::DS_AND_RTN_B32: - return "ds_and_rtn_b32"; - case Ds::Op::DS_OR_RTN_B32: - return "ds_or_rtn_b32"; - case Ds::Op::DS_XOR_RTN_B32: - return "ds_xor_rtn_b32"; - case Ds::Op::DS_MSKOR_RTN_B32: - return "ds_mskor_rtn_b32"; - case Ds::Op::DS_WRXCHG_RTN_B32: - return "ds_wrxchg_rtn_b32"; - case Ds::Op::DS_WRXCHG2_RTN_B32: - return "ds_wrxchg2_rtn_b32"; - case Ds::Op::DS_WRXCHG2ST64_RTN_B32: - return "ds_wrxchg2st64_rtn_b32"; - case Ds::Op::DS_CMPST_RTN_B32: - return "ds_cmpst_rtn_b32"; - case Ds::Op::DS_CMPST_RTN_F32: - return "ds_cmpst_rtn_f32"; - case Ds::Op::DS_MIN_RTN_F32: - return "ds_min_rtn_f32"; - case Ds::Op::DS_MAX_RTN_F32: - return "ds_max_rtn_f32"; - case Ds::Op::DS_WRAP_RTN_B32: - return "ds_wrap_rtn_b32"; - case Ds::Op::DS_SWIZZLE_B32: - return "ds_swizzle_b32"; - case Ds::Op::DS_READ_B32: - return "ds_read_b32"; - case Ds::Op::DS_READ2_B32: - return "ds_read2_b32"; - case Ds::Op::DS_READ2ST64_B32: - return "ds_read2st64_b32"; - case Ds::Op::DS_READ_I8: - return "ds_read_i8"; - case Ds::Op::DS_READ_U8: - return "ds_read_u8"; - case Ds::Op::DS_READ_I16: - return "ds_read_i16"; - case Ds::Op::DS_READ_U16: - return "ds_read_u16"; - case Ds::Op::DS_CONSUME: - return "ds_consume"; - case Ds::Op::DS_APPEND: - return "ds_append"; - case Ds::Op::DS_ORDERED_COUNT: - return "ds_ordered_count"; - case Ds::Op::DS_ADD_U64: - return "ds_add_u64"; - case Ds::Op::DS_SUB_U64: - return "ds_sub_u64"; - case Ds::Op::DS_RSUB_U64: - return "ds_rsub_u64"; - case Ds::Op::DS_INC_U64: - return "ds_inc_u64"; - case Ds::Op::DS_DEC_U64: - return "ds_dec_u64"; - case Ds::Op::DS_MIN_I64: - return "ds_min_i64"; - case Ds::Op::DS_MAX_I64: - return "ds_max_i64"; - case Ds::Op::DS_MIN_U64: - return "ds_min_u64"; - case Ds::Op::DS_MAX_U64: - return "ds_max_u64"; - case Ds::Op::DS_AND_B64: - return "ds_and_b64"; - case Ds::Op::DS_OR_B64: - return "ds_or_b64"; - case Ds::Op::DS_XOR_B64: - return "ds_xor_b64"; - case Ds::Op::DS_MSKOR_B64: - return "ds_mskor_b64"; - case Ds::Op::DS_WRITE_B64: - return "ds_write_b64"; - case Ds::Op::DS_WRITE2_B64: - return "ds_write2_b64"; - case Ds::Op::DS_WRITE2ST64_B64: - return "ds_write2st64_b64"; - case Ds::Op::DS_CMPST_B64: - return "ds_cmpst_b64"; - case Ds::Op::DS_CMPST_F64: - return "ds_cmpst_f64"; - case Ds::Op::DS_MIN_F64: - return "ds_min_f64"; - case Ds::Op::DS_MAX_F64: - return "ds_max_f64"; - case Ds::Op::DS_ADD_RTN_U64: - return "ds_add_rtn_u64"; - case Ds::Op::DS_SUB_RTN_U64: - return "ds_sub_rtn_u64"; - case Ds::Op::DS_RSUB_RTN_U64: - return "ds_rsub_rtn_u64"; - case Ds::Op::DS_INC_RTN_U64: - return "ds_inc_rtn_u64"; - case Ds::Op::DS_DEC_RTN_U64: - return "ds_dec_rtn_u64"; - case Ds::Op::DS_MIN_RTN_I64: - return "ds_min_rtn_i64"; - case Ds::Op::DS_MAX_RTN_I64: - return "ds_max_rtn_i64"; - case Ds::Op::DS_MIN_RTN_U64: - return "ds_min_rtn_u64"; - case Ds::Op::DS_MAX_RTN_U64: - return "ds_max_rtn_u64"; - case Ds::Op::DS_AND_RTN_B64: - return "ds_and_rtn_b64"; - case Ds::Op::DS_OR_RTN_B64: - return "ds_or_rtn_b64"; - case Ds::Op::DS_XOR_RTN_B64: - return "ds_xor_rtn_b64"; - case Ds::Op::DS_MSKOR_RTN_B64: - return "ds_mskor_rtn_b64"; - case Ds::Op::DS_WRXCHG_RTN_B64: - return "ds_wrxchg_rtn_b64"; - case Ds::Op::DS_WRXCHG2_RTN_B64: - return "ds_wrxchg2_rtn_b64"; - case Ds::Op::DS_WRXCHG2ST64_RTN_B64: - return "ds_wrxchg2st64_rtn_b64"; - case Ds::Op::DS_CMPST_RTN_B64: - return "ds_cmpst_rtn_b64"; - case Ds::Op::DS_CMPST_RTN_F64: - return "ds_cmpst_rtn_f64"; - case Ds::Op::DS_MIN_RTN_F64: - return "ds_min_rtn_f64"; - case Ds::Op::DS_MAX_RTN_F64: - return "ds_max_rtn_f64"; - case Ds::Op::DS_READ_B64: - return "ds_read_b64"; - case Ds::Op::DS_READ2_B64: - return "ds_read2_b64"; - case Ds::Op::DS_READ2ST64_B64: - return "ds_read2st64_b64"; - case Ds::Op::DS_CONDXCHG32_RTN_B64: - return "ds_condxchg32_rtn_b64"; - case Ds::Op::DS_ADD_SRC2_U32: - return "ds_add_src2_u32"; - case Ds::Op::DS_SUB_SRC2_U32: - return "ds_sub_src2_u32"; - case Ds::Op::DS_RSUB_SRC2_U32: - return "ds_rsub_src2_u32"; - case Ds::Op::DS_INC_SRC2_U32: - return "ds_inc_src2_u32"; - case Ds::Op::DS_DEC_SRC2_U32: - return "ds_dec_src2_u32"; - case Ds::Op::DS_MIN_SRC2_I32: - return "ds_min_src2_i32"; - case Ds::Op::DS_MAX_SRC2_I32: - return "ds_max_src2_i32"; - case Ds::Op::DS_MIN_SRC2_U32: - return "ds_min_src2_u32"; - case Ds::Op::DS_MAX_SRC2_U32: - return "ds_max_src2_u32"; - case Ds::Op::DS_AND_SRC2_B32: - return "ds_and_src2_b32"; - case Ds::Op::DS_OR_SRC2_B32: - return "ds_or_src2_b32"; - case Ds::Op::DS_XOR_SRC2_B32: - return "ds_xor_src2_b32"; - case Ds::Op::DS_WRITE_SRC2_B32: - return "ds_write_src2_b32"; - case Ds::Op::DS_MIN_SRC2_F32: - return "ds_min_src2_f32"; - case Ds::Op::DS_MAX_SRC2_F32: - return "ds_max_src2_f32"; - case Ds::Op::DS_ADD_SRC2_U64: - return "ds_add_src2_u64"; - case Ds::Op::DS_SUB_SRC2_U64: - return "ds_sub_src2_u64"; - case Ds::Op::DS_RSUB_SRC2_U64: - return "ds_rsub_src2_u64"; - case Ds::Op::DS_INC_SRC2_U64: - return "ds_inc_src2_u64"; - case Ds::Op::DS_DEC_SRC2_U64: - return "ds_dec_src2_u64"; - case Ds::Op::DS_MIN_SRC2_I64: - return "ds_min_src2_i64"; - case Ds::Op::DS_MAX_SRC2_I64: - return "ds_max_src2_i64"; - case Ds::Op::DS_MIN_SRC2_U64: - return "ds_min_src2_u64"; - case Ds::Op::DS_MAX_SRC2_U64: - return "ds_max_src2_u64"; - case Ds::Op::DS_AND_SRC2_B64: - return "ds_and_src2_b64"; - case Ds::Op::DS_OR_SRC2_B64: - return "ds_or_src2_b64"; - case Ds::Op::DS_XOR_SRC2_B64: - return "ds_xor_src2_b64"; - case Ds::Op::DS_WRITE_SRC2_B64: - return "ds_write_src2_b64"; - case Ds::Op::DS_MIN_SRC2_F64: - return "ds_min_src2_f64"; - case Ds::Op::DS_MAX_SRC2_F64: - return "ds_max_src2_f64"; - case Ds::Op::DS_WRITE_B96: - return "ds_write_b96"; - case Ds::Op::DS_WRITE_B128: - return "ds_write_b128"; - case Ds::Op::DS_CONDXCHG32_RTN_B128: - return "ds_condxchg32_rtn_b128"; - case Ds::Op::DS_READ_B96: - return "ds_read_b96"; - case Ds::Op::DS_READ_B128: - return "ds_read_b128"; - default: - return nullptr; - } +const char* amdgpu::shader::dsOpcodeToString(Ds::Op op) +{ + switch (op) + { + case Ds::Op::DS_ADD_U32: + return "ds_add_u32"; + case Ds::Op::DS_SUB_U32: + return "ds_sub_u32"; + case Ds::Op::DS_RSUB_U32: + return "ds_rsub_u32"; + case Ds::Op::DS_INC_U32: + return "ds_inc_u32"; + case Ds::Op::DS_DEC_U32: + return "ds_dec_u32"; + case Ds::Op::DS_MIN_I32: + return "ds_min_i32"; + case Ds::Op::DS_MAX_I32: + return "ds_max_i32"; + case Ds::Op::DS_MIN_U32: + return "ds_min_u32"; + case Ds::Op::DS_MAX_U32: + return "ds_max_u32"; + case Ds::Op::DS_AND_B32: + return "ds_and_b32"; + case Ds::Op::DS_OR_B32: + return "ds_or_b32"; + case Ds::Op::DS_XOR_B32: + return "ds_xor_b32"; + case Ds::Op::DS_MSKOR_B32: + return "ds_mskor_b32"; + case Ds::Op::DS_WRITE_B32: + return "ds_write_b32"; + case Ds::Op::DS_WRITE2_B32: + return "ds_write2_b32"; + case Ds::Op::DS_WRITE2ST64_B32: + return "ds_write2st64_b32"; + case Ds::Op::DS_CMPST_B32: + return "ds_cmpst_b32"; + case Ds::Op::DS_CMPST_F32: + return "ds_cmpst_f32"; + case Ds::Op::DS_MIN_F32: + return "ds_min_f32"; + case Ds::Op::DS_MAX_F32: + return "ds_max_f32"; + case Ds::Op::DS_NOP: + return "ds_nop"; + case Ds::Op::DS_GWS_SEMA_RELEASE_ALL: + return "ds_gws_sema_release_all"; + case Ds::Op::DS_GWS_INIT: + return "ds_gws_init"; + case Ds::Op::DS_GWS_SEMA_V: + return "ds_gws_sema_v"; + case Ds::Op::DS_GWS_SEMA_BR: + return "ds_gws_sema_br"; + case Ds::Op::DS_GWS_SEMA_P: + return "ds_gws_sema_p"; + case Ds::Op::DS_GWS_BARRIER: + return "ds_gws_barrier"; + case Ds::Op::DS_WRITE_B8: + return "ds_write_b8"; + case Ds::Op::DS_WRITE_B16: + return "ds_write_b16"; + case Ds::Op::DS_ADD_RTN_U32: + return "ds_add_rtn_u32"; + case Ds::Op::DS_SUB_RTN_U32: + return "ds_sub_rtn_u32"; + case Ds::Op::DS_RSUB_RTN_U32: + return "ds_rsub_rtn_u32"; + case Ds::Op::DS_INC_RTN_U32: + return "ds_inc_rtn_u32"; + case Ds::Op::DS_DEC_RTN_U32: + return "ds_dec_rtn_u32"; + case Ds::Op::DS_MIN_RTN_I32: + return "ds_min_rtn_i32"; + case Ds::Op::DS_MAX_RTN_I32: + return "ds_max_rtn_i32"; + case Ds::Op::DS_MIN_RTN_U32: + return "ds_min_rtn_u32"; + case Ds::Op::DS_MAX_RTN_U32: + return "ds_max_rtn_u32"; + case Ds::Op::DS_AND_RTN_B32: + return "ds_and_rtn_b32"; + case Ds::Op::DS_OR_RTN_B32: + return "ds_or_rtn_b32"; + case Ds::Op::DS_XOR_RTN_B32: + return "ds_xor_rtn_b32"; + case Ds::Op::DS_MSKOR_RTN_B32: + return "ds_mskor_rtn_b32"; + case Ds::Op::DS_WRXCHG_RTN_B32: + return "ds_wrxchg_rtn_b32"; + case Ds::Op::DS_WRXCHG2_RTN_B32: + return "ds_wrxchg2_rtn_b32"; + case Ds::Op::DS_WRXCHG2ST64_RTN_B32: + return "ds_wrxchg2st64_rtn_b32"; + case Ds::Op::DS_CMPST_RTN_B32: + return "ds_cmpst_rtn_b32"; + case Ds::Op::DS_CMPST_RTN_F32: + return "ds_cmpst_rtn_f32"; + case Ds::Op::DS_MIN_RTN_F32: + return "ds_min_rtn_f32"; + case Ds::Op::DS_MAX_RTN_F32: + return "ds_max_rtn_f32"; + case Ds::Op::DS_WRAP_RTN_B32: + return "ds_wrap_rtn_b32"; + case Ds::Op::DS_SWIZZLE_B32: + return "ds_swizzle_b32"; + case Ds::Op::DS_READ_B32: + return "ds_read_b32"; + case Ds::Op::DS_READ2_B32: + return "ds_read2_b32"; + case Ds::Op::DS_READ2ST64_B32: + return "ds_read2st64_b32"; + case Ds::Op::DS_READ_I8: + return "ds_read_i8"; + case Ds::Op::DS_READ_U8: + return "ds_read_u8"; + case Ds::Op::DS_READ_I16: + return "ds_read_i16"; + case Ds::Op::DS_READ_U16: + return "ds_read_u16"; + case Ds::Op::DS_CONSUME: + return "ds_consume"; + case Ds::Op::DS_APPEND: + return "ds_append"; + case Ds::Op::DS_ORDERED_COUNT: + return "ds_ordered_count"; + case Ds::Op::DS_ADD_U64: + return "ds_add_u64"; + case Ds::Op::DS_SUB_U64: + return "ds_sub_u64"; + case Ds::Op::DS_RSUB_U64: + return "ds_rsub_u64"; + case Ds::Op::DS_INC_U64: + return "ds_inc_u64"; + case Ds::Op::DS_DEC_U64: + return "ds_dec_u64"; + case Ds::Op::DS_MIN_I64: + return "ds_min_i64"; + case Ds::Op::DS_MAX_I64: + return "ds_max_i64"; + case Ds::Op::DS_MIN_U64: + return "ds_min_u64"; + case Ds::Op::DS_MAX_U64: + return "ds_max_u64"; + case Ds::Op::DS_AND_B64: + return "ds_and_b64"; + case Ds::Op::DS_OR_B64: + return "ds_or_b64"; + case Ds::Op::DS_XOR_B64: + return "ds_xor_b64"; + case Ds::Op::DS_MSKOR_B64: + return "ds_mskor_b64"; + case Ds::Op::DS_WRITE_B64: + return "ds_write_b64"; + case Ds::Op::DS_WRITE2_B64: + return "ds_write2_b64"; + case Ds::Op::DS_WRITE2ST64_B64: + return "ds_write2st64_b64"; + case Ds::Op::DS_CMPST_B64: + return "ds_cmpst_b64"; + case Ds::Op::DS_CMPST_F64: + return "ds_cmpst_f64"; + case Ds::Op::DS_MIN_F64: + return "ds_min_f64"; + case Ds::Op::DS_MAX_F64: + return "ds_max_f64"; + case Ds::Op::DS_ADD_RTN_U64: + return "ds_add_rtn_u64"; + case Ds::Op::DS_SUB_RTN_U64: + return "ds_sub_rtn_u64"; + case Ds::Op::DS_RSUB_RTN_U64: + return "ds_rsub_rtn_u64"; + case Ds::Op::DS_INC_RTN_U64: + return "ds_inc_rtn_u64"; + case Ds::Op::DS_DEC_RTN_U64: + return "ds_dec_rtn_u64"; + case Ds::Op::DS_MIN_RTN_I64: + return "ds_min_rtn_i64"; + case Ds::Op::DS_MAX_RTN_I64: + return "ds_max_rtn_i64"; + case Ds::Op::DS_MIN_RTN_U64: + return "ds_min_rtn_u64"; + case Ds::Op::DS_MAX_RTN_U64: + return "ds_max_rtn_u64"; + case Ds::Op::DS_AND_RTN_B64: + return "ds_and_rtn_b64"; + case Ds::Op::DS_OR_RTN_B64: + return "ds_or_rtn_b64"; + case Ds::Op::DS_XOR_RTN_B64: + return "ds_xor_rtn_b64"; + case Ds::Op::DS_MSKOR_RTN_B64: + return "ds_mskor_rtn_b64"; + case Ds::Op::DS_WRXCHG_RTN_B64: + return "ds_wrxchg_rtn_b64"; + case Ds::Op::DS_WRXCHG2_RTN_B64: + return "ds_wrxchg2_rtn_b64"; + case Ds::Op::DS_WRXCHG2ST64_RTN_B64: + return "ds_wrxchg2st64_rtn_b64"; + case Ds::Op::DS_CMPST_RTN_B64: + return "ds_cmpst_rtn_b64"; + case Ds::Op::DS_CMPST_RTN_F64: + return "ds_cmpst_rtn_f64"; + case Ds::Op::DS_MIN_RTN_F64: + return "ds_min_rtn_f64"; + case Ds::Op::DS_MAX_RTN_F64: + return "ds_max_rtn_f64"; + case Ds::Op::DS_READ_B64: + return "ds_read_b64"; + case Ds::Op::DS_READ2_B64: + return "ds_read2_b64"; + case Ds::Op::DS_READ2ST64_B64: + return "ds_read2st64_b64"; + case Ds::Op::DS_CONDXCHG32_RTN_B64: + return "ds_condxchg32_rtn_b64"; + case Ds::Op::DS_ADD_SRC2_U32: + return "ds_add_src2_u32"; + case Ds::Op::DS_SUB_SRC2_U32: + return "ds_sub_src2_u32"; + case Ds::Op::DS_RSUB_SRC2_U32: + return "ds_rsub_src2_u32"; + case Ds::Op::DS_INC_SRC2_U32: + return "ds_inc_src2_u32"; + case Ds::Op::DS_DEC_SRC2_U32: + return "ds_dec_src2_u32"; + case Ds::Op::DS_MIN_SRC2_I32: + return "ds_min_src2_i32"; + case Ds::Op::DS_MAX_SRC2_I32: + return "ds_max_src2_i32"; + case Ds::Op::DS_MIN_SRC2_U32: + return "ds_min_src2_u32"; + case Ds::Op::DS_MAX_SRC2_U32: + return "ds_max_src2_u32"; + case Ds::Op::DS_AND_SRC2_B32: + return "ds_and_src2_b32"; + case Ds::Op::DS_OR_SRC2_B32: + return "ds_or_src2_b32"; + case Ds::Op::DS_XOR_SRC2_B32: + return "ds_xor_src2_b32"; + case Ds::Op::DS_WRITE_SRC2_B32: + return "ds_write_src2_b32"; + case Ds::Op::DS_MIN_SRC2_F32: + return "ds_min_src2_f32"; + case Ds::Op::DS_MAX_SRC2_F32: + return "ds_max_src2_f32"; + case Ds::Op::DS_ADD_SRC2_U64: + return "ds_add_src2_u64"; + case Ds::Op::DS_SUB_SRC2_U64: + return "ds_sub_src2_u64"; + case Ds::Op::DS_RSUB_SRC2_U64: + return "ds_rsub_src2_u64"; + case Ds::Op::DS_INC_SRC2_U64: + return "ds_inc_src2_u64"; + case Ds::Op::DS_DEC_SRC2_U64: + return "ds_dec_src2_u64"; + case Ds::Op::DS_MIN_SRC2_I64: + return "ds_min_src2_i64"; + case Ds::Op::DS_MAX_SRC2_I64: + return "ds_max_src2_i64"; + case Ds::Op::DS_MIN_SRC2_U64: + return "ds_min_src2_u64"; + case Ds::Op::DS_MAX_SRC2_U64: + return "ds_max_src2_u64"; + case Ds::Op::DS_AND_SRC2_B64: + return "ds_and_src2_b64"; + case Ds::Op::DS_OR_SRC2_B64: + return "ds_or_src2_b64"; + case Ds::Op::DS_XOR_SRC2_B64: + return "ds_xor_src2_b64"; + case Ds::Op::DS_WRITE_SRC2_B64: + return "ds_write_src2_b64"; + case Ds::Op::DS_MIN_SRC2_F64: + return "ds_min_src2_f64"; + case Ds::Op::DS_MAX_SRC2_F64: + return "ds_max_src2_f64"; + case Ds::Op::DS_WRITE_B96: + return "ds_write_b96"; + case Ds::Op::DS_WRITE_B128: + return "ds_write_b128"; + case Ds::Op::DS_CONDXCHG32_RTN_B128: + return "ds_condxchg32_rtn_b128"; + case Ds::Op::DS_READ_B96: + return "ds_read_b96"; + case Ds::Op::DS_READ_B128: + return "ds_read_b128"; + default: + return nullptr; + } } -const char *amdgpu::shader::vintrpOpcodeToString(Vintrp::Op op) { - switch (op) { - case Vintrp::Op::V_INTERP_P1_F32: - return "v_interp_p1_f32"; - case Vintrp::Op::V_INTERP_P2_F32: - return "v_interp_p2_f32"; - case Vintrp::Op::V_INTERP_MOV_F32: - return "v_interp_mov_f32"; - default: - return nullptr; - } +const char* amdgpu::shader::vintrpOpcodeToString(Vintrp::Op op) +{ + switch (op) + { + case Vintrp::Op::V_INTERP_P1_F32: + return "v_interp_p1_f32"; + case Vintrp::Op::V_INTERP_P2_F32: + return "v_interp_p2_f32"; + case Vintrp::Op::V_INTERP_MOV_F32: + return "v_interp_mov_f32"; + default: + return nullptr; + } } -const char *amdgpu::shader::opcodeToString(InstructionClass instClass, int op) { - switch (instClass) { - case InstructionClass::Vop2: - return vop2OpcodeToString(static_cast(op)); - case InstructionClass::Sop2: - return sop2OpcodeToString(static_cast(op)); - case InstructionClass::Sopk: - return sopkOpcodeToString(static_cast(op)); - case InstructionClass::Smrd: - return smrdOpcodeToString(static_cast(op)); - case InstructionClass::Vop3: - return vop3OpcodeToString(static_cast(op)); - case InstructionClass::Mubuf: - return mubufOpcodeToString(static_cast(op)); - case InstructionClass::Mtbuf: - return mtbufOpcodeToString(static_cast(op)); - case InstructionClass::Mimg: - return mimgOpcodeToString(static_cast(op)); - case InstructionClass::Ds: - return dsOpcodeToString(static_cast(op)); - case InstructionClass::Vintrp: - return vintrpOpcodeToString(static_cast(op)); - case InstructionClass::Exp: - return nullptr; - case InstructionClass::Vop1: - return vop1OpcodeToString(static_cast(op)); - case InstructionClass::Vopc: - return vopcOpcodeToString(static_cast(op)); - case InstructionClass::Sop1: - return sop1OpcodeToString(static_cast(op)); - case InstructionClass::Sopc: - return sopcOpcodeToString(static_cast(op)); - case InstructionClass::Sopp: - return soppOpcodeToString(static_cast(op)); - - default: - return nullptr; - } +const char* amdgpu::shader::opcodeToString(InstructionClass instClass, int op) +{ + switch (instClass) + { + case InstructionClass::Vop2: + return vop2OpcodeToString(static_cast(op)); + case InstructionClass::Sop2: + return sop2OpcodeToString(static_cast(op)); + case InstructionClass::Sopk: + return sopkOpcodeToString(static_cast(op)); + case InstructionClass::Smrd: + return smrdOpcodeToString(static_cast(op)); + case InstructionClass::Vop3: + return vop3OpcodeToString(static_cast(op)); + case InstructionClass::Mubuf: + return mubufOpcodeToString(static_cast(op)); + case InstructionClass::Mtbuf: + return mtbufOpcodeToString(static_cast(op)); + case InstructionClass::Mimg: + return mimgOpcodeToString(static_cast(op)); + case InstructionClass::Ds: + return dsOpcodeToString(static_cast(op)); + case InstructionClass::Vintrp: + return vintrpOpcodeToString(static_cast(op)); + case InstructionClass::Exp: + return nullptr; + case InstructionClass::Vop1: + return vop1OpcodeToString(static_cast(op)); + case InstructionClass::Vopc: + return vopcOpcodeToString(static_cast(op)); + case InstructionClass::Sop1: + return sop1OpcodeToString(static_cast(op)); + case InstructionClass::Sopc: + return sopcOpcodeToString(static_cast(op)); + case InstructionClass::Sopp: + return soppOpcodeToString(static_cast(op)); + + default: + return nullptr; + } } -void amdgpu::shader::Sop1::dump() const { - int instSize = kMinInstSize; - printSop1Opcode(op); - std::printf(" "); - instSize += printScalarOperand(sdst, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(ssrc0, inst + instSize); +void amdgpu::shader::Sop1::dump() const +{ + int instSize = kMinInstSize; + printSop1Opcode(op); + std::printf(" "); + instSize += printScalarOperand(sdst, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(ssrc0, inst + instSize); } -void amdgpu::shader::Sopk::dump() const { - int instSize = kMinInstSize; - printSopkOpcode(op); - std::printf(" "); - instSize += printScalarOperand(sdst, inst + instSize); - std::printf(", %d", simm); +void amdgpu::shader::Sopk::dump() const +{ + int instSize = kMinInstSize; + printSopkOpcode(op); + std::printf(" "); + instSize += printScalarOperand(sdst, inst + instSize); + std::printf(", %d", simm); } -void amdgpu::shader::Sopc::dump() const { - int instSize = kMinInstSize; - printSopcOpcode(op); - std::printf(" "); - instSize += printScalarOperand(ssrc0, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(ssrc1, inst + instSize); +void amdgpu::shader::Sopc::dump() const +{ + int instSize = kMinInstSize; + printSopcOpcode(op); + std::printf(" "); + instSize += printScalarOperand(ssrc0, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(ssrc1, inst + instSize); } -void amdgpu::shader::Sop2::dump() const { - int instSize = kMinInstSize; - printSop2Opcode(op); - std::printf(" "); - instSize += printScalarOperand(sdst, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(ssrc0, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(ssrc1, inst + instSize); +void amdgpu::shader::Sop2::dump() const +{ + int instSize = kMinInstSize; + printSop2Opcode(op); + std::printf(" "); + instSize += printScalarOperand(sdst, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(ssrc0, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(ssrc1, inst + instSize); } -void amdgpu::shader::Sopp::dump() const { - int instSize = kMinInstSize; - printSoppOpcode(op); - std::printf(" "); - instSize += printScalarOperand(simm, inst + instSize); +void amdgpu::shader::Sopp::dump() const +{ + int instSize = kMinInstSize; + printSoppOpcode(op); + std::printf(" "); + instSize += printScalarOperand(simm, inst + instSize); } -void amdgpu::shader::Vop1::dump() const { - int instSize = kMinInstSize; - printVop1Opcode(op); - std::printf(" "); - instSize += printVectorOperand(vdst, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(src0, inst + instSize); +void amdgpu::shader::Vop1::dump() const +{ + int instSize = kMinInstSize; + printVop1Opcode(op); + std::printf(" "); + instSize += printVectorOperand(vdst, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(src0, inst + instSize); } -void amdgpu::shader::Vop2::dump() const { - int instSize = kMinInstSize; - printVop2Opcode(op); - std::printf(" "); - instSize += printVectorOperand(vdst, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(src0, inst + instSize); - std::printf(", "); - instSize += printVectorOperand(vsrc1, inst + instSize); - - if (op == Vop2::Op::V_MADMK_F32 || op == Vop2::Op::V_MADAK_F32) { - std::printf(", "); - instSize += printScalarOperand(255, inst + instSize); - } +void amdgpu::shader::Vop2::dump() const +{ + int instSize = kMinInstSize; + printVop2Opcode(op); + std::printf(" "); + instSize += printVectorOperand(vdst, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(src0, inst + instSize); + std::printf(", "); + instSize += printVectorOperand(vsrc1, inst + instSize); + + if (op == Vop2::Op::V_MADMK_F32 || op == Vop2::Op::V_MADAK_F32) + { + std::printf(", "); + instSize += printScalarOperand(255, inst + instSize); + } } -void amdgpu::shader::Vop3::dump() const { +void amdgpu::shader::Vop3::dump() const +{ - /* + /* v_add_i32 v_addc_u32 v_sub_i32 @@ -2940,222 +3047,237 @@ void amdgpu::shader::Vop3::dump() const { v_div_scale_f64 */ - int instSize = kMinInstSize; - printVop3Opcode(op); - std::printf(" "); - instSize += printVectorOperand(vdst, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(src0, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(src1, inst + instSize); - std::printf(", "); - instSize += printScalarOperand(src2, inst + instSize); - - std::printf(" #abs=%x, clmp=%x, neg=%x, omod=%x, ", abs, clmp, neg, omod); - instSize += printScalarOperand(sdst, inst + instSize); + int instSize = kMinInstSize; + printVop3Opcode(op); + std::printf(" "); + instSize += printVectorOperand(vdst, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(src0, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(src1, inst + instSize); + std::printf(", "); + instSize += printScalarOperand(src2, inst + instSize); + + std::printf(" #abs=%x, clmp=%x, neg=%x, omod=%x, ", abs, clmp, neg, omod); + instSize += printScalarOperand(sdst, inst + instSize); } -void amdgpu::shader::Vopc::dump() const { - int instSize = kMinInstSize; +void amdgpu::shader::Vopc::dump() const +{ + int instSize = kMinInstSize; - printVopcOpcode(op); - std::printf(" "); - instSize += printScalarOperand(src0, inst + instSize); - std::printf(", "); - instSize += printVectorOperand(vsrc1, inst + instSize); + printVopcOpcode(op); + std::printf(" "); + instSize += printScalarOperand(src0, inst + instSize); + std::printf(", "); + instSize += printVectorOperand(vsrc1, inst + instSize); } -void amdgpu::shader::Smrd::dump() const { - int instSize = kMinInstSize; - - printSmrdOpcode(op); - printf(" "); - printScalarOperand(sdst, inst + instSize); - printf(", "); - printScalarOperand(sbase << 1, inst + instSize); - printf(", "); - - if (imm) { - printf("%u", offset << 2); - } else { - printScalarOperand(offset, inst + instSize); - } - - std::printf(" #sdst=%x,sbase=%x,imm=%x,offset=%x", sdst, sbase, imm, offset); +void amdgpu::shader::Smrd::dump() const +{ + int instSize = kMinInstSize; + + printSmrdOpcode(op); + printf(" "); + printScalarOperand(sdst, inst + instSize); + printf(", "); + printScalarOperand(sbase << 1, inst + instSize); + printf(", "); + + if (imm) + { + printf("%u", offset << 2); + } + else + { + printScalarOperand(offset, inst + instSize); + } + + std::printf(" #sdst=%x,sbase=%x,imm=%x,offset=%x", sdst, sbase, imm, offset); } -void amdgpu::shader::Mubuf::dump() const { - int instSize = kMinInstSize; - - printMubufOpcode(op); - printf(" "); - printVectorOperand(vdata, inst + instSize); - printf(", "); - printVectorOperand(vaddr, inst + instSize); - printf(", "); - printScalarOperand(srsrc << 2, inst + instSize); - printf(", "); - printScalarOperand(soffset, inst + instSize); - printf(" #offset=%x, " - "offen=%x,idxen=%x,glc=%x,lds=%x,vaddr=%x,vdata=%x,srsrc=%x,slc=%x," - "tfe=%x,soffset=%d", - offset, offen, idxen, glc, lds, vaddr, vdata, srsrc, slc, tfe, - soffset); +void amdgpu::shader::Mubuf::dump() const +{ + int instSize = kMinInstSize; + + printMubufOpcode(op); + printf(" "); + printVectorOperand(vdata, inst + instSize); + printf(", "); + printVectorOperand(vaddr, inst + instSize); + printf(", "); + printScalarOperand(srsrc << 2, inst + instSize); + printf(", "); + printScalarOperand(soffset, inst + instSize); + printf(" #offset=%x, " + "offen=%x,idxen=%x,glc=%x,lds=%x,vaddr=%x,vdata=%x,srsrc=%x,slc=%x," + "tfe=%x,soffset=%d", + offset, offen, idxen, glc, lds, vaddr, vdata, srsrc, slc, tfe, + soffset); } -void amdgpu::shader::Mtbuf::dump() const { - int instSize = kMinInstSize; - - printMtbufOpcode(op); - printf(" "); - printVectorOperand(vdata, inst + instSize); - printf(", "); - printScalarOperand(srsrc << 2, inst + instSize); - printf(", "); - printScalarOperand(soffset, inst + instSize); - printf(" #offset=%x,offen=%x,idxen=%x,glc=%x,op=%x,dfmt=%x,nfmt=%x,vaddr=%x," - "vdata=%x,srsrc=%x,slc=%x,tfe=%x,soffset=%x", - offset, offen, idxen, glc, (unsigned)op, dfmt, nfmt, vaddr, vdata, - srsrc, slc, tfe, soffset); +void amdgpu::shader::Mtbuf::dump() const +{ + int instSize = kMinInstSize; + + printMtbufOpcode(op); + printf(" "); + printVectorOperand(vdata, inst + instSize); + printf(", "); + printScalarOperand(srsrc << 2, inst + instSize); + printf(", "); + printScalarOperand(soffset, inst + instSize); + printf(" #offset=%x,offen=%x,idxen=%x,glc=%x,op=%x,dfmt=%x,nfmt=%x,vaddr=%x," + "vdata=%x,srsrc=%x,slc=%x,tfe=%x,soffset=%x", + offset, offen, idxen, glc, (unsigned)op, dfmt, nfmt, vaddr, vdata, + srsrc, slc, tfe, soffset); } -void amdgpu::shader::Mimg::dump() const { - int instSize = kMinInstSize; +void amdgpu::shader::Mimg::dump() const +{ + int instSize = kMinInstSize; - printMimgOpcode(op); + printMimgOpcode(op); - printf(" #dmask=%x,unrm=%x,glc=%x,da=%x,r128=%x,tfe=%x,lwe=%x,slc=%x," - "vaddr=%x,vdata=%x,srsrc=%x,ssamp=%x", - dmask, unrm, glc, da, r128, tfe, lwe, slc, vaddr, vdata, srsrc, ssamp); + printf(" #dmask=%x,unrm=%x,glc=%x,da=%x,r128=%x,tfe=%x,lwe=%x,slc=%x," + "vaddr=%x,vdata=%x,srsrc=%x,ssamp=%x", + dmask, unrm, glc, da, r128, tfe, lwe, slc, vaddr, vdata, srsrc, ssamp); } -void amdgpu::shader::Ds::dump() const { - int instSize = kMinInstSize; +void amdgpu::shader::Ds::dump() const +{ + int instSize = kMinInstSize; - printDsOpcode(op); + printDsOpcode(op); } -void amdgpu::shader::Vintrp::dump() const { - int instSize = kMinInstSize; +void amdgpu::shader::Vintrp::dump() const +{ + int instSize = kMinInstSize; - printVintrpOpcode(op); - printf(" "); - instSize += printVectorOperand(vdst, inst + instSize); - printf(", "); - instSize += printVectorOperand(vsrc, inst + instSize); - const char channels[] = {'x', 'y', 'z', 'w'}; + printVintrpOpcode(op); + printf(" "); + instSize += printVectorOperand(vdst, inst + instSize); + printf(", "); + instSize += printVectorOperand(vsrc, inst + instSize); + const char channels[] = {'x', 'y', 'z', 'w'}; - printf(", attr%d.%c", attr, channels[attrChan]); + printf(", attr%d.%c", attr, channels[attrChan]); } -void amdgpu::shader::Exp::dump() const { - int instSize = kMinInstSize; - - printExpTarget(target); - printf(" "); - instSize += printVectorOperand(vsrc0, inst + instSize); - printf(", "); - instSize += printVectorOperand(vsrc1, inst + instSize); - printf(", "); - instSize += printVectorOperand(vsrc2, inst + instSize); - printf(", "); - instSize += printVectorOperand(vsrc3, inst + instSize); - printf(" #en=%x, compr=%x, done=%x, vm=%x", en, compr, done, vm); +void amdgpu::shader::Exp::dump() const +{ + int instSize = kMinInstSize; + + printExpTarget(target); + printf(" "); + instSize += printVectorOperand(vsrc0, inst + instSize); + printf(", "); + instSize += printVectorOperand(vsrc1, inst + instSize); + printf(", "); + instSize += printVectorOperand(vsrc2, inst + instSize); + printf(", "); + instSize += printVectorOperand(vsrc3, inst + instSize); + printf(" #en=%x, compr=%x, done=%x, vm=%x", en, compr, done, vm); } -void amdgpu::shader::Instruction::dump() const { - printf("%-6s ", instructionClassToString(instClass)); - - switch (instClass) { - case InstructionClass::Invalid: - break; - case InstructionClass::Vop2: - Vop2(inst).dump(); - return; - case InstructionClass::Sop2: - Sop2(inst).dump(); - return; - case InstructionClass::Sopk: - Sopk(inst).dump(); - return; - case InstructionClass::Smrd: - Smrd(inst).dump(); - return; - case InstructionClass::Vop3: - Vop3(inst).dump(); - return; - case InstructionClass::Mubuf: - Mubuf(inst).dump(); - return; - case InstructionClass::Mtbuf: - Mtbuf(inst).dump(); - return; - case InstructionClass::Mimg: - Mimg(inst).dump(); - return; - case InstructionClass::Ds: - Ds(inst).dump(); - return; - case InstructionClass::Vintrp: - Vintrp(inst).dump(); - return; - case InstructionClass::Exp: - Exp(inst).dump(); - return; - case InstructionClass::Vop1: - Vop1(inst).dump(); - return; - case InstructionClass::Vopc: - Vopc(inst).dump(); - return; - case InstructionClass::Sop1: - Sop1(inst).dump(); - return; - case InstructionClass::Sopc: - Sopc(inst).dump(); - return; - case InstructionClass::Sopp: - Sopp(inst).dump(); - return; - } - - printf(""); +void amdgpu::shader::Instruction::dump() const +{ + printf("%-6s ", instructionClassToString(instClass)); + + switch (instClass) + { + case InstructionClass::Invalid: + break; + case InstructionClass::Vop2: + Vop2(inst).dump(); + return; + case InstructionClass::Sop2: + Sop2(inst).dump(); + return; + case InstructionClass::Sopk: + Sopk(inst).dump(); + return; + case InstructionClass::Smrd: + Smrd(inst).dump(); + return; + case InstructionClass::Vop3: + Vop3(inst).dump(); + return; + case InstructionClass::Mubuf: + Mubuf(inst).dump(); + return; + case InstructionClass::Mtbuf: + Mtbuf(inst).dump(); + return; + case InstructionClass::Mimg: + Mimg(inst).dump(); + return; + case InstructionClass::Ds: + Ds(inst).dump(); + return; + case InstructionClass::Vintrp: + Vintrp(inst).dump(); + return; + case InstructionClass::Exp: + Exp(inst).dump(); + return; + case InstructionClass::Vop1: + Vop1(inst).dump(); + return; + case InstructionClass::Vopc: + Vopc(inst).dump(); + return; + case InstructionClass::Sop1: + Sop1(inst).dump(); + return; + case InstructionClass::Sopc: + Sopc(inst).dump(); + return; + case InstructionClass::Sopp: + Sopp(inst).dump(); + return; + } + + printf(""); } -const char * -amdgpu::shader::instructionClassToString(InstructionClass instrClass) { - switch (instrClass) { - case InstructionClass::Invalid: - return "INVALID"; - case InstructionClass::Vop2: - return "VOP2"; - case InstructionClass::Sop2: - return "SOP2"; - case InstructionClass::Sopk: - return "SOPK"; - case InstructionClass::Smrd: - return "SMRD"; - case InstructionClass::Vop3: - return "VOP3"; - case InstructionClass::Mubuf: - return "MUBUF"; - case InstructionClass::Mtbuf: - return "MTBUF"; - case InstructionClass::Mimg: - return "MIMG"; - case InstructionClass::Ds: - return "DS"; - case InstructionClass::Vintrp: - return "VINTRP"; - case InstructionClass::Exp: - return "EXP"; - case InstructionClass::Vop1: - return "VOP1"; - case InstructionClass::Vopc: - return "VOPC"; - case InstructionClass::Sop1: - return "SOP1"; - case InstructionClass::Sopc: - return "SOPC"; - case InstructionClass::Sopp: - return "SOPP"; - } - - __builtin_trap(); +const char* +amdgpu::shader::instructionClassToString(InstructionClass instrClass) +{ + switch (instrClass) + { + case InstructionClass::Invalid: + return "INVALID"; + case InstructionClass::Vop2: + return "VOP2"; + case InstructionClass::Sop2: + return "SOP2"; + case InstructionClass::Sopk: + return "SOPK"; + case InstructionClass::Smrd: + return "SMRD"; + case InstructionClass::Vop3: + return "VOP3"; + case InstructionClass::Mubuf: + return "MUBUF"; + case InstructionClass::Mtbuf: + return "MTBUF"; + case InstructionClass::Mimg: + return "MIMG"; + case InstructionClass::Ds: + return "DS"; + case InstructionClass::Vintrp: + return "VINTRP"; + case InstructionClass::Exp: + return "EXP"; + case InstructionClass::Vop1: + return "VOP1"; + case InstructionClass::Vopc: + return "VOPC"; + case InstructionClass::Sop1: + return "SOP1"; + case InstructionClass::Sopc: + return "SOPC"; + case InstructionClass::Sopp: + return "SOPP"; + } + + __builtin_trap(); } diff --git a/hw/amdgpu/shader/src/RegisterState.cpp b/hw/amdgpu/shader/src/RegisterState.cpp index 9ad39f1e..79cd1821 100644 --- a/hw/amdgpu/shader/src/RegisterState.cpp +++ b/hw/amdgpu/shader/src/RegisterState.cpp @@ -2,86 +2,96 @@ #include "util/unreachable.hpp" amdgpu::shader::Value -amdgpu::shader::RegisterState::getRegister(RegisterId regId) { - auto offset = regId.getOffset(); +amdgpu::shader::RegisterState::getRegister(RegisterId regId) +{ + auto offset = regId.getOffset(); - if (regId.isScalar()) { - switch (offset) { - case 0 ... 103: - return sgprs[offset]; - case 106: - return vccLo; - case 107: - return vccHi; - case 124: - return m0; - case 126: - return execLo; - case 127: - return execHi; - case 253: - return scc; - case 254: - return ldsDirect; - } + if (regId.isScalar()) + { + switch (offset) + { + case 0 ... 103: + return sgprs[offset]; + case 106: + return vccLo; + case 107: + return vccHi; + case 124: + return m0; + case 126: + return execLo; + case 127: + return execHi; + case 253: + return scc; + case 254: + return ldsDirect; + } - util::unreachable(); - } + util::unreachable(); + } - if (regId.isVector()) { - return vgprs[offset]; - } + if (regId.isVector()) + { + return vgprs[offset]; + } - if (regId.isAttr()) { - return attrs[offset]; - } + if (regId.isAttr()) + { + return attrs[offset]; + } - util::unreachable(); + util::unreachable(); } -void amdgpu::shader::RegisterState::setRegister(RegisterId regId, Value value) { - auto offset = regId.getOffset(); +void amdgpu::shader::RegisterState::setRegister(RegisterId regId, Value value) +{ + auto offset = regId.getOffset(); - if (regId.isScalar()) { - switch (offset) { - case 0 ... 103: - sgprs[offset] = value; - return; - case 106: - vccLo = value; - return; - case 107: - vccHi = value; - return; - case 124: - m0 = value; - return; - case 126: - execLo = value; - return; - case 127: - execHi = value; - return; - case 253: - scc = value; - return; - case 254: - ldsDirect = value; - return; - } + if (regId.isScalar()) + { + switch (offset) + { + case 0 ... 103: + sgprs[offset] = value; + return; + case 106: + vccLo = value; + return; + case 107: + vccHi = value; + return; + case 124: + m0 = value; + return; + case 126: + execLo = value; + return; + case 127: + execHi = value; + return; + case 253: + scc = value; + return; + case 254: + ldsDirect = value; + return; + } - util::unreachable(); - } + util::unreachable(); + } - if (regId.isVector()) { - vgprs[offset] = value; - return; - } + if (regId.isVector()) + { + vgprs[offset] = value; + return; + } - if (regId.isAttr()) { - attrs[offset] = value; - return; - } + if (regId.isAttr()) + { + attrs[offset] = value; + return; + } - util::unreachable(); + util::unreachable(); } diff --git a/hw/amdgpu/shader/src/TypeId.cpp b/hw/amdgpu/shader/src/TypeId.cpp index 1a4a6c69..b4f8efab 100644 --- a/hw/amdgpu/shader/src/TypeId.cpp +++ b/hw/amdgpu/shader/src/TypeId.cpp @@ -1,134 +1,140 @@ #include "TypeId.hpp" #include "util/unreachable.hpp" -amdgpu::shader::TypeId amdgpu::shader::TypeId::getBaseType() const { - switch (raw) { - case TypeId::Void: - case TypeId::Bool: - case TypeId::SInt8: - case TypeId::UInt8: - case TypeId::SInt16: - case TypeId::UInt16: - case TypeId::SInt32: - case TypeId::UInt32: - case TypeId::SInt64: - case TypeId::UInt64: - case TypeId::Float16: - case TypeId::Float32: - case TypeId::Float64: - case TypeId::Sampler: - case TypeId::Image2D: - case TypeId::StorageImage2D: - case TypeId::SampledImage2D: - return raw; +amdgpu::shader::TypeId amdgpu::shader::TypeId::getBaseType() const +{ + switch (raw) + { + case TypeId::Void: + case TypeId::Bool: + case TypeId::SInt8: + case TypeId::UInt8: + case TypeId::SInt16: + case TypeId::UInt16: + case TypeId::SInt32: + case TypeId::UInt32: + case TypeId::SInt64: + case TypeId::UInt64: + case TypeId::Float16: + case TypeId::Float32: + case TypeId::Float64: + case TypeId::Sampler: + case TypeId::Image2D: + case TypeId::StorageImage2D: + case TypeId::SampledImage2D: + return raw; - case TypeId::UInt32x2: - case TypeId::UInt32x3: - case TypeId::UInt32x4: - case TypeId::ArrayUInt32x8: - case TypeId::ArrayUInt32x16: - return TypeId::UInt32; + case TypeId::UInt32x2: + case TypeId::UInt32x3: + case TypeId::UInt32x4: + case TypeId::ArrayUInt32x8: + case TypeId::ArrayUInt32x16: + return TypeId::UInt32; - case TypeId::Float32x2: - case TypeId::Float32x3: - case TypeId::Float32x4: - case TypeId::ArrayFloat32x8: - case TypeId::ArrayFloat32x16: - return TypeId::Float32; - } + case TypeId::Float32x2: + case TypeId::Float32x3: + case TypeId::Float32x4: + case TypeId::ArrayFloat32x8: + case TypeId::ArrayFloat32x16: + return TypeId::Float32; + } - util::unreachable(); + util::unreachable(); } -std::size_t amdgpu::shader::TypeId::getSize() const { - switch (raw) { - case TypeId::Void: - case TypeId::Sampler: - case TypeId::StorageImage2D: - case TypeId::Image2D: - case TypeId::SampledImage2D: - return 0; - case TypeId::Bool: - return 1; - case TypeId::SInt8: - case TypeId::UInt8: - return 1; - case TypeId::SInt16: - case TypeId::UInt16: - return 2; - case TypeId::SInt32: - case TypeId::UInt32: - return 4; - case TypeId::SInt64: - case TypeId::UInt64: - return 8; - case TypeId::Float16: - return 2; - case TypeId::Float32: - return 4; - case TypeId::Float64: - return 8; +std::size_t amdgpu::shader::TypeId::getSize() const +{ + switch (raw) + { + case TypeId::Void: + case TypeId::Sampler: + case TypeId::StorageImage2D: + case TypeId::Image2D: + case TypeId::SampledImage2D: + return 0; + case TypeId::Bool: + return 1; + case TypeId::SInt8: + case TypeId::UInt8: + return 1; + case TypeId::SInt16: + case TypeId::UInt16: + return 2; + case TypeId::SInt32: + case TypeId::UInt32: + return 4; + case TypeId::SInt64: + case TypeId::UInt64: + return 8; + case TypeId::Float16: + return 2; + case TypeId::Float32: + return 4; + case TypeId::Float64: + return 8; - case TypeId::UInt32x2: - case TypeId::UInt32x3: - case TypeId::UInt32x4: - case TypeId::ArrayUInt32x8: - case TypeId::ArrayUInt32x16: - case TypeId::Float32x2: - case TypeId::Float32x3: - case TypeId::Float32x4: - case TypeId::ArrayFloat32x8: - case TypeId::ArrayFloat32x16: - return getElementsCount() * getBaseType().getSize(); - } + case TypeId::UInt32x2: + case TypeId::UInt32x3: + case TypeId::UInt32x4: + case TypeId::ArrayUInt32x8: + case TypeId::ArrayUInt32x16: + case TypeId::Float32x2: + case TypeId::Float32x3: + case TypeId::Float32x4: + case TypeId::ArrayFloat32x8: + case TypeId::ArrayFloat32x16: + return getElementsCount() * getBaseType().getSize(); + } - util::unreachable(); + util::unreachable(); } -std::size_t amdgpu::shader::TypeId::getElementsCount() const { - switch (raw) { - case TypeId::Bool: - case TypeId::SInt8: - case TypeId::UInt8: - case TypeId::SInt16: - case TypeId::UInt16: - case TypeId::SInt32: - case TypeId::UInt32: - case TypeId::SInt64: - case TypeId::UInt64: - case TypeId::Float16: - case TypeId::Float32: - case TypeId::Float64: - return 1; +std::size_t amdgpu::shader::TypeId::getElementsCount() const +{ + switch (raw) + { + case TypeId::Bool: + case TypeId::SInt8: + case TypeId::UInt8: + case TypeId::SInt16: + case TypeId::UInt16: + case TypeId::SInt32: + case TypeId::UInt32: + case TypeId::SInt64: + case TypeId::UInt64: + case TypeId::Float16: + case TypeId::Float32: + case TypeId::Float64: + return 1; - case TypeId::UInt32x2: - return 2; - case TypeId::UInt32x3: - return 3; - case TypeId::UInt32x4: - return 4; - case TypeId::ArrayUInt32x8: - return 8; - case TypeId::ArrayUInt32x16: - return 16; - case TypeId::Float32x2: - return 2; - case TypeId::Float32x3: - return 3; - case TypeId::Float32x4: - return 4; - case TypeId::ArrayFloat32x8: - return 8; - case TypeId::ArrayFloat32x16: - return 16; + case TypeId::UInt32x2: + return 2; + case TypeId::UInt32x3: + return 3; + case TypeId::UInt32x4: + return 4; + case TypeId::ArrayUInt32x8: + return 8; + case TypeId::ArrayUInt32x16: + return 16; + case TypeId::Float32x2: + return 2; + case TypeId::Float32x3: + return 3; + case TypeId::Float32x4: + return 4; + case TypeId::ArrayFloat32x8: + return 8; + case TypeId::ArrayFloat32x16: + return 16; - case TypeId::Void: - case TypeId::Sampler: - case TypeId::Image2D: - case TypeId::StorageImage2D: - case TypeId::SampledImage2D: - return 0; - } + case TypeId::Void: + case TypeId::Sampler: + case TypeId::Image2D: + case TypeId::StorageImage2D: + case TypeId::SampledImage2D: + return 0; + } - util::unreachable(); + util::unreachable(); } diff --git a/hw/amdgpu/shader/src/cf.cpp b/hw/amdgpu/shader/src/cf.cpp index 2f18a071..f8bc313f 100644 --- a/hw/amdgpu/shader/src/cf.cpp +++ b/hw/amdgpu/shader/src/cf.cpp @@ -3,115 +3,133 @@ #include #include -void cf::BasicBlock::split(BasicBlock *target) { - assert(target->address > address); - target->size = size - (target->address - address); - size = target->address - address; - - for (std::size_t i = 0, count = getSuccessorsCount(); i < count; ++i) { - auto succ = getSuccessor(i); - succ->predecessors.erase(this); - succ->predecessors.insert(target); - target->successors[i] = successors[i]; - successors[i] = nullptr; - } - - target->terminator = terminator; - terminator = TerminatorKind::None; - - createBranch(target); +void cf::BasicBlock::split(BasicBlock* target) +{ + assert(target->address > address); + target->size = size - (target->address - address); + size = target->address - address; + + for (std::size_t i = 0, count = getSuccessorsCount(); i < count; ++i) + { + auto succ = getSuccessor(i); + succ->predecessors.erase(this); + succ->predecessors.insert(target); + target->successors[i] = successors[i]; + successors[i] = nullptr; + } + + target->terminator = terminator; + terminator = TerminatorKind::None; + + createBranch(target); } -void cf::BasicBlock::createConditionalBranch(BasicBlock *ifTrue, - BasicBlock *ifFalse) { - assert(terminator == TerminatorKind::None); - assert(getSuccessorsCount() == 0); - ifTrue->predecessors.insert(this); - ifFalse->predecessors.insert(this); +void cf::BasicBlock::createConditionalBranch(BasicBlock* ifTrue, + BasicBlock* ifFalse) +{ + assert(terminator == TerminatorKind::None); + assert(getSuccessorsCount() == 0); + ifTrue->predecessors.insert(this); + ifFalse->predecessors.insert(this); - successors[0] = ifTrue; - successors[1] = ifFalse; + successors[0] = ifTrue; + successors[1] = ifFalse; - terminator = TerminatorKind::Branch; + terminator = TerminatorKind::Branch; } -void cf::BasicBlock::createBranch(BasicBlock *target) { - assert(terminator == TerminatorKind::None); - assert(getSuccessorsCount() == 0); +void cf::BasicBlock::createBranch(BasicBlock* target) +{ + assert(terminator == TerminatorKind::None); + assert(getSuccessorsCount() == 0); - target->predecessors.insert(this); - successors[0] = target; + target->predecessors.insert(this); + successors[0] = target; - terminator = TerminatorKind::Branch; + terminator = TerminatorKind::Branch; } -void cf::BasicBlock::createBranchToUnknown() { - assert(terminator == TerminatorKind::None); - assert(getSuccessorsCount() == 0); +void cf::BasicBlock::createBranchToUnknown() +{ + assert(terminator == TerminatorKind::None); + assert(getSuccessorsCount() == 0); - terminator = TerminatorKind::BranchToUnknown; + terminator = TerminatorKind::BranchToUnknown; } -void cf::BasicBlock::createReturn() { - assert(terminator == TerminatorKind::None); - assert(getSuccessorsCount() == 0); +void cf::BasicBlock::createReturn() +{ + assert(terminator == TerminatorKind::None); + assert(getSuccessorsCount() == 0); - terminator = TerminatorKind::Return; + terminator = TerminatorKind::Return; } -void cf::BasicBlock::replaceSuccessor(BasicBlock *origBB, BasicBlock *newBB) { - origBB->predecessors.erase(this); - newBB->predecessors.insert(this); +void cf::BasicBlock::replaceSuccessor(BasicBlock* origBB, BasicBlock* newBB) +{ + origBB->predecessors.erase(this); + newBB->predecessors.insert(this); - if (origBB == successors[0]) { - successors[0] = newBB; - return; - } + if (origBB == successors[0]) + { + successors[0] = newBB; + return; + } - if (origBB == successors[1]) { - successors[1] = newBB; - return; - } + if (origBB == successors[1]) + { + successors[1] = newBB; + return; + } - std::abort(); + std::abort(); } -bool cf::BasicBlock::hasDirectPredecessor(const BasicBlock &block) const { - for (auto pred : predecessors) { - if (pred == &block) { - return true; - } - } - - return false; +bool cf::BasicBlock::hasDirectPredecessor(const BasicBlock& block) const +{ + for (auto pred : predecessors) + { + if (pred == &block) + { + return true; + } + } + + return false; } -bool cf::BasicBlock::hasPredecessor(const BasicBlock &block) const { - if (&block == this) { - return hasDirectPredecessor(block); - } - - std::vector workList; - std::unordered_set visited; - workList.push_back(this); - visited.insert(this); - - while (!workList.empty()) { - auto node = workList.back(); - - if (node == &block) { - return true; - } - - workList.pop_back(); - workList.reserve(workList.size() + predecessors.size()); - - for (auto pred : predecessors) { - if (visited.insert(pred).second) { - workList.push_back(pred); - } - } - } - - return false; +bool cf::BasicBlock::hasPredecessor(const BasicBlock& block) const +{ + if (&block == this) + { + return hasDirectPredecessor(block); + } + + std::vector workList; + std::unordered_set visited; + workList.push_back(this); + visited.insert(this); + + while (!workList.empty()) + { + auto node = workList.back(); + + if (node == &block) + { + return true; + } + + workList.pop_back(); + workList.reserve(workList.size() + predecessors.size()); + + for (auto pred : predecessors) + { + if (visited.insert(pred).second) + { + workList.push_back(pred); + } + } + } + + return false; } diff --git a/hw/amdgpu/shader/src/scf.cpp b/hw/amdgpu/shader/src/scf.cpp index 80bfd53a..7bfd773b 100644 --- a/hw/amdgpu/shader/src/scf.cpp +++ b/hw/amdgpu/shader/src/scf.cpp @@ -2,248 +2,294 @@ #include "cf.hpp" #include -void scf::Block::eraseFrom(Node *endBefore) { - mEnd = endBefore->getPrev(); - if (mEnd != nullptr) { - mEnd->mNext = nullptr; - } else { - mBegin = nullptr; - } +void scf::Block::eraseFrom(Node* endBefore) +{ + mEnd = endBefore->getPrev(); + if (mEnd != nullptr) + { + mEnd->mNext = nullptr; + } + else + { + mBegin = nullptr; + } } -void scf::Block::splitInto(Block *target, Node *splitPoint) { - auto targetEnd = std::exchange(mEnd, splitPoint->mPrev); - - if (mEnd != nullptr) { - mEnd->mNext = nullptr; - } else { - mBegin = nullptr; - } - - for (auto node = splitPoint; node != nullptr; node = node->getNext()) { - node->mParent = target; - } - - if (target->mEnd != nullptr) { - target->mEnd->mNext = splitPoint; - } - - splitPoint->mPrev = target->mEnd; - target->mEnd = targetEnd; - - if (target->mBegin == nullptr) { - target->mBegin = splitPoint; - } +void scf::Block::splitInto(Block* target, Node* splitPoint) +{ + auto targetEnd = std::exchange(mEnd, splitPoint->mPrev); + + if (mEnd != nullptr) + { + mEnd->mNext = nullptr; + } + else + { + mBegin = nullptr; + } + + for (auto node = splitPoint; node != nullptr; node = node->getNext()) + { + node->mParent = target; + } + + if (target->mEnd != nullptr) + { + target->mEnd->mNext = splitPoint; + } + + splitPoint->mPrev = target->mEnd; + target->mEnd = targetEnd; + + if (target->mBegin == nullptr) + { + target->mBegin = splitPoint; + } } -scf::Block *scf::Block::split(Context &context, Node *splitPoint) { - auto result = context.create(); - splitInto(result, splitPoint); - return result; +scf::Block* scf::Block::split(Context& context, Node* splitPoint) +{ + auto result = context.create(); + splitInto(result, splitPoint); + return result; } -static scf::BasicBlock *findJumpTargetIn(scf::Block *parentBlock, - scf::Block *testBlock) { - auto jumpNode = dynCast(testBlock->getLastNode()); +static scf::BasicBlock* findJumpTargetIn(scf::Block* parentBlock, + scf::Block* testBlock) +{ + auto jumpNode = dynCast(testBlock->getLastNode()); - if (jumpNode == nullptr || jumpNode->target->getParent() != parentBlock) { - return nullptr; - } + if (jumpNode == nullptr || jumpNode->target->getParent() != parentBlock) + { + return nullptr; + } - return jumpNode->target; + return jumpNode->target; } -static bool transformJumpToLoop(scf::Context &ctxt, scf::Block *block) { - // bb0 - // bb1 - // if true { - // bb2 - // jump bb1 - // } else { - // bb3 - // } - // - // --> - // - // bb0 - // loop { - // bb1 - // if false { - // break - // } - // bb2 - // } - // bb3 - - if (block->isEmpty()) { - return false; - } - - auto ifElse = dynCast(block->getLastNode()); - - if (ifElse == nullptr) { - return false; - } - - auto loopTarget = findJumpTargetIn(block, ifElse->ifTrue); - auto loopBlock = ifElse->ifTrue; - auto invariantBlock = ifElse->ifFalse; - - if (loopTarget == nullptr) { - loopTarget = findJumpTargetIn(block, ifElse->ifFalse); - loopBlock = ifElse->ifFalse; - invariantBlock = ifElse->ifTrue; - - if (loopTarget == nullptr) { - return false; - } - } - - auto loopBody = block->split(ctxt, loopTarget); - auto loop = ctxt.create(loopBody); - block->append(loop); - - for (auto node = invariantBlock->getRootNode(); node != nullptr;) { - auto nextNode = node->getNext(); - invariantBlock->detachNode(node); - block->append(node); - node = nextNode; - } - - loopBlock->detachNode(loopBlock->getLastNode()); - - for (auto node = loopBlock->getRootNode(); node != nullptr;) { - auto nextNode = node->getNext(); - loopBlock->detachNode(node); - loopBody->append(node); - node = nextNode; - } - - invariantBlock->append(ctxt.create()); - - return true; +static bool transformJumpToLoop(scf::Context& ctxt, scf::Block* block) +{ + // bb0 + // bb1 + // if true { + // bb2 + // jump bb1 + // } else { + // bb3 + // } + // + // --> + // + // bb0 + // loop { + // bb1 + // if false { + // break + // } + // bb2 + // } + // bb3 + + if (block->isEmpty()) + { + return false; + } + + auto ifElse = dynCast(block->getLastNode()); + + if (ifElse == nullptr) + { + return false; + } + + auto loopTarget = findJumpTargetIn(block, ifElse->ifTrue); + auto loopBlock = ifElse->ifTrue; + auto invariantBlock = ifElse->ifFalse; + + if (loopTarget == nullptr) + { + loopTarget = findJumpTargetIn(block, ifElse->ifFalse); + loopBlock = ifElse->ifFalse; + invariantBlock = ifElse->ifTrue; + + if (loopTarget == nullptr) + { + return false; + } + } + + auto loopBody = block->split(ctxt, loopTarget); + auto loop = ctxt.create(loopBody); + block->append(loop); + + for (auto node = invariantBlock->getRootNode(); node != nullptr;) + { + auto nextNode = node->getNext(); + invariantBlock->detachNode(node); + block->append(node); + node = nextNode; + } + + loopBlock->detachNode(loopBlock->getLastNode()); + + for (auto node = loopBlock->getRootNode(); node != nullptr;) + { + auto nextNode = node->getNext(); + loopBlock->detachNode(node); + loopBody->append(node); + node = nextNode; + } + + invariantBlock->append(ctxt.create()); + + return true; } -static bool moveSameLastBlocksTo(scf::IfElse *ifElse, scf::Block *block) { - if (ifElse->ifTrue->isEmpty() || ifElse->ifFalse->isEmpty()) { - return false; - } - - auto ifTrueIt = ifElse->ifTrue->getLastNode(); - auto ifFalseIt = ifElse->ifFalse->getLastNode(); - - while (ifTrueIt != nullptr && ifFalseIt != nullptr) { - if (!ifTrueIt->isEqual(*ifFalseIt)) { - break; - } - - ifTrueIt = ifTrueIt->getPrev(); - ifFalseIt = ifFalseIt->getPrev(); - } - - if (ifTrueIt == ifElse->ifTrue->getLastNode()) { - return false; - } - - if (ifTrueIt == nullptr) { - ifTrueIt = ifElse->ifTrue->getRootNode(); - } else { - ifTrueIt = ifTrueIt->getNext(); - } - - if (ifFalseIt == nullptr) { - ifFalseIt = ifElse->ifFalse->getRootNode(); - } else { - ifFalseIt = ifFalseIt->getNext(); - } - - ifElse->ifTrue->splitInto(block, ifTrueIt); - ifElse->ifFalse->eraseFrom(ifFalseIt); - return true; +static bool moveSameLastBlocksTo(scf::IfElse* ifElse, scf::Block* block) +{ + if (ifElse->ifTrue->isEmpty() || ifElse->ifFalse->isEmpty()) + { + return false; + } + + auto ifTrueIt = ifElse->ifTrue->getLastNode(); + auto ifFalseIt = ifElse->ifFalse->getLastNode(); + + while (ifTrueIt != nullptr && ifFalseIt != nullptr) + { + if (!ifTrueIt->isEqual(*ifFalseIt)) + { + break; + } + + ifTrueIt = ifTrueIt->getPrev(); + ifFalseIt = ifFalseIt->getPrev(); + } + + if (ifTrueIt == ifElse->ifTrue->getLastNode()) + { + return false; + } + + if (ifTrueIt == nullptr) + { + ifTrueIt = ifElse->ifTrue->getRootNode(); + } + else + { + ifTrueIt = ifTrueIt->getNext(); + } + + if (ifFalseIt == nullptr) + { + ifFalseIt = ifElse->ifFalse->getRootNode(); + } + else + { + ifFalseIt = ifFalseIt->getNext(); + } + + ifElse->ifTrue->splitInto(block, ifTrueIt); + ifElse->ifFalse->eraseFrom(ifFalseIt); + return true; } -class Structurizer { - scf::Context &context; +class Structurizer +{ + scf::Context& context; public: - Structurizer(scf::Context &context) : context(context) {} + Structurizer(scf::Context& context) + : context(context) + { + } - scf::Block *structurize(cf::BasicBlock *bb) { - return structurizeBlock(bb, {}); - } + scf::Block* structurize(cf::BasicBlock* bb) + { + return structurizeBlock(bb, {}); + } public: - scf::IfElse *structurizeIfElse( - cf::BasicBlock *ifTrue, cf::BasicBlock *ifFalse, - std::unordered_map &visited) { - auto ifTrueBlock = structurizeBlock(ifTrue, visited); - auto ifFalseBlock = structurizeBlock(ifFalse, visited); - - return context.create(ifTrueBlock, ifFalseBlock); - } - - scf::Block *structurizeBlock( - cf::BasicBlock *bb, - std::unordered_map visited) { - auto result = context.create(); - std::vector workList; - workList.push_back(bb); - - while (!workList.empty()) { - auto block = workList.back(); - workList.pop_back(); - - auto [it, inserted] = visited.try_emplace(block, nullptr); - if (!inserted) { - result->append(context.create(it->second)); - continue; - } - - auto scfBlock = context.create(block->getAddress(), - block->getSize()); - it->second = scfBlock; - result->append(scfBlock); - - switch (block->getTerminator()) { - case cf::TerminatorKind::None: - std::abort(); - break; - - case cf::TerminatorKind::Branch: - switch (block->getSuccessorsCount()) { - case 1: - workList.push_back(block->getSuccessor(0)); - break; - - case 2: { - auto ifElse = structurizeIfElse(block->getSuccessor(0), - block->getSuccessor(1), visited); - result->append(ifElse); - - while (moveSameLastBlocksTo(ifElse, result) || - transformJumpToLoop(context, result)) { - ; - } - - break; - } - } - break; - - case cf::TerminatorKind::BranchToUnknown: - result->append(context.create()); - break; - - case cf::TerminatorKind::Return: - result->append(context.create()); - break; - } - } - - return result; - } + scf::IfElse* structurizeIfElse( + cf::BasicBlock* ifTrue, cf::BasicBlock* ifFalse, + std::unordered_map& visited) + { + auto ifTrueBlock = structurizeBlock(ifTrue, visited); + auto ifFalseBlock = structurizeBlock(ifFalse, visited); + + return context.create(ifTrueBlock, ifFalseBlock); + } + + scf::Block* structurizeBlock( + cf::BasicBlock* bb, + std::unordered_map visited) + { + auto result = context.create(); + std::vector workList; + workList.push_back(bb); + + while (!workList.empty()) + { + auto block = workList.back(); + workList.pop_back(); + + auto [it, inserted] = visited.try_emplace(block, nullptr); + if (!inserted) + { + result->append(context.create(it->second)); + continue; + } + + auto scfBlock = context.create(block->getAddress(), + block->getSize()); + it->second = scfBlock; + result->append(scfBlock); + + switch (block->getTerminator()) + { + case cf::TerminatorKind::None: + std::abort(); + break; + + case cf::TerminatorKind::Branch: + switch (block->getSuccessorsCount()) + { + case 1: + workList.push_back(block->getSuccessor(0)); + break; + + case 2: + { + auto ifElse = structurizeIfElse(block->getSuccessor(0), + block->getSuccessor(1), visited); + result->append(ifElse); + + while (moveSameLastBlocksTo(ifElse, result) || + transformJumpToLoop(context, result)) + { + ; + } + + break; + } + } + break; + + case cf::TerminatorKind::BranchToUnknown: + result->append(context.create()); + break; + + case cf::TerminatorKind::Return: + result->append(context.create()); + break; + } + } + + return result; + } }; -scf::Block *scf::structurize(Context &ctxt, cf::BasicBlock *bb) { - return Structurizer{ctxt}.structurize(bb); +scf::Block* scf::structurize(Context& ctxt, cf::BasicBlock* bb) +{ + return Structurizer{ctxt}.structurize(bb); } diff --git a/orbis-kernel/include/orbis/AudioOut.hpp b/orbis-kernel/include/orbis/AudioOut.hpp index fb96a109..209f6ddc 100644 --- a/orbis-kernel/include/orbis/AudioOut.hpp +++ b/orbis-kernel/include/orbis/AudioOut.hpp @@ -12,224 +12,265 @@ #include #include -namespace orbis { -struct AudioOutChannelInfo { - std::int32_t port{}; - std::int32_t idControl{}; - std::int32_t channel{}; - Ref evf; -}; - -struct AudioOutParams { - std::uint64_t control{}; - std::uint32_t formatChannels{}; - float unk0{}; - float unk1{}; - float unk2{}; - float unk3{}; - float unk4{}; - float unk5{}; - float unk6{}; - float unk7{}; - std::uint32_t formatIsFloat{}; - std::uint64_t freq{}; - std::uint32_t formatIsStd{}; - std::uint32_t seek{}; - std::uint32_t seekPart{}; - std::uint64_t unk8{}; - std::uint32_t port{}; - std::uint32_t unk9{}; - std::uint64_t unk10{}; - std::uint32_t sampleLength{}; -}; - -struct AudioOut { - std::mutex thrMtx; - std::mutex soxMtx; - std::vector threads; - AudioOutChannelInfo channelInfo; - std::atomic exit{false}; - - AudioOut() { - if (sox_init() != SOX_SUCCESS) { - ORBIS_LOG_FATAL("Failed to initialize sox"); - std::abort(); - } - } - - ~AudioOut() { - exit = true; - for (auto &thread : threads) { - thread.join(); - } - sox_quit(); - } - - void start() { - std::lock_guard lock(thrMtx); - threads.push_back(std::thread( - [this, channelInfo = channelInfo] { channelEntry(channelInfo); })); - } - -private: - void channelEntry(AudioOutChannelInfo info) { - char control_shm_name[32]; - char audio_shm_name[32]; - - std::snprintf(control_shm_name, sizeof(control_shm_name), "/rpcsx-shm_%d_C", - info.idControl); - std::snprintf(audio_shm_name, sizeof(audio_shm_name), "/rpcsx-shm_%d_%d_A", - info.channel, info.port); - - int controlFd = - ::shm_open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - if (controlFd == -1) { - perror("shm_open"); - std::abort(); - } - - struct stat controlStat; - if (::fstat(controlFd, &controlStat)) { - perror("shm_open"); - std::abort(); - } - - auto controlPtr = reinterpret_cast( - ::mmap(NULL, controlStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, - controlFd, 0)); - if (controlPtr == MAP_FAILED) { - perror("mmap"); - std::abort(); - } - - int bufferFd = - ::shm_open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (bufferFd == -1) { - perror("open"); - std::abort(); - } - - struct stat bufferStat; - if (::fstat(bufferFd, &bufferStat)) { - perror("shm_open"); - std::abort(); - } - - auto audioBuffer = ::mmap(NULL, bufferStat.st_size, PROT_READ | PROT_WRITE, - MAP_SHARED, bufferFd, 0); - auto bitPattern = 1u << info.port; - - auto portOffset = 32 + 0x94 * info.port * 4; - - auto *params = reinterpret_cast(controlPtr + portOffset); - - // samples length will be inited after some time, so we wait for it - while (params->sampleLength == 0) { - } - - ORBIS_LOG_NOTICE("AudioOut: params", params->port, params->control, - params->formatChannels, params->formatIsFloat, - params->formatIsStd, params->freq, params->sampleLength); - - unsigned inChannels = 2; - unsigned inSamples = params->sampleLength; - sox_rate_t sampleRate = 48000; // probably there is no point to parse - // frequency, because it's always 48000 - if (params->formatChannels == 2 && !params->formatIsFloat) { - inChannels = 1; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO"); - } else if (params->formatChannels == 4 && !params->formatIsFloat) { - inChannels = 2; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO"); - } else if (params->formatChannels == 16 && !params->formatIsFloat && - !params->formatIsStd) { - inChannels = 8; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH"); - } else if (params->formatChannels == 16 && !params->formatIsFloat && - params->formatIsStd) { - inChannels = 8; - ORBIS_LOG_NOTICE( - "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD"); - } else if (params->formatChannels == 4 && params->formatIsFloat) { - inChannels = 1; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO"); - } else if (params->formatChannels == 8 && params->formatIsFloat) { - inChannels = 2; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO"); - } else if (params->formatChannels == 32 && params->formatIsFloat && - !params->formatIsStd) { - inChannels = 8; - ORBIS_LOG_NOTICE( - "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH"); - } else if (params->formatChannels == 32 && params->formatIsFloat && - params->formatIsStd) { - inChannels = 8; - ORBIS_LOG_NOTICE("AudioOut: format is " - "ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD"); - } else { - ORBIS_LOG_ERROR("AudioOut: unknown format type"); - } - - sox_signalinfo_t out_si = { - .rate = sampleRate, - .channels = inChannels, - .precision = SOX_SAMPLE_PRECISION, - }; - - // need to be locked because libsox doesn't like simultaneous opening of the - // output - std::unique_lock lock(soxMtx); - sox_format_t *output = - sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); - soxMtx.unlock(); - - if (!output) { - std::abort(); - } - - std::vector samples(inSamples * inChannels); - - std::size_t clips = 0; - SOX_SAMPLE_LOCALS; - - while (!exit.load(std::memory_order::relaxed)) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - if (!params->formatIsFloat) { - auto data = reinterpret_cast(audioBuffer); - for (std::size_t i = 0; i < samples.size(); i++) { - samples[i] = SOX_SIGNED_16BIT_TO_SAMPLE(data[i], clips); - } - } else { - auto data = reinterpret_cast(audioBuffer); - for (std::size_t i = 0; i < samples.size(); i++) { - samples[i] = SOX_FLOAT_32BIT_TO_SAMPLE(data[i], clips); - } - } - - if (sox_write(output, samples.data(), samples.size()) != samples.size()) { - ORBIS_LOG_ERROR("AudioOut: sox_write failed"); - } - - // skip sceAudioOutMix%x event - info.evf->set(bitPattern); - - // set zero to freeing audiooutput - params->control = 0; - } - - sox_close(output); - - ::munmap(audioBuffer, bufferStat.st_size); - ::munmap(controlPtr, controlStat.st_size); - - ::close(controlFd); - ::close(bufferFd); - } -}; +namespace orbis +{ + struct AudioOutChannelInfo + { + std::int32_t port{}; + std::int32_t idControl{}; + std::int32_t channel{}; + Ref evf; + }; + + struct AudioOutParams + { + std::uint64_t control{}; + std::uint32_t formatChannels{}; + float unk0{}; + float unk1{}; + float unk2{}; + float unk3{}; + float unk4{}; + float unk5{}; + float unk6{}; + float unk7{}; + std::uint32_t formatIsFloat{}; + std::uint64_t freq{}; + std::uint32_t formatIsStd{}; + std::uint32_t seek{}; + std::uint32_t seekPart{}; + std::uint64_t unk8{}; + std::uint32_t port{}; + std::uint32_t unk9{}; + std::uint64_t unk10{}; + std::uint32_t sampleLength{}; + }; + + struct AudioOut + { + std::mutex thrMtx; + std::mutex soxMtx; + std::vector threads; + AudioOutChannelInfo channelInfo; + std::atomic exit{false}; + + AudioOut() + { + if (sox_init() != SOX_SUCCESS) + { + ORBIS_LOG_FATAL("Failed to initialize sox"); + std::abort(); + } + } + + ~AudioOut() + { + exit = true; + for (auto& thread : threads) + { + thread.join(); + } + sox_quit(); + } + + void start() + { + std::lock_guard lock(thrMtx); + threads.push_back(std::thread( + [this, channelInfo = channelInfo] { channelEntry(channelInfo); })); + } + + private: + void channelEntry(AudioOutChannelInfo info) + { + char control_shm_name[32]; + char audio_shm_name[32]; + + std::snprintf(control_shm_name, sizeof(control_shm_name), "/rpcsx-shm_%d_C", + info.idControl); + std::snprintf(audio_shm_name, sizeof(audio_shm_name), "/rpcsx-shm_%d_%d_A", + info.channel, info.port); + + int controlFd = + ::shm_open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (controlFd == -1) + { + perror("shm_open"); + std::abort(); + } + + struct stat controlStat; + if (::fstat(controlFd, &controlStat)) + { + perror("shm_open"); + std::abort(); + } + + auto controlPtr = reinterpret_cast( + ::mmap(NULL, controlStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + controlFd, 0)); + if (controlPtr == MAP_FAILED) + { + perror("mmap"); + std::abort(); + } + + int bufferFd = + ::shm_open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (bufferFd == -1) + { + perror("open"); + std::abort(); + } + + struct stat bufferStat; + if (::fstat(bufferFd, &bufferStat)) + { + perror("shm_open"); + std::abort(); + } + + auto audioBuffer = ::mmap(NULL, bufferStat.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, bufferFd, 0); + auto bitPattern = 1u << info.port; + + auto portOffset = 32 + 0x94 * info.port * 4; + + auto* params = reinterpret_cast(controlPtr + portOffset); + + // samples length will be inited after some time, so we wait for it + while (params->sampleLength == 0) + { + } + + ORBIS_LOG_NOTICE("AudioOut: params", params->port, params->control, + params->formatChannels, params->formatIsFloat, + params->formatIsStd, params->freq, params->sampleLength); + + unsigned inChannels = 2; + unsigned inSamples = params->sampleLength; + sox_rate_t sampleRate = 48000; // probably there is no point to parse + // frequency, because it's always 48000 + if (params->formatChannels == 2 && !params->formatIsFloat) + { + inChannels = 1; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO"); + } + else if (params->formatChannels == 4 && !params->formatIsFloat) + { + inChannels = 2; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO"); + } + else if (params->formatChannels == 16 && !params->formatIsFloat && + !params->formatIsStd) + { + inChannels = 8; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH"); + } + else if (params->formatChannels == 16 && !params->formatIsFloat && + params->formatIsStd) + { + inChannels = 8; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD"); + } + else if (params->formatChannels == 4 && params->formatIsFloat) + { + inChannels = 1; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO"); + } + else if (params->formatChannels == 8 && params->formatIsFloat) + { + inChannels = 2; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO"); + } + else if (params->formatChannels == 32 && params->formatIsFloat && + !params->formatIsStd) + { + inChannels = 8; + ORBIS_LOG_NOTICE( + "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH"); + } + else if (params->formatChannels == 32 && params->formatIsFloat && + params->formatIsStd) + { + inChannels = 8; + ORBIS_LOG_NOTICE("AudioOut: format is " + "ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD"); + } + else + { + ORBIS_LOG_ERROR("AudioOut: unknown format type"); + } + + sox_signalinfo_t out_si = { + .rate = sampleRate, + .channels = inChannels, + .precision = SOX_SAMPLE_PRECISION, + }; + + // need to be locked because libsox doesn't like simultaneous opening of the + // output + std::unique_lock lock(soxMtx); + sox_format_t* output = + sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); + soxMtx.unlock(); + + if (!output) + { + std::abort(); + } + + std::vector samples(inSamples * inChannels); + + std::size_t clips = 0; + SOX_SAMPLE_LOCALS; + + while (!exit.load(std::memory_order::relaxed)) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + if (!params->formatIsFloat) + { + auto data = reinterpret_cast(audioBuffer); + for (std::size_t i = 0; i < samples.size(); i++) + { + samples[i] = SOX_SIGNED_16BIT_TO_SAMPLE(data[i], clips); + } + } + else + { + auto data = reinterpret_cast(audioBuffer); + for (std::size_t i = 0; i < samples.size(); i++) + { + samples[i] = SOX_FLOAT_32BIT_TO_SAMPLE(data[i], clips); + } + } + + if (sox_write(output, samples.data(), samples.size()) != samples.size()) + { + ORBIS_LOG_ERROR("AudioOut: sox_write failed"); + } + + // skip sceAudioOutMix%x event + info.evf->set(bitPattern); + + // set zero to freeing audiooutput + params->control = 0; + } + + sox_close(output); + + ::munmap(audioBuffer, bufferStat.st_size); + ::munmap(controlPtr, controlStat.st_size); + + ::close(controlFd); + ::close(bufferFd); + } + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/KernelAllocator.hpp b/orbis-kernel/include/orbis/KernelAllocator.hpp index a4371324..284ce017 100644 --- a/orbis-kernel/include/orbis/KernelAllocator.hpp +++ b/orbis-kernel/include/orbis/KernelAllocator.hpp @@ -9,55 +9,66 @@ #include #include -namespace orbis { -inline namespace utils { -void *kalloc(std::size_t size, std::size_t align); -void kfree(void *ptr, std::size_t size); -template struct kallocator { - using value_type = T; +namespace orbis +{ + inline namespace utils + { + void* kalloc(std::size_t size, std::size_t align); + void kfree(void* ptr, std::size_t size); + template + struct kallocator + { + using value_type = T; - template struct rebind { - using other = kallocator; - }; + template + struct rebind + { + using other = kallocator; + }; - T *allocate(std::size_t n) { - return static_cast(kalloc(sizeof(T) * n, alignof(T))); - } + T* allocate(std::size_t n) + { + return static_cast(kalloc(sizeof(T) * n, alignof(T))); + } - void deallocate(T *p, std::size_t n) { kfree(p, sizeof(T) * n); } + void deallocate(T* p, std::size_t n) { kfree(p, sizeof(T) * n); } - template - friend constexpr bool operator==(const kallocator &, - const kallocator &) noexcept { - return true; - } -}; + template + friend constexpr bool operator==(const kallocator&, + const kallocator&) noexcept + { + return true; + } + }; -using kstring = - std::basic_string, kallocator>; -template using kvector = std::vector>; -template using kdeque = std::deque>; -template > -using kmap = std::map>>; -template > -using kmultimap = std::multimap>>; -template , - typename Pred = std::equal_to> -using kunmap = - std::unordered_map>>; -} // namespace utils + using kstring = + std::basic_string, kallocator>; + template + using kvector = std::vector>; + template + using kdeque = std::deque>; + template > + using kmap = std::map>>; + template > + using kmultimap = std::multimap>>; + template , + typename Pred = std::equal_to> + using kunmap = + std::unordered_map>>; + } // namespace utils -template - requires(std::is_constructible_v) -T *knew(Args &&...args) { - auto loc = static_cast(utils::kalloc(sizeof(T), alignof(T))); - auto res = std::construct_at(loc, std::forward(args)...); - if constexpr (requires(T *t) { t->_total_size = sizeof(T); }) - res->_total_size = sizeof(T); - return res; -} + template + requires(std::is_constructible_v) + T* knew(Args&&... args) + { + auto loc = static_cast(utils::kalloc(sizeof(T), alignof(T))); + auto res = std::construct_at(loc, std::forward(args)...); + if constexpr (requires(T * t) { t->_total_size = sizeof(T); }) + res->_total_size = sizeof(T); + return res; + } -// clang-format off + // clang-format off template void kdelete(T *ptr) { auto total_size = sizeof(T); if constexpr (requires(T *t) { t->_total_size = sizeof(T); }) @@ -67,6 +78,6 @@ template void kdelete(T *ptr) { ptr->~T(); utils::kfree(ptr, total_size); } -// clang-format on + // clang-format on } // namespace orbis diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 3987dbc0..ff987526 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -15,164 +15,187 @@ #include #include -namespace orbis { -struct Process; -struct Thread; - -struct UmtxKey { - // TODO: may contain a reference to a shared memory - std::uintptr_t addr; - orbis::pid_t pid; - - auto operator<=>(const UmtxKey &) const = default; -}; - -struct UmtxCond { - Thread *thr; - utils::shared_cv cv; - - UmtxCond(Thread *thr) : thr(thr) {} -}; - -struct UmtxChain { - utils::shared_mutex mtx; - utils::kmultimap sleep_queue; - utils::kmultimap spare_queue; - - std::pair *enqueue(UmtxKey &key, Thread *thr); - void erase(std::pair *obj); - uint notify_one(const UmtxKey &key); - uint notify_all(const UmtxKey &key); -}; - -class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final { -public: - KernelContext(); - ~KernelContext(); - - Process *createProcess(pid_t pid); - void deleteProcess(Process *proc); - Process *findProcessById(pid_t pid) const; - - long getTscFreq(); - - void *kalloc(std::size_t size, - std::size_t align = __STDCPP_DEFAULT_NEW_ALIGNMENT__); - void kfree(void *ptr, std::size_t size); - - std::pair createEventFlag(utils::kstring name, - std::int32_t flags, - std::uint64_t initPattern) { - std::lock_guard lock(m_evf_mtx); - - auto [it, inserted] = m_event_flags.try_emplace(std::move(name), nullptr); - if (inserted) { - it->second = knew(flags, initPattern); - std::strncpy(it->second->name, it->first.c_str(), 32); - } - - return {it->second.get(), inserted}; - } - - Ref findEventFlag(std::string_view name) { - std::lock_guard lock(m_evf_mtx); - - if (auto it = m_event_flags.find(name); it != m_event_flags.end()) { - return it->second; - } - - return {}; - } - - std::pair createSemaphore(utils::kstring name, - std::uint32_t attrs, - std::int32_t initCount, - std::int32_t maxCount) { - std::lock_guard lock(m_sem_mtx); - auto [it, inserted] = m_semaphores.try_emplace(std::move(name), nullptr); - if (inserted) { - it->second = knew(attrs, initCount, maxCount); - } - - return {it->second.get(), inserted}; - } - - Ref findSemaphore(std::string_view name) { - std::lock_guard lock(m_sem_mtx); - if (auto it = m_semaphores.find(name); it != m_semaphores.end()) { - return it->second; - } - - return {}; - } - - std::pair createIpmiServer(utils::kstring name) { - std::lock_guard lock(m_sem_mtx); - auto [it, inserted] = mIpmiServers.try_emplace(std::move(name), nullptr); - if (inserted) { - it->second = knew(name); - } - - return {it->second.get(), inserted}; - } - - Ref findIpmiServer(std::string_view name) { - std::lock_guard lock(m_sem_mtx); - if (auto it = mIpmiServers.find(name); it != mIpmiServers.end()) { - return it->second; - } - - return {}; - } - - enum { - c_golden_ratio_prime = 2654404609u, - c_umtx_chains = 512, - c_umtx_shifts = 23, - }; - - // Use getUmtxChain0 or getUmtxChain1 - std::tuple> - getUmtxChainIndexed(int i, Thread *t, uint32_t flags, void *ptr); - - // Internal Umtx: Wait/Cv/Sem - auto getUmtxChain0(Thread *t, uint32_t flags, void *ptr) { - return getUmtxChainIndexed(0, t, flags, ptr); - } - - // Internal Umtx: Mutex/Umtx/Rwlock - auto getUmtxChain1(Thread *t, uint32_t flags, void *ptr) { - return getUmtxChainIndexed(1, t, flags, ptr); - } - - Ref shmDevice; - Ref dmemDevice; - Ref blockpoolDevice; - AudioOut *audioOut = nullptr; - -private: - mutable pthread_mutex_t m_heap_mtx; - void *m_heap_next = this + 1; - bool m_heap_is_freeing = false; - utils::kmultimap m_free_heap; - utils::kmultimap m_used_node; - - UmtxChain m_umtx_chains[2][c_umtx_chains]{}; - - std::atomic m_tsc_freq{0}; - - mutable shared_mutex m_proc_mtx; - utils::LinkedNode *m_processes = nullptr; - - shared_mutex m_evf_mtx; - utils::kmap> m_event_flags; - - shared_mutex m_sem_mtx; - utils::kmap> m_semaphores; - - shared_mutex mIpmiServerMtx; - utils::kmap> mIpmiServers; -}; - -extern KernelContext &g_context; +namespace orbis +{ + struct Process; + struct Thread; + + struct UmtxKey + { + // TODO: may contain a reference to a shared memory + std::uintptr_t addr; + orbis::pid_t pid; + + auto operator<=>(const UmtxKey&) const = default; + }; + + struct UmtxCond + { + Thread* thr; + utils::shared_cv cv; + + UmtxCond(Thread* thr) + : thr(thr) + { + } + }; + + struct UmtxChain + { + utils::shared_mutex mtx; + utils::kmultimap sleep_queue; + utils::kmultimap spare_queue; + + std::pair* enqueue(UmtxKey& key, Thread* thr); + void erase(std::pair* obj); + uint notify_one(const UmtxKey& key); + uint notify_all(const UmtxKey& key); + }; + + class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final + { + public: + KernelContext(); + ~KernelContext(); + + Process* createProcess(pid_t pid); + void deleteProcess(Process* proc); + Process* findProcessById(pid_t pid) const; + + long getTscFreq(); + + void* kalloc(std::size_t size, + std::size_t align = __STDCPP_DEFAULT_NEW_ALIGNMENT__); + void kfree(void* ptr, std::size_t size); + + std::pair createEventFlag(utils::kstring name, + std::int32_t flags, + std::uint64_t initPattern) + { + std::lock_guard lock(m_evf_mtx); + + auto [it, inserted] = m_event_flags.try_emplace(std::move(name), nullptr); + if (inserted) + { + it->second = knew(flags, initPattern); + std::strncpy(it->second->name, it->first.c_str(), 32); + } + + return {it->second.get(), inserted}; + } + + Ref findEventFlag(std::string_view name) + { + std::lock_guard lock(m_evf_mtx); + + if (auto it = m_event_flags.find(name); it != m_event_flags.end()) + { + return it->second; + } + + return {}; + } + + std::pair createSemaphore(utils::kstring name, + std::uint32_t attrs, + std::int32_t initCount, + std::int32_t maxCount) + { + std::lock_guard lock(m_sem_mtx); + auto [it, inserted] = m_semaphores.try_emplace(std::move(name), nullptr); + if (inserted) + { + it->second = knew(attrs, initCount, maxCount); + } + + return {it->second.get(), inserted}; + } + + Ref findSemaphore(std::string_view name) + { + std::lock_guard lock(m_sem_mtx); + if (auto it = m_semaphores.find(name); it != m_semaphores.end()) + { + return it->second; + } + + return {}; + } + + std::pair createIpmiServer(utils::kstring name) + { + std::lock_guard lock(m_sem_mtx); + auto [it, inserted] = mIpmiServers.try_emplace(std::move(name), nullptr); + if (inserted) + { + it->second = knew(name); + } + + return {it->second.get(), inserted}; + } + + Ref findIpmiServer(std::string_view name) + { + std::lock_guard lock(m_sem_mtx); + if (auto it = mIpmiServers.find(name); it != mIpmiServers.end()) + { + return it->second; + } + + return {}; + } + + enum + { + c_golden_ratio_prime = 2654404609u, + c_umtx_chains = 512, + c_umtx_shifts = 23, + }; + + // Use getUmtxChain0 or getUmtxChain1 + std::tuple> + getUmtxChainIndexed(int i, Thread* t, uint32_t flags, void* ptr); + + // Internal Umtx: Wait/Cv/Sem + auto getUmtxChain0(Thread* t, uint32_t flags, void* ptr) + { + return getUmtxChainIndexed(0, t, flags, ptr); + } + + // Internal Umtx: Mutex/Umtx/Rwlock + auto getUmtxChain1(Thread* t, uint32_t flags, void* ptr) + { + return getUmtxChainIndexed(1, t, flags, ptr); + } + + Ref shmDevice; + Ref dmemDevice; + Ref blockpoolDevice; + AudioOut* audioOut = nullptr; + + private: + mutable pthread_mutex_t m_heap_mtx; + void* m_heap_next = this + 1; + bool m_heap_is_freeing = false; + utils::kmultimap m_free_heap; + utils::kmultimap m_used_node; + + UmtxChain m_umtx_chains[2][c_umtx_chains]{}; + + std::atomic m_tsc_freq{0}; + + mutable shared_mutex m_proc_mtx; + utils::LinkedNode* m_processes = nullptr; + + shared_mutex m_evf_mtx; + utils::kmap> m_event_flags; + + shared_mutex m_sem_mtx; + utils::kmap> m_semaphores; + + shared_mutex mIpmiServerMtx; + utils::kmap> mIpmiServers; + }; + + extern KernelContext& g_context; } // namespace orbis diff --git a/orbis-kernel/include/orbis/error/ErrorCode.hpp b/orbis-kernel/include/orbis/error/ErrorCode.hpp index d5254bc4..9790441d 100644 --- a/orbis-kernel/include/orbis/error/ErrorCode.hpp +++ b/orbis-kernel/include/orbis/error/ErrorCode.hpp @@ -1,111 +1,113 @@ #pragma once -namespace orbis { -enum class ErrorCode : int { - PERM = 1, // Operation not permitted - NOENT = 2, // No such file or directory - SRCH = 3, // No such process - INTR = 4, // Interrupted system call - IO = 5, // Input/output error - NXIO = 6, // Device not configured - TOOBIG = 7, // Argument list too long - NOEXEC = 8, // Exec format error - BADF = 9, // Bad file descriptor - CHILD = 10, // No child processes - DEADLK = 11, // Resource deadlock avoided +namespace orbis +{ + enum class ErrorCode : int + { + PERM = 1, // Operation not permitted + NOENT = 2, // No such file or directory + SRCH = 3, // No such process + INTR = 4, // Interrupted system call + IO = 5, // Input/output error + NXIO = 6, // Device not configured + TOOBIG = 7, // Argument list too long + NOEXEC = 8, // Exec format error + BADF = 9, // Bad file descriptor + CHILD = 10, // No child processes + DEADLK = 11, // Resource deadlock avoided - NOMEM = 12, // Cannot allocate memory - ACCES = 13, // Permission denied - FAULT = 14, // Bad address - NOTBLK = 15, // Block device required - BUSY = 16, // Device busy - EXIST = 17, // File exists - XDEV = 18, // Cross-device link - NODEV = 19, // Operation not supported by device - NOTDIR = 20, // Not a directory - ISDIR = 21, // Is a directory - INVAL = 22, // Invalid argument - NFILE = 23, // Too many open files in system - MFILE = 24, // Too many open files - NOTTY = 25, // Inappropriate ioctl for device - TXTBSY = 26, // Text file busy - FBIG = 27, // File too large - NOSPC = 28, // No space left on device - SPIPE = 29, // Illegal seek - ROFS = 30, // Read-only filesystem - MLINK = 31, // Too many links - PIPE = 32, // Broken pipe + NOMEM = 12, // Cannot allocate memory + ACCES = 13, // Permission denied + FAULT = 14, // Bad address + NOTBLK = 15, // Block device required + BUSY = 16, // Device busy + EXIST = 17, // File exists + XDEV = 18, // Cross-device link + NODEV = 19, // Operation not supported by device + NOTDIR = 20, // Not a directory + ISDIR = 21, // Is a directory + INVAL = 22, // Invalid argument + NFILE = 23, // Too many open files in system + MFILE = 24, // Too many open files + NOTTY = 25, // Inappropriate ioctl for device + TXTBSY = 26, // Text file busy + FBIG = 27, // File too large + NOSPC = 28, // No space left on device + SPIPE = 29, // Illegal seek + ROFS = 30, // Read-only filesystem + MLINK = 31, // Too many links + PIPE = 32, // Broken pipe - DOM = 33, // Numerical argument out of domain - RANGE = 34, // Result too large + DOM = 33, // Numerical argument out of domain + RANGE = 34, // Result too large - AGAIN = 35, // Resource temporarily unavailable - WOULDBLOCK = AGAIN, // Operation would block - INPROGRESS = 36, // Operation now in progress - ALREADY = 37, // Operation already in progress + AGAIN = 35, // Resource temporarily unavailable + WOULDBLOCK = AGAIN, // Operation would block + INPROGRESS = 36, // Operation now in progress + ALREADY = 37, // Operation already in progress - NOTSOCK = 38, // Socket operation on non-socket - DESTADDRREQ = 39, // Destination address required - MSGSIZE = 40, // Message too long - PROTOTYPE = 41, // Protocol wrong type for socket - NOPROTOOPT = 42, // Protocol not available - PROTONOSUPPORT = 43, // Protocol not supported - SOCKTNOSUPPORT = 44, // Socket type not supported - OPNOTSUPP = 45, // Operation not supported - NOTSUP = OPNOTSUPP, // Operation not supported - PFNOSUPPORT = 46, // Protocol family not supported - AFNOSUPPORT = 47, // Address family not supported by protocol family - ADDRINUSE = 48, // Address already in use - ADDRNOTAVAIL = 49, // Can't assign requested address + NOTSOCK = 38, // Socket operation on non-socket + DESTADDRREQ = 39, // Destination address required + MSGSIZE = 40, // Message too long + PROTOTYPE = 41, // Protocol wrong type for socket + NOPROTOOPT = 42, // Protocol not available + PROTONOSUPPORT = 43, // Protocol not supported + SOCKTNOSUPPORT = 44, // Socket type not supported + OPNOTSUPP = 45, // Operation not supported + NOTSUP = OPNOTSUPP, // Operation not supported + PFNOSUPPORT = 46, // Protocol family not supported + AFNOSUPPORT = 47, // Address family not supported by protocol family + ADDRINUSE = 48, // Address already in use + ADDRNOTAVAIL = 49, // Can't assign requested address - NETDOWN = 50, // Network is down - NETUNREACH = 51, // Network is unreachable - NETRESET = 52, // Network dropped connection on reset - CONNABORTED = 53, // Software caused connection abort - CONNRESET = 54, // Connection reset by peer - NOBUFS = 55, // No buffer space available - ISCONN = 56, // Socket is already connected - NOTCONN = 57, // Socket is not connected - SHUTDOWN = 58, // Can't send after socket shutdown - TOOMANYREFS = 59, // Too many references: can't splice - TIMEDOUT = 60, // Operation timed out - CONNREFUSED = 61, // Connection refused + NETDOWN = 50, // Network is down + NETUNREACH = 51, // Network is unreachable + NETRESET = 52, // Network dropped connection on reset + CONNABORTED = 53, // Software caused connection abort + CONNRESET = 54, // Connection reset by peer + NOBUFS = 55, // No buffer space available + ISCONN = 56, // Socket is already connected + NOTCONN = 57, // Socket is not connected + SHUTDOWN = 58, // Can't send after socket shutdown + TOOMANYREFS = 59, // Too many references: can't splice + TIMEDOUT = 60, // Operation timed out + CONNREFUSED = 61, // Connection refused - LOOP = 62, // Too many levels of symbolic links - NAMETOOLONG = 63, // File name too long - HOSTDOWN = 64, // Host is down - HOSTUNREACH = 65, // No route to host - NOTEMPTY = 66, // Directory not empty - PROCLIM = 67, // Too many processes - USERS = 68, // Too many users - DQUOT = 69, // Disc quota exceeded - STALE = 70, // Stale NFS file handle - REMOTE = 71, // Too many levels of remote in path - BADRPC = 72, // RPC struct is bad - RPCMISMATCH = 73, // RPC version wrong - PROGUNAVAIL = 74, // RPC prog. not avail - PROGMISMATCH = 75, // Program version wrong - PROCUNAVAIL = 76, // Bad procedure for program - NOLCK = 77, // No locks available - NOSYS = 78, // Function not implemented - FTYPE = 79, // Inappropriate file type or format - AUTH = 80, // Authentication error - NEEDAUTH = 81, // Need authenticator - IDRM = 82, // Identifier removed - NOMSG = 83, // No message of desired type - OVERFLOW = 84, // Value too large to be stored in data type - CANCELED = 85, // Operation canceled - ILSEQ = 86, // Illegal byte sequence - NOATTR = 87, // Attribute not found + LOOP = 62, // Too many levels of symbolic links + NAMETOOLONG = 63, // File name too long + HOSTDOWN = 64, // Host is down + HOSTUNREACH = 65, // No route to host + NOTEMPTY = 66, // Directory not empty + PROCLIM = 67, // Too many processes + USERS = 68, // Too many users + DQUOT = 69, // Disc quota exceeded + STALE = 70, // Stale NFS file handle + REMOTE = 71, // Too many levels of remote in path + BADRPC = 72, // RPC struct is bad + RPCMISMATCH = 73, // RPC version wrong + PROGUNAVAIL = 74, // RPC prog. not avail + PROGMISMATCH = 75, // Program version wrong + PROCUNAVAIL = 76, // Bad procedure for program + NOLCK = 77, // No locks available + NOSYS = 78, // Function not implemented + FTYPE = 79, // Inappropriate file type or format + AUTH = 80, // Authentication error + NEEDAUTH = 81, // Need authenticator + IDRM = 82, // Identifier removed + NOMSG = 83, // No message of desired type + OVERFLOW = 84, // Value too large to be stored in data type + CANCELED = 85, // Operation canceled + ILSEQ = 86, // Illegal byte sequence + NOATTR = 87, // Attribute not found - DOOFUS = 88, // Programming error + DOOFUS = 88, // Programming error - BADMSG = 89, // Bad message - MULTIHOP = 90, // Multihop attempted - NOLINK = 91, // Link has been severed - PROTO = 92, // Protocol error + BADMSG = 89, // Bad message + MULTIHOP = 90, // Multihop attempted + NOLINK = 91, // Link has been severed + PROTO = 92, // Protocol error - NOTCAPABLE = 93, // Capabilities insufficient - CAPMODE = 94, // Not permitted in capability mode -}; + NOTCAPABLE = 93, // Capabilities insufficient + CAPMODE = 94, // Not permitted in capability mode + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/error/SysResult.hpp b/orbis-kernel/include/orbis/error/SysResult.hpp index 99308d6a..07a66bf0 100644 --- a/orbis-kernel/include/orbis/error/SysResult.hpp +++ b/orbis-kernel/include/orbis/error/SysResult.hpp @@ -1,22 +1,28 @@ #pragma once -namespace orbis { -enum class ErrorCode : int; +namespace orbis +{ + enum class ErrorCode : int; -class SysResult { - int mValue = 0; + class SysResult + { + int mValue = 0; -public: - SysResult() = default; - SysResult(ErrorCode ec) : mValue(-static_cast(ec)) {} + public: + SysResult() = default; + SysResult(ErrorCode ec) + : mValue(-static_cast(ec)) + { + } - [[nodiscard]] static SysResult notAnError(ErrorCode ec) { - SysResult result; - result.mValue = static_cast(ec); - return result; - } + [[nodiscard]] static SysResult notAnError(ErrorCode ec) + { + SysResult result; + result.mValue = static_cast(ec); + return result; + } - [[nodiscard]] int value() const { return mValue < 0 ? -mValue : mValue; } - [[nodiscard]] bool isError() const { return mValue < 0; } -}; + [[nodiscard]] int value() const { return mValue < 0 ? -mValue : mValue; } + [[nodiscard]] bool isError() const { return mValue < 0; } + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/evf.hpp b/orbis-kernel/include/orbis/evf.hpp index 8403109e..a6d70b76 100644 --- a/orbis-kernel/include/orbis/evf.hpp +++ b/orbis-kernel/include/orbis/evf.hpp @@ -6,91 +6,113 @@ #include #include -namespace orbis { -enum { - kEvfAttrThFifo = 0x01, - kEvfAttrThPrio = 0x02, - kEvfAttrSingle = 0x10, - kEvfAttrMulti = 0x20, - kEvfAttrShared = 0x100, -}; - -enum { - kEvfWaitModeAnd = 0x01, - kEvfWaitModeOr = 0x02, - kEvfWaitModeClearAll = 0x10, - kEvfWaitModeClearPat = 0x20, -}; - -struct EventFlag final { - char name[32]; - - bool isDeleted = false; - std::uint8_t attrs; - std::atomic references{0}; - std::atomic value; - - struct WaitingThread { - Thread *thread; - std::uint64_t bitPattern; - std::uint8_t waitMode; - - bool operator==(const WaitingThread &) const = default; - - bool test(std::uint64_t value) const { - if (waitMode & kEvfWaitModeAnd) { - return (value & bitPattern) == bitPattern; - } - - return (value & bitPattern) != 0; - } - - std::uint64_t applyClear(std::uint64_t value) { - if (waitMode & kEvfWaitModeClearAll) { - return 0; - } - - if (waitMode & kEvfWaitModeClearPat) { - return value & ~bitPattern; - } - - return value; - } - }; - - utils::shared_mutex queueMtx; - utils::kvector waitingThreads; - - enum class NotifyType { Set, Cancel, Destroy }; - - explicit EventFlag(std::int32_t attrs, std::uint64_t initPattern) - : attrs(attrs), value(initPattern) {} - - ErrorCode wait(Thread *thread, std::uint8_t waitMode, - std::uint64_t bitPattern, std::uint32_t *timeout); - ErrorCode tryWait(Thread *thread, std::uint8_t waitMode, - std::uint64_t bitPattern); - std::size_t notify(NotifyType type, std::uint64_t bits); - - std::size_t destroy() { return notify(NotifyType::Destroy, {}); } - - std::size_t cancel(std::uint64_t value) { - return notify(NotifyType::Cancel, value); - } - - std::size_t set(std::uint64_t bits) { return notify(NotifyType::Set, bits); } - - void clear(std::uint64_t bits) { - writer_lock lock(queueMtx); - value.fetch_and(bits, std::memory_order::relaxed); - } - - void incRef() { references.fetch_add(1, std::memory_order::relaxed); } - - void decRef() { - if (references.fetch_sub(1, std::memory_order::relaxed) == 1) { - kdelete(this); - } - } -}; +namespace orbis +{ + enum + { + kEvfAttrThFifo = 0x01, + kEvfAttrThPrio = 0x02, + kEvfAttrSingle = 0x10, + kEvfAttrMulti = 0x20, + kEvfAttrShared = 0x100, + }; + + enum + { + kEvfWaitModeAnd = 0x01, + kEvfWaitModeOr = 0x02, + kEvfWaitModeClearAll = 0x10, + kEvfWaitModeClearPat = 0x20, + }; + + struct EventFlag final + { + char name[32]; + + bool isDeleted = false; + std::uint8_t attrs; + std::atomic references{0}; + std::atomic value; + + struct WaitingThread + { + Thread* thread; + std::uint64_t bitPattern; + std::uint8_t waitMode; + + bool operator==(const WaitingThread&) const = default; + + bool test(std::uint64_t value) const + { + if (waitMode & kEvfWaitModeAnd) + { + return (value & bitPattern) == bitPattern; + } + + return (value & bitPattern) != 0; + } + + std::uint64_t applyClear(std::uint64_t value) + { + if (waitMode & kEvfWaitModeClearAll) + { + return 0; + } + + if (waitMode & kEvfWaitModeClearPat) + { + return value & ~bitPattern; + } + + return value; + } + }; + + utils::shared_mutex queueMtx; + utils::kvector waitingThreads; + + enum class NotifyType + { + Set, + Cancel, + Destroy + }; + + explicit EventFlag(std::int32_t attrs, std::uint64_t initPattern) + : attrs(attrs) + , value(initPattern) + { + } + + ErrorCode wait(Thread* thread, std::uint8_t waitMode, + std::uint64_t bitPattern, std::uint32_t* timeout); + ErrorCode tryWait(Thread* thread, std::uint8_t waitMode, + std::uint64_t bitPattern); + std::size_t notify(NotifyType type, std::uint64_t bits); + + std::size_t destroy() { return notify(NotifyType::Destroy, {}); } + + std::size_t cancel(std::uint64_t value) + { + return notify(NotifyType::Cancel, value); + } + + std::size_t set(std::uint64_t bits) { return notify(NotifyType::Set, bits); } + + void clear(std::uint64_t bits) + { + writer_lock lock(queueMtx); + value.fetch_and(bits, std::memory_order::relaxed); + } + + void incRef() { references.fetch_add(1, std::memory_order::relaxed); } + + void decRef() + { + if (references.fetch_sub(1, std::memory_order::relaxed) == 1) + { + kdelete(this); + } + } + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/file.hpp b/orbis-kernel/include/orbis/file.hpp index ef19226f..ca3056ee 100644 --- a/orbis-kernel/include/orbis/file.hpp +++ b/orbis-kernel/include/orbis/file.hpp @@ -7,46 +7,49 @@ #include "utils/SharedMutex.hpp" #include -namespace orbis { -struct File; -struct KNote; -struct Thread; -struct Stat; -struct Uio; - -struct FileOps { - std::int32_t flags; - ErrorCode (*ioctl)(File *file, std::uint64_t request, void *argp, - Thread *thread) = nullptr; - ErrorCode (*read)(File *file, Uio *uio, Thread *thread) = nullptr; - ErrorCode (*write)(File *file, Uio *uio, Thread *thread) = nullptr; - - ErrorCode (*truncate)(File *file, std::uint64_t len, - Thread *thread) = nullptr; - - ErrorCode (*poll)(File *file, std::uint32_t events, Thread *thread) = nullptr; - - ErrorCode (*kqfilter)(File *file, KNote *kn, Thread *thread) = nullptr; - - ErrorCode (*stat)(File *file, Stat *sb, Thread *thread) = nullptr; - - ErrorCode (*mkdir)(File *file, const char *path, std::int32_t mode) = nullptr; - - // TODO: chown - // TODO: chmod - - ErrorCode (*mmap)(File *file, void **address, std::uint64_t size, - std::int32_t prot, std::int32_t flags, std::int64_t offset, - Thread *thread) = nullptr; - ErrorCode (*munmap)(File *file, void **address, std::uint64_t size, - Thread *thread) = nullptr; -}; - -struct File : RcBase { - shared_mutex mtx; - const FileOps *ops = nullptr; - Ref device; - std::uint64_t nextOff = 0; - utils::kvector dirEntries; -}; +namespace orbis +{ + struct File; + struct KNote; + struct Thread; + struct Stat; + struct Uio; + + struct FileOps + { + std::int32_t flags; + ErrorCode (*ioctl)(File* file, std::uint64_t request, void* argp, + Thread* thread) = nullptr; + ErrorCode (*read)(File* file, Uio* uio, Thread* thread) = nullptr; + ErrorCode (*write)(File* file, Uio* uio, Thread* thread) = nullptr; + + ErrorCode (*truncate)(File* file, std::uint64_t len, + Thread* thread) = nullptr; + + ErrorCode (*poll)(File* file, std::uint32_t events, Thread* thread) = nullptr; + + ErrorCode (*kqfilter)(File* file, KNote* kn, Thread* thread) = nullptr; + + ErrorCode (*stat)(File* file, Stat* sb, Thread* thread) = nullptr; + + ErrorCode (*mkdir)(File* file, const char* path, std::int32_t mode) = nullptr; + + // TODO: chown + // TODO: chmod + + ErrorCode (*mmap)(File* file, void** address, std::uint64_t size, + std::int32_t prot, std::int32_t flags, std::int64_t offset, + Thread* thread) = nullptr; + ErrorCode (*munmap)(File* file, void** address, std::uint64_t size, + Thread* thread) = nullptr; + }; + + struct File : RcBase + { + shared_mutex mtx; + const FileOps* ops = nullptr; + Ref device; + std::uint64_t nextOff = 0; + utils::kvector dirEntries; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/ipmi.hpp b/orbis-kernel/include/orbis/ipmi.hpp index 7f3aeddd..b6141e67 100644 --- a/orbis-kernel/include/orbis/ipmi.hpp +++ b/orbis-kernel/include/orbis/ipmi.hpp @@ -3,17 +3,26 @@ #include "KernelAllocator.hpp" #include "utils/Rc.hpp" -namespace orbis { -struct IpmiServer : RcBase { - kstring name; +namespace orbis +{ + struct IpmiServer : RcBase + { + kstring name; - explicit IpmiServer(kstring name) : name(std::move(name)) {} -}; + explicit IpmiServer(kstring name) + : name(std::move(name)) + { + } + }; -struct IpmiClient : RcBase { - Ref connection; - kstring name; + struct IpmiClient : RcBase + { + Ref connection; + kstring name; - explicit IpmiClient(kstring name) : name(std::move(name)) {} -}; + explicit IpmiClient(kstring name) + : name(std::move(name)) + { + } + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/module.hpp b/orbis-kernel/include/orbis/module.hpp index 43507ddc..3cf1be79 100644 --- a/orbis-kernel/include/orbis/module.hpp +++ b/orbis-kernel/include/orbis/module.hpp @@ -1,7 +1,7 @@ #pragma once -#include "module/Module.hpp" // IWYU pragma: export -#include "module/ModuleHandle.hpp" // IWYU pragma: export -#include "module/ModuleInfo.hpp" // IWYU pragma: export -#include "module/ModuleInfoEx.hpp" // IWYU pragma: export +#include "module/Module.hpp" // IWYU pragma: export +#include "module/ModuleHandle.hpp" // IWYU pragma: export +#include "module/ModuleInfo.hpp" // IWYU pragma: export +#include "module/ModuleInfoEx.hpp" // IWYU pragma: export #include "module/ModuleSegment.hpp" // IWYU pragma: export diff --git a/orbis-kernel/include/orbis/module/Module.hpp b/orbis-kernel/include/orbis/module/Module.hpp index cedc08cc..4117f008 100644 --- a/orbis-kernel/include/orbis/module/Module.hpp +++ b/orbis-kernel/include/orbis/module/Module.hpp @@ -11,131 +11,148 @@ #include #include -namespace orbis { -struct Thread; -struct Process; - -struct ModuleNeeded { - utils::kstring name; - std::uint16_t version; - std::uint64_t attr; - bool isExport; -}; - -enum class SymbolBind : std::uint8_t { Local, Global, Weak, Unique = 10 }; - -enum class SymbolVisibility : std::uint8_t { - Default, - Internal, - Hidden, - Protected -}; - -enum class SymbolType : std::uint8_t { - NoType, - Object, - Function, - Section, - File, - Common, - Tls, - IFunc = 10, -}; - -struct Symbol { - std::int32_t moduleIndex; - std::uint32_t libraryIndex; - std::uint64_t id; - std::uint64_t address; - std::uint64_t size; - SymbolVisibility visibility; - SymbolBind bind; - SymbolType type; -}; - -struct Relocation { - std::uint64_t offset; - std::uint32_t relType; - std::uint32_t symbolIndex; - std::int64_t addend; -}; - -struct Module final { - Process *proc{}; - utils::kstring vfsPath; - char moduleName[256]{}; - char soName[256]{}; - ModuleHandle id{}; - uint32_t tlsIndex{}; - ptr tlsInit{}; - uint32_t tlsInitSize{}; - uint32_t tlsSize{}; - uint32_t tlsOffset{}; - uint32_t tlsAlign{}; - ptr initProc{}; - ptr finiProc{}; - ptr ehFrameHdr{}; - ptr ehFrame{}; - uint32_t ehFrameHdrSize{}; - uint32_t ehFrameSize{}; - ModuleSegment segments[4]{}; - uint32_t segmentCount{}; - std::uint8_t fingerprint[20]{}; - ptr base{}; - uint64_t size{}; - ptr stackStart{}; - ptr stackEnd{}; - ptr processParam{}; - uint64_t processParamSize{}; - ptr moduleParam{}; - uint64_t moduleParamSize{}; - - ptr pltGot{}; - - uint64_t attributes{}; - uint16_t version{}; - uint16_t type{}; - uint16_t flags{}; - uint64_t entryPoint{}; - - uint32_t phNum{}; - uint64_t phdrAddress{}; - - bool isTlsDone = false; - - utils::kvector symbols; - utils::kvector pltRelocations; - utils::kvector nonPltRelocations; - utils::kvector neededModules; - utils::kvector neededLibraries; - utils::kvector> importedModules; - utils::kvector> namespaceModules; - utils::kvector needed; - - std::atomic references{0}; - unsigned _total_size = 0; - - void incRef() { - if (_total_size != sizeof(Module)) - std::abort(); - if (references.fetch_add(1, std::memory_order::relaxed) > 512) { - assert(!"too many references"); - } - } - - void decRef() { - if (references.fetch_sub(1, std::memory_order::relaxed) == 1 && - proc != nullptr) { - destroy(); - } - } - - orbis::SysResult relocate(Process *process); - -private: - void destroy(); -}; - -utils::Ref createModule(Thread *p, std::string vfsPath, - const char *name); +namespace orbis +{ + struct Thread; + struct Process; + + struct ModuleNeeded + { + utils::kstring name; + std::uint16_t version; + std::uint64_t attr; + bool isExport; + }; + + enum class SymbolBind : std::uint8_t + { + Local, + Global, + Weak, + Unique = 10 + }; + + enum class SymbolVisibility : std::uint8_t + { + Default, + Internal, + Hidden, + Protected + }; + + enum class SymbolType : std::uint8_t + { + NoType, + Object, + Function, + Section, + File, + Common, + Tls, + IFunc = 10, + }; + + struct Symbol + { + std::int32_t moduleIndex; + std::uint32_t libraryIndex; + std::uint64_t id; + std::uint64_t address; + std::uint64_t size; + SymbolVisibility visibility; + SymbolBind bind; + SymbolType type; + }; + + struct Relocation + { + std::uint64_t offset; + std::uint32_t relType; + std::uint32_t symbolIndex; + std::int64_t addend; + }; + + struct Module final + { + Process* proc{}; + utils::kstring vfsPath; + char moduleName[256]{}; + char soName[256]{}; + ModuleHandle id{}; + uint32_t tlsIndex{}; + ptr tlsInit{}; + uint32_t tlsInitSize{}; + uint32_t tlsSize{}; + uint32_t tlsOffset{}; + uint32_t tlsAlign{}; + ptr initProc{}; + ptr finiProc{}; + ptr ehFrameHdr{}; + ptr ehFrame{}; + uint32_t ehFrameHdrSize{}; + uint32_t ehFrameSize{}; + ModuleSegment segments[4]{}; + uint32_t segmentCount{}; + std::uint8_t fingerprint[20]{}; + ptr base{}; + uint64_t size{}; + ptr stackStart{}; + ptr stackEnd{}; + ptr processParam{}; + uint64_t processParamSize{}; + ptr moduleParam{}; + uint64_t moduleParamSize{}; + + ptr pltGot{}; + + uint64_t attributes{}; + uint16_t version{}; + uint16_t type{}; + uint16_t flags{}; + uint64_t entryPoint{}; + + uint32_t phNum{}; + uint64_t phdrAddress{}; + + bool isTlsDone = false; + + utils::kvector symbols; + utils::kvector pltRelocations; + utils::kvector nonPltRelocations; + utils::kvector neededModules; + utils::kvector neededLibraries; + utils::kvector> importedModules; + utils::kvector> namespaceModules; + utils::kvector needed; + + std::atomic references{0}; + unsigned _total_size = 0; + + void incRef() + { + if (_total_size != sizeof(Module)) + std::abort(); + if (references.fetch_add(1, std::memory_order::relaxed) > 512) + { + assert(!"too many references"); + } + } + + void decRef() + { + if (references.fetch_sub(1, std::memory_order::relaxed) == 1 && + proc != nullptr) + { + destroy(); + } + } + + orbis::SysResult relocate(Process* process); + + private: + void destroy(); + }; + + utils::Ref createModule(Thread* p, std::string vfsPath, + const char* name); } // namespace orbis diff --git a/orbis-kernel/include/orbis/module/ModuleHandle.hpp b/orbis-kernel/include/orbis/module/ModuleHandle.hpp index 28c07f01..2f9fcc9f 100644 --- a/orbis-kernel/include/orbis/module/ModuleHandle.hpp +++ b/orbis-kernel/include/orbis/module/ModuleHandle.hpp @@ -2,6 +2,9 @@ #include -namespace orbis { -enum class ModuleHandle : std::uint32_t {}; +namespace orbis +{ + enum class ModuleHandle : std::uint32_t + { + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/module/ModuleInfo.hpp b/orbis-kernel/include/orbis/module/ModuleInfo.hpp index b4c78e3b..8ae9c9ed 100644 --- a/orbis-kernel/include/orbis/module/ModuleInfo.hpp +++ b/orbis-kernel/include/orbis/module/ModuleInfo.hpp @@ -4,12 +4,14 @@ #include "orbis-config.hpp" -namespace orbis { -struct ModuleInfo { - uint64_t size; - char name[256]; - ModuleSegment segments[4]; - uint32_t segmentCount; - uint8_t fingerprint[20]; -}; +namespace orbis +{ + struct ModuleInfo + { + uint64_t size; + char name[256]; + ModuleSegment segments[4]; + uint32_t segmentCount; + uint8_t fingerprint[20]; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/module/ModuleInfoEx.hpp b/orbis-kernel/include/orbis/module/ModuleInfoEx.hpp index e5a615bc..25fa709b 100644 --- a/orbis-kernel/include/orbis/module/ModuleInfoEx.hpp +++ b/orbis-kernel/include/orbis/module/ModuleInfoEx.hpp @@ -4,27 +4,29 @@ #include "orbis-config.hpp" -namespace orbis { -struct ModuleInfoEx { - uint64_t size; - char name[256]; - uint32_t id; - uint32_t tlsIndex; - ptr tlsInit; - uint32_t tlsInitSize; - uint32_t tlsSize; - uint32_t tlsOffset; - uint32_t tlsAlign; - ptr initProc; - ptr finiProc; - uint64_t reserved1; - uint64_t reserved2; - ptr ehFrameHdr; - ptr ehFrame; - uint32_t ehFrameHdrSize; - uint32_t ehFrameSize; - ModuleSegment segments[4]; - uint32_t segmentCount; - uint32_t refCount; -}; +namespace orbis +{ + struct ModuleInfoEx + { + uint64_t size; + char name[256]; + uint32_t id; + uint32_t tlsIndex; + ptr tlsInit; + uint32_t tlsInitSize; + uint32_t tlsSize; + uint32_t tlsOffset; + uint32_t tlsAlign; + ptr initProc; + ptr finiProc; + uint64_t reserved1; + uint64_t reserved2; + ptr ehFrameHdr; + ptr ehFrame; + uint32_t ehFrameHdrSize; + uint32_t ehFrameSize; + ModuleSegment segments[4]; + uint32_t segmentCount; + uint32_t refCount; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/module/ModuleSegment.hpp b/orbis-kernel/include/orbis/module/ModuleSegment.hpp index b5185854..0c0c0021 100644 --- a/orbis-kernel/include/orbis/module/ModuleSegment.hpp +++ b/orbis-kernel/include/orbis/module/ModuleSegment.hpp @@ -2,10 +2,12 @@ #include "orbis-config.hpp" -namespace orbis { -struct ModuleSegment { - ptr addr; - uint32_t size; - uint32_t prot; -}; +namespace orbis +{ + struct ModuleSegment + { + ptr addr; + uint32_t size; + uint32_t prot; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/osem.hpp b/orbis-kernel/include/orbis/osem.hpp index ab68af84..98da634f 100644 --- a/orbis-kernel/include/orbis/osem.hpp +++ b/orbis-kernel/include/orbis/osem.hpp @@ -7,39 +7,49 @@ #include #include -namespace orbis { -enum { - kSemaAttrThFifo = 1, - kSemaAttrThPrio = 2, - kSemaAttrShared = 256, -}; - -struct Semaphore final { - char name[32]; - - bool isDeleted = false; - std::uint8_t attrs; - std::atomic references{0}; - std::atomic value; - const sint maxValue; - utils::shared_mutex mtx; - utils::shared_cv cond; - - Semaphore(uint attrs, sint value, sint max) - : attrs(attrs), value(value), maxValue(max) {} - - void destroy() { - std::lock_guard lock(mtx); - isDeleted = true; - cond.notify_all(mtx); - } - - void incRef() { references.fetch_add(1, std::memory_order::relaxed); } - - void decRef() { - if (references.fetch_sub(1, std::memory_order::relaxed) == 1) { - kdelete(this); - } - } -}; +namespace orbis +{ + enum + { + kSemaAttrThFifo = 1, + kSemaAttrThPrio = 2, + kSemaAttrShared = 256, + }; + + struct Semaphore final + { + char name[32]; + + bool isDeleted = false; + std::uint8_t attrs; + std::atomic references{0}; + std::atomic value; + const sint maxValue; + utils::shared_mutex mtx; + utils::shared_cv cond; + + Semaphore(uint attrs, sint value, sint max) + : attrs(attrs) + , value(value) + , maxValue(max) + { + } + + void destroy() + { + std::lock_guard lock(mtx); + isDeleted = true; + cond.notify_all(mtx); + } + + void incRef() { references.fetch_add(1, std::memory_order::relaxed); } + + void decRef() + { + if (references.fetch_sub(1, std::memory_order::relaxed) == 1) + { + kdelete(this); + } + } + }; } // namespace orbis \ No newline at end of file diff --git a/orbis-kernel/include/orbis/stat.hpp b/orbis-kernel/include/orbis/stat.hpp index c99c522c..3512fbba 100644 --- a/orbis-kernel/include/orbis/stat.hpp +++ b/orbis-kernel/include/orbis/stat.hpp @@ -3,45 +3,49 @@ #include "orbis-config.hpp" #include "time.hpp" -namespace orbis { -struct Stat { - uint32_t dev; // inode's device - uint32_t ino; // inode's number - uint16_t mode; // inode protection mode - uint16_t nlink; // number of hard links - uint32_t uid; // user ID of the file's owner - uint32_t gid; // group ID of the file's group - uint32_t rdev; // device type - timespec atim; // time of last access - timespec mtim; // time of last data modification - timespec ctim; // time of last file status change - off_t size; // file size, in bytes - int64_t blocks; // blocks allocated for file - uint32_t blksize; // optimal blocksize for I/O - uint32_t flags; // user defined flags for file - uint32_t gen; // file generation number - int32_t lspare; - timespec birthtim; // time of file creation -}; +namespace orbis +{ + struct Stat + { + uint32_t dev; // inode's device + uint32_t ino; // inode's number + uint16_t mode; // inode protection mode + uint16_t nlink; // number of hard links + uint32_t uid; // user ID of the file's owner + uint32_t gid; // group ID of the file's group + uint32_t rdev; // device type + timespec atim; // time of last access + timespec mtim; // time of last data modification + timespec ctim; // time of last file status change + off_t size; // file size, in bytes + int64_t blocks; // blocks allocated for file + uint32_t blksize; // optimal blocksize for I/O + uint32_t flags; // user defined flags for file + uint32_t gen; // file generation number + int32_t lspare; + timespec birthtim; // time of file creation + }; -struct Dirent { - uint32_t fileno; - uint16_t reclen; - uint8_t type; - uint8_t namlen; - char name[256]; -}; + struct Dirent + { + uint32_t fileno; + uint16_t reclen; + uint8_t type; + uint8_t namlen; + char name[256]; + }; -enum { - kDtUnknown = 0, - kDtFifo = 1, - kDtChr = 2, - kDtDir = 4, - kDtBlk = 6, - kDtReg = 8, - kDtLnk = 10, - kDtSock = 12, - kDtWht = 14, -}; + enum + { + kDtUnknown = 0, + kDtFifo = 1, + kDtChr = 2, + kDtDir = 4, + kDtBlk = 6, + kDtReg = 8, + kDtLnk = 10, + kDtSock = 12, + kDtWht = 14, + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/sys/sys_sce.hpp b/orbis-kernel/include/orbis/sys/sys_sce.hpp index ecbe4039..af39af3d 100644 --- a/orbis-kernel/include/orbis/sys/sys_sce.hpp +++ b/orbis-kernel/include/orbis/sys/sys_sce.hpp @@ -1,11 +1,13 @@ #pragma once -namespace orbis { -enum { - kNamedObjTypeMutex = 0x101, - kNamedObjTypeCond = 0x102, - kNamedObjTypeRwlock = 0x103, - kNamedObjTypeBarrier = 0x104, - kNamedObjTypeEqueue = 0x107, -}; +namespace orbis +{ + enum + { + kNamedObjTypeMutex = 0x101, + kNamedObjTypeCond = 0x102, + kNamedObjTypeRwlock = 0x103, + kNamedObjTypeBarrier = 0x104, + kNamedObjTypeEqueue = 0x107, + }; } diff --git a/orbis-kernel/include/orbis/sys/syscall.hpp b/orbis-kernel/include/orbis/sys/syscall.hpp index fe72c592..c28e4ea1 100644 --- a/orbis-kernel/include/orbis/sys/syscall.hpp +++ b/orbis-kernel/include/orbis/sys/syscall.hpp @@ -1,599 +1,601 @@ #pragma once -namespace orbis { -enum Syscall { - kSYS_syscall = 0, - kSYS_exit = 1, - kSYS_fork = 2, - kSYS_read = 3, - kSYS_write = 4, - kSYS_open = 5, - kSYS_close = 6, - kSYS_wait4 = 7, - kSYS_link = 9, - kSYS_unlink = 10, - kSYS_chdir = 12, - kSYS_fchdir = 13, - kSYS_mknod = 14, - kSYS_chmod = 15, - kSYS_chown = 16, - kSYS_break = 17, - kSYS_freebsd4_getfsstat = 18, - kSYS_getpid = 20, - kSYS_mount = 21, - kSYS_unmount = 22, - kSYS_setuid = 23, - kSYS_getuid = 24, - kSYS_geteuid = 25, - kSYS_ptrace = 26, - kSYS_recvmsg = 27, - kSYS_sendmsg = 28, - kSYS_recvfrom = 29, - kSYS_accept = 30, - kSYS_getpeername = 31, - kSYS_getsockname = 32, - kSYS_access = 33, - kSYS_chflags = 34, - kSYS_fchflags = 35, - kSYS_sync = 36, - kSYS_kill = 37, - kSYS_getppid = 39, - kSYS_dup = 41, - kSYS_pipe = 42, - kSYS_getegid = 43, - kSYS_profil = 44, - kSYS_ktrace = 45, - kSYS_getgid = 47, - kSYS_getlogin = 49, - kSYS_setlogin = 50, - kSYS_acct = 51, - kSYS_sigaltstack = 53, - kSYS_ioctl = 54, - kSYS_reboot = 55, - kSYS_revoke = 56, - kSYS_symlink = 57, - kSYS_readlink = 58, - kSYS_execve = 59, - kSYS_umask = 60, - kSYS_chroot = 61, - kSYS_msync = 65, - kSYS_vfork = 66, - kSYS_sbrk = 69, - kSYS_sstk = 70, - kSYS_vadvise = 72, - kSYS_munmap = 73, - kSYS_mprotect = 74, - kSYS_madvise = 75, - kSYS_mincore = 78, - kSYS_getgroups = 79, - kSYS_setgroups = 80, - kSYS_getpgrp = 81, - kSYS_setpgid = 82, - kSYS_setitimer = 83, - kSYS_swapon = 85, - kSYS_getitimer = 86, - kSYS_getdtablesize = 89, - kSYS_dup2 = 90, - kSYS_fcntl = 92, - kSYS_select = 93, - kSYS_fsync = 95, - kSYS_setpriority = 96, - kSYS_socket = 97, - kSYS_connect = 98, - kSYS_getpriority = 100, - kSYS_bind = 104, - kSYS_setsockopt = 105, - kSYS_listen = 106, - kSYS_gettimeofday = 116, - kSYS_getrusage = 117, - kSYS_getsockopt = 118, - kSYS_readv = 120, - kSYS_writev = 121, - kSYS_settimeofday = 122, - kSYS_fchown = 123, - kSYS_fchmod = 124, - kSYS_setreuid = 126, - kSYS_setregid = 127, - kSYS_rename = 128, - kSYS_flock = 131, - kSYS_mkfifo = 132, - kSYS_sendto = 133, - kSYS_shutdown = 134, - kSYS_socketpair = 135, - kSYS_mkdir = 136, - kSYS_rmdir = 137, - kSYS_utimes = 138, - kSYS_adjtime = 140, - kSYS_setsid = 147, - kSYS_quotactl = 148, - kSYS_nlm_syscall = 154, - kSYS_nfssvc = 155, - kSYS_freebsd4_statfs = 157, - kSYS_freebsd4_fstatfs = 158, - kSYS_lgetfh = 160, - kSYS_getfh = 161, - kSYS_freebsd4_getdomainname = 162, - kSYS_freebsd4_setdomainname = 163, - kSYS_freebsd4_uname = 164, - kSYS_sysarch = 165, - kSYS_rtprio = 166, - kSYS_semsys = 169, - kSYS_msgsys = 170, - kSYS_shmsys = 171, - kSYS_freebsd6_pread = 173, - kSYS_freebsd6_pwrite = 174, - kSYS_setfib = 175, - kSYS_ntp_adjtime = 176, - kSYS_setgid = 181, - kSYS_setegid = 182, - kSYS_seteuid = 183, - kSYS_stat = 188, - kSYS_fstat = 189, - kSYS_lstat = 190, - kSYS_pathconf = 191, - kSYS_fpathconf = 192, - kSYS_getrlimit = 194, - kSYS_setrlimit = 195, - kSYS_getdirentries = 196, - kSYS_freebsd6_mmap = 197, - kSYS___syscall = 198, - kSYS_freebsd6_lseek = 199, - kSYS_freebsd6_truncate = 200, - kSYS_freebsd6_ftruncate = 201, - kSYS___sysctl = 202, - kSYS_mlock = 203, - kSYS_munlock = 204, - kSYS_undelete = 205, - kSYS_futimes = 206, - kSYS_getpgid = 207, - kSYS_poll = 209, - kSYS_freebsd7___semctl = 220, - kSYS_semget = 221, - kSYS_semop = 222, - kSYS_freebsd7_msgctl = 224, - kSYS_msgget = 225, - kSYS_msgsnd = 226, - kSYS_msgrcv = 227, - kSYS_shmat = 228, - kSYS_freebsd7_shmctl = 229, - kSYS_shmdt = 230, - kSYS_shmget = 231, - kSYS_clock_gettime = 232, - kSYS_clock_settime = 233, - kSYS_clock_getres = 234, - kSYS_ktimer_create = 235, - kSYS_ktimer_delete = 236, - kSYS_ktimer_settime = 237, - kSYS_ktimer_gettime = 238, - kSYS_ktimer_getoverrun = 239, - kSYS_nanosleep = 240, - kSYS_ffclock_getcounter = 241, - kSYS_ffclock_setestimate = 242, - kSYS_ffclock_getestimate = 243, - kSYS_clock_getcpuclockid2 = 247, - kSYS_ntp_gettime = 248, - kSYS_minherit = 250, - kSYS_rfork = 251, - kSYS_openbsd_poll = 252, - kSYS_issetugid = 253, - kSYS_lchown = 254, - kSYS_aio_read = 255, - kSYS_aio_write = 256, - kSYS_lio_listio = 257, - kSYS_getdents = 272, - kSYS_lchmod = 274, - kSYS_netbsd_lchown = 275, - kSYS_lutimes = 276, - kSYS_netbsd_msync = 277, - kSYS_nstat = 278, - kSYS_nfstat = 279, - kSYS_nlstat = 280, - kSYS_preadv = 289, - kSYS_pwritev = 290, - kSYS_freebsd4_fhstatfs = 297, - kSYS_fhopen = 298, - kSYS_fhstat = 299, - kSYS_modnext = 300, - kSYS_modstat = 301, - kSYS_modfnext = 302, - kSYS_modfind = 303, - kSYS_kldload = 304, - kSYS_kldunload = 305, - kSYS_kldfind = 306, - kSYS_kldnext = 307, - kSYS_kldstat = 308, - kSYS_kldfirstmod = 309, - kSYS_getsid = 310, - kSYS_setresuid = 311, - kSYS_setresgid = 312, - kSYS_aio_return = 314, - kSYS_aio_suspend = 315, - kSYS_aio_cancel = 316, - kSYS_aio_error = 317, - kSYS_oaio_read = 318, - kSYS_oaio_write = 319, - kSYS_olio_listio = 320, - kSYS_yield = 321, - kSYS_mlockall = 324, - kSYS_munlockall = 325, - kSYS___getcwd = 326, - kSYS_sched_setparam = 327, - kSYS_sched_getparam = 328, - kSYS_sched_setscheduler = 329, - kSYS_sched_getscheduler = 330, - kSYS_sched_yield = 331, - kSYS_sched_get_priority_max = 332, - kSYS_sched_get_priority_min = 333, - kSYS_sched_rr_get_interval = 334, - kSYS_utrace = 335, - kSYS_freebsd4_sendfile = 336, - kSYS_kldsym = 337, - kSYS_jail = 338, - kSYS_nnpfs_syscall = 339, - kSYS_sigprocmask = 340, - kSYS_sigsuspend = 341, - kSYS_freebsd4_sigaction = 342, - kSYS_sigpending = 343, - kSYS_freebsd4_sigreturn = 344, - kSYS_sigtimedwait = 345, - kSYS_sigwaitinfo = 346, - kSYS___acl_get_file = 347, - kSYS___acl_set_file = 348, - kSYS___acl_get_fd = 349, - kSYS___acl_set_fd = 350, - kSYS___acl_delete_file = 351, - kSYS___acl_delete_fd = 352, - kSYS___acl_aclcheck_file = 353, - kSYS___acl_aclcheck_fd = 354, - kSYS_extattrctl = 355, - kSYS_extattr_set_file = 356, - kSYS_extattr_get_file = 357, - kSYS_extattr_delete_file = 358, - kSYS_aio_waitcomplete = 359, - kSYS_getresuid = 360, - kSYS_getresgid = 361, - kSYS_kqueue = 362, - kSYS_kevent = 363, - kSYS_extattr_set_fd = 371, - kSYS_extattr_get_fd = 372, - kSYS_extattr_delete_fd = 373, - kSYS___setugid = 374, - kSYS_eaccess = 376, - kSYS_afs3_syscall = 377, - kSYS_nmount = 378, - kSYS___mac_get_proc = 384, - kSYS___mac_set_proc = 385, - kSYS___mac_get_fd = 386, - kSYS___mac_get_file = 387, - kSYS___mac_set_fd = 388, - kSYS___mac_set_file = 389, - kSYS_kenv = 390, - kSYS_lchflags = 391, - kSYS_uuidgen = 392, - kSYS_sendfile = 393, - kSYS_mac_syscall = 394, - kSYS_getfsstat = 395, - kSYS_statfs = 396, - kSYS_fstatfs = 397, - kSYS_fhstatfs = 398, - kSYS_ksem_close = 400, - kSYS_ksem_post = 401, - kSYS_ksem_wait = 402, - kSYS_ksem_trywait = 403, - kSYS_ksem_init = 404, - kSYS_ksem_open = 405, - kSYS_ksem_unlink = 406, - kSYS_ksem_getvalue = 407, - kSYS_ksem_destroy = 408, - kSYS___mac_get_pid = 409, - kSYS___mac_get_link = 410, - kSYS___mac_set_link = 411, - kSYS_extattr_set_link = 412, - kSYS_extattr_get_link = 413, - kSYS_extattr_delete_link = 414, - kSYS___mac_execve = 415, - kSYS_sigaction = 416, - kSYS_sigreturn = 417, - kSYS_getcontext = 421, - kSYS_setcontext = 422, - kSYS_swapcontext = 423, - kSYS_swapoff = 424, - kSYS___acl_get_link = 425, - kSYS___acl_set_link = 426, - kSYS___acl_delete_link = 427, - kSYS___acl_aclcheck_link = 428, - kSYS_sigwait = 429, - kSYS_thr_create = 430, - kSYS_thr_exit = 431, - kSYS_thr_self = 432, - kSYS_thr_kill = 433, - kSYS__umtx_lock = 434, - kSYS__umtx_unlock = 435, - kSYS_jail_attach = 436, - kSYS_extattr_list_fd = 437, - kSYS_extattr_list_file = 438, - kSYS_extattr_list_link = 439, - kSYS_ksem_timedwait = 441, - kSYS_thr_suspend = 442, - kSYS_thr_wake = 443, - kSYS_kldunloadf = 444, - kSYS_audit = 445, - kSYS_auditon = 446, - kSYS_getauid = 447, - kSYS_setauid = 448, - kSYS_getaudit = 449, - kSYS_setaudit = 450, - kSYS_getaudit_addr = 451, - kSYS_setaudit_addr = 452, - kSYS_auditctl = 453, - kSYS__umtx_op = 454, - kSYS_thr_new = 455, - kSYS_sigqueue = 456, - kSYS_kmq_open = 457, - kSYS_kmq_setattr = 458, - kSYS_kmq_timedreceive = 459, - kSYS_kmq_timedsend = 460, - kSYS_kmq_notify = 461, - kSYS_kmq_unlink = 462, - kSYS_abort2 = 463, - kSYS_thr_set_name = 464, - kSYS_aio_fsync = 465, - kSYS_rtprio_thread = 466, - kSYS_sctp_peeloff = 471, - kSYS_sctp_generic_sendmsg = 472, - kSYS_sctp_generic_sendmsg_iov = 473, - kSYS_sctp_generic_recvmsg = 474, - kSYS_pread = 475, - kSYS_pwrite = 476, - kSYS_mmap = 477, - kSYS_lseek = 478, - kSYS_truncate = 479, - kSYS_ftruncate = 480, - kSYS_thr_kill2 = 481, - kSYS_shm_open = 482, - kSYS_shm_unlink = 483, - kSYS_cpuset = 484, - kSYS_cpuset_setid = 485, - kSYS_cpuset_getid = 486, - kSYS_cpuset_getaffinity = 487, - kSYS_cpuset_setaffinity = 488, - kSYS_faccessat = 489, - kSYS_fchmodat = 490, - kSYS_fchownat = 491, - kSYS_fexecve = 492, - kSYS_fstatat = 493, - kSYS_futimesat = 494, - kSYS_linkat = 495, - kSYS_mkdirat = 496, - kSYS_mkfifoat = 497, - kSYS_mknodat = 498, - kSYS_openat = 499, - kSYS_readlinkat = 500, - kSYS_renameat = 501, - kSYS_symlinkat = 502, - kSYS_unlinkat = 503, - kSYS_posix_openpt = 504, - kSYS_gssd_syscall = 505, - kSYS_jail_get = 506, - kSYS_jail_set = 507, - kSYS_jail_remove = 508, - kSYS_closefrom = 509, - kSYS___semctl = 510, - kSYS_msgctl = 511, - kSYS_shmctl = 512, - kSYS_lpathconf = 513, - kSYS_cap_new = 514, - kSYS_cap_getrights = 515, - kSYS_cap_enter = 516, - kSYS_cap_getmode = 517, - kSYS_pdfork = 518, - kSYS_pdkill = 519, - kSYS_pdgetpid = 520, - kSYS_pselect = 522, - kSYS_getloginclass = 523, - kSYS_setloginclass = 524, - kSYS_rctl_get_racct = 525, - kSYS_rctl_get_rules = 526, - kSYS_rctl_get_limits = 527, - kSYS_rctl_add_rule = 528, - kSYS_rctl_remove_rule = 529, - kSYS_posix_fallocate = 530, - kSYS_posix_fadvise = 531, +namespace orbis +{ + enum Syscall + { + kSYS_syscall = 0, + kSYS_exit = 1, + kSYS_fork = 2, + kSYS_read = 3, + kSYS_write = 4, + kSYS_open = 5, + kSYS_close = 6, + kSYS_wait4 = 7, + kSYS_link = 9, + kSYS_unlink = 10, + kSYS_chdir = 12, + kSYS_fchdir = 13, + kSYS_mknod = 14, + kSYS_chmod = 15, + kSYS_chown = 16, + kSYS_break = 17, + kSYS_freebsd4_getfsstat = 18, + kSYS_getpid = 20, + kSYS_mount = 21, + kSYS_unmount = 22, + kSYS_setuid = 23, + kSYS_getuid = 24, + kSYS_geteuid = 25, + kSYS_ptrace = 26, + kSYS_recvmsg = 27, + kSYS_sendmsg = 28, + kSYS_recvfrom = 29, + kSYS_accept = 30, + kSYS_getpeername = 31, + kSYS_getsockname = 32, + kSYS_access = 33, + kSYS_chflags = 34, + kSYS_fchflags = 35, + kSYS_sync = 36, + kSYS_kill = 37, + kSYS_getppid = 39, + kSYS_dup = 41, + kSYS_pipe = 42, + kSYS_getegid = 43, + kSYS_profil = 44, + kSYS_ktrace = 45, + kSYS_getgid = 47, + kSYS_getlogin = 49, + kSYS_setlogin = 50, + kSYS_acct = 51, + kSYS_sigaltstack = 53, + kSYS_ioctl = 54, + kSYS_reboot = 55, + kSYS_revoke = 56, + kSYS_symlink = 57, + kSYS_readlink = 58, + kSYS_execve = 59, + kSYS_umask = 60, + kSYS_chroot = 61, + kSYS_msync = 65, + kSYS_vfork = 66, + kSYS_sbrk = 69, + kSYS_sstk = 70, + kSYS_vadvise = 72, + kSYS_munmap = 73, + kSYS_mprotect = 74, + kSYS_madvise = 75, + kSYS_mincore = 78, + kSYS_getgroups = 79, + kSYS_setgroups = 80, + kSYS_getpgrp = 81, + kSYS_setpgid = 82, + kSYS_setitimer = 83, + kSYS_swapon = 85, + kSYS_getitimer = 86, + kSYS_getdtablesize = 89, + kSYS_dup2 = 90, + kSYS_fcntl = 92, + kSYS_select = 93, + kSYS_fsync = 95, + kSYS_setpriority = 96, + kSYS_socket = 97, + kSYS_connect = 98, + kSYS_getpriority = 100, + kSYS_bind = 104, + kSYS_setsockopt = 105, + kSYS_listen = 106, + kSYS_gettimeofday = 116, + kSYS_getrusage = 117, + kSYS_getsockopt = 118, + kSYS_readv = 120, + kSYS_writev = 121, + kSYS_settimeofday = 122, + kSYS_fchown = 123, + kSYS_fchmod = 124, + kSYS_setreuid = 126, + kSYS_setregid = 127, + kSYS_rename = 128, + kSYS_flock = 131, + kSYS_mkfifo = 132, + kSYS_sendto = 133, + kSYS_shutdown = 134, + kSYS_socketpair = 135, + kSYS_mkdir = 136, + kSYS_rmdir = 137, + kSYS_utimes = 138, + kSYS_adjtime = 140, + kSYS_setsid = 147, + kSYS_quotactl = 148, + kSYS_nlm_syscall = 154, + kSYS_nfssvc = 155, + kSYS_freebsd4_statfs = 157, + kSYS_freebsd4_fstatfs = 158, + kSYS_lgetfh = 160, + kSYS_getfh = 161, + kSYS_freebsd4_getdomainname = 162, + kSYS_freebsd4_setdomainname = 163, + kSYS_freebsd4_uname = 164, + kSYS_sysarch = 165, + kSYS_rtprio = 166, + kSYS_semsys = 169, + kSYS_msgsys = 170, + kSYS_shmsys = 171, + kSYS_freebsd6_pread = 173, + kSYS_freebsd6_pwrite = 174, + kSYS_setfib = 175, + kSYS_ntp_adjtime = 176, + kSYS_setgid = 181, + kSYS_setegid = 182, + kSYS_seteuid = 183, + kSYS_stat = 188, + kSYS_fstat = 189, + kSYS_lstat = 190, + kSYS_pathconf = 191, + kSYS_fpathconf = 192, + kSYS_getrlimit = 194, + kSYS_setrlimit = 195, + kSYS_getdirentries = 196, + kSYS_freebsd6_mmap = 197, + kSYS___syscall = 198, + kSYS_freebsd6_lseek = 199, + kSYS_freebsd6_truncate = 200, + kSYS_freebsd6_ftruncate = 201, + kSYS___sysctl = 202, + kSYS_mlock = 203, + kSYS_munlock = 204, + kSYS_undelete = 205, + kSYS_futimes = 206, + kSYS_getpgid = 207, + kSYS_poll = 209, + kSYS_freebsd7___semctl = 220, + kSYS_semget = 221, + kSYS_semop = 222, + kSYS_freebsd7_msgctl = 224, + kSYS_msgget = 225, + kSYS_msgsnd = 226, + kSYS_msgrcv = 227, + kSYS_shmat = 228, + kSYS_freebsd7_shmctl = 229, + kSYS_shmdt = 230, + kSYS_shmget = 231, + kSYS_clock_gettime = 232, + kSYS_clock_settime = 233, + kSYS_clock_getres = 234, + kSYS_ktimer_create = 235, + kSYS_ktimer_delete = 236, + kSYS_ktimer_settime = 237, + kSYS_ktimer_gettime = 238, + kSYS_ktimer_getoverrun = 239, + kSYS_nanosleep = 240, + kSYS_ffclock_getcounter = 241, + kSYS_ffclock_setestimate = 242, + kSYS_ffclock_getestimate = 243, + kSYS_clock_getcpuclockid2 = 247, + kSYS_ntp_gettime = 248, + kSYS_minherit = 250, + kSYS_rfork = 251, + kSYS_openbsd_poll = 252, + kSYS_issetugid = 253, + kSYS_lchown = 254, + kSYS_aio_read = 255, + kSYS_aio_write = 256, + kSYS_lio_listio = 257, + kSYS_getdents = 272, + kSYS_lchmod = 274, + kSYS_netbsd_lchown = 275, + kSYS_lutimes = 276, + kSYS_netbsd_msync = 277, + kSYS_nstat = 278, + kSYS_nfstat = 279, + kSYS_nlstat = 280, + kSYS_preadv = 289, + kSYS_pwritev = 290, + kSYS_freebsd4_fhstatfs = 297, + kSYS_fhopen = 298, + kSYS_fhstat = 299, + kSYS_modnext = 300, + kSYS_modstat = 301, + kSYS_modfnext = 302, + kSYS_modfind = 303, + kSYS_kldload = 304, + kSYS_kldunload = 305, + kSYS_kldfind = 306, + kSYS_kldnext = 307, + kSYS_kldstat = 308, + kSYS_kldfirstmod = 309, + kSYS_getsid = 310, + kSYS_setresuid = 311, + kSYS_setresgid = 312, + kSYS_aio_return = 314, + kSYS_aio_suspend = 315, + kSYS_aio_cancel = 316, + kSYS_aio_error = 317, + kSYS_oaio_read = 318, + kSYS_oaio_write = 319, + kSYS_olio_listio = 320, + kSYS_yield = 321, + kSYS_mlockall = 324, + kSYS_munlockall = 325, + kSYS___getcwd = 326, + kSYS_sched_setparam = 327, + kSYS_sched_getparam = 328, + kSYS_sched_setscheduler = 329, + kSYS_sched_getscheduler = 330, + kSYS_sched_yield = 331, + kSYS_sched_get_priority_max = 332, + kSYS_sched_get_priority_min = 333, + kSYS_sched_rr_get_interval = 334, + kSYS_utrace = 335, + kSYS_freebsd4_sendfile = 336, + kSYS_kldsym = 337, + kSYS_jail = 338, + kSYS_nnpfs_syscall = 339, + kSYS_sigprocmask = 340, + kSYS_sigsuspend = 341, + kSYS_freebsd4_sigaction = 342, + kSYS_sigpending = 343, + kSYS_freebsd4_sigreturn = 344, + kSYS_sigtimedwait = 345, + kSYS_sigwaitinfo = 346, + kSYS___acl_get_file = 347, + kSYS___acl_set_file = 348, + kSYS___acl_get_fd = 349, + kSYS___acl_set_fd = 350, + kSYS___acl_delete_file = 351, + kSYS___acl_delete_fd = 352, + kSYS___acl_aclcheck_file = 353, + kSYS___acl_aclcheck_fd = 354, + kSYS_extattrctl = 355, + kSYS_extattr_set_file = 356, + kSYS_extattr_get_file = 357, + kSYS_extattr_delete_file = 358, + kSYS_aio_waitcomplete = 359, + kSYS_getresuid = 360, + kSYS_getresgid = 361, + kSYS_kqueue = 362, + kSYS_kevent = 363, + kSYS_extattr_set_fd = 371, + kSYS_extattr_get_fd = 372, + kSYS_extattr_delete_fd = 373, + kSYS___setugid = 374, + kSYS_eaccess = 376, + kSYS_afs3_syscall = 377, + kSYS_nmount = 378, + kSYS___mac_get_proc = 384, + kSYS___mac_set_proc = 385, + kSYS___mac_get_fd = 386, + kSYS___mac_get_file = 387, + kSYS___mac_set_fd = 388, + kSYS___mac_set_file = 389, + kSYS_kenv = 390, + kSYS_lchflags = 391, + kSYS_uuidgen = 392, + kSYS_sendfile = 393, + kSYS_mac_syscall = 394, + kSYS_getfsstat = 395, + kSYS_statfs = 396, + kSYS_fstatfs = 397, + kSYS_fhstatfs = 398, + kSYS_ksem_close = 400, + kSYS_ksem_post = 401, + kSYS_ksem_wait = 402, + kSYS_ksem_trywait = 403, + kSYS_ksem_init = 404, + kSYS_ksem_open = 405, + kSYS_ksem_unlink = 406, + kSYS_ksem_getvalue = 407, + kSYS_ksem_destroy = 408, + kSYS___mac_get_pid = 409, + kSYS___mac_get_link = 410, + kSYS___mac_set_link = 411, + kSYS_extattr_set_link = 412, + kSYS_extattr_get_link = 413, + kSYS_extattr_delete_link = 414, + kSYS___mac_execve = 415, + kSYS_sigaction = 416, + kSYS_sigreturn = 417, + kSYS_getcontext = 421, + kSYS_setcontext = 422, + kSYS_swapcontext = 423, + kSYS_swapoff = 424, + kSYS___acl_get_link = 425, + kSYS___acl_set_link = 426, + kSYS___acl_delete_link = 427, + kSYS___acl_aclcheck_link = 428, + kSYS_sigwait = 429, + kSYS_thr_create = 430, + kSYS_thr_exit = 431, + kSYS_thr_self = 432, + kSYS_thr_kill = 433, + kSYS__umtx_lock = 434, + kSYS__umtx_unlock = 435, + kSYS_jail_attach = 436, + kSYS_extattr_list_fd = 437, + kSYS_extattr_list_file = 438, + kSYS_extattr_list_link = 439, + kSYS_ksem_timedwait = 441, + kSYS_thr_suspend = 442, + kSYS_thr_wake = 443, + kSYS_kldunloadf = 444, + kSYS_audit = 445, + kSYS_auditon = 446, + kSYS_getauid = 447, + kSYS_setauid = 448, + kSYS_getaudit = 449, + kSYS_setaudit = 450, + kSYS_getaudit_addr = 451, + kSYS_setaudit_addr = 452, + kSYS_auditctl = 453, + kSYS__umtx_op = 454, + kSYS_thr_new = 455, + kSYS_sigqueue = 456, + kSYS_kmq_open = 457, + kSYS_kmq_setattr = 458, + kSYS_kmq_timedreceive = 459, + kSYS_kmq_timedsend = 460, + kSYS_kmq_notify = 461, + kSYS_kmq_unlink = 462, + kSYS_abort2 = 463, + kSYS_thr_set_name = 464, + kSYS_aio_fsync = 465, + kSYS_rtprio_thread = 466, + kSYS_sctp_peeloff = 471, + kSYS_sctp_generic_sendmsg = 472, + kSYS_sctp_generic_sendmsg_iov = 473, + kSYS_sctp_generic_recvmsg = 474, + kSYS_pread = 475, + kSYS_pwrite = 476, + kSYS_mmap = 477, + kSYS_lseek = 478, + kSYS_truncate = 479, + kSYS_ftruncate = 480, + kSYS_thr_kill2 = 481, + kSYS_shm_open = 482, + kSYS_shm_unlink = 483, + kSYS_cpuset = 484, + kSYS_cpuset_setid = 485, + kSYS_cpuset_getid = 486, + kSYS_cpuset_getaffinity = 487, + kSYS_cpuset_setaffinity = 488, + kSYS_faccessat = 489, + kSYS_fchmodat = 490, + kSYS_fchownat = 491, + kSYS_fexecve = 492, + kSYS_fstatat = 493, + kSYS_futimesat = 494, + kSYS_linkat = 495, + kSYS_mkdirat = 496, + kSYS_mkfifoat = 497, + kSYS_mknodat = 498, + kSYS_openat = 499, + kSYS_readlinkat = 500, + kSYS_renameat = 501, + kSYS_symlinkat = 502, + kSYS_unlinkat = 503, + kSYS_posix_openpt = 504, + kSYS_gssd_syscall = 505, + kSYS_jail_get = 506, + kSYS_jail_set = 507, + kSYS_jail_remove = 508, + kSYS_closefrom = 509, + kSYS___semctl = 510, + kSYS_msgctl = 511, + kSYS_shmctl = 512, + kSYS_lpathconf = 513, + kSYS_cap_new = 514, + kSYS_cap_getrights = 515, + kSYS_cap_enter = 516, + kSYS_cap_getmode = 517, + kSYS_pdfork = 518, + kSYS_pdkill = 519, + kSYS_pdgetpid = 520, + kSYS_pselect = 522, + kSYS_getloginclass = 523, + kSYS_setloginclass = 524, + kSYS_rctl_get_racct = 525, + kSYS_rctl_get_rules = 526, + kSYS_rctl_get_limits = 527, + kSYS_rctl_add_rule = 528, + kSYS_rctl_remove_rule = 529, + kSYS_posix_fallocate = 530, + kSYS_posix_fadvise = 531, - kSYS_netcontrol = 99, - kSYS_netabort = 101, - kSYS_netgetsockinfo = 102, - kSYS_socketex = 113, - kSYS_socketclose = 114, - kSYS_netgetiflist = 125, - kSYS_kqueueex = 141, - kSYS_mtypeprotect = 379, - kSYS_regmgr_call = 532, - kSYS_jitshm_create = 533, - kSYS_jitshm_alias = 534, - kSYS_dl_get_list = 535, - kSYS_dl_get_info = 536, - kSYS_dl_notify_event = 537, - kSYS_evf_create = 538, - kSYS_evf_delete = 539, - kSYS_evf_open = 540, - kSYS_evf_close = 541, - kSYS_evf_wait = 542, - kSYS_evf_trywait = 543, - kSYS_evf_set = 544, - kSYS_evf_clear = 545, - kSYS_evf_cancel = 546, - kSYS_query_memory_protection = 547, - kSYS_batch_map = 548, - kSYS_osem_create = 549, - kSYS_osem_delete = 550, - kSYS_osem_open = 551, - kSYS_osem_close = 552, - kSYS_osem_wait = 553, - kSYS_osem_trywait = 554, - kSYS_osem_post = 555, - kSYS_osem_cancel = 556, - kSYS_namedobj_create = 557, - kSYS_namedobj_delete = 558, - kSYS_set_vm_container = 559, - kSYS_debug_init = 560, - kSYS_suspend_process = 561, - kSYS_resume_process = 562, - kSYS_opmc_enable = 563, - kSYS_opmc_disable = 564, - kSYS_opmc_set_ctl = 565, - kSYS_opmc_set_ctr = 566, - kSYS_opmc_get_ctr = 567, - kSYS_budget_create = 568, - kSYS_budget_delete = 569, - kSYS_budget_get = 570, - kSYS_budget_set = 571, - kSYS_virtual_query = 572, - kSYS_mdbg_call = 573, - kSYS_obs_sblock_create = 574, - kSYS_obs_sblock_delete = 575, - kSYS_obs_sblock_enter = 576, - kSYS_obs_sblock_exit = 577, - kSYS_obs_sblock_xenter = 578, - kSYS_obs_sblock_xexit = 579, - kSYS_obs_eport_create = 580, - kSYS_obs_eport_delete = 581, - kSYS_obs_eport_trigger = 582, - kSYS_obs_eport_open = 583, - kSYS_obs_eport_close = 584, - kSYS_is_in_sandbox = 585, - kSYS_dmem_container = 586, - kSYS_get_authinfo = 587, - kSYS_mname = 588, - kSYS_dynlib_dlopen = 589, - kSYS_dynlib_dlclose = 590, - kSYS_dynlib_dlsym = 591, - kSYS_dynlib_get_list = 592, - kSYS_dynlib_get_info = 593, - kSYS_dynlib_load_prx = 594, - kSYS_dynlib_unload_prx = 595, - kSYS_dynlib_do_copy_relocations = 596, - kSYS_dynlib_prepare_dlclose = 597, - kSYS_dynlib_get_proc_param = 598, - kSYS_dynlib_process_needed_and_relocate = 599, - kSYS_sandbox_path = 600, - kSYS_mdbg_service = 601, - kSYS_randomized_path = 602, - kSYS_rdup = 603, - kSYS_dl_get_metadata = 604, - kSYS_workaround8849 = 605, - kSYS_is_development_mode = 606, - kSYS_get_self_auth_info = 607, - kSYS_dynlib_get_info_ex = 608, - kSYS_budget_getid = 609, - kSYS_budget_get_ptype = 610, - kSYS_get_paging_stats_of_all_threads = 611, - kSYS_get_proc_type_info = 612, - kSYS_get_resident_count = 613, - kSYS_prepare_to_suspend_process = 614, - kSYS_get_resident_fmem_count = 615, - kSYS_thr_get_name = 616, - kSYS_set_gpo = 617, - kSYS_get_paging_stats_of_all_objects = 618, - kSYS_test_debug_rwmem = 619, - kSYS_free_stack = 620, - kSYS_suspend_system = 621, - kSYS_ipmimgr_call = 622, - kSYS_get_gpo = 623, - kSYS_get_vm_map_timestamp = 624, - kSYS_opmc_set_hw = 625, - kSYS_opmc_get_hw = 626, - kSYS_get_cpu_usage_all = 627, - kSYS_mmap_dmem = 628, - kSYS_physhm_open = 629, - kSYS_physhm_unlink = 630, - kSYS_resume_internal_hdd = 631, - kSYS_thr_suspend_ucontext = 632, - kSYS_thr_resume_ucontext = 633, - kSYS_thr_get_ucontext = 634, - kSYS_thr_set_ucontext = 635, - kSYS_set_timezone_info = 636, - kSYS_set_phys_fmem_limit = 637, - kSYS_utc_to_localtime = 638, - kSYS_localtime_to_utc = 639, - kSYS_set_uevt = 640, - kSYS_get_cpu_usage_proc = 641, - kSYS_get_map_statistics = 642, - kSYS_set_chicken_switches = 643, - kSYS_extend_page_table_pool = 644, - kSYS_extend_page_table_pool2 = 645, - kSYS_get_kernel_mem_statistics = 646, - kSYS_get_sdk_compiled_version = 647, - kSYS_app_state_change = 648, - kSYS_dynlib_get_obj_member = 649, - kSYS_budget_get_ptype_of_budget = 650, - kSYS_prepare_to_resume_process = 651, - kSYS_process_terminate = 652, - kSYS_blockpool_open = 653, - kSYS_blockpool_map = 654, - kSYS_blockpool_unmap = 655, - kSYS_dynlib_get_info_for_libdbg = 656, - kSYS_blockpool_batch = 657, - kSYS_fdatasync = 658, - kSYS_dynlib_get_list2 = 659, - kSYS_dynlib_get_info2 = 660, - kSYS_aio_submit = 661, - kSYS_aio_multi_delete = 662, - kSYS_aio_multi_wait = 663, - kSYS_aio_multi_poll = 664, - kSYS_aio_get_data = 665, - kSYS_aio_multi_cancel = 666, - kSYS_get_bio_usage_all = 667, - kSYS_aio_create = 668, - kSYS_aio_submit_cmd = 669, - kSYS_aio_init = 670, - kSYS_get_page_table_stats = 671, - kSYS_dynlib_get_list_for_libdbg = 672, - kSYS_blockpool_move = 673, - kSYS_virtual_query_all = 674, - kSYS_reserve_2mb_page = 675, - kSYS_cpumode_yield = 676, + kSYS_netcontrol = 99, + kSYS_netabort = 101, + kSYS_netgetsockinfo = 102, + kSYS_socketex = 113, + kSYS_socketclose = 114, + kSYS_netgetiflist = 125, + kSYS_kqueueex = 141, + kSYS_mtypeprotect = 379, + kSYS_regmgr_call = 532, + kSYS_jitshm_create = 533, + kSYS_jitshm_alias = 534, + kSYS_dl_get_list = 535, + kSYS_dl_get_info = 536, + kSYS_dl_notify_event = 537, + kSYS_evf_create = 538, + kSYS_evf_delete = 539, + kSYS_evf_open = 540, + kSYS_evf_close = 541, + kSYS_evf_wait = 542, + kSYS_evf_trywait = 543, + kSYS_evf_set = 544, + kSYS_evf_clear = 545, + kSYS_evf_cancel = 546, + kSYS_query_memory_protection = 547, + kSYS_batch_map = 548, + kSYS_osem_create = 549, + kSYS_osem_delete = 550, + kSYS_osem_open = 551, + kSYS_osem_close = 552, + kSYS_osem_wait = 553, + kSYS_osem_trywait = 554, + kSYS_osem_post = 555, + kSYS_osem_cancel = 556, + kSYS_namedobj_create = 557, + kSYS_namedobj_delete = 558, + kSYS_set_vm_container = 559, + kSYS_debug_init = 560, + kSYS_suspend_process = 561, + kSYS_resume_process = 562, + kSYS_opmc_enable = 563, + kSYS_opmc_disable = 564, + kSYS_opmc_set_ctl = 565, + kSYS_opmc_set_ctr = 566, + kSYS_opmc_get_ctr = 567, + kSYS_budget_create = 568, + kSYS_budget_delete = 569, + kSYS_budget_get = 570, + kSYS_budget_set = 571, + kSYS_virtual_query = 572, + kSYS_mdbg_call = 573, + kSYS_obs_sblock_create = 574, + kSYS_obs_sblock_delete = 575, + kSYS_obs_sblock_enter = 576, + kSYS_obs_sblock_exit = 577, + kSYS_obs_sblock_xenter = 578, + kSYS_obs_sblock_xexit = 579, + kSYS_obs_eport_create = 580, + kSYS_obs_eport_delete = 581, + kSYS_obs_eport_trigger = 582, + kSYS_obs_eport_open = 583, + kSYS_obs_eport_close = 584, + kSYS_is_in_sandbox = 585, + kSYS_dmem_container = 586, + kSYS_get_authinfo = 587, + kSYS_mname = 588, + kSYS_dynlib_dlopen = 589, + kSYS_dynlib_dlclose = 590, + kSYS_dynlib_dlsym = 591, + kSYS_dynlib_get_list = 592, + kSYS_dynlib_get_info = 593, + kSYS_dynlib_load_prx = 594, + kSYS_dynlib_unload_prx = 595, + kSYS_dynlib_do_copy_relocations = 596, + kSYS_dynlib_prepare_dlclose = 597, + kSYS_dynlib_get_proc_param = 598, + kSYS_dynlib_process_needed_and_relocate = 599, + kSYS_sandbox_path = 600, + kSYS_mdbg_service = 601, + kSYS_randomized_path = 602, + kSYS_rdup = 603, + kSYS_dl_get_metadata = 604, + kSYS_workaround8849 = 605, + kSYS_is_development_mode = 606, + kSYS_get_self_auth_info = 607, + kSYS_dynlib_get_info_ex = 608, + kSYS_budget_getid = 609, + kSYS_budget_get_ptype = 610, + kSYS_get_paging_stats_of_all_threads = 611, + kSYS_get_proc_type_info = 612, + kSYS_get_resident_count = 613, + kSYS_prepare_to_suspend_process = 614, + kSYS_get_resident_fmem_count = 615, + kSYS_thr_get_name = 616, + kSYS_set_gpo = 617, + kSYS_get_paging_stats_of_all_objects = 618, + kSYS_test_debug_rwmem = 619, + kSYS_free_stack = 620, + kSYS_suspend_system = 621, + kSYS_ipmimgr_call = 622, + kSYS_get_gpo = 623, + kSYS_get_vm_map_timestamp = 624, + kSYS_opmc_set_hw = 625, + kSYS_opmc_get_hw = 626, + kSYS_get_cpu_usage_all = 627, + kSYS_mmap_dmem = 628, + kSYS_physhm_open = 629, + kSYS_physhm_unlink = 630, + kSYS_resume_internal_hdd = 631, + kSYS_thr_suspend_ucontext = 632, + kSYS_thr_resume_ucontext = 633, + kSYS_thr_get_ucontext = 634, + kSYS_thr_set_ucontext = 635, + kSYS_set_timezone_info = 636, + kSYS_set_phys_fmem_limit = 637, + kSYS_utc_to_localtime = 638, + kSYS_localtime_to_utc = 639, + kSYS_set_uevt = 640, + kSYS_get_cpu_usage_proc = 641, + kSYS_get_map_statistics = 642, + kSYS_set_chicken_switches = 643, + kSYS_extend_page_table_pool = 644, + kSYS_extend_page_table_pool2 = 645, + kSYS_get_kernel_mem_statistics = 646, + kSYS_get_sdk_compiled_version = 647, + kSYS_app_state_change = 648, + kSYS_dynlib_get_obj_member = 649, + kSYS_budget_get_ptype_of_budget = 650, + kSYS_prepare_to_resume_process = 651, + kSYS_process_terminate = 652, + kSYS_blockpool_open = 653, + kSYS_blockpool_map = 654, + kSYS_blockpool_unmap = 655, + kSYS_dynlib_get_info_for_libdbg = 656, + kSYS_blockpool_batch = 657, + kSYS_fdatasync = 658, + kSYS_dynlib_get_list2 = 659, + kSYS_dynlib_get_info2 = 660, + kSYS_aio_submit = 661, + kSYS_aio_multi_delete = 662, + kSYS_aio_multi_wait = 663, + kSYS_aio_multi_poll = 664, + kSYS_aio_get_data = 665, + kSYS_aio_multi_cancel = 666, + kSYS_get_bio_usage_all = 667, + kSYS_aio_create = 668, + kSYS_aio_submit_cmd = 669, + kSYS_aio_init = 670, + kSYS_get_page_table_stats = 671, + kSYS_dynlib_get_list_for_libdbg = 672, + kSYS_blockpool_move = 673, + kSYS_virtual_query_all = 674, + kSYS_reserve_2mb_page = 675, + kSYS_cpumode_yield = 676, - kSYS_wait6 = 677, - kSYS_cap_rights_limit = 678, - kSYS_cap_ioctls_limit = 679, - kSYS_cap_ioctls_get = 680, - kSYS_cap_fcntls_limit = 681, - kSYS_cap_fcntls_get = 682, - kSYS_bindat = 683, - kSYS_connectat = 684, - kSYS_chflagsat = 685, - kSYS_accept4 = 686, - kSYS_pipe2 = 687, - kSYS_aio_mlock = 688, - kSYS_procctl = 689, - kSYS_ppoll = 690, - kSYS_futimens = 691, - kSYS_utimensat = 692, - kSYS_numa_getaffinity = 693, - kSYS_numa_setaffinity = 694, - kSYS_apr_submit = 700, - kSYS_apr_resolve = 701, - kSYS_apr_stat = 702, - kSYS_apr_wait = 703, - kSYS_apr_ctrl = 704, - kSYS_get_phys_page_size = 705, - kSYS_begin_app_mount = 706, - kSYS_end_app_mount = 707, - kSYS_fsc2h_ctrl = 708, - kSYS_streamwrite = 709, - kSYS_app_save = 710, - kSYS_app_restore = 711, - kSYS_saved_app_delete = 712, - kSYS_get_ppr_sdk_compiled_version = 713, - kSYS_notify_app_event = 714, - kSYS_ioreq = 715, - kSYS_openintr = 716, - kSYS_dl_get_info_2 = 717, - kSYS_acinfo_add = 718, - kSYS_acinfo_delete = 719, - kSYS_acinfo_get_all_for_coredump = 720, - kSYS_ampr_ctrl_debug = 721, - kSYS_workspace_ctrl = 722, -}; + kSYS_wait6 = 677, + kSYS_cap_rights_limit = 678, + kSYS_cap_ioctls_limit = 679, + kSYS_cap_ioctls_get = 680, + kSYS_cap_fcntls_limit = 681, + kSYS_cap_fcntls_get = 682, + kSYS_bindat = 683, + kSYS_connectat = 684, + kSYS_chflagsat = 685, + kSYS_accept4 = 686, + kSYS_pipe2 = 687, + kSYS_aio_mlock = 688, + kSYS_procctl = 689, + kSYS_ppoll = 690, + kSYS_futimens = 691, + kSYS_utimensat = 692, + kSYS_numa_getaffinity = 693, + kSYS_numa_setaffinity = 694, + kSYS_apr_submit = 700, + kSYS_apr_resolve = 701, + kSYS_apr_stat = 702, + kSYS_apr_wait = 703, + kSYS_apr_ctrl = 704, + kSYS_get_phys_page_size = 705, + kSYS_begin_app_mount = 706, + kSYS_end_app_mount = 707, + kSYS_fsc2h_ctrl = 708, + kSYS_streamwrite = 709, + kSYS_app_save = 710, + kSYS_app_restore = 711, + kSYS_saved_app_delete = 712, + kSYS_get_ppr_sdk_compiled_version = 713, + kSYS_notify_app_event = 714, + kSYS_ioreq = 715, + kSYS_openintr = 716, + kSYS_dl_get_info_2 = 717, + kSYS_acinfo_add = 718, + kSYS_acinfo_delete = 719, + kSYS_acinfo_get_all_for_coredump = 720, + kSYS_ampr_ctrl_debug = 721, + kSYS_workspace_ctrl = 722, + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/sys/sysentry.hpp b/orbis-kernel/include/orbis/sys/sysentry.hpp index 8858ec7d..37c824f7 100644 --- a/orbis-kernel/include/orbis/sys/sysentry.hpp +++ b/orbis-kernel/include/orbis/sys/sysentry.hpp @@ -3,13 +3,14 @@ #include "orbis-config.hpp" #include "orbis/thread/sysent.hpp" -namespace orbis { -extern sysentvec freebsd9_sysvec; -extern sysentvec freebsd11_sysvec; -extern sysentvec ps4_sysvec; -extern sysentvec ps5_sysvec; +namespace orbis +{ + extern sysentvec freebsd9_sysvec; + extern sysentvec freebsd11_sysvec; + extern sysentvec ps4_sysvec; + extern sysentvec ps5_sysvec; -struct Thread; -void syscall_entry(Thread *thread); -const char *getSysentName(SysResult (*sysent)(Thread *, uint64_t *)); + struct Thread; + void syscall_entry(Thread* thread); + const char* getSysentName(SysResult (*sysent)(Thread*, uint64_t*)); } // namespace orbis diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index 05f4120c..369db91a 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -2,830 +2,831 @@ #include #include -namespace orbis { -using acl_type_t = sint; -using key_t = sint; -using semid_t = uint64_t; -using cpusetid_t = sint; -using cpuwhich_t = sint; -using cpulevel_t = sint; -using SceKernelModule = ModuleHandle; +namespace orbis +{ + using acl_type_t = sint; + using key_t = sint; + using semid_t = uint64_t; + using cpusetid_t = sint; + using cpuwhich_t = sint; + using cpulevel_t = sint; + using SceKernelModule = ModuleHandle; -struct MemoryProtection; -struct ModuleInfo; -struct ModuleInfoEx; -struct KEvent; -struct timespec; -struct Stat; -struct stack_t; -struct IoVec; + struct MemoryProtection; + struct ModuleInfo; + struct ModuleInfoEx; + struct KEvent; + struct timespec; + struct Stat; + struct stack_t; + struct IoVec; -SysResult nosys(Thread *thread); + SysResult nosys(Thread* thread); -SysResult sys_exit(Thread *thread, sint status); -SysResult sys_fork(Thread *thread); -SysResult sys_read(Thread *thread, sint fd, ptr buf, size_t nbyte); -SysResult sys_write(Thread *thread, sint fd, ptr buf, size_t nbyte); -SysResult sys_open(Thread *thread, ptr path, sint flags, sint mode); -SysResult sys_close(Thread *thread, sint fd); -SysResult sys_wait4(Thread *thread, sint pid, ptr status, sint options, - ptr rusage); -SysResult sys_link(Thread *thread, ptr path, ptr link); -SysResult sys_unlink(Thread *thread, ptr path); -SysResult sys_chdir(Thread *thread, ptr path); -SysResult sys_fchdir(Thread *thread, sint fd); -SysResult sys_mknod(Thread *thread, ptr path, sint mode, sint dev); -SysResult sys_chmod(Thread *thread, ptr path, sint mode); -SysResult sys_chown(Thread *thread, ptr path, sint uid, sint gid); -SysResult sys_obreak(Thread *thread, ptr nsize); -SysResult sys_getpid(Thread *thread); -SysResult sys_mount(Thread *thread, ptr type, ptr path, sint flags, - caddr_t data); -SysResult sys_unmount(Thread *thread, ptr path, sint flags); -SysResult sys_setuid(Thread *thread, uid_t uid); -SysResult sys_getuid(Thread *thread); -SysResult sys_geteuid(Thread *thread); -SysResult sys_ptrace(Thread *thread, sint req, pid_t pid, caddr_t addr, - sint data); -SysResult sys_recvmsg(Thread *thread, sint s, ptr msg, - sint flags); -SysResult sys_sendmsg(Thread *thread, sint s, ptr msg, - sint flags); -SysResult sys_recvfrom(Thread *thread, sint s, caddr_t buf, size_t len, - sint flags, ptr from, - ptr fromlenaddr); -SysResult sys_accept(Thread *thread, sint s, ptr from, - ptr fromlenaddr); -SysResult sys_getpeername(Thread *thread, sint fdes, ptr asa, - ptr alen); -SysResult sys_getsockname(Thread *thread, sint fdes, ptr asa, - ptr alen); -SysResult sys_access(Thread *thread, ptr path, sint flags); -SysResult sys_chflags(Thread *thread, ptr path, sint flags); -SysResult sys_fchflags(Thread *thread, sint fd, sint flags); -SysResult sys_sync(Thread *thread); -SysResult sys_kill(Thread *thread, sint pid, sint signum); -SysResult sys_getppid(Thread *thread); -SysResult sys_dup(Thread *thread, uint fd); -SysResult sys_pipe(Thread *thread); -SysResult sys_getegid(Thread *thread); -SysResult sys_profil(Thread *thread, caddr_t samples, size_t size, - size_t offset, uint scale); -SysResult sys_ktrace(Thread *thread, ptr fname, sint ops, sint facs, - sint pit); -SysResult sys_getgid(Thread *thread); -SysResult sys_getlogin(Thread *thread, ptr namebuf, uint namelen); -SysResult sys_setlogin(Thread *thread, ptr namebuf); -SysResult sys_acct(Thread *thread, ptr path); -SysResult sys_sigaltstack(Thread *thread, ptr ss, ptr oss); -SysResult sys_ioctl(Thread *thread, sint fd, ulong com, caddr_t data); -SysResult sys_reboot(Thread *thread, sint opt); -SysResult sys_revoke(Thread *thread, ptr path); -SysResult sys_symlink(Thread *thread, ptr path, ptr link); -SysResult sys_readlink(Thread *thread, ptr path, ptr buf, - size_t count); -SysResult sys_execve(Thread *thread, ptr fname, ptr> argv, - ptr> envv); -SysResult sys_umask(Thread *thread, sint newmask); -SysResult sys_chroot(Thread *thread, ptr path); -SysResult sys_msync(Thread *thread, ptr addr, size_t len, sint flags); -SysResult sys_vfork(Thread *thread); -SysResult sys_sbrk(Thread *thread, sint incr); -SysResult sys_sstk(Thread *thread, sint incr); -SysResult sys_ovadvise(Thread *thread, sint anom); -SysResult sys_munmap(Thread *thread, ptr addr, size_t len); -SysResult sys_mprotect(Thread *thread, ptr addr, size_t len, - sint prot); -SysResult sys_madvise(Thread *thread, ptr addr, size_t len, sint behav); -SysResult sys_mincore(Thread *thread, ptr addr, size_t len, - ptr vec); -SysResult sys_getgroups(Thread *thread, uint gidsetsize, ptr gidset); -SysResult sys_setgroups(Thread *thread, uint gidsetsize, ptr gidset); -SysResult sys_getpgrp(Thread *thread); -SysResult sys_setpgid(Thread *thread, sint pid, sint pgid); -SysResult sys_setitimer(Thread *thread, uint which, ptr itv, - ptr oitv); -SysResult sys_swapon(Thread *thread, ptr name); -SysResult sys_getitimer(Thread *thread, uint which, ptr itv); -SysResult sys_getdtablesize(Thread *thread); -SysResult sys_dup2(Thread *thread, uint from, uint to); -SysResult sys_fcntl(Thread *thread, sint fd, sint cmd, slong arg); -SysResult sys_select(Thread *thread, sint nd, ptr in, - ptr out, ptr ex, - ptr tv); -SysResult sys_fsync(Thread *thread, sint fd); -SysResult sys_setpriority(Thread *thread, sint which, sint who, sint prio); -SysResult sys_socket(Thread *thread, sint domain, sint type, sint protocol); -SysResult sys_connect(Thread *thread, sint s, caddr_t name, sint namelen); -SysResult sys_getpriority(Thread *thread, sint which, sint who); -SysResult sys_bind(Thread *thread, sint s, caddr_t name, sint namelen); -SysResult sys_setsockopt(Thread *thread, sint s, sint level, sint name, - caddr_t val, sint valsize); -SysResult sys_listen(Thread *thread, sint s, sint backlog); -SysResult sys_gettimeofday(Thread *thread, ptr tp, - ptr tzp); -SysResult sys_getrusage(Thread *thread, sint who, ptr rusage); -SysResult sys_getsockopt(Thread *thread, sint s, sint level, sint name, - caddr_t val, ptr avalsize); -SysResult sys_readv(Thread *thread, sint fd, ptr iovp, uint iovcnt); -SysResult sys_writev(Thread *thread, sint fd, ptr iovp, uint iovcnt); -SysResult sys_settimeofday(Thread *thread, ptr tp, - ptr tzp); -SysResult sys_fchown(Thread *thread, sint fd, sint uid, sint gid); -SysResult sys_fchmod(Thread *thread, sint fd, sint mode); -SysResult sys_setreuid(Thread *thread, sint ruid, sint euid); -SysResult sys_setregid(Thread *thread, sint rgid, sint egid); -SysResult sys_rename(Thread *thread, ptr from, ptr to); -SysResult sys_flock(Thread *thread, sint fd, sint how); -SysResult sys_mkfifo(Thread *thread, ptr path, sint mode); -SysResult sys_sendto(Thread *thread, sint s, caddr_t buf, size_t len, - sint flags, caddr_t to, sint tolen); -SysResult sys_shutdown(Thread *thread, sint s, sint how); -SysResult sys_socketpair(Thread *thread, sint domain, sint type, sint protocol, - ptr rsv); -SysResult sys_mkdir(Thread *thread, ptr path, sint mode); -SysResult sys_rmdir(Thread *thread, ptr path); -SysResult sys_utimes(Thread *thread, ptr path, ptr tptr); -SysResult sys_adjtime(Thread *thread, ptr delta, - ptr olddelta); -SysResult sys_setsid(Thread *thread); -SysResult sys_quotactl(Thread *thread, ptr path, sint cmd, sint uid, - caddr_t arg); -SysResult sys_nlm_syscall(Thread *thread, sint debug_level, sint grace_period, - sint addr_count, ptr> addrs); -SysResult sys_nfssvc(Thread *thread, sint flag, caddr_t argp); -SysResult sys_lgetfh(Thread *thread, ptr fname, ptr fhp); -SysResult sys_getfh(Thread *thread, ptr fname, ptr fhp); -SysResult sys_sysarch(Thread *thread, sint op, ptr parms); -SysResult sys_rtprio(Thread *thread, sint function, pid_t pid, - ptr rtp); -SysResult sys_semsys(Thread *thread, sint which, sint a2, sint a3, sint a4, - sint a5); -SysResult sys_msgsys(Thread *thread, sint which, sint a2, sint a3, sint a4, - sint a5, sint a6); -SysResult sys_shmsys(Thread *thread, sint which, sint a2, sint a3, sint a4); -SysResult sys_freebsd6_pread(Thread *thread, sint fd, ptr buf, - size_t nbyte, sint pad, off_t offset); -SysResult sys_freebsd6_pwrite(Thread *thread, sint fd, ptr buf, - size_t nbyte, sint pad, off_t offset); -SysResult sys_setfib(Thread *thread, sint fib); -SysResult sys_ntp_adjtime(Thread *thread, ptr tp); -SysResult sys_setgid(Thread *thread, gid_t gid); -SysResult sys_setegid(Thread *thread, gid_t egid); -SysResult sys_seteuid(Thread *thread, uid_t euid); -SysResult sys_stat(Thread *thread, ptr path, ptr ub); -SysResult sys_fstat(Thread *thread, sint fd, ptr ub); -SysResult sys_lstat(Thread *thread, ptr path, ptr ub); -SysResult sys_pathconf(Thread *thread, ptr path, sint name); -SysResult sys_fpathconf(Thread *thread, sint fd, sint name); -SysResult sys_getrlimit(Thread *thread, uint which, ptr rlp); -SysResult sys_setrlimit(Thread *thread, uint which, ptr rlp); -SysResult sys_getdirentries(Thread *thread, sint fd, ptr buf, uint count, - ptr basep); -SysResult sys_freebsd6_mmap(Thread *thread, caddr_t addr, size_t len, sint prot, - sint flags, sint fd, sint pad, off_t pos); -SysResult sys_freebsd6_lseek(Thread *thread, sint fd, sint pad, off_t offset, - sint whence); -SysResult sys_freebsd6_truncate(Thread *thread, ptr path, sint pad, - off_t length); -SysResult sys_freebsd6_ftruncate(Thread *thread, sint fd, sint pad, - off_t length); -SysResult sys___sysctl(Thread *thread, ptr name, uint namelen, - ptr old, ptr oldenp, ptr new_, - size_t newlen); -SysResult sys_mlock(Thread *thread, ptr addr, size_t len); -SysResult sys_munlock(Thread *thread, ptr addr, size_t len); -SysResult sys_undelete(Thread *thread, ptr path); -SysResult sys_futimes(Thread *thread, sint fd, ptr tptr); -SysResult sys_getpgid(Thread *thread, pid_t pid); -SysResult sys_poll(Thread *thread, ptr fds, uint nfds, - sint timeout); -SysResult sys_semget(Thread *thread, key_t key, sint nsems, sint semflg); -SysResult sys_semop(Thread *thread, sint semid, ptr sops, - size_t nspos); -SysResult sys_msgget(Thread *thread, key_t key, sint msgflg); -SysResult sys_msgsnd(Thread *thread, sint msqid, ptr msgp, - size_t msgsz, sint msgflg); -SysResult sys_msgrcv(Thread *thread, sint msqid, ptr msgp, size_t msgsz, - slong msgtyp, sint msgflg); -SysResult sys_shmat(Thread *thread, sint shmid, ptr shmaddr, - sint shmflg); -SysResult sys_shmdt(Thread *thread, ptr shmaddr); -SysResult sys_shmget(Thread *thread, key_t key, size_t size, sint shmflg); -SysResult sys_clock_gettime(Thread *thread, clockid_t clock_id, - ptr tp); -SysResult sys_clock_settime(Thread *thread, clockid_t clock_id, - ptr tp); -SysResult sys_clock_getres(Thread *thread, clockid_t clock_id, - ptr tp); -SysResult sys_ktimer_create(Thread *thread, clockid_t clock_id, - ptr evp, ptr timerid); -SysResult sys_ktimer_delete(Thread *thread, sint timerid); -SysResult sys_ktimer_settime(Thread *thread, sint timerid, sint flags, - ptr value, - ptr ovalue); -SysResult sys_ktimer_gettime(Thread *thread, sint timerid, - ptr value); -SysResult sys_ktimer_getoverrun(Thread *thread, sint timerid); -SysResult sys_nanosleep(Thread *thread, cptr rqtp, - ptr rmtp); -SysResult sys_ntp_gettime(Thread *thread, ptr ntvp); -SysResult sys_minherit(Thread *thread, ptr addr, size_t len, - sint inherit); -SysResult sys_rfork(Thread *thread, sint flags); -SysResult sys_openbsd_poll(Thread *thread, ptr fds, uint nfds, - sint timeout); -SysResult sys_issetugid(Thread *thread); -SysResult sys_lchown(Thread *thread, ptr path, sint uid, sint gid); -SysResult sys_aio_read(Thread *thread, ptr aiocbp); -SysResult sys_aio_write(Thread *thread, ptr aiocbp); -SysResult sys_lio_listio(Thread *thread, sint mode, - ptr> aiocbp, sint nent, - ptr sig); -SysResult sys_getdents(Thread *thread, sint fd, ptr buf, size_t count); -SysResult sys_lchmod(Thread *thread, ptr path, mode_t mode); -SysResult sys_lutimes(Thread *thread, ptr path, ptr tptr); -SysResult sys_nstat(Thread *thread, ptr path, ptr ub); -SysResult sys_nfstat(Thread *thread, sint fd, ptr sb); -SysResult sys_nlstat(Thread *thread, ptr path, ptr ub); -SysResult sys_preadv(Thread *thread, sint fd, ptr iovp, uint iovcnt, - off_t offset); -SysResult sys_pwritev(Thread *thread, sint fd, ptr iovp, uint iovcnt, - off_t offset); -SysResult sys_fhopen(Thread *thread, ptr u_fhp, - sint flags); -SysResult sys_fhstat(Thread *thread, ptr u_fhp, - ptr sb); -SysResult sys_modnext(Thread *thread, sint modid); -SysResult sys_modstat(Thread *thread, sint modid, ptr stat); -SysResult sys_modfnext(Thread *thread, sint modid); -SysResult sys_modfind(Thread *thread, ptr name); -SysResult sys_kldload(Thread *thread, ptr file); -SysResult sys_kldunload(Thread *thread, sint fileid); -SysResult sys_kldfind(Thread *thread, ptr name); -SysResult sys_kldnext(Thread *thread, sint fileid); -SysResult sys_kldstat(Thread *thread, sint fileid, - ptr stat); -SysResult sys_kldfirstmod(Thread *thread, sint fileid); -SysResult sys_getsid(Thread *thread, pid_t pid); -SysResult sys_setresuid(Thread *thread, uid_t ruid, uid_t euid, uid_t suid); -SysResult sys_setresgid(Thread *thread, gid_t rgid, gid_t egid, gid_t sgid); -SysResult sys_aio_return(Thread *thread, ptr aiocbp); -SysResult sys_aio_suspend(Thread *thread, ptr aiocbp, sint nent, - ptr timeout); -SysResult sys_aio_cancel(Thread *thread, sint fd, ptr aiocbp); -SysResult sys_aio_error(Thread *thread, ptr aiocbp); -SysResult sys_oaio_read(Thread *thread, ptr aiocbp); -SysResult sys_oaio_write(Thread *thread, ptr aiocbp); -SysResult sys_olio_listio(Thread *thread, sint mode, - ptr> acb_list, sint nent, - ptr sig); -SysResult sys_yield(Thread *thread); -SysResult sys_mlockall(Thread *thread, sint how); -SysResult sys_munlockall(Thread *thread); -SysResult sys___getcwd(Thread *thread, ptr buf, uint buflen); -SysResult sys_sched_setparam(Thread *thread, pid_t pid, - ptr param); -SysResult sys_sched_getparam(Thread *thread, pid_t pid, - ptr param); -SysResult sys_sched_setscheduler(Thread *thread, pid_t pid, sint policy, - ptr param); -SysResult sys_sched_getscheduler(Thread *thread, pid_t pid); -SysResult sys_sched_yield(Thread *thread); -SysResult sys_sched_get_priority_max(Thread *thread, sint policy); -SysResult sys_sched_get_priority_min(Thread *thread, sint policy); -SysResult sys_sched_rr_get_interval(Thread *thread, pid_t pid, - ptr interval); -SysResult sys_utrace(Thread *thread, ptr addr, size_t len); -SysResult sys_kldsym(Thread *thread, sint fileid, sint cmd, ptr data); -SysResult sys_jail(Thread *thread, ptr jail); -SysResult sys_nnpfs_syscall(Thread *thread, sint operation, ptr a_pathP, - sint opcode, ptr a_paramsP, - sint a_followSymlinks); -SysResult sys_sigprocmask(Thread *thread, sint how, ptr set, - ptr oset); -SysResult sys_sigsuspend(Thread *thread, ptr set); -SysResult sys_sigpending(Thread *thread, ptr set); -SysResult sys_sigtimedwait(Thread *thread, ptr set, - ptr info, - ptr timeout); -SysResult sys_sigwaitinfo(Thread *thread, ptr set, - ptr info); -SysResult sys___acl_get_file(Thread *thread, ptr path, acl_type_t type, - ptr aclp); -SysResult sys___acl_set_file(Thread *thread, ptr path, acl_type_t type, - ptr aclp); -SysResult sys___acl_get_fd(Thread *thread, sint filedes, acl_type_t type, - ptr aclp); -SysResult sys___acl_set_fd(Thread *thread, sint filedes, acl_type_t type, - ptr aclp); -SysResult sys___acl_delete_file(Thread *thread, ptr path, - acl_type_t type); -SysResult sys___acl_delete_fd(Thread *thread, sint filedes, acl_type_t type); -SysResult sys___acl_aclcheck_file(Thread *thread, ptr path, - acl_type_t type, ptr aclp); -SysResult sys___acl_aclcheck_fd(Thread *thread, sint filedes, acl_type_t type, - ptr aclp); -SysResult sys_extattrctl(Thread *thread, ptr path, char cmd, - ptr filename, sint attrnamespace, - ptr attrname); -SysResult sys_extattr_set_file(Thread *thread, ptr path, - sint attrnamespace, ptr filename, - ptr data, size_t nbytes); -SysResult sys_extattr_get_file(Thread *thread, ptr path, - sint attrnamespace, ptr filename, - ptr data, size_t nbytes); -SysResult sys_extattr_delete_file(Thread *thread, ptr path, - sint attrnamespace, ptr attrname); -SysResult sys_aio_waitcomplete(Thread *thread, ptr> aiocbp, - ptr timeout); -SysResult sys_getresuid(Thread *thread, ptr ruid, ptr euid, - ptr suid); -SysResult sys_getresgid(Thread *thread, ptr rgid, ptr egid, - ptr sgid); -SysResult sys_kqueue(Thread *thread); -SysResult sys_kevent(Thread *thread, sint fd, ptr changelist, - sint nchanges, ptr eventlist, sint nevents, - ptr timeout); -SysResult sys_extattr_set_fd(Thread *thread, sint fd, sint attrnamespace, - ptr attrname, ptr data, - size_t nbytes); -SysResult sys_extattr_get_fd(Thread *thread, sint fd, sint attrnamespace, - ptr attrname, ptr data, - size_t nbytes); -SysResult sys_extattr_delete_fd(Thread *thread, sint fd, sint attrnamespace, - ptr attrname); -SysResult sys___setugid(Thread *thread, sint flags); -SysResult sys_eaccess(Thread *thread, ptr path, sint flags); -SysResult sys_afs3_syscall(Thread *thread, slong syscall, slong param1, - slong param2, slong param3, slong param4, - slong param5, slong param6); -SysResult sys_nmount(Thread *thread, ptr iovp, uint iovcnt, sint flags); -SysResult sys___mac_get_proc(Thread *thread, ptr mac_p); -SysResult sys___mac_set_proc(Thread *thread, ptr mac_p); -SysResult sys___mac_get_fd(Thread *thread, sint fd, ptr mac_p); -SysResult sys___mac_get_file(Thread *thread, ptr path, - ptr mac_p); -SysResult sys___mac_set_fd(Thread *thread, sint fd, ptr mac_p); -SysResult sys___mac_set_file(Thread *thread, ptr path, - ptr mac_p); -SysResult sys_kenv(Thread *thread, sint what, ptr name, - ptr value, sint len); -SysResult sys_lchflags(Thread *thread, ptr path, sint flags); -SysResult sys_uuidgen(Thread *thread, ptr store, sint count); -SysResult sys_sendfile(Thread *thread, sint fd, sint s, off_t offset, - size_t nbytes, ptr hdtr, - ptr sbytes, sint flags); -SysResult sys_mac_syscall(Thread *thread, ptr policy, sint call, - ptr arg); -SysResult sys_getfsstat(Thread *thread, ptr buf, slong bufsize, - sint flags); -SysResult sys_statfs(Thread *thread, ptr path, ptr buf); -SysResult sys_fstatfs(Thread *thread, sint fd, ptr buf); -SysResult sys_fhstatfs(Thread *thread, ptr u_fhp, - ptr buf); -SysResult sys_ksem_close(Thread *thread, semid_t id); -SysResult sys_ksem_post(Thread *thread, semid_t id); -SysResult sys_ksem_wait(Thread *thread, semid_t id); -SysResult sys_ksem_trywait(Thread *thread, semid_t id); -SysResult sys_ksem_init(Thread *thread, ptr idp, uint value); -SysResult sys_ksem_open(Thread *thread, ptr idp, ptr name, - sint oflag, mode_t mode, uint value); -SysResult sys_ksem_unlink(Thread *thread, ptr name); -SysResult sys_ksem_getvalue(Thread *thread, semid_t id, ptr value); -SysResult sys_ksem_destroy(Thread *thread, semid_t id); -SysResult sys___mac_get_pid(Thread *thread, pid_t pid, ptr mac_p); -SysResult sys___mac_get_link(Thread *thread, ptr path_p, - ptr mac_p); -SysResult sys___mac_set_link(Thread *thread, ptr path_p, - ptr mac_p); -SysResult sys_extattr_set_link(Thread *thread, ptr path, - sint attrnamespace, ptr attrname, - ptr data, size_t nbytes); -SysResult sys_extattr_get_link(Thread *thread, ptr path, - sint attrnamespace, ptr attrname, - ptr data, size_t nbytes); -SysResult sys_extattr_delete_link(Thread *thread, ptr path, - sint attrnamespace, ptr attrname); -SysResult sys___mac_execve(Thread *thread, ptr fname, ptr> argv, - ptr> envv, ptr mac_p); -SysResult sys_sigaction(Thread *thread, sint sig, ptr act, - ptr oact); -SysResult sys_sigreturn(Thread *thread, ptr sigcntxp); -SysResult sys_getcontext(Thread *thread, ptr ucp); -SysResult sys_setcontext(Thread *thread, ptr ucp); -SysResult sys_swapcontext(Thread *thread, ptr oucp, - ptr ucp); -SysResult sys_swapoff(Thread *thread, ptr name); -SysResult sys___acl_get_link(Thread *thread, ptr path, - acl_type_t type, ptr aclp); -SysResult sys___acl_set_link(Thread *thread, ptr path, - acl_type_t type, ptr aclp); -SysResult sys___acl_delete_link(Thread *thread, ptr path, - acl_type_t type); -SysResult sys___acl_aclcheck_link(Thread *thread, ptr path, - acl_type_t type, ptr aclp); -SysResult sys_sigwait(Thread *thread, ptr set, - ptr sig); -SysResult sys_thr_create(Thread *thread, ptr ctxt, - ptr arg, sint flags); -SysResult sys_thr_exit(Thread *thread, ptr state); -SysResult sys_thr_self(Thread *thread, ptr id); -SysResult sys_thr_kill(Thread *thread, slong id, sint sig); -SysResult sys__umtx_lock(Thread *thread, ptr umtx); -SysResult sys__umtx_unlock(Thread *thread, ptr umtx); -SysResult sys_jail_attach(Thread *thread, sint jid); -SysResult sys_extattr_list_fd(Thread *thread, sint fd, sint attrnamespace, - ptr data, size_t nbytes); -SysResult sys_extattr_list_file(Thread *thread, ptr path, - sint attrnamespace, ptr data, - size_t nbytes); -SysResult sys_extattr_list_link(Thread *thread, ptr path, - sint attrnamespace, ptr data, - size_t nbytes); -SysResult sys_ksem_timedwait(Thread *thread, semid_t id, - ptr abstime); -SysResult sys_thr_suspend(Thread *thread, ptr timeout); -SysResult sys_thr_wake(Thread *thread, slong id); -SysResult sys_kldunloadf(Thread *thread, slong fileid, sint flags); -SysResult sys_audit(Thread *thread, ptr record, uint length); -SysResult sys_auditon(Thread *thread, sint cmd, ptr data, uint length); -SysResult sys_getauid(Thread *thread, ptr auid); -SysResult sys_setauid(Thread *thread, ptr auid); -SysResult sys_getaudit(Thread *thread, ptr auditinfo); -SysResult sys_setaudit(Thread *thread, ptr auditinfo); -SysResult sys_getaudit_addr(Thread *thread, - ptr auditinfo_addr, - uint length); -SysResult sys_setaudit_addr(Thread *thread, - ptr auditinfo_addr, - uint length); -SysResult sys_auditctl(Thread *thread, ptr path); -SysResult sys__umtx_op(Thread *thread, ptr obj, sint op, ulong val, - ptr uaddr1, ptr uaddr2); -SysResult sys_thr_new(Thread *thread, ptr param, - sint param_size); -SysResult sys_sigqueue(Thread *thread, pid_t pid, sint signum, ptr value); -SysResult sys_kmq_open(Thread *thread, ptr path, sint flags, - mode_t mode, ptr attr); -SysResult sys_kmq_setattr(Thread *thread, sint mqd, - ptr attr, - ptr oattr); -SysResult sys_kmq_timedreceive(Thread *thread, sint mqd, - ptr msg_ptr, size_t msg_len, - ptr msg_prio, - ptr abstimeout); -SysResult sys_kmq_timedsend(Thread *thread, sint mqd, ptr msg_ptr, - size_t msg_len, ptr msg_prio, - ptr abstimeout); -SysResult sys_kmq_notify(Thread *thread, sint mqd, - ptr sigev); -SysResult sys_kmq_unlink(Thread *thread, ptr path); -SysResult sys_abort2(Thread *thread, ptr why, sint narg, - ptr> args); -SysResult sys_thr_set_name(Thread *thread, slong id, ptr name); -SysResult sys_aio_fsync(Thread *thread, sint op, ptr aiocbp); -SysResult sys_rtprio_thread(Thread *thread, sint function, lwpid_t lwpid, - ptr rtp); -SysResult sys_sctp_peeloff(Thread *thread, sint sd, uint32_t name); -SysResult sys_sctp_generic_sendmsg(Thread *thread, sint sd, caddr_t msg, - sint mlen, caddr_t to, __socklen_t tolen, - ptr sinfo, - sint flags); -SysResult sys_sctp_generic_sendmsg_iov(Thread *thread, sint sd, ptr iov, - sint iovlen, caddr_t to, - __socklen_t tolen, - ptr sinfo, - sint flags); -SysResult sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr iov, - sint iovlen, caddr_t from, - __socklen_t fromlen, - ptr sinfo, - sint flags); -SysResult sys_pread(Thread *thread, sint fd, ptr buf, size_t nbyte, - off_t offset); -SysResult sys_pwrite(Thread *thread, sint fd, ptr buf, size_t nbyte, - off_t offset); -SysResult sys_mmap(Thread *thread, caddr_t addr, size_t len, sint prot, - sint flags, sint fd, off_t pos); -SysResult sys_lseek(Thread *thread, sint fd, off_t offset, sint whence); -SysResult sys_truncate(Thread *thread, ptr path, off_t length); -SysResult sys_ftruncate(Thread *thread, sint fd, off_t length); -SysResult sys_thr_kill2(Thread *thread, pid_t pid, slong id, sint sig); -SysResult sys_shm_open(Thread *thread, ptr path, sint flags, - mode_t mode); -SysResult sys_shm_unlink(Thread *thread, ptr path); -SysResult sys_cpuset(Thread *thread, ptr setid); -SysResult sys_cpuset_setid(Thread *thread, cpuwhich_t which, id_t id, - cpusetid_t setid); -SysResult sys_cpuset_getid(Thread *thread, cpulevel_t level, cpuwhich_t which, - id_t id, ptr setid); -SysResult sys_cpuset_getaffinity(Thread *thread, cpulevel_t level, - cpuwhich_t which, id_t id, size_t cpusetsize, - ptr mask); -SysResult sys_cpuset_setaffinity(Thread *thread, cpulevel_t level, - cpuwhich_t which, id_t id, size_t cpusetsize, - ptr mask); -SysResult sys_faccessat(Thread *thread, sint fd, ptr path, sint mode, - sint flag); -SysResult sys_fchmodat(Thread *thread, sint fd, ptr path, mode_t mode, - sint flag); -SysResult sys_fchownat(Thread *thread, sint fd, ptr path, uid_t uid, - gid_t gid, sint flag); -SysResult sys_fexecve(Thread *thread, sint fd, ptr> argv, - ptr> envv); -SysResult sys_fstatat(Thread *thread, sint fd, ptr path, ptr buf, - sint flag); -SysResult sys_futimesat(Thread *thread, sint fd, ptr path, - ptr times); -SysResult sys_linkat(Thread *thread, sint fd1, ptr path1, sint fd2, - ptr path2, sint flag); -SysResult sys_mkdirat(Thread *thread, sint fd, ptr path, mode_t mode); -SysResult sys_mkfifoat(Thread *thread, sint fd, ptr path, mode_t mode); -SysResult sys_mknodat(Thread *thread, sint fd, ptr path, mode_t mode, - dev_t dev); -SysResult sys_openat(Thread *thread, sint fd, ptr path, sint flag, - mode_t mode); -SysResult sys_readlinkat(Thread *thread, sint fd, ptr path, ptr buf, - size_t bufsize); -SysResult sys_renameat(Thread *thread, sint oldfd, ptr old, sint newfd, - ptr new_); -SysResult sys_symlinkat(Thread *thread, ptr path1, sint fd, - ptr path2); -SysResult sys_unlinkat(Thread *thread, sint fd, ptr path, sint flag); -SysResult sys_posix_openpt(Thread *thread, sint flags); -SysResult sys_gssd_syscall(Thread *thread, ptr path); -SysResult sys_jail_get(Thread *thread, ptr iovp, uint iovcnt, - sint flags); -SysResult sys_jail_set(Thread *thread, ptr iovp, uint iovcnt, - sint flags); -SysResult sys_jail_remove(Thread *thread, sint jid); -SysResult sys_closefrom(Thread *thread, sint lowfd); -SysResult sys___semctl(Thread *thread, sint semid, sint semnum, sint cmd, - ptr arg); -SysResult sys_msgctl(Thread *thread, sint msqid, sint cmd, - ptr buf); -SysResult sys_shmctl(Thread *thread, sint shmid, sint cmd, - ptr buf); -SysResult sys_lpathconf(Thread *thread, ptr path, sint name); -SysResult sys_cap_new(Thread *thread, sint fd, uint64_t rights); -SysResult sys_cap_getrights(Thread *thread, sint fd, ptr rights); -SysResult sys_cap_enter(Thread *thread); -SysResult sys_cap_getmode(Thread *thread, ptr modep); -SysResult sys_pdfork(Thread *thread, ptr fdp, sint flags); -SysResult sys_pdkill(Thread *thread, sint fd, sint signum); -SysResult sys_pdgetpid(Thread *thread, sint fd, ptr pidp); -SysResult sys_pselect(Thread *thread, sint nd, ptr in, ptr ou, - ptr ex, ptr ts, - ptr sm); -SysResult sys_getloginclass(Thread *thread, ptr namebuf, size_t namelen); -SysResult sys_setloginclass(Thread *thread, ptr namebuf); -SysResult sys_rctl_get_racct(Thread *thread, ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen); -SysResult sys_rctl_get_rules(Thread *thread, ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen); -SysResult sys_rctl_get_limits(Thread *thread, ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen); -SysResult sys_rctl_add_rule(Thread *thread, ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen); -SysResult sys_rctl_remove_rule(Thread *thread, ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen); -SysResult sys_posix_fallocate(Thread *thread, sint fd, off_t offset, off_t len); -SysResult sys_posix_fadvise(Thread *thread, sint fd, off_t offset, off_t len, - sint advice); + SysResult sys_exit(Thread* thread, sint status); + SysResult sys_fork(Thread* thread); + SysResult sys_read(Thread* thread, sint fd, ptr buf, size_t nbyte); + SysResult sys_write(Thread* thread, sint fd, ptr buf, size_t nbyte); + SysResult sys_open(Thread* thread, ptr path, sint flags, sint mode); + SysResult sys_close(Thread* thread, sint fd); + SysResult sys_wait4(Thread* thread, sint pid, ptr status, sint options, + ptr rusage); + SysResult sys_link(Thread* thread, ptr path, ptr link); + SysResult sys_unlink(Thread* thread, ptr path); + SysResult sys_chdir(Thread* thread, ptr path); + SysResult sys_fchdir(Thread* thread, sint fd); + SysResult sys_mknod(Thread* thread, ptr path, sint mode, sint dev); + SysResult sys_chmod(Thread* thread, ptr path, sint mode); + SysResult sys_chown(Thread* thread, ptr path, sint uid, sint gid); + SysResult sys_obreak(Thread* thread, ptr nsize); + SysResult sys_getpid(Thread* thread); + SysResult sys_mount(Thread* thread, ptr type, ptr path, sint flags, + caddr_t data); + SysResult sys_unmount(Thread* thread, ptr path, sint flags); + SysResult sys_setuid(Thread* thread, uid_t uid); + SysResult sys_getuid(Thread* thread); + SysResult sys_geteuid(Thread* thread); + SysResult sys_ptrace(Thread* thread, sint req, pid_t pid, caddr_t addr, + sint data); + SysResult sys_recvmsg(Thread* thread, sint s, ptr msg, + sint flags); + SysResult sys_sendmsg(Thread* thread, sint s, ptr msg, + sint flags); + SysResult sys_recvfrom(Thread* thread, sint s, caddr_t buf, size_t len, + sint flags, ptr from, + ptr fromlenaddr); + SysResult sys_accept(Thread* thread, sint s, ptr from, + ptr fromlenaddr); + SysResult sys_getpeername(Thread* thread, sint fdes, ptr asa, + ptr alen); + SysResult sys_getsockname(Thread* thread, sint fdes, ptr asa, + ptr alen); + SysResult sys_access(Thread* thread, ptr path, sint flags); + SysResult sys_chflags(Thread* thread, ptr path, sint flags); + SysResult sys_fchflags(Thread* thread, sint fd, sint flags); + SysResult sys_sync(Thread* thread); + SysResult sys_kill(Thread* thread, sint pid, sint signum); + SysResult sys_getppid(Thread* thread); + SysResult sys_dup(Thread* thread, uint fd); + SysResult sys_pipe(Thread* thread); + SysResult sys_getegid(Thread* thread); + SysResult sys_profil(Thread* thread, caddr_t samples, size_t size, + size_t offset, uint scale); + SysResult sys_ktrace(Thread* thread, ptr fname, sint ops, sint facs, + sint pit); + SysResult sys_getgid(Thread* thread); + SysResult sys_getlogin(Thread* thread, ptr namebuf, uint namelen); + SysResult sys_setlogin(Thread* thread, ptr namebuf); + SysResult sys_acct(Thread* thread, ptr path); + SysResult sys_sigaltstack(Thread* thread, ptr ss, ptr oss); + SysResult sys_ioctl(Thread* thread, sint fd, ulong com, caddr_t data); + SysResult sys_reboot(Thread* thread, sint opt); + SysResult sys_revoke(Thread* thread, ptr path); + SysResult sys_symlink(Thread* thread, ptr path, ptr link); + SysResult sys_readlink(Thread* thread, ptr path, ptr buf, + size_t count); + SysResult sys_execve(Thread* thread, ptr fname, ptr> argv, + ptr> envv); + SysResult sys_umask(Thread* thread, sint newmask); + SysResult sys_chroot(Thread* thread, ptr path); + SysResult sys_msync(Thread* thread, ptr addr, size_t len, sint flags); + SysResult sys_vfork(Thread* thread); + SysResult sys_sbrk(Thread* thread, sint incr); + SysResult sys_sstk(Thread* thread, sint incr); + SysResult sys_ovadvise(Thread* thread, sint anom); + SysResult sys_munmap(Thread* thread, ptr addr, size_t len); + SysResult sys_mprotect(Thread* thread, ptr addr, size_t len, + sint prot); + SysResult sys_madvise(Thread* thread, ptr addr, size_t len, sint behav); + SysResult sys_mincore(Thread* thread, ptr addr, size_t len, + ptr vec); + SysResult sys_getgroups(Thread* thread, uint gidsetsize, ptr gidset); + SysResult sys_setgroups(Thread* thread, uint gidsetsize, ptr gidset); + SysResult sys_getpgrp(Thread* thread); + SysResult sys_setpgid(Thread* thread, sint pid, sint pgid); + SysResult sys_setitimer(Thread* thread, uint which, ptr itv, + ptr oitv); + SysResult sys_swapon(Thread* thread, ptr name); + SysResult sys_getitimer(Thread* thread, uint which, ptr itv); + SysResult sys_getdtablesize(Thread* thread); + SysResult sys_dup2(Thread* thread, uint from, uint to); + SysResult sys_fcntl(Thread* thread, sint fd, sint cmd, slong arg); + SysResult sys_select(Thread* thread, sint nd, ptr in, + ptr out, ptr ex, + ptr tv); + SysResult sys_fsync(Thread* thread, sint fd); + SysResult sys_setpriority(Thread* thread, sint which, sint who, sint prio); + SysResult sys_socket(Thread* thread, sint domain, sint type, sint protocol); + SysResult sys_connect(Thread* thread, sint s, caddr_t name, sint namelen); + SysResult sys_getpriority(Thread* thread, sint which, sint who); + SysResult sys_bind(Thread* thread, sint s, caddr_t name, sint namelen); + SysResult sys_setsockopt(Thread* thread, sint s, sint level, sint name, + caddr_t val, sint valsize); + SysResult sys_listen(Thread* thread, sint s, sint backlog); + SysResult sys_gettimeofday(Thread* thread, ptr tp, + ptr tzp); + SysResult sys_getrusage(Thread* thread, sint who, ptr rusage); + SysResult sys_getsockopt(Thread* thread, sint s, sint level, sint name, + caddr_t val, ptr avalsize); + SysResult sys_readv(Thread* thread, sint fd, ptr iovp, uint iovcnt); + SysResult sys_writev(Thread* thread, sint fd, ptr iovp, uint iovcnt); + SysResult sys_settimeofday(Thread* thread, ptr tp, + ptr tzp); + SysResult sys_fchown(Thread* thread, sint fd, sint uid, sint gid); + SysResult sys_fchmod(Thread* thread, sint fd, sint mode); + SysResult sys_setreuid(Thread* thread, sint ruid, sint euid); + SysResult sys_setregid(Thread* thread, sint rgid, sint egid); + SysResult sys_rename(Thread* thread, ptr from, ptr to); + SysResult sys_flock(Thread* thread, sint fd, sint how); + SysResult sys_mkfifo(Thread* thread, ptr path, sint mode); + SysResult sys_sendto(Thread* thread, sint s, caddr_t buf, size_t len, + sint flags, caddr_t to, sint tolen); + SysResult sys_shutdown(Thread* thread, sint s, sint how); + SysResult sys_socketpair(Thread* thread, sint domain, sint type, sint protocol, + ptr rsv); + SysResult sys_mkdir(Thread* thread, ptr path, sint mode); + SysResult sys_rmdir(Thread* thread, ptr path); + SysResult sys_utimes(Thread* thread, ptr path, ptr tptr); + SysResult sys_adjtime(Thread* thread, ptr delta, + ptr olddelta); + SysResult sys_setsid(Thread* thread); + SysResult sys_quotactl(Thread* thread, ptr path, sint cmd, sint uid, + caddr_t arg); + SysResult sys_nlm_syscall(Thread* thread, sint debug_level, sint grace_period, + sint addr_count, ptr> addrs); + SysResult sys_nfssvc(Thread* thread, sint flag, caddr_t argp); + SysResult sys_lgetfh(Thread* thread, ptr fname, ptr fhp); + SysResult sys_getfh(Thread* thread, ptr fname, ptr fhp); + SysResult sys_sysarch(Thread* thread, sint op, ptr parms); + SysResult sys_rtprio(Thread* thread, sint function, pid_t pid, + ptr rtp); + SysResult sys_semsys(Thread* thread, sint which, sint a2, sint a3, sint a4, + sint a5); + SysResult sys_msgsys(Thread* thread, sint which, sint a2, sint a3, sint a4, + sint a5, sint a6); + SysResult sys_shmsys(Thread* thread, sint which, sint a2, sint a3, sint a4); + SysResult sys_freebsd6_pread(Thread* thread, sint fd, ptr buf, + size_t nbyte, sint pad, off_t offset); + SysResult sys_freebsd6_pwrite(Thread* thread, sint fd, ptr buf, + size_t nbyte, sint pad, off_t offset); + SysResult sys_setfib(Thread* thread, sint fib); + SysResult sys_ntp_adjtime(Thread* thread, ptr tp); + SysResult sys_setgid(Thread* thread, gid_t gid); + SysResult sys_setegid(Thread* thread, gid_t egid); + SysResult sys_seteuid(Thread* thread, uid_t euid); + SysResult sys_stat(Thread* thread, ptr path, ptr ub); + SysResult sys_fstat(Thread* thread, sint fd, ptr ub); + SysResult sys_lstat(Thread* thread, ptr path, ptr ub); + SysResult sys_pathconf(Thread* thread, ptr path, sint name); + SysResult sys_fpathconf(Thread* thread, sint fd, sint name); + SysResult sys_getrlimit(Thread* thread, uint which, ptr rlp); + SysResult sys_setrlimit(Thread* thread, uint which, ptr rlp); + SysResult sys_getdirentries(Thread* thread, sint fd, ptr buf, uint count, + ptr basep); + SysResult sys_freebsd6_mmap(Thread* thread, caddr_t addr, size_t len, sint prot, + sint flags, sint fd, sint pad, off_t pos); + SysResult sys_freebsd6_lseek(Thread* thread, sint fd, sint pad, off_t offset, + sint whence); + SysResult sys_freebsd6_truncate(Thread* thread, ptr path, sint pad, + off_t length); + SysResult sys_freebsd6_ftruncate(Thread* thread, sint fd, sint pad, + off_t length); + SysResult sys___sysctl(Thread* thread, ptr name, uint namelen, + ptr old, ptr oldenp, ptr new_, + size_t newlen); + SysResult sys_mlock(Thread* thread, ptr addr, size_t len); + SysResult sys_munlock(Thread* thread, ptr addr, size_t len); + SysResult sys_undelete(Thread* thread, ptr path); + SysResult sys_futimes(Thread* thread, sint fd, ptr tptr); + SysResult sys_getpgid(Thread* thread, pid_t pid); + SysResult sys_poll(Thread* thread, ptr fds, uint nfds, + sint timeout); + SysResult sys_semget(Thread* thread, key_t key, sint nsems, sint semflg); + SysResult sys_semop(Thread* thread, sint semid, ptr sops, + size_t nspos); + SysResult sys_msgget(Thread* thread, key_t key, sint msgflg); + SysResult sys_msgsnd(Thread* thread, sint msqid, ptr msgp, + size_t msgsz, sint msgflg); + SysResult sys_msgrcv(Thread* thread, sint msqid, ptr msgp, size_t msgsz, + slong msgtyp, sint msgflg); + SysResult sys_shmat(Thread* thread, sint shmid, ptr shmaddr, + sint shmflg); + SysResult sys_shmdt(Thread* thread, ptr shmaddr); + SysResult sys_shmget(Thread* thread, key_t key, size_t size, sint shmflg); + SysResult sys_clock_gettime(Thread* thread, clockid_t clock_id, + ptr tp); + SysResult sys_clock_settime(Thread* thread, clockid_t clock_id, + ptr tp); + SysResult sys_clock_getres(Thread* thread, clockid_t clock_id, + ptr tp); + SysResult sys_ktimer_create(Thread* thread, clockid_t clock_id, + ptr evp, ptr timerid); + SysResult sys_ktimer_delete(Thread* thread, sint timerid); + SysResult sys_ktimer_settime(Thread* thread, sint timerid, sint flags, + ptr value, + ptr ovalue); + SysResult sys_ktimer_gettime(Thread* thread, sint timerid, + ptr value); + SysResult sys_ktimer_getoverrun(Thread* thread, sint timerid); + SysResult sys_nanosleep(Thread* thread, cptr rqtp, + ptr rmtp); + SysResult sys_ntp_gettime(Thread* thread, ptr ntvp); + SysResult sys_minherit(Thread* thread, ptr addr, size_t len, + sint inherit); + SysResult sys_rfork(Thread* thread, sint flags); + SysResult sys_openbsd_poll(Thread* thread, ptr fds, uint nfds, + sint timeout); + SysResult sys_issetugid(Thread* thread); + SysResult sys_lchown(Thread* thread, ptr path, sint uid, sint gid); + SysResult sys_aio_read(Thread* thread, ptr aiocbp); + SysResult sys_aio_write(Thread* thread, ptr aiocbp); + SysResult sys_lio_listio(Thread* thread, sint mode, + ptr> aiocbp, sint nent, + ptr sig); + SysResult sys_getdents(Thread* thread, sint fd, ptr buf, size_t count); + SysResult sys_lchmod(Thread* thread, ptr path, mode_t mode); + SysResult sys_lutimes(Thread* thread, ptr path, ptr tptr); + SysResult sys_nstat(Thread* thread, ptr path, ptr ub); + SysResult sys_nfstat(Thread* thread, sint fd, ptr sb); + SysResult sys_nlstat(Thread* thread, ptr path, ptr ub); + SysResult sys_preadv(Thread* thread, sint fd, ptr iovp, uint iovcnt, + off_t offset); + SysResult sys_pwritev(Thread* thread, sint fd, ptr iovp, uint iovcnt, + off_t offset); + SysResult sys_fhopen(Thread* thread, ptr u_fhp, + sint flags); + SysResult sys_fhstat(Thread* thread, ptr u_fhp, + ptr sb); + SysResult sys_modnext(Thread* thread, sint modid); + SysResult sys_modstat(Thread* thread, sint modid, ptr stat); + SysResult sys_modfnext(Thread* thread, sint modid); + SysResult sys_modfind(Thread* thread, ptr name); + SysResult sys_kldload(Thread* thread, ptr file); + SysResult sys_kldunload(Thread* thread, sint fileid); + SysResult sys_kldfind(Thread* thread, ptr name); + SysResult sys_kldnext(Thread* thread, sint fileid); + SysResult sys_kldstat(Thread* thread, sint fileid, + ptr stat); + SysResult sys_kldfirstmod(Thread* thread, sint fileid); + SysResult sys_getsid(Thread* thread, pid_t pid); + SysResult sys_setresuid(Thread* thread, uid_t ruid, uid_t euid, uid_t suid); + SysResult sys_setresgid(Thread* thread, gid_t rgid, gid_t egid, gid_t sgid); + SysResult sys_aio_return(Thread* thread, ptr aiocbp); + SysResult sys_aio_suspend(Thread* thread, ptr aiocbp, sint nent, + ptr timeout); + SysResult sys_aio_cancel(Thread* thread, sint fd, ptr aiocbp); + SysResult sys_aio_error(Thread* thread, ptr aiocbp); + SysResult sys_oaio_read(Thread* thread, ptr aiocbp); + SysResult sys_oaio_write(Thread* thread, ptr aiocbp); + SysResult sys_olio_listio(Thread* thread, sint mode, + ptr> acb_list, sint nent, + ptr sig); + SysResult sys_yield(Thread* thread); + SysResult sys_mlockall(Thread* thread, sint how); + SysResult sys_munlockall(Thread* thread); + SysResult sys___getcwd(Thread* thread, ptr buf, uint buflen); + SysResult sys_sched_setparam(Thread* thread, pid_t pid, + ptr param); + SysResult sys_sched_getparam(Thread* thread, pid_t pid, + ptr param); + SysResult sys_sched_setscheduler(Thread* thread, pid_t pid, sint policy, + ptr param); + SysResult sys_sched_getscheduler(Thread* thread, pid_t pid); + SysResult sys_sched_yield(Thread* thread); + SysResult sys_sched_get_priority_max(Thread* thread, sint policy); + SysResult sys_sched_get_priority_min(Thread* thread, sint policy); + SysResult sys_sched_rr_get_interval(Thread* thread, pid_t pid, + ptr interval); + SysResult sys_utrace(Thread* thread, ptr addr, size_t len); + SysResult sys_kldsym(Thread* thread, sint fileid, sint cmd, ptr data); + SysResult sys_jail(Thread* thread, ptr jail); + SysResult sys_nnpfs_syscall(Thread* thread, sint operation, ptr a_pathP, + sint opcode, ptr a_paramsP, + sint a_followSymlinks); + SysResult sys_sigprocmask(Thread* thread, sint how, ptr set, + ptr oset); + SysResult sys_sigsuspend(Thread* thread, ptr set); + SysResult sys_sigpending(Thread* thread, ptr set); + SysResult sys_sigtimedwait(Thread* thread, ptr set, + ptr info, + ptr timeout); + SysResult sys_sigwaitinfo(Thread* thread, ptr set, + ptr info); + SysResult sys___acl_get_file(Thread* thread, ptr path, acl_type_t type, + ptr aclp); + SysResult sys___acl_set_file(Thread* thread, ptr path, acl_type_t type, + ptr aclp); + SysResult sys___acl_get_fd(Thread* thread, sint filedes, acl_type_t type, + ptr aclp); + SysResult sys___acl_set_fd(Thread* thread, sint filedes, acl_type_t type, + ptr aclp); + SysResult sys___acl_delete_file(Thread* thread, ptr path, + acl_type_t type); + SysResult sys___acl_delete_fd(Thread* thread, sint filedes, acl_type_t type); + SysResult sys___acl_aclcheck_file(Thread* thread, ptr path, + acl_type_t type, ptr aclp); + SysResult sys___acl_aclcheck_fd(Thread* thread, sint filedes, acl_type_t type, + ptr aclp); + SysResult sys_extattrctl(Thread* thread, ptr path, char cmd, + ptr filename, sint attrnamespace, + ptr attrname); + SysResult sys_extattr_set_file(Thread* thread, ptr path, + sint attrnamespace, ptr filename, + ptr data, size_t nbytes); + SysResult sys_extattr_get_file(Thread* thread, ptr path, + sint attrnamespace, ptr filename, + ptr data, size_t nbytes); + SysResult sys_extattr_delete_file(Thread* thread, ptr path, + sint attrnamespace, ptr attrname); + SysResult sys_aio_waitcomplete(Thread* thread, ptr> aiocbp, + ptr timeout); + SysResult sys_getresuid(Thread* thread, ptr ruid, ptr euid, + ptr suid); + SysResult sys_getresgid(Thread* thread, ptr rgid, ptr egid, + ptr sgid); + SysResult sys_kqueue(Thread* thread); + SysResult sys_kevent(Thread* thread, sint fd, ptr changelist, + sint nchanges, ptr eventlist, sint nevents, + ptr timeout); + SysResult sys_extattr_set_fd(Thread* thread, sint fd, sint attrnamespace, + ptr attrname, ptr data, + size_t nbytes); + SysResult sys_extattr_get_fd(Thread* thread, sint fd, sint attrnamespace, + ptr attrname, ptr data, + size_t nbytes); + SysResult sys_extattr_delete_fd(Thread* thread, sint fd, sint attrnamespace, + ptr attrname); + SysResult sys___setugid(Thread* thread, sint flags); + SysResult sys_eaccess(Thread* thread, ptr path, sint flags); + SysResult sys_afs3_syscall(Thread* thread, slong syscall, slong param1, + slong param2, slong param3, slong param4, + slong param5, slong param6); + SysResult sys_nmount(Thread* thread, ptr iovp, uint iovcnt, sint flags); + SysResult sys___mac_get_proc(Thread* thread, ptr mac_p); + SysResult sys___mac_set_proc(Thread* thread, ptr mac_p); + SysResult sys___mac_get_fd(Thread* thread, sint fd, ptr mac_p); + SysResult sys___mac_get_file(Thread* thread, ptr path, + ptr mac_p); + SysResult sys___mac_set_fd(Thread* thread, sint fd, ptr mac_p); + SysResult sys___mac_set_file(Thread* thread, ptr path, + ptr mac_p); + SysResult sys_kenv(Thread* thread, sint what, ptr name, + ptr value, sint len); + SysResult sys_lchflags(Thread* thread, ptr path, sint flags); + SysResult sys_uuidgen(Thread* thread, ptr store, sint count); + SysResult sys_sendfile(Thread* thread, sint fd, sint s, off_t offset, + size_t nbytes, ptr hdtr, + ptr sbytes, sint flags); + SysResult sys_mac_syscall(Thread* thread, ptr policy, sint call, + ptr arg); + SysResult sys_getfsstat(Thread* thread, ptr buf, slong bufsize, + sint flags); + SysResult sys_statfs(Thread* thread, ptr path, ptr buf); + SysResult sys_fstatfs(Thread* thread, sint fd, ptr buf); + SysResult sys_fhstatfs(Thread* thread, ptr u_fhp, + ptr buf); + SysResult sys_ksem_close(Thread* thread, semid_t id); + SysResult sys_ksem_post(Thread* thread, semid_t id); + SysResult sys_ksem_wait(Thread* thread, semid_t id); + SysResult sys_ksem_trywait(Thread* thread, semid_t id); + SysResult sys_ksem_init(Thread* thread, ptr idp, uint value); + SysResult sys_ksem_open(Thread* thread, ptr idp, ptr name, + sint oflag, mode_t mode, uint value); + SysResult sys_ksem_unlink(Thread* thread, ptr name); + SysResult sys_ksem_getvalue(Thread* thread, semid_t id, ptr value); + SysResult sys_ksem_destroy(Thread* thread, semid_t id); + SysResult sys___mac_get_pid(Thread* thread, pid_t pid, ptr mac_p); + SysResult sys___mac_get_link(Thread* thread, ptr path_p, + ptr mac_p); + SysResult sys___mac_set_link(Thread* thread, ptr path_p, + ptr mac_p); + SysResult sys_extattr_set_link(Thread* thread, ptr path, + sint attrnamespace, ptr attrname, + ptr data, size_t nbytes); + SysResult sys_extattr_get_link(Thread* thread, ptr path, + sint attrnamespace, ptr attrname, + ptr data, size_t nbytes); + SysResult sys_extattr_delete_link(Thread* thread, ptr path, + sint attrnamespace, ptr attrname); + SysResult sys___mac_execve(Thread* thread, ptr fname, ptr> argv, + ptr> envv, ptr mac_p); + SysResult sys_sigaction(Thread* thread, sint sig, ptr act, + ptr oact); + SysResult sys_sigreturn(Thread* thread, ptr sigcntxp); + SysResult sys_getcontext(Thread* thread, ptr ucp); + SysResult sys_setcontext(Thread* thread, ptr ucp); + SysResult sys_swapcontext(Thread* thread, ptr oucp, + ptr ucp); + SysResult sys_swapoff(Thread* thread, ptr name); + SysResult sys___acl_get_link(Thread* thread, ptr path, + acl_type_t type, ptr aclp); + SysResult sys___acl_set_link(Thread* thread, ptr path, + acl_type_t type, ptr aclp); + SysResult sys___acl_delete_link(Thread* thread, ptr path, + acl_type_t type); + SysResult sys___acl_aclcheck_link(Thread* thread, ptr path, + acl_type_t type, ptr aclp); + SysResult sys_sigwait(Thread* thread, ptr set, + ptr sig); + SysResult sys_thr_create(Thread* thread, ptr ctxt, + ptr arg, sint flags); + SysResult sys_thr_exit(Thread* thread, ptr state); + SysResult sys_thr_self(Thread* thread, ptr id); + SysResult sys_thr_kill(Thread* thread, slong id, sint sig); + SysResult sys__umtx_lock(Thread* thread, ptr umtx); + SysResult sys__umtx_unlock(Thread* thread, ptr umtx); + SysResult sys_jail_attach(Thread* thread, sint jid); + SysResult sys_extattr_list_fd(Thread* thread, sint fd, sint attrnamespace, + ptr data, size_t nbytes); + SysResult sys_extattr_list_file(Thread* thread, ptr path, + sint attrnamespace, ptr data, + size_t nbytes); + SysResult sys_extattr_list_link(Thread* thread, ptr path, + sint attrnamespace, ptr data, + size_t nbytes); + SysResult sys_ksem_timedwait(Thread* thread, semid_t id, + ptr abstime); + SysResult sys_thr_suspend(Thread* thread, ptr timeout); + SysResult sys_thr_wake(Thread* thread, slong id); + SysResult sys_kldunloadf(Thread* thread, slong fileid, sint flags); + SysResult sys_audit(Thread* thread, ptr record, uint length); + SysResult sys_auditon(Thread* thread, sint cmd, ptr data, uint length); + SysResult sys_getauid(Thread* thread, ptr auid); + SysResult sys_setauid(Thread* thread, ptr auid); + SysResult sys_getaudit(Thread* thread, ptr auditinfo); + SysResult sys_setaudit(Thread* thread, ptr auditinfo); + SysResult sys_getaudit_addr(Thread* thread, + ptr auditinfo_addr, + uint length); + SysResult sys_setaudit_addr(Thread* thread, + ptr auditinfo_addr, + uint length); + SysResult sys_auditctl(Thread* thread, ptr path); + SysResult sys__umtx_op(Thread* thread, ptr obj, sint op, ulong val, + ptr uaddr1, ptr uaddr2); + SysResult sys_thr_new(Thread* thread, ptr param, + sint param_size); + SysResult sys_sigqueue(Thread* thread, pid_t pid, sint signum, ptr value); + SysResult sys_kmq_open(Thread* thread, ptr path, sint flags, + mode_t mode, ptr attr); + SysResult sys_kmq_setattr(Thread* thread, sint mqd, + ptr attr, + ptr oattr); + SysResult sys_kmq_timedreceive(Thread* thread, sint mqd, + ptr msg_ptr, size_t msg_len, + ptr msg_prio, + ptr abstimeout); + SysResult sys_kmq_timedsend(Thread* thread, sint mqd, ptr msg_ptr, + size_t msg_len, ptr msg_prio, + ptr abstimeout); + SysResult sys_kmq_notify(Thread* thread, sint mqd, + ptr sigev); + SysResult sys_kmq_unlink(Thread* thread, ptr path); + SysResult sys_abort2(Thread* thread, ptr why, sint narg, + ptr> args); + SysResult sys_thr_set_name(Thread* thread, slong id, ptr name); + SysResult sys_aio_fsync(Thread* thread, sint op, ptr aiocbp); + SysResult sys_rtprio_thread(Thread* thread, sint function, lwpid_t lwpid, + ptr rtp); + SysResult sys_sctp_peeloff(Thread* thread, sint sd, uint32_t name); + SysResult sys_sctp_generic_sendmsg(Thread* thread, sint sd, caddr_t msg, + sint mlen, caddr_t to, __socklen_t tolen, + ptr sinfo, + sint flags); + SysResult sys_sctp_generic_sendmsg_iov(Thread* thread, sint sd, ptr iov, + sint iovlen, caddr_t to, + __socklen_t tolen, + ptr sinfo, + sint flags); + SysResult sys_sctp_generic_recvmsg(Thread* thread, sint sd, ptr iov, + sint iovlen, caddr_t from, + __socklen_t fromlen, + ptr sinfo, + sint flags); + SysResult sys_pread(Thread* thread, sint fd, ptr buf, size_t nbyte, + off_t offset); + SysResult sys_pwrite(Thread* thread, sint fd, ptr buf, size_t nbyte, + off_t offset); + SysResult sys_mmap(Thread* thread, caddr_t addr, size_t len, sint prot, + sint flags, sint fd, off_t pos); + SysResult sys_lseek(Thread* thread, sint fd, off_t offset, sint whence); + SysResult sys_truncate(Thread* thread, ptr path, off_t length); + SysResult sys_ftruncate(Thread* thread, sint fd, off_t length); + SysResult sys_thr_kill2(Thread* thread, pid_t pid, slong id, sint sig); + SysResult sys_shm_open(Thread* thread, ptr path, sint flags, + mode_t mode); + SysResult sys_shm_unlink(Thread* thread, ptr path); + SysResult sys_cpuset(Thread* thread, ptr setid); + SysResult sys_cpuset_setid(Thread* thread, cpuwhich_t which, id_t id, + cpusetid_t setid); + SysResult sys_cpuset_getid(Thread* thread, cpulevel_t level, cpuwhich_t which, + id_t id, ptr setid); + SysResult sys_cpuset_getaffinity(Thread* thread, cpulevel_t level, + cpuwhich_t which, id_t id, size_t cpusetsize, + ptr mask); + SysResult sys_cpuset_setaffinity(Thread* thread, cpulevel_t level, + cpuwhich_t which, id_t id, size_t cpusetsize, + ptr mask); + SysResult sys_faccessat(Thread* thread, sint fd, ptr path, sint mode, + sint flag); + SysResult sys_fchmodat(Thread* thread, sint fd, ptr path, mode_t mode, + sint flag); + SysResult sys_fchownat(Thread* thread, sint fd, ptr path, uid_t uid, + gid_t gid, sint flag); + SysResult sys_fexecve(Thread* thread, sint fd, ptr> argv, + ptr> envv); + SysResult sys_fstatat(Thread* thread, sint fd, ptr path, ptr buf, + sint flag); + SysResult sys_futimesat(Thread* thread, sint fd, ptr path, + ptr times); + SysResult sys_linkat(Thread* thread, sint fd1, ptr path1, sint fd2, + ptr path2, sint flag); + SysResult sys_mkdirat(Thread* thread, sint fd, ptr path, mode_t mode); + SysResult sys_mkfifoat(Thread* thread, sint fd, ptr path, mode_t mode); + SysResult sys_mknodat(Thread* thread, sint fd, ptr path, mode_t mode, + dev_t dev); + SysResult sys_openat(Thread* thread, sint fd, ptr path, sint flag, + mode_t mode); + SysResult sys_readlinkat(Thread* thread, sint fd, ptr path, ptr buf, + size_t bufsize); + SysResult sys_renameat(Thread* thread, sint oldfd, ptr old, sint newfd, + ptr new_); + SysResult sys_symlinkat(Thread* thread, ptr path1, sint fd, + ptr path2); + SysResult sys_unlinkat(Thread* thread, sint fd, ptr path, sint flag); + SysResult sys_posix_openpt(Thread* thread, sint flags); + SysResult sys_gssd_syscall(Thread* thread, ptr path); + SysResult sys_jail_get(Thread* thread, ptr iovp, uint iovcnt, + sint flags); + SysResult sys_jail_set(Thread* thread, ptr iovp, uint iovcnt, + sint flags); + SysResult sys_jail_remove(Thread* thread, sint jid); + SysResult sys_closefrom(Thread* thread, sint lowfd); + SysResult sys___semctl(Thread* thread, sint semid, sint semnum, sint cmd, + ptr arg); + SysResult sys_msgctl(Thread* thread, sint msqid, sint cmd, + ptr buf); + SysResult sys_shmctl(Thread* thread, sint shmid, sint cmd, + ptr buf); + SysResult sys_lpathconf(Thread* thread, ptr path, sint name); + SysResult sys_cap_new(Thread* thread, sint fd, uint64_t rights); + SysResult sys_cap_getrights(Thread* thread, sint fd, ptr rights); + SysResult sys_cap_enter(Thread* thread); + SysResult sys_cap_getmode(Thread* thread, ptr modep); + SysResult sys_pdfork(Thread* thread, ptr fdp, sint flags); + SysResult sys_pdkill(Thread* thread, sint fd, sint signum); + SysResult sys_pdgetpid(Thread* thread, sint fd, ptr pidp); + SysResult sys_pselect(Thread* thread, sint nd, ptr in, ptr ou, + ptr ex, ptr ts, + ptr sm); + SysResult sys_getloginclass(Thread* thread, ptr namebuf, size_t namelen); + SysResult sys_setloginclass(Thread* thread, ptr namebuf); + SysResult sys_rctl_get_racct(Thread* thread, ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen); + SysResult sys_rctl_get_rules(Thread* thread, ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen); + SysResult sys_rctl_get_limits(Thread* thread, ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen); + SysResult sys_rctl_add_rule(Thread* thread, ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen); + SysResult sys_rctl_remove_rule(Thread* thread, ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen); + SysResult sys_posix_fallocate(Thread* thread, sint fd, off_t offset, off_t len); + SysResult sys_posix_fadvise(Thread* thread, sint fd, off_t offset, off_t len, + sint advice); -SysResult sys_netcontrol(Thread *thread, sint fd, uint op, ptr buf, - uint nbuf); -SysResult sys_netabort(Thread *thread /* TODO */); -SysResult sys_netgetsockinfo(Thread *thread /* TODO */); -SysResult sys_socketex(Thread *thread, ptr name, sint domain, - sint type, sint protocol); -SysResult sys_socketclose(Thread *thread, sint fd); -SysResult sys_netgetiflist(Thread *thread /* TODO */); -SysResult sys_kqueueex(Thread *thread /* TODO */); -SysResult sys_mtypeprotect(Thread *thread /* TODO */); -SysResult sys_regmgr_call(Thread *thread, uint32_t op, uint32_t id, - ptr result, ptr value, uint64_t type); -SysResult sys_jitshm_create(Thread *thread /* TODO */); -SysResult sys_jitshm_alias(Thread *thread /* TODO */); -SysResult sys_dl_get_list(Thread *thread /* TODO */); -SysResult sys_dl_get_info(Thread *thread /* TODO */); -SysResult sys_dl_notify_event(Thread *thread /* TODO */); -SysResult sys_evf_create(Thread *thread, ptr name, sint attrs, - uint64_t initPattern); -SysResult sys_evf_delete(Thread *thread, sint id); -SysResult sys_evf_open(Thread *thread, ptr name); -SysResult sys_evf_close(Thread *thread, sint id); -SysResult sys_evf_wait(Thread *thread, sint id, uint64_t patternSet, - uint64_t mode, ptr pPatternSet, - ptr pTimeout); -SysResult sys_evf_trywait(Thread *thread, sint id, uint64_t patternSet, - uint64_t mode, - ptr pPatternSet); // FIXME: verify args -SysResult sys_evf_set(Thread *thread, sint id, uint64_t value); -SysResult sys_evf_clear(Thread *thread, sint id, uint64_t value); -SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value, - ptr pNumWaitThreads); -SysResult sys_query_memory_protection(Thread *thread, ptr address, - ptr protection); -SysResult sys_batch_map(Thread *thread /* TODO */); -SysResult sys_osem_create(Thread *thread, ptr name, uint attrs, - sint initCount, sint maxCount); -SysResult sys_osem_delete(Thread *thread, sint id); -SysResult sys_osem_open(Thread *thread, ptr name); -SysResult sys_osem_close(Thread *thread, sint id); -SysResult sys_osem_wait(Thread *thread, sint id, sint need, ptr pTimeout); -SysResult sys_osem_trywait(Thread *thread, sint id, sint need); -SysResult sys_osem_post(Thread *thread, sint id, sint count); -SysResult sys_osem_cancel(Thread *thread, sint id, sint set, - ptr pNumWaitThreads); -SysResult sys_namedobj_create(Thread *thread, ptr name, - ptr object, uint16_t type); -SysResult sys_namedobj_delete(Thread *thread, uint id, uint16_t type); -SysResult sys_set_vm_container(Thread *thread /* TODO */); -SysResult sys_debug_init(Thread *thread /* TODO */); -SysResult sys_suspend_process(Thread *thread, pid_t pid); -SysResult sys_resume_process(Thread *thread, pid_t pid); -SysResult sys_opmc_enable(Thread *thread /* TODO */); -SysResult sys_opmc_disable(Thread *thread /* TODO */); -SysResult sys_opmc_set_ctl(Thread *thread /* TODO */); -SysResult sys_opmc_set_ctr(Thread *thread /* TODO */); -SysResult sys_opmc_get_ctr(Thread *thread /* TODO */); -SysResult sys_budget_create(Thread *thread /* TODO */); -SysResult sys_budget_delete(Thread *thread /* TODO */); -SysResult sys_budget_get(Thread *thread /* TODO */); -SysResult sys_budget_set(Thread *thread /* TODO */); -SysResult sys_virtual_query(Thread *thread, ptr addr, uint64_t unk, - ptr info, size_t infosz); -SysResult sys_mdbg_call(Thread *thread /* TODO */); -SysResult sys_obs_sblock_create(Thread *thread /* TODO */); -SysResult sys_obs_sblock_delete(Thread *thread /* TODO */); -SysResult sys_obs_sblock_enter(Thread *thread /* TODO */); -SysResult sys_obs_sblock_exit(Thread *thread /* TODO */); -SysResult sys_obs_sblock_xenter(Thread *thread /* TODO */); -SysResult sys_obs_sblock_xexit(Thread *thread /* TODO */); -SysResult sys_obs_eport_create(Thread *thread /* TODO */); -SysResult sys_obs_eport_delete(Thread *thread /* TODO */); -SysResult sys_obs_eport_trigger(Thread *thread /* TODO */); -SysResult sys_obs_eport_open(Thread *thread /* TODO */); -SysResult sys_obs_eport_close(Thread *thread /* TODO */); -SysResult sys_is_in_sandbox(Thread *thread /* TODO */); -SysResult sys_dmem_container(Thread *thread, uint id); -SysResult sys_get_authinfo(Thread *thread, pid_t pid, ptr info); -SysResult sys_mname(Thread *thread, uint64_t address, uint64_t length, - ptr name); -SysResult sys_dynlib_dlopen(Thread *thread /* TODO */); -SysResult sys_dynlib_dlclose(Thread *thread /* TODO */); -SysResult sys_dynlib_dlsym(Thread *thread, SceKernelModule handle, - ptr symbol, ptr> addrp); -SysResult sys_dynlib_get_list(Thread *thread, ptr pArray, - size_t numArray, ptr pActualNum); -SysResult sys_dynlib_get_info(Thread *thread, SceKernelModule handle, - ptr pInfo); -SysResult sys_dynlib_load_prx(Thread *thread, ptr name, - uint64_t arg1, ptr pHandle, - uint64_t arg3); -SysResult sys_dynlib_unload_prx(Thread *thread, - SceKernelModule handle /* TODO*/); -SysResult sys_dynlib_do_copy_relocations(Thread *thread); -SysResult sys_dynlib_prepare_dlclose(Thread *thread /* TODO */); -SysResult sys_dynlib_get_proc_param(Thread *thread, ptr> procParam, - ptr procParamSize); -SysResult sys_dynlib_process_needed_and_relocate(Thread *thread); -SysResult sys_sandbox_path(Thread *thread /* TODO */); -SysResult sys_mdbg_service(Thread *thread, uint32_t op, ptr arg0, - ptr arg1); -SysResult sys_randomized_path(Thread *thread /* TODO */); -SysResult sys_rdup(Thread *thread /* TODO */); -SysResult sys_dl_get_metadata(Thread *thread /* TODO */); -SysResult sys_workaround8849(Thread *thread /* TODO */); -SysResult sys_is_development_mode(Thread *thread /* TODO */); -SysResult sys_get_self_auth_info(Thread *thread /* TODO */); -SysResult sys_dynlib_get_info_ex(Thread *thread, SceKernelModule handle, - ptr unk, - ptr destModuleInfoEx); -SysResult sys_budget_getid(Thread *thread); -SysResult sys_budget_get_ptype(Thread *thread, sint budgetId); -SysResult sys_get_paging_stats_of_all_threads(Thread *thread /* TODO */); -SysResult sys_get_proc_type_info(Thread *thread, ptr destProcessInfo); -SysResult sys_get_resident_count(Thread *thread, pid_t pid); -SysResult sys_prepare_to_suspend_process(Thread *thread, pid_t pid); -SysResult sys_get_resident_fmem_count(Thread *thread, pid_t pid); -SysResult sys_thr_get_name(Thread *thread, lwpid_t lwpid); -SysResult sys_set_gpo(Thread *thread /* TODO */); -SysResult sys_get_paging_stats_of_all_objects(Thread *thread /* TODO */); -SysResult sys_test_debug_rwmem(Thread *thread /* TODO */); -SysResult sys_free_stack(Thread *thread /* TODO */); -SysResult sys_suspend_system(Thread *thread /* TODO */); -SysResult sys_ipmimgr_call(Thread *thread, uint op, uint kid, ptr result, - ptr params, uint64_t paramsz, uint64_t arg6); -SysResult sys_get_gpo(Thread *thread /* TODO */); -SysResult sys_get_vm_map_timestamp(Thread *thread /* TODO */); -SysResult sys_opmc_set_hw(Thread *thread /* TODO */); -SysResult sys_opmc_get_hw(Thread *thread /* TODO */); -SysResult sys_get_cpu_usage_all(Thread *thread /* TODO */); -SysResult sys_mmap_dmem(Thread *thread, caddr_t addr, size_t len, - sint memoryType, sint prot, sint flags, - off_t directMemoryStart); -SysResult sys_physhm_open(Thread *thread /* TODO */); -SysResult sys_physhm_unlink(Thread *thread /* TODO */); -SysResult sys_resume_internal_hdd(Thread *thread /* TODO */); -SysResult sys_thr_suspend_ucontext(Thread *thread /* TODO */); -SysResult sys_thr_resume_ucontext(Thread *thread /* TODO */); -SysResult sys_thr_get_ucontext(Thread *thread /* TODO */); -SysResult sys_thr_set_ucontext(Thread *thread /* TODO */); -SysResult sys_set_timezone_info(Thread *thread /* TODO */); -SysResult sys_set_phys_fmem_limit(Thread *thread /* TODO */); -SysResult sys_utc_to_localtime(Thread *thread, int64_t time, int64_t *localtime, - orbis::timesec *_sec, int *_dst_sec); -SysResult sys_localtime_to_utc(Thread *thread, int64_t time, uint unk, - int64_t *ptime, orbis::timesec *_sec, - int *_dst_sec); -SysResult sys_set_uevt(Thread *thread /* TODO */); -SysResult sys_get_cpu_usage_proc(Thread *thread /* TODO */); -SysResult sys_get_map_statistics(Thread *thread /* TODO */); -SysResult sys_set_chicken_switches(Thread *thread /* TODO */); -SysResult sys_extend_page_table_pool(Thread *thread); -SysResult sys_extend_page_table_pool2(Thread *thread); -SysResult sys_get_kernel_mem_statistics(Thread *thread /* TODO */); -SysResult sys_get_sdk_compiled_version(Thread *thread /* TODO */); -SysResult sys_app_state_change(Thread *thread /* TODO */); -SysResult sys_dynlib_get_obj_member(Thread *thread, SceKernelModule handle, - uint64_t index, ptr> addrp); -SysResult sys_budget_get_ptype_of_budget(Thread *thread /* TODO */); -SysResult sys_prepare_to_resume_process(Thread *thread /* TODO */); -SysResult sys_process_terminate(Thread *thread /* TODO */); -SysResult sys_blockpool_open(Thread *thread); -SysResult sys_blockpool_map(Thread *thread, caddr_t addr, size_t len, sint prot, - sint flags); -SysResult sys_blockpool_unmap(Thread *thread, caddr_t addr, size_t len, - sint flags); -SysResult sys_dynlib_get_info_for_libdbg(Thread *thread /* TODO */); -SysResult sys_blockpool_batch(Thread *thread /* TODO */); -SysResult sys_fdatasync(Thread *thread /* TODO */); -SysResult sys_dynlib_get_list2(Thread *thread /* TODO */); -SysResult sys_dynlib_get_info2(Thread *thread /* TODO */); -SysResult sys_aio_submit(Thread *thread /* TODO */); -SysResult sys_aio_multi_delete(Thread *thread /* TODO */); -SysResult sys_aio_multi_wait(Thread *thread /* TODO */); -SysResult sys_aio_multi_poll(Thread *thread /* TODO */); -SysResult sys_aio_get_data(Thread *thread /* TODO */); -SysResult sys_aio_multi_cancel(Thread *thread /* TODO */); -SysResult sys_get_bio_usage_all(Thread *thread /* TODO */); -SysResult sys_aio_create(Thread *thread /* TODO */); -SysResult sys_aio_submit_cmd(Thread *thread /* TODO */); -SysResult sys_aio_init(Thread *thread /* TODO */); -SysResult sys_get_page_table_stats(Thread *thread /* TODO */); -SysResult sys_dynlib_get_list_for_libdbg(Thread *thread /* TODO */); -SysResult sys_blockpool_move(Thread *thread /* TODO */); -SysResult sys_virtual_query_all(Thread *thread /* TODO */); -SysResult sys_reserve_2mb_page(Thread *thread /* TODO */); -SysResult sys_cpumode_yield(Thread *thread /* TODO */); + SysResult sys_netcontrol(Thread* thread, sint fd, uint op, ptr buf, + uint nbuf); + SysResult sys_netabort(Thread* thread /* TODO */); + SysResult sys_netgetsockinfo(Thread* thread /* TODO */); + SysResult sys_socketex(Thread* thread, ptr name, sint domain, + sint type, sint protocol); + SysResult sys_socketclose(Thread* thread, sint fd); + SysResult sys_netgetiflist(Thread* thread /* TODO */); + SysResult sys_kqueueex(Thread* thread /* TODO */); + SysResult sys_mtypeprotect(Thread* thread /* TODO */); + SysResult sys_regmgr_call(Thread* thread, uint32_t op, uint32_t id, + ptr result, ptr value, uint64_t type); + SysResult sys_jitshm_create(Thread* thread /* TODO */); + SysResult sys_jitshm_alias(Thread* thread /* TODO */); + SysResult sys_dl_get_list(Thread* thread /* TODO */); + SysResult sys_dl_get_info(Thread* thread /* TODO */); + SysResult sys_dl_notify_event(Thread* thread /* TODO */); + SysResult sys_evf_create(Thread* thread, ptr name, sint attrs, + uint64_t initPattern); + SysResult sys_evf_delete(Thread* thread, sint id); + SysResult sys_evf_open(Thread* thread, ptr name); + SysResult sys_evf_close(Thread* thread, sint id); + SysResult sys_evf_wait(Thread* thread, sint id, uint64_t patternSet, + uint64_t mode, ptr pPatternSet, + ptr pTimeout); + SysResult sys_evf_trywait(Thread* thread, sint id, uint64_t patternSet, + uint64_t mode, + ptr pPatternSet); // FIXME: verify args + SysResult sys_evf_set(Thread* thread, sint id, uint64_t value); + SysResult sys_evf_clear(Thread* thread, sint id, uint64_t value); + SysResult sys_evf_cancel(Thread* thread, sint id, uint64_t value, + ptr pNumWaitThreads); + SysResult sys_query_memory_protection(Thread* thread, ptr address, + ptr protection); + SysResult sys_batch_map(Thread* thread /* TODO */); + SysResult sys_osem_create(Thread* thread, ptr name, uint attrs, + sint initCount, sint maxCount); + SysResult sys_osem_delete(Thread* thread, sint id); + SysResult sys_osem_open(Thread* thread, ptr name); + SysResult sys_osem_close(Thread* thread, sint id); + SysResult sys_osem_wait(Thread* thread, sint id, sint need, ptr pTimeout); + SysResult sys_osem_trywait(Thread* thread, sint id, sint need); + SysResult sys_osem_post(Thread* thread, sint id, sint count); + SysResult sys_osem_cancel(Thread* thread, sint id, sint set, + ptr pNumWaitThreads); + SysResult sys_namedobj_create(Thread* thread, ptr name, + ptr object, uint16_t type); + SysResult sys_namedobj_delete(Thread* thread, uint id, uint16_t type); + SysResult sys_set_vm_container(Thread* thread /* TODO */); + SysResult sys_debug_init(Thread* thread /* TODO */); + SysResult sys_suspend_process(Thread* thread, pid_t pid); + SysResult sys_resume_process(Thread* thread, pid_t pid); + SysResult sys_opmc_enable(Thread* thread /* TODO */); + SysResult sys_opmc_disable(Thread* thread /* TODO */); + SysResult sys_opmc_set_ctl(Thread* thread /* TODO */); + SysResult sys_opmc_set_ctr(Thread* thread /* TODO */); + SysResult sys_opmc_get_ctr(Thread* thread /* TODO */); + SysResult sys_budget_create(Thread* thread /* TODO */); + SysResult sys_budget_delete(Thread* thread /* TODO */); + SysResult sys_budget_get(Thread* thread /* TODO */); + SysResult sys_budget_set(Thread* thread /* TODO */); + SysResult sys_virtual_query(Thread* thread, ptr addr, uint64_t unk, + ptr info, size_t infosz); + SysResult sys_mdbg_call(Thread* thread /* TODO */); + SysResult sys_obs_sblock_create(Thread* thread /* TODO */); + SysResult sys_obs_sblock_delete(Thread* thread /* TODO */); + SysResult sys_obs_sblock_enter(Thread* thread /* TODO */); + SysResult sys_obs_sblock_exit(Thread* thread /* TODO */); + SysResult sys_obs_sblock_xenter(Thread* thread /* TODO */); + SysResult sys_obs_sblock_xexit(Thread* thread /* TODO */); + SysResult sys_obs_eport_create(Thread* thread /* TODO */); + SysResult sys_obs_eport_delete(Thread* thread /* TODO */); + SysResult sys_obs_eport_trigger(Thread* thread /* TODO */); + SysResult sys_obs_eport_open(Thread* thread /* TODO */); + SysResult sys_obs_eport_close(Thread* thread /* TODO */); + SysResult sys_is_in_sandbox(Thread* thread /* TODO */); + SysResult sys_dmem_container(Thread* thread, uint id); + SysResult sys_get_authinfo(Thread* thread, pid_t pid, ptr info); + SysResult sys_mname(Thread* thread, uint64_t address, uint64_t length, + ptr name); + SysResult sys_dynlib_dlopen(Thread* thread /* TODO */); + SysResult sys_dynlib_dlclose(Thread* thread /* TODO */); + SysResult sys_dynlib_dlsym(Thread* thread, SceKernelModule handle, + ptr symbol, ptr> addrp); + SysResult sys_dynlib_get_list(Thread* thread, ptr pArray, + size_t numArray, ptr pActualNum); + SysResult sys_dynlib_get_info(Thread* thread, SceKernelModule handle, + ptr pInfo); + SysResult sys_dynlib_load_prx(Thread* thread, ptr name, + uint64_t arg1, ptr pHandle, + uint64_t arg3); + SysResult sys_dynlib_unload_prx(Thread* thread, + SceKernelModule handle /* TODO*/); + SysResult sys_dynlib_do_copy_relocations(Thread* thread); + SysResult sys_dynlib_prepare_dlclose(Thread* thread /* TODO */); + SysResult sys_dynlib_get_proc_param(Thread* thread, ptr> procParam, + ptr procParamSize); + SysResult sys_dynlib_process_needed_and_relocate(Thread* thread); + SysResult sys_sandbox_path(Thread* thread /* TODO */); + SysResult sys_mdbg_service(Thread* thread, uint32_t op, ptr arg0, + ptr arg1); + SysResult sys_randomized_path(Thread* thread /* TODO */); + SysResult sys_rdup(Thread* thread /* TODO */); + SysResult sys_dl_get_metadata(Thread* thread /* TODO */); + SysResult sys_workaround8849(Thread* thread /* TODO */); + SysResult sys_is_development_mode(Thread* thread /* TODO */); + SysResult sys_get_self_auth_info(Thread* thread /* TODO */); + SysResult sys_dynlib_get_info_ex(Thread* thread, SceKernelModule handle, + ptr unk, + ptr destModuleInfoEx); + SysResult sys_budget_getid(Thread* thread); + SysResult sys_budget_get_ptype(Thread* thread, sint budgetId); + SysResult sys_get_paging_stats_of_all_threads(Thread* thread /* TODO */); + SysResult sys_get_proc_type_info(Thread* thread, ptr destProcessInfo); + SysResult sys_get_resident_count(Thread* thread, pid_t pid); + SysResult sys_prepare_to_suspend_process(Thread* thread, pid_t pid); + SysResult sys_get_resident_fmem_count(Thread* thread, pid_t pid); + SysResult sys_thr_get_name(Thread* thread, lwpid_t lwpid); + SysResult sys_set_gpo(Thread* thread /* TODO */); + SysResult sys_get_paging_stats_of_all_objects(Thread* thread /* TODO */); + SysResult sys_test_debug_rwmem(Thread* thread /* TODO */); + SysResult sys_free_stack(Thread* thread /* TODO */); + SysResult sys_suspend_system(Thread* thread /* TODO */); + SysResult sys_ipmimgr_call(Thread* thread, uint op, uint kid, ptr result, + ptr params, uint64_t paramsz, uint64_t arg6); + SysResult sys_get_gpo(Thread* thread /* TODO */); + SysResult sys_get_vm_map_timestamp(Thread* thread /* TODO */); + SysResult sys_opmc_set_hw(Thread* thread /* TODO */); + SysResult sys_opmc_get_hw(Thread* thread /* TODO */); + SysResult sys_get_cpu_usage_all(Thread* thread /* TODO */); + SysResult sys_mmap_dmem(Thread* thread, caddr_t addr, size_t len, + sint memoryType, sint prot, sint flags, + off_t directMemoryStart); + SysResult sys_physhm_open(Thread* thread /* TODO */); + SysResult sys_physhm_unlink(Thread* thread /* TODO */); + SysResult sys_resume_internal_hdd(Thread* thread /* TODO */); + SysResult sys_thr_suspend_ucontext(Thread* thread /* TODO */); + SysResult sys_thr_resume_ucontext(Thread* thread /* TODO */); + SysResult sys_thr_get_ucontext(Thread* thread /* TODO */); + SysResult sys_thr_set_ucontext(Thread* thread /* TODO */); + SysResult sys_set_timezone_info(Thread* thread /* TODO */); + SysResult sys_set_phys_fmem_limit(Thread* thread /* TODO */); + SysResult sys_utc_to_localtime(Thread* thread, int64_t time, int64_t* localtime, + orbis::timesec* _sec, int* _dst_sec); + SysResult sys_localtime_to_utc(Thread* thread, int64_t time, uint unk, + int64_t* ptime, orbis::timesec* _sec, + int* _dst_sec); + SysResult sys_set_uevt(Thread* thread /* TODO */); + SysResult sys_get_cpu_usage_proc(Thread* thread /* TODO */); + SysResult sys_get_map_statistics(Thread* thread /* TODO */); + SysResult sys_set_chicken_switches(Thread* thread /* TODO */); + SysResult sys_extend_page_table_pool(Thread* thread); + SysResult sys_extend_page_table_pool2(Thread* thread); + SysResult sys_get_kernel_mem_statistics(Thread* thread /* TODO */); + SysResult sys_get_sdk_compiled_version(Thread* thread /* TODO */); + SysResult sys_app_state_change(Thread* thread /* TODO */); + SysResult sys_dynlib_get_obj_member(Thread* thread, SceKernelModule handle, + uint64_t index, ptr> addrp); + SysResult sys_budget_get_ptype_of_budget(Thread* thread /* TODO */); + SysResult sys_prepare_to_resume_process(Thread* thread /* TODO */); + SysResult sys_process_terminate(Thread* thread /* TODO */); + SysResult sys_blockpool_open(Thread* thread); + SysResult sys_blockpool_map(Thread* thread, caddr_t addr, size_t len, sint prot, + sint flags); + SysResult sys_blockpool_unmap(Thread* thread, caddr_t addr, size_t len, + sint flags); + SysResult sys_dynlib_get_info_for_libdbg(Thread* thread /* TODO */); + SysResult sys_blockpool_batch(Thread* thread /* TODO */); + SysResult sys_fdatasync(Thread* thread /* TODO */); + SysResult sys_dynlib_get_list2(Thread* thread /* TODO */); + SysResult sys_dynlib_get_info2(Thread* thread /* TODO */); + SysResult sys_aio_submit(Thread* thread /* TODO */); + SysResult sys_aio_multi_delete(Thread* thread /* TODO */); + SysResult sys_aio_multi_wait(Thread* thread /* TODO */); + SysResult sys_aio_multi_poll(Thread* thread /* TODO */); + SysResult sys_aio_get_data(Thread* thread /* TODO */); + SysResult sys_aio_multi_cancel(Thread* thread /* TODO */); + SysResult sys_get_bio_usage_all(Thread* thread /* TODO */); + SysResult sys_aio_create(Thread* thread /* TODO */); + SysResult sys_aio_submit_cmd(Thread* thread /* TODO */); + SysResult sys_aio_init(Thread* thread /* TODO */); + SysResult sys_get_page_table_stats(Thread* thread /* TODO */); + SysResult sys_dynlib_get_list_for_libdbg(Thread* thread /* TODO */); + SysResult sys_blockpool_move(Thread* thread /* TODO */); + SysResult sys_virtual_query_all(Thread* thread /* TODO */); + SysResult sys_reserve_2mb_page(Thread* thread /* TODO */); + SysResult sys_cpumode_yield(Thread* thread /* TODO */); -SysResult sys_wait6(Thread *thread /* TODO */); -SysResult sys_cap_rights_limit(Thread *thread /* TODO */); -SysResult sys_cap_ioctls_limit(Thread *thread /* TODO */); -SysResult sys_cap_ioctls_get(Thread *thread /* TODO */); -SysResult sys_cap_fcntls_limit(Thread *thread /* TODO */); -SysResult sys_cap_fcntls_get(Thread *thread /* TODO */); -SysResult sys_bindat(Thread *thread /* TODO */); -SysResult sys_connectat(Thread *thread /* TODO */); -SysResult sys_chflagsat(Thread *thread /* TODO */); -SysResult sys_accept4(Thread *thread /* TODO */); -SysResult sys_pipe2(Thread *thread /* TODO */); -SysResult sys_aio_mlock(Thread *thread /* TODO */); -SysResult sys_procctl(Thread *thread /* TODO */); -SysResult sys_ppoll(Thread *thread /* TODO */); -SysResult sys_futimens(Thread *thread /* TODO */); -SysResult sys_utimensat(Thread *thread /* TODO */); -SysResult sys_numa_getaffinity(Thread *thread /* TODO */); -SysResult sys_numa_setaffinity(Thread *thread /* TODO */); -SysResult sys_apr_submit(Thread *thread /* TODO */); -SysResult sys_apr_resolve(Thread *thread /* TODO */); -SysResult sys_apr_stat(Thread *thread /* TODO */); -SysResult sys_apr_wait(Thread *thread /* TODO */); -SysResult sys_apr_ctrl(Thread *thread /* TODO */); -SysResult sys_get_phys_page_size(Thread *thread /* TODO */); -SysResult sys_begin_app_mount(Thread *thread /* TODO */); -SysResult sys_end_app_mount(Thread *thread /* TODO */); -SysResult sys_fsc2h_ctrl(Thread *thread /* TODO */); -SysResult sys_streamwrite(Thread *thread /* TODO */); -SysResult sys_app_save(Thread *thread /* TODO */); -SysResult sys_app_restore(Thread *thread /* TODO */); -SysResult sys_saved_app_delete(Thread *thread /* TODO */); -SysResult sys_get_ppr_sdk_compiled_version(Thread *thread /* TODO */); -SysResult sys_notify_app_event(Thread *thread /* TODO */); -SysResult sys_ioreq(Thread *thread /* TODO */); -SysResult sys_openintr(Thread *thread /* TODO */); -SysResult sys_dl_get_info_2(Thread *thread /* TODO */); -SysResult sys_acinfo_add(Thread *thread /* TODO */); -SysResult sys_acinfo_delete(Thread *thread /* TODO */); -SysResult sys_acinfo_get_all_for_coredump(Thread *thread /* TODO */); -SysResult sys_ampr_ctrl_debug(Thread *thread /* TODO */); -SysResult sys_workspace_ctrl(Thread *thread /* TODO */); + SysResult sys_wait6(Thread* thread /* TODO */); + SysResult sys_cap_rights_limit(Thread* thread /* TODO */); + SysResult sys_cap_ioctls_limit(Thread* thread /* TODO */); + SysResult sys_cap_ioctls_get(Thread* thread /* TODO */); + SysResult sys_cap_fcntls_limit(Thread* thread /* TODO */); + SysResult sys_cap_fcntls_get(Thread* thread /* TODO */); + SysResult sys_bindat(Thread* thread /* TODO */); + SysResult sys_connectat(Thread* thread /* TODO */); + SysResult sys_chflagsat(Thread* thread /* TODO */); + SysResult sys_accept4(Thread* thread /* TODO */); + SysResult sys_pipe2(Thread* thread /* TODO */); + SysResult sys_aio_mlock(Thread* thread /* TODO */); + SysResult sys_procctl(Thread* thread /* TODO */); + SysResult sys_ppoll(Thread* thread /* TODO */); + SysResult sys_futimens(Thread* thread /* TODO */); + SysResult sys_utimensat(Thread* thread /* TODO */); + SysResult sys_numa_getaffinity(Thread* thread /* TODO */); + SysResult sys_numa_setaffinity(Thread* thread /* TODO */); + SysResult sys_apr_submit(Thread* thread /* TODO */); + SysResult sys_apr_resolve(Thread* thread /* TODO */); + SysResult sys_apr_stat(Thread* thread /* TODO */); + SysResult sys_apr_wait(Thread* thread /* TODO */); + SysResult sys_apr_ctrl(Thread* thread /* TODO */); + SysResult sys_get_phys_page_size(Thread* thread /* TODO */); + SysResult sys_begin_app_mount(Thread* thread /* TODO */); + SysResult sys_end_app_mount(Thread* thread /* TODO */); + SysResult sys_fsc2h_ctrl(Thread* thread /* TODO */); + SysResult sys_streamwrite(Thread* thread /* TODO */); + SysResult sys_app_save(Thread* thread /* TODO */); + SysResult sys_app_restore(Thread* thread /* TODO */); + SysResult sys_saved_app_delete(Thread* thread /* TODO */); + SysResult sys_get_ppr_sdk_compiled_version(Thread* thread /* TODO */); + SysResult sys_notify_app_event(Thread* thread /* TODO */); + SysResult sys_ioreq(Thread* thread /* TODO */); + SysResult sys_openintr(Thread* thread /* TODO */); + SysResult sys_dl_get_info_2(Thread* thread /* TODO */); + SysResult sys_acinfo_add(Thread* thread /* TODO */); + SysResult sys_acinfo_delete(Thread* thread /* TODO */); + SysResult sys_acinfo_get_all_for_coredump(Thread* thread /* TODO */); + SysResult sys_ampr_ctrl_debug(Thread* thread /* TODO */); + SysResult sys_workspace_ctrl(Thread* thread /* TODO */); } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread.hpp b/orbis-kernel/include/orbis/thread.hpp index 8778f7c2..8e006f5d 100644 --- a/orbis-kernel/include/orbis/thread.hpp +++ b/orbis-kernel/include/orbis/thread.hpp @@ -1,10 +1,10 @@ #pragma once -#include "thread/Process.hpp" // IWYU pragma: export -#include "thread/ProcessOps.hpp" // IWYU pragma: export +#include "thread/Process.hpp" // IWYU pragma: export +#include "thread/ProcessOps.hpp" // IWYU pragma: export #include "thread/ProcessState.hpp" // IWYU pragma: export -#include "thread/Thread.hpp" // IWYU pragma: export -#include "thread/ThreadState.hpp" // IWYU pragma: export -#include "thread/cpuset.hpp" // IWYU pragma: export -#include "thread/sysent.hpp" // IWYU pragma: export -#include "thread/types.hpp" // IWYU pragma: export +#include "thread/Thread.hpp" // IWYU pragma: export +#include "thread/ThreadState.hpp" // IWYU pragma: export +#include "thread/cpuset.hpp" // IWYU pragma: export +#include "thread/sysent.hpp" // IWYU pragma: export +#include "thread/types.hpp" // IWYU pragma: export diff --git a/orbis-kernel/include/orbis/thread/Process.hpp b/orbis-kernel/include/orbis/thread/Process.hpp index 6fd7b49e..bb9eac45 100644 --- a/orbis-kernel/include/orbis/thread/Process.hpp +++ b/orbis-kernel/include/orbis/thread/Process.hpp @@ -12,66 +12,73 @@ #include "orbis/utils/IdMap.hpp" #include "orbis/utils/SharedMutex.hpp" -namespace orbis { -class KernelContext; -struct Thread; -struct ProcessOps; -struct sysentvec; +namespace orbis +{ + class KernelContext; + struct Thread; + struct ProcessOps; + struct sysentvec; -struct NamedObjInfo { - void *idptr; - uint16_t ty; -}; + struct NamedObjInfo + { + void* idptr; + uint16_t ty; + }; -struct NamedMemoryRange { - uint64_t begin, end; + struct NamedMemoryRange + { + uint64_t begin, end; - constexpr bool operator<(const NamedMemoryRange &rhs) const { - return end <= rhs.begin; - } + constexpr bool operator<(const NamedMemoryRange& rhs) const + { + return end <= rhs.begin; + } - friend constexpr bool operator<(const NamedMemoryRange &lhs, uint64_t ptr) { - return lhs.end <= ptr; - } + friend constexpr bool operator<(const NamedMemoryRange& lhs, uint64_t ptr) + { + return lhs.end <= ptr; + } - friend constexpr bool operator<(uint64_t ptr, const NamedMemoryRange &rhs) { - return ptr < rhs.begin; - } -}; + friend constexpr bool operator<(uint64_t ptr, const NamedMemoryRange& rhs) + { + return ptr < rhs.begin; + } + }; -struct Process final { - KernelContext *context = nullptr; - pid_t pid = -1; - sysentvec *sysent = nullptr; - ProcessState state = ProcessState::NEW; - Process *parentProcess = nullptr; - shared_mutex mtx; - void (*onSysEnter)(Thread *thread, int id, uint64_t *args, - int argsCount) = nullptr; - void (*onSysExit)(Thread *thread, int id, uint64_t *args, int argsCount, - SysResult result) = nullptr; - ptr processParam = nullptr; - uint64_t processParamSize = 0; - const ProcessOps *ops = nullptr; + struct Process final + { + KernelContext* context = nullptr; + pid_t pid = -1; + sysentvec* sysent = nullptr; + ProcessState state = ProcessState::NEW; + Process* parentProcess = nullptr; + shared_mutex mtx; + void (*onSysEnter)(Thread* thread, int id, uint64_t* args, + int argsCount) = nullptr; + void (*onSysExit)(Thread* thread, int id, uint64_t* args, int argsCount, + SysResult result) = nullptr; + ptr processParam = nullptr; + uint64_t processParamSize = 0; + const ProcessOps* ops = nullptr; - std::uint64_t nextTlsSlot = 1; - std::uint64_t lastTlsOffset = 0; + std::uint64_t nextTlsSlot = 1; + std::uint64_t lastTlsOffset = 0; - utils::RcIdMap evfMap; - utils::RcIdMap semMap; - utils::RcIdMap ipmiClientMap; - utils::RcIdMap ipmiServerMap; - utils::RcIdMap modulesMap; - utils::OwningIdMap threadsMap; - utils::RcIdMap fileDescriptors; + utils::RcIdMap evfMap; + utils::RcIdMap semMap; + utils::RcIdMap ipmiClientMap; + utils::RcIdMap ipmiServerMap; + utils::RcIdMap modulesMap; + utils::OwningIdMap threadsMap; + utils::RcIdMap fileDescriptors; - // Named objects for debugging - utils::shared_mutex namedObjMutex; - utils::kmap namedObjNames; - utils::OwningIdMap namedObjIds; + // Named objects for debugging + utils::shared_mutex namedObjMutex; + utils::kmap namedObjNames; + utils::OwningIdMap namedObjIds; - // Named memory ranges for debugging - utils::shared_mutex namedMemMutex; - utils::kmap namedMem; -}; + // Named memory ranges for debugging + utils::shared_mutex namedMemMutex; + utils::kmap namedMem; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/ProcessOps.hpp b/orbis-kernel/include/orbis/thread/ProcessOps.hpp index 86f408c0..c230b15e 100644 --- a/orbis-kernel/include/orbis/thread/ProcessOps.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessOps.hpp @@ -5,76 +5,78 @@ #include "orbis-config.hpp" #include "orbis/utils/Rc.hpp" -namespace orbis { -struct Thread; -struct Module; -struct timespec; -struct File; -struct MemoryProtection; +namespace orbis +{ + struct Thread; + struct Module; + struct timespec; + struct File; + struct MemoryProtection; -struct ProcessOps { - SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot, - sint flags, sint fd, off_t pos); - SysResult (*dmem_mmap)(Thread *thread, caddr_t addr, size_t len, - sint memoryType, sint prot, sint flags, - off_t directMemoryStart); - SysResult (*munmap)(Thread *thread, ptr addr, size_t len); - SysResult (*msync)(Thread *thread, ptr addr, size_t len, sint flags); - SysResult (*mprotect)(Thread *thread, ptr addr, size_t len, - sint prot); - SysResult (*minherit)(Thread *thread, ptr addr, size_t len, - sint inherit); - SysResult (*madvise)(Thread *thread, ptr addr, size_t len, sint behav); - SysResult (*mincore)(Thread *thread, ptr addr, size_t len, - ptr vec); - SysResult (*mlock)(Thread *thread, ptr addr, size_t len); - SysResult (*mlockall)(Thread *thread, sint how); - SysResult (*munlockall)(Thread *thread); - SysResult (*munlock)(Thread *thread, ptr addr, size_t len); - SysResult (*virtual_query)(Thread *thread, ptr addr, sint flags, - ptr info, ulong infoSize); - SysResult (*query_memory_protection)(Thread *thread, ptr address, - ptr protection); + struct ProcessOps + { + SysResult (*mmap)(Thread* thread, caddr_t addr, size_t len, sint prot, + sint flags, sint fd, off_t pos); + SysResult (*dmem_mmap)(Thread* thread, caddr_t addr, size_t len, + sint memoryType, sint prot, sint flags, + off_t directMemoryStart); + SysResult (*munmap)(Thread* thread, ptr addr, size_t len); + SysResult (*msync)(Thread* thread, ptr addr, size_t len, sint flags); + SysResult (*mprotect)(Thread* thread, ptr addr, size_t len, + sint prot); + SysResult (*minherit)(Thread* thread, ptr addr, size_t len, + sint inherit); + SysResult (*madvise)(Thread* thread, ptr addr, size_t len, sint behav); + SysResult (*mincore)(Thread* thread, ptr addr, size_t len, + ptr vec); + SysResult (*mlock)(Thread* thread, ptr addr, size_t len); + SysResult (*mlockall)(Thread* thread, sint how); + SysResult (*munlockall)(Thread* thread); + SysResult (*munlock)(Thread* thread, ptr addr, size_t len); + SysResult (*virtual_query)(Thread* thread, ptr addr, sint flags, + ptr info, ulong infoSize); + SysResult (*query_memory_protection)(Thread* thread, ptr address, + ptr protection); - SysResult (*open)(Thread *thread, ptr path, sint flags, sint mode, - Ref *file); - SysResult (*shm_open)(Thread *thread, const char *path, sint flags, sint mode, - Ref *file); - SysResult (*mkdir)(Thread *thread, ptr path, sint mode); - SysResult (*rmdir)(Thread *thread, ptr path); - SysResult (*rename)(Thread *thread, ptr from, ptr to); - SysResult (*blockpool_open)(Thread *thread, Ref *file); - SysResult (*blockpool_map)(Thread *thread, caddr_t addr, size_t len, - sint prot, sint flags); - SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len); - SysResult (*socket)(Thread *thread, ptr name, sint domain, - sint type, sint protocol, Ref *file); - SysResult (*shm_unlink)(Thread *thread, const char *path); - SysResult (*dynlib_get_obj_member)(Thread *thread, ModuleHandle handle, - uint64_t index, ptr> addrp); - SysResult (*dynlib_dlsym)(Thread *thread, ModuleHandle handle, - ptr symbol, ptr> addrp); - SysResult (*dynlib_do_copy_relocations)(Thread *thread); - SysResult (*dynlib_load_prx)(Thread *thread, ptr name, - uint64_t arg1, ptr pHandle, - uint64_t arg3); - SysResult (*dynlib_unload_prx)(Thread *thread, ModuleHandle handle); + SysResult (*open)(Thread* thread, ptr path, sint flags, sint mode, + Ref* file); + SysResult (*shm_open)(Thread* thread, const char* path, sint flags, sint mode, + Ref* file); + SysResult (*mkdir)(Thread* thread, ptr path, sint mode); + SysResult (*rmdir)(Thread* thread, ptr path); + SysResult (*rename)(Thread* thread, ptr from, ptr to); + SysResult (*blockpool_open)(Thread* thread, Ref* file); + SysResult (*blockpool_map)(Thread* thread, caddr_t addr, size_t len, + sint prot, sint flags); + SysResult (*blockpool_unmap)(Thread* thread, caddr_t addr, size_t len); + SysResult (*socket)(Thread* thread, ptr name, sint domain, + sint type, sint protocol, Ref* file); + SysResult (*shm_unlink)(Thread* thread, const char* path); + SysResult (*dynlib_get_obj_member)(Thread* thread, ModuleHandle handle, + uint64_t index, ptr> addrp); + SysResult (*dynlib_dlsym)(Thread* thread, ModuleHandle handle, + ptr symbol, ptr> addrp); + SysResult (*dynlib_do_copy_relocations)(Thread* thread); + SysResult (*dynlib_load_prx)(Thread* thread, ptr name, + uint64_t arg1, ptr pHandle, + uint64_t arg3); + SysResult (*dynlib_unload_prx)(Thread* thread, ModuleHandle handle); - SysResult (*thr_create)(Thread *thread, ptr ctxt, - ptr arg, sint flags); - SysResult (*thr_new)(Thread *thread, ptr param, sint param_size); - SysResult (*thr_exit)(Thread *thread, ptr state); - SysResult (*thr_kill)(Thread *thread, slong id, sint sig); - SysResult (*thr_kill2)(Thread *thread, pid_t pid, slong id, sint sig); - SysResult (*thr_suspend)(Thread *thread, ptr timeout); - SysResult (*thr_wake)(Thread *thread, slong id); - SysResult (*thr_set_name)(Thread *thread, slong id, ptr name); + SysResult (*thr_create)(Thread* thread, ptr ctxt, + ptr arg, sint flags); + SysResult (*thr_new)(Thread* thread, ptr param, sint param_size); + SysResult (*thr_exit)(Thread* thread, ptr state); + SysResult (*thr_kill)(Thread* thread, slong id, sint sig); + SysResult (*thr_kill2)(Thread* thread, pid_t pid, slong id, sint sig); + SysResult (*thr_suspend)(Thread* thread, ptr timeout); + SysResult (*thr_wake)(Thread* thread, slong id); + SysResult (*thr_set_name)(Thread* thread, slong id, ptr name); - SysResult (*exit)(Thread *thread, sint status); + SysResult (*exit)(Thread* thread, sint status); - SysResult (*processNeeded)(Thread *thread); - SysResult (*registerEhFrames)(Thread *thread); + SysResult (*processNeeded)(Thread* thread); + SysResult (*registerEhFrames)(Thread* thread); - void (*where)(Thread *); -}; + void (*where)(Thread*); + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/ProcessState.hpp b/orbis-kernel/include/orbis/thread/ProcessState.hpp index 7329f986..1740ea38 100644 --- a/orbis-kernel/include/orbis/thread/ProcessState.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessState.hpp @@ -2,10 +2,12 @@ #include -namespace orbis { -enum class ProcessState : std::uint32_t { - NEW, // In creation - NORMAL, // threads can be run - ZOMBIE -}; +namespace orbis +{ + enum class ProcessState : std::uint32_t + { + NEW, // In creation + NORMAL, // threads can be run + ZOMBIE + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/RegisterId.hpp b/orbis-kernel/include/orbis/thread/RegisterId.hpp index cda5efc3..0c544585 100644 --- a/orbis-kernel/include/orbis/thread/RegisterId.hpp +++ b/orbis-kernel/include/orbis/thread/RegisterId.hpp @@ -1,23 +1,25 @@ #pragma once -namespace orbis { -enum class RegisterId { - r15, - r14, - r13, - r12, - r11, - r10, - r9, - r8, - rdi, - rsi, - rbp, - rbx, - rdx, - rcx, - rax, - rsp, - rflags, -}; +namespace orbis +{ + enum class RegisterId + { + r15, + r14, + r13, + r12, + r11, + r10, + r9, + r8, + rdi, + rsi, + rbp, + rbx, + rdx, + rcx, + rax, + rsp, + rflags, + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/Thread.hpp b/orbis-kernel/include/orbis/thread/Thread.hpp index 26241757..8ebbc975 100644 --- a/orbis-kernel/include/orbis/thread/Thread.hpp +++ b/orbis-kernel/include/orbis/thread/Thread.hpp @@ -8,35 +8,37 @@ #include "../utils/SharedMutex.hpp" #include -namespace orbis { -struct Process; -struct Thread { - utils::shared_mutex mtx; - Process *tproc = nullptr; - uint64_t retval[2]{}; - void *context{}; - ptr stackStart; - ptr stackEnd; - uint64_t fsBase{}; - uint64_t gsBase{}; - char name[32]{}; - - uint64_t sigMask[4] = {0x7fff'ffff, 0}; - - lwpid_t tid = -1; - ThreadState state = ThreadState::INACTIVE; - std::thread handle; - - // Used to wake up thread in sleep queue - utils::shared_cv sync_cv; - uint64_t evfResultPattern; - uint64_t evfIsCancelled; - - // Print backtrace - void where(); - - // FIXME: implement thread destruction - void incRef() {} - void decRef() {} -}; +namespace orbis +{ + struct Process; + struct Thread + { + utils::shared_mutex mtx; + Process* tproc = nullptr; + uint64_t retval[2]{}; + void* context{}; + ptr stackStart; + ptr stackEnd; + uint64_t fsBase{}; + uint64_t gsBase{}; + char name[32]{}; + + uint64_t sigMask[4] = {0x7fff'ffff, 0}; + + lwpid_t tid = -1; + ThreadState state = ThreadState::INACTIVE; + std::thread handle; + + // Used to wake up thread in sleep queue + utils::shared_cv sync_cv; + uint64_t evfResultPattern; + uint64_t evfIsCancelled; + + // Print backtrace + void where(); + + // FIXME: implement thread destruction + void incRef() {} + void decRef() {} + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/ThreadState.hpp b/orbis-kernel/include/orbis/thread/ThreadState.hpp index c2dd9242..c36f718b 100644 --- a/orbis-kernel/include/orbis/thread/ThreadState.hpp +++ b/orbis-kernel/include/orbis/thread/ThreadState.hpp @@ -2,12 +2,14 @@ #include -namespace orbis { -enum class ThreadState : std::uint32_t { - INACTIVE, - INHIBITED, - CAN_RUN, - RUNQ, - RUNNING -}; +namespace orbis +{ + enum class ThreadState : std::uint32_t + { + INACTIVE, + INHIBITED, + CAN_RUN, + RUNQ, + RUNNING + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/cpuset.hpp b/orbis-kernel/include/orbis/thread/cpuset.hpp index 4e417ce9..346cf240 100644 --- a/orbis-kernel/include/orbis/thread/cpuset.hpp +++ b/orbis-kernel/include/orbis/thread/cpuset.hpp @@ -2,11 +2,13 @@ #include "orbis-config.hpp" -namespace orbis { -static constexpr auto NCPUBITS = sizeof(slong) * 8; -static constexpr auto NCPUWORDS = 128 / NCPUBITS; +namespace orbis +{ + static constexpr auto NCPUBITS = sizeof(slong) * 8; + static constexpr auto NCPUWORDS = 128 / NCPUBITS; -struct cpuset { - slong bits[NCPUWORDS]; -}; + struct cpuset + { + slong bits[NCPUWORDS]; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/sysent.hpp b/orbis-kernel/include/orbis/thread/sysent.hpp index 01f37e1b..041de7b9 100644 --- a/orbis-kernel/include/orbis/thread/sysent.hpp +++ b/orbis-kernel/include/orbis/thread/sysent.hpp @@ -2,17 +2,20 @@ #include "orbis-config.hpp" -namespace orbis { -struct Thread; -using sy_call_t = SysResult(Thread *, uint64_t *); +namespace orbis +{ + struct Thread; + using sy_call_t = SysResult(Thread*, uint64_t*); -struct sysent { - sint narg; - sy_call_t *call; -}; + struct sysent + { + sint narg; + sy_call_t* call; + }; -struct sysentvec { - sint size; - const sysent *table; -}; + struct sysentvec + { + sint size; + const sysent* table; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/types.hpp b/orbis-kernel/include/orbis/thread/types.hpp index 33f576eb..8a0349e9 100644 --- a/orbis-kernel/include/orbis/thread/types.hpp +++ b/orbis-kernel/include/orbis/thread/types.hpp @@ -1,31 +1,34 @@ #pragma once #include "orbis-config.hpp" -namespace orbis { -using lwpid_t = int32_t; -using pid_t = int64_t; -using uid_t = uint32_t; -using gid_t = uint32_t; +namespace orbis +{ + using lwpid_t = int32_t; + using pid_t = int64_t; + using uid_t = uint32_t; + using gid_t = uint32_t; -struct rtprio { - uint16_t type; - uint16_t prio; -}; + struct rtprio + { + uint16_t type; + uint16_t prio; + }; -struct thr_param { - ptr start_func; - ptr arg; - ptr stack_base; - size_t stack_size; - ptr tls_base; - size_t tls_size; - ptr child_tid; // Address to store the new thread identifier, for the - // child's use - ptr parent_tid; // Address to store the new thread identifier, for the - // parent's use - sint flags; // Thread creation flags. The flags member may specify the - // following flags: - ptr rtp; // Real-time scheduling priority for the new thread. May be - // NULL to inherit the priority from the creating thread -}; + struct thr_param + { + ptr start_func; + ptr arg; + ptr stack_base; + size_t stack_size; + ptr tls_base; + size_t tls_size; + ptr child_tid; // Address to store the new thread identifier, for the + // child's use + ptr parent_tid; // Address to store the new thread identifier, for the + // parent's use + sint flags; // Thread creation flags. The flags member may specify the + // following flags: + ptr rtp; // Real-time scheduling priority for the new thread. May be + // NULL to inherit the priority from the creating thread + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/time.hpp b/orbis-kernel/include/orbis/time.hpp index 4f030873..428e5510 100644 --- a/orbis-kernel/include/orbis/time.hpp +++ b/orbis-kernel/include/orbis/time.hpp @@ -2,22 +2,27 @@ #include "orbis-config.hpp" -namespace orbis { -struct timespec { - uint64_t sec; - uint64_t nsec; -}; -struct timeval { - int64_t tv_sec; - int64_t tv_usec; -}; -struct timezone { - sint tz_mineast; - sint tz_dsttime; -}; -struct timesec { - int64_t tz_time; - sint tz_secwest; - sint tz_dstsec; -}; +namespace orbis +{ + struct timespec + { + uint64_t sec; + uint64_t nsec; + }; + struct timeval + { + int64_t tv_sec; + int64_t tv_usec; + }; + struct timezone + { + sint tz_mineast; + sint tz_dsttime; + }; + struct timesec + { + int64_t tz_time; + sint tz_secwest; + sint tz_dstsec; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/uio.hpp b/orbis-kernel/include/orbis/uio.hpp index f1f8c476..b363f157 100644 --- a/orbis-kernel/include/orbis/uio.hpp +++ b/orbis-kernel/include/orbis/uio.hpp @@ -2,28 +2,36 @@ #include -namespace orbis { -struct IoVec { - void *base; // Base address - std::uint64_t len; // Length -}; +namespace orbis +{ + struct IoVec + { + void* base; // Base address + std::uint64_t len; // Length + }; -enum class UioRw : std::uint8_t { Read, Write }; + enum class UioRw : std::uint8_t + { + Read, + Write + }; -// Segment flag values -enum class UioSeg : std::uint8_t { - UserSpace, // from user data space - SysSpace, // from system space - NoCopy // don't copy, already in object -}; + // Segment flag values + enum class UioSeg : std::uint8_t + { + UserSpace, // from user data space + SysSpace, // from system space + NoCopy // don't copy, already in object + }; -struct Uio { - std::uint64_t offset; - IoVec *iov; - std::uint32_t iovcnt; - std::int64_t resid; - UioSeg segflg; - UioRw rw; - void *td; -}; + struct Uio + { + std::uint64_t offset; + IoVec* iov; + std::uint32_t iovcnt; + std::int64_t resid; + UioSeg segflg; + UioRw rw; + void* td; + }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/umtx.hpp b/orbis-kernel/include/orbis/umtx.hpp index 480ec62d..5b1c6c7b 100644 --- a/orbis-kernel/include/orbis/umtx.hpp +++ b/orbis-kernel/include/orbis/umtx.hpp @@ -7,91 +7,97 @@ #include #include -namespace orbis { -inline constexpr ulong kUmtxUnowned = 0; -inline constexpr ulong kUmtxContested = std::numeric_limits::min(); +namespace orbis +{ + inline constexpr ulong kUmtxUnowned = 0; + inline constexpr ulong kUmtxContested = std::numeric_limits::min(); -inline constexpr auto kUsyncProcessShared = 1; + inline constexpr auto kUsyncProcessShared = 1; -inline constexpr auto kUmutexUnowned = 0; -inline constexpr auto kUmutexContested = 0x80000000; -inline constexpr auto kUmutexErrorCheck = 2; -inline constexpr auto kUmutexPrioInherit = 4; -inline constexpr auto kUmutexPrioProtect = 8; + inline constexpr auto kUmutexUnowned = 0; + inline constexpr auto kUmutexContested = 0x80000000; + inline constexpr auto kUmutexErrorCheck = 2; + inline constexpr auto kUmutexPrioInherit = 4; + inline constexpr auto kUmutexPrioProtect = 8; -inline constexpr auto kUrwLockPreferReader = 2; -inline constexpr auto kUrwLockWriteOwner = 0x80000000; -inline constexpr auto kUrwLockWriteWaiters = 0x40000000; -inline constexpr auto kUrwLockReadWaiters = 0x20000000; -inline constexpr auto kUrwLockMaxReaders = 0x1fffffff; + inline constexpr auto kUrwLockPreferReader = 2; + inline constexpr auto kUrwLockWriteOwner = 0x80000000; + inline constexpr auto kUrwLockWriteWaiters = 0x40000000; + inline constexpr auto kUrwLockReadWaiters = 0x20000000; + inline constexpr auto kUrwLockMaxReaders = 0x1fffffff; -inline constexpr auto kCvWaitCheckUnparking = 0x01; -inline constexpr auto kCvWaitAbsTime = 0x02; -inline constexpr auto kCvWaitClockId = 0x04; + inline constexpr auto kCvWaitCheckUnparking = 0x01; + inline constexpr auto kCvWaitAbsTime = 0x02; + inline constexpr auto kCvWaitClockId = 0x04; -inline constexpr auto kSemNamed = 2; + inline constexpr auto kSemNamed = 2; -struct umtx { - std::atomic owner; // Owner of the mutex -}; + struct umtx + { + std::atomic owner; // Owner of the mutex + }; -struct umutex { - std::atomic owner; // Owner of the mutex - uint32_t flags; // Flags of the mutex - uint32_t ceilings[2]; // Priority protect ceiling - uint32_t spare[4]; -}; + struct umutex + { + std::atomic owner; // Owner of the mutex + uint32_t flags; // Flags of the mutex + uint32_t ceilings[2]; // Priority protect ceiling + uint32_t spare[4]; + }; -struct ucond { - std::atomic has_waiters; // Has waiters in kernel - uint32_t flags; // Flags of the condition variable - uint32_t clockid; // Clock id - uint32_t spare[1]; // Spare space -}; + struct ucond + { + std::atomic has_waiters; // Has waiters in kernel + uint32_t flags; // Flags of the condition variable + uint32_t clockid; // Clock id + uint32_t spare[1]; // Spare space + }; -struct urwlock { - std::atomic state; - uint32_t flags; - uint32_t blocked_readers; - uint32_t blocked_writers; - uint32_t spare[4]; -}; + struct urwlock + { + std::atomic state; + uint32_t flags; + uint32_t blocked_readers; + uint32_t blocked_writers; + uint32_t spare[4]; + }; -struct usem { - std::atomic has_waiters; - std::atomic count; - uint32_t flags; -}; + struct usem + { + std::atomic has_waiters; + std::atomic count; + uint32_t flags; + }; -struct Thread; -ErrorCode umtx_lock_umtx(Thread *thread, ptr umtx, ulong id, - std::uint64_t ut); -ErrorCode umtx_unlock_umtx(Thread *thread, ptr umtx, ulong id); -ErrorCode umtx_wait(Thread *thread, ptr addr, ulong id, std::uint64_t ut, - bool is32, bool ipc); -ErrorCode umtx_wake(Thread *thread, ptr addr, sint n_wake); -ErrorCode umtx_trylock_umutex(Thread *thread, ptr m); -ErrorCode umtx_lock_umutex(Thread *thread, ptr m, std::uint64_t ut); -ErrorCode umtx_unlock_umutex(Thread *thread, ptr m); -ErrorCode umtx_set_ceiling(Thread *thread, ptr m, std::uint32_t ceiling, - ptr oldCeiling); -ErrorCode umtx_cv_wait(Thread *thread, ptr cv, ptr m, - std::uint64_t ut, ulong wflags); -ErrorCode umtx_cv_signal(Thread *thread, ptr cv); -ErrorCode umtx_cv_broadcast(Thread *thread, ptr cv); -ErrorCode umtx_rw_rdlock(Thread *thread, ptr obj, std::int64_t val, - ptr uaddr1, ptr uaddr2); -ErrorCode umtx_rw_wrlock(Thread *thread, ptr obj, std::int64_t val, - ptr uaddr1, ptr uaddr2); -ErrorCode umtx_rw_unlock(Thread *thread, ptr obj, std::int64_t val, - ptr uaddr1, ptr uaddr2); -ErrorCode umtx_wake_private(Thread *thread, ptr uaddr, sint n_wake); -ErrorCode umtx_wait_umutex(Thread *thread, ptr m, std::uint64_t ut); -ErrorCode umtx_wake_umutex(Thread *thread, ptr m); -ErrorCode umtx_sem_wait(Thread *thread, ptr sem, std::uint64_t ut); -ErrorCode umtx_sem_wake(Thread *thread, ptr sem); -ErrorCode umtx_nwake_private(Thread *thread, ptr uaddrs, - std::int64_t count); -ErrorCode umtx_wake2_umutex(Thread *thread, ptr obj, std::int64_t val, - ptr uaddr1, ptr uaddr2); + struct Thread; + ErrorCode umtx_lock_umtx(Thread* thread, ptr umtx, ulong id, + std::uint64_t ut); + ErrorCode umtx_unlock_umtx(Thread* thread, ptr umtx, ulong id); + ErrorCode umtx_wait(Thread* thread, ptr addr, ulong id, std::uint64_t ut, + bool is32, bool ipc); + ErrorCode umtx_wake(Thread* thread, ptr addr, sint n_wake); + ErrorCode umtx_trylock_umutex(Thread* thread, ptr m); + ErrorCode umtx_lock_umutex(Thread* thread, ptr m, std::uint64_t ut); + ErrorCode umtx_unlock_umutex(Thread* thread, ptr m); + ErrorCode umtx_set_ceiling(Thread* thread, ptr m, std::uint32_t ceiling, + ptr oldCeiling); + ErrorCode umtx_cv_wait(Thread* thread, ptr cv, ptr m, + std::uint64_t ut, ulong wflags); + ErrorCode umtx_cv_signal(Thread* thread, ptr cv); + ErrorCode umtx_cv_broadcast(Thread* thread, ptr cv); + ErrorCode umtx_rw_rdlock(Thread* thread, ptr obj, std::int64_t val, + ptr uaddr1, ptr uaddr2); + ErrorCode umtx_rw_wrlock(Thread* thread, ptr obj, std::int64_t val, + ptr uaddr1, ptr uaddr2); + ErrorCode umtx_rw_unlock(Thread* thread, ptr obj, std::int64_t val, + ptr uaddr1, ptr uaddr2); + ErrorCode umtx_wake_private(Thread* thread, ptr uaddr, sint n_wake); + ErrorCode umtx_wait_umutex(Thread* thread, ptr m, std::uint64_t ut); + ErrorCode umtx_wake_umutex(Thread* thread, ptr m); + ErrorCode umtx_sem_wait(Thread* thread, ptr sem, std::uint64_t ut); + ErrorCode umtx_sem_wake(Thread* thread, ptr sem); + ErrorCode umtx_nwake_private(Thread* thread, ptr uaddrs, + std::int64_t count); + ErrorCode umtx_wake2_umutex(Thread* thread, ptr obj, std::int64_t val, + ptr uaddr1, ptr uaddr2); } // namespace orbis \ No newline at end of file diff --git a/orbis-kernel/include/orbis/utils/AtomicOp.hpp b/orbis-kernel/include/orbis/utils/AtomicOp.hpp index be6c7849..a43bb4ed 100644 --- a/orbis-kernel/include/orbis/utils/AtomicOp.hpp +++ b/orbis-kernel/include/orbis/utils/AtomicOp.hpp @@ -4,71 +4,89 @@ #include #include -namespace orbis { -inline namespace utils { -// Atomic operation; returns old value, or pair of old value and return value -// (cancel op if evaluates to false) -template > -inline std::conditional_t, T, std::pair> -atomic_fetch_op(std::atomic &v, F func) { - T _new, old = v.load(); - while (true) { - _new = old; - if constexpr (std::is_void_v) { - std::invoke(func, _new); - if (v.compare_exchange_strong(old, _new)) [[likely]] { - return old; - } - } else { - RT ret = std::invoke(func, _new); - if (!ret || v.compare_exchange_strong(old, _new)) [[likely]] { - return {old, std::move(ret)}; - } - } - } -} +namespace orbis +{ + inline namespace utils + { + // Atomic operation; returns old value, or pair of old value and return value + // (cancel op if evaluates to false) + template > + inline std::conditional_t, T, std::pair> + atomic_fetch_op(std::atomic& v, F func) + { + T _new, old = v.load(); + while (true) + { + _new = old; + if constexpr (std::is_void_v) + { + std::invoke(func, _new); + if (v.compare_exchange_strong(old, _new)) [[likely]] + { + return old; + } + } + else + { + RT ret = std::invoke(func, _new); + if (!ret || v.compare_exchange_strong(old, _new)) [[likely]] + { + return {old, std::move(ret)}; + } + } + } + } -// Atomic operation; returns function result value, function is the lambda -template > -inline RT atomic_op(std::atomic &v, F func) { - T _new, old = v.load(); - while (true) { - _new = old; - if constexpr (std::is_void_v) { - std::invoke(func, _new); - if (v.compare_exchange_strong(old, _new)) [[likely]] { - return; - } - } else { - RT result = std::invoke(func, _new); - if (v.compare_exchange_strong(old, _new)) [[likely]] { - return result; - } - } - } -} + // Atomic operation; returns function result value, function is the lambda + template > + inline RT atomic_op(std::atomic& v, F func) + { + T _new, old = v.load(); + while (true) + { + _new = old; + if constexpr (std::is_void_v) + { + std::invoke(func, _new); + if (v.compare_exchange_strong(old, _new)) [[likely]] + { + return; + } + } + else + { + RT result = std::invoke(func, _new); + if (v.compare_exchange_strong(old, _new)) [[likely]] + { + return result; + } + } + } + } #if defined(__ATOMIC_HLE_ACQUIRE) && defined(__ATOMIC_HLE_RELEASE) -static constexpr int s_hle_ack = __ATOMIC_SEQ_CST | __ATOMIC_HLE_ACQUIRE; -static constexpr int s_hle_rel = __ATOMIC_SEQ_CST | __ATOMIC_HLE_RELEASE; + static constexpr int s_hle_ack = __ATOMIC_SEQ_CST | __ATOMIC_HLE_ACQUIRE; + static constexpr int s_hle_rel = __ATOMIC_SEQ_CST | __ATOMIC_HLE_RELEASE; #else -static constexpr int s_hle_ack = __ATOMIC_SEQ_CST; -static constexpr int s_hle_rel = __ATOMIC_SEQ_CST; + static constexpr int s_hle_ack = __ATOMIC_SEQ_CST; + static constexpr int s_hle_rel = __ATOMIC_SEQ_CST; #endif -template -inline bool compare_exchange_hle_acq(std::atomic &dest, T &comp, T exch) { - static_assert(sizeof(T) == 4 || sizeof(T) == 8); - static_assert(std::atomic::is_always_lock_free); - return __atomic_compare_exchange(reinterpret_cast(&dest), &comp, &exch, - false, s_hle_ack, s_hle_ack); -} + template + inline bool compare_exchange_hle_acq(std::atomic& dest, T& comp, T exch) + { + static_assert(sizeof(T) == 4 || sizeof(T) == 8); + static_assert(std::atomic::is_always_lock_free); + return __atomic_compare_exchange(reinterpret_cast(&dest), &comp, &exch, + false, s_hle_ack, s_hle_ack); + } -template -inline T fetch_add_hle_rel(std::atomic &dest, T value) { - static_assert(sizeof(T) == 4 || sizeof(T) == 8); - static_assert(std::atomic::is_always_lock_free); - return __atomic_fetch_add(reinterpret_cast(&dest), value, s_hle_rel); -} -} // namespace utils + template + inline T fetch_add_hle_rel(std::atomic& dest, T value) + { + static_assert(sizeof(T) == 4 || sizeof(T) == 8); + static_assert(std::atomic::is_always_lock_free); + return __atomic_fetch_add(reinterpret_cast(&dest), value, s_hle_rel); + } + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/BitSet.hpp b/orbis-kernel/include/orbis/utils/BitSet.hpp index 4ce02886..4fd213bf 100644 --- a/orbis-kernel/include/orbis/utils/BitSet.hpp +++ b/orbis-kernel/include/orbis/utils/BitSet.hpp @@ -3,51 +3,63 @@ #include #include -namespace orbis { -inline namespace utils { -template struct BitSet { - using chunk_type = std::uint64_t; - static constexpr auto BitsPerChunk = sizeof(chunk_type) * 8; - static constexpr auto ChunkCount = (Count + BitsPerChunk - 1) / BitsPerChunk; - chunk_type _bits[ChunkCount]{}; - - constexpr std::size_t countr_one() const { - std::size_t result = 0; - for (auto bits : _bits) { - auto count = std::countr_one(bits); - result += count; - - if (count != BitsPerChunk) { - break; - } - } - - return result; - } - - constexpr std::size_t countr_zero(std::size_t offset = 0) const { - std::size_t result = 0; - - if (auto chunkOffset = offset % BitsPerChunk) { - auto count = - std::countr_zero(_bits[offset / BitsPerChunk] >> chunkOffset); - - if (count != BitsPerChunk) { - return count + offset; - } - - offset = (offset + BitsPerChunk - 1) & ~(BitsPerChunk - 1); - } - - for (auto i = offset / BitsPerChunk; i < ChunkCount; ++i) { - auto count = std::countr_zero(_bits[i]); - result += count; - - if (count != BitsPerChunk) { - break; - } - } - /* +namespace orbis +{ + inline namespace utils + { + template + struct BitSet + { + using chunk_type = std::uint64_t; + static constexpr auto BitsPerChunk = sizeof(chunk_type) * 8; + static constexpr auto ChunkCount = (Count + BitsPerChunk - 1) / BitsPerChunk; + chunk_type _bits[ChunkCount]{}; + + constexpr std::size_t countr_one() const + { + std::size_t result = 0; + for (auto bits : _bits) + { + auto count = std::countr_one(bits); + result += count; + + if (count != BitsPerChunk) + { + break; + } + } + + return result; + } + + constexpr std::size_t countr_zero(std::size_t offset = 0) const + { + std::size_t result = 0; + + if (auto chunkOffset = offset % BitsPerChunk) + { + auto count = + std::countr_zero(_bits[offset / BitsPerChunk] >> chunkOffset); + + if (count != BitsPerChunk) + { + return count + offset; + } + + offset = (offset + BitsPerChunk - 1) & ~(BitsPerChunk - 1); + } + + for (auto i = offset / BitsPerChunk; i < ChunkCount; ++i) + { + auto count = std::countr_zero(_bits[i]); + result += count; + + if (count != BitsPerChunk) + { + break; + } + } + /* for (auto bits : _bits) { auto count = std::countr_zero(bits); result += count; @@ -58,47 +70,57 @@ template struct BitSet { } */ - return result + offset; - } - - bool empty() const { - for (auto bits : _bits) { - if (bits != 0) { - return false; - } - } - - return true; - } - - bool full() const { - if constexpr (Count < BitsPerChunk) { - return _bits[0] == (static_cast(1) << Count) - 1; - } - - for (auto bits : _bits) { - if (bits != ~static_cast(0)) { - return false; - } - } - - return true; - } - - constexpr void clear(std::size_t index) { - _bits[index / BitsPerChunk] &= - ~(static_cast(1) << (index % BitsPerChunk)); - } - - constexpr void set(std::size_t index) { - _bits[index / BitsPerChunk] |= static_cast(1) - << (index % BitsPerChunk); - } - - constexpr bool test(std::size_t index) const { - return (_bits[index / BitsPerChunk] & - (static_cast(1) << (index % BitsPerChunk))) != 0; - } -}; -} // namespace utils + return result + offset; + } + + bool empty() const + { + for (auto bits : _bits) + { + if (bits != 0) + { + return false; + } + } + + return true; + } + + bool full() const + { + if constexpr (Count < BitsPerChunk) + { + return _bits[0] == (static_cast(1) << Count) - 1; + } + + for (auto bits : _bits) + { + if (bits != ~static_cast(0)) + { + return false; + } + } + + return true; + } + + constexpr void clear(std::size_t index) + { + _bits[index / BitsPerChunk] &= + ~(static_cast(1) << (index % BitsPerChunk)); + } + + constexpr void set(std::size_t index) + { + _bits[index / BitsPerChunk] |= static_cast(1) + << (index % BitsPerChunk); + } + + constexpr bool test(std::size_t index) const + { + return (_bits[index / BitsPerChunk] & + (static_cast(1) << (index % BitsPerChunk))) != 0; + } + }; + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/IdMap.hpp b/orbis-kernel/include/orbis/utils/IdMap.hpp index 416388fd..adcb47ec 100644 --- a/orbis-kernel/include/orbis/utils/IdMap.hpp +++ b/orbis-kernel/include/orbis/utils/IdMap.hpp @@ -10,347 +10,404 @@ #include #include -namespace orbis { -inline namespace utils { -template - requires(MaxId > MinId) -class RcIdMap { - static constexpr auto ChunkSize = std::min(MaxId - MinId, 64); - static constexpr auto ChunkCount = - (MaxId - MinId + ChunkSize - 1) / ChunkSize; +namespace orbis +{ + inline namespace utils + { + template + requires(MaxId > MinId) class RcIdMap + { + static constexpr auto ChunkSize = std::min(MaxId - MinId, 64); + static constexpr auto ChunkCount = + (MaxId - MinId + ChunkSize - 1) / ChunkSize; + + struct IdMapChunk + { + BitSet mask = {}; + T* objects[ChunkSize]{}; + + ~IdMapChunk() + { + std::size_t index = mask.countr_zero(); + + while (index < ChunkSize) + { + objects[index]->decRef(); + index = mask.countr_zero(index + 1); + } + } + + std::size_t insert(T* object) + { + std::size_t index = mask.countr_one(); + mask.set(index); + objects[index] = object; + + return index; + } + + T* get(std::size_t index) { return objects[index]; } + + void remove(std::size_t index) + { + objects[index]->decRef(); + objects[index] = nullptr; + mask.clear(index); + } + }; + + IdMapChunk m_chunks[ChunkCount]{}; + BitSet m_fullChunks; + + public: + static constexpr auto npos = static_cast(~static_cast(0)); + + shared_mutex mutex; + + struct end_iterator + { + }; + + class iterator + { + const IdMapChunk* chunks = nullptr; + std::size_t chunk = 0; + std::size_t index = 0; + + public: + iterator(const IdMapChunk* chunks) + : chunks(chunks) + { + findNext(); + } + + iterator& operator++() + { + ++index; + findNext(); + return *this; + } + + std::pair operator*() const + { + return {static_cast(chunk * ChunkSize + index + MinId), + chunks[chunk].objects[index]}; + } + + bool operator!=(const end_iterator&) const { return chunk < ChunkCount; } + bool operator==(const end_iterator&) const { return chunk >= ChunkCount; } + + private: + void findNext() + { + while (chunk < ChunkCount) + { + index = chunks[chunk].mask.countr_zero(index); + + if (index < ChunkSize) + { + break; + } + + index = 0; + chunk++; + } + } + }; + + void walk(auto cb) + { + std::lock_guard lock(mutex); + + for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) + { + std::size_t index = m_chunks[chunk].mask.countr_zero(); + + while (index < ChunkSize) + { + cb(static_cast(index + chunk * ChunkSize + MinId), + m_chunks[chunk].objects[index]); + + index = m_chunks[chunk].mask.countr_zero(index + 1); + } + } + } + + iterator begin() const { return iterator{m_chunks}; } + + end_iterator end() const { return {}; } + + private: + IdT insert_impl(T* object) + { + std::lock_guard lock(mutex); + + auto page = m_fullChunks.countr_one(); + + if (page == ChunkCount) + { + return npos; + } + + auto index = m_chunks[page].insert(object); + + if (m_chunks[page].mask.full()) + { + m_fullChunks.set(page); + } + + return {static_cast(page * ChunkSize + index + MinId)}; + } + + public: + IdT insert(T* object) + { + auto result = insert_impl(object); + + if (result != npos) + { + object->incRef(); + } + + return result; + } + + IdT insert(const Ref& ref) { return insert(ref.get()); } + + IdT insert(Ref&& ref) + { + auto object = ref.release(); + auto result = insert_impl(object); + + if (result == npos) + { + object->decRef(); + } + + return result; + } + + T* get(IdT id) + { + const auto rawId = static_cast(id) - MinId; + + if (rawId >= MaxId - MinId) + { + return nullptr; + } + + const auto chunk = rawId / ChunkSize; + const auto index = rawId % ChunkSize; + + std::lock_guard lock(mutex); + + if (!m_chunks[chunk].mask.test(index)) + { + return nullptr; + } + + return m_chunks[chunk].get(index); + } - struct IdMapChunk { - BitSet mask = {}; - T *objects[ChunkSize]{}; + bool destroy(IdT id) requires requires(T t) { t.destroy(); } + { + const auto rawId = static_cast(id) - MinId; - ~IdMapChunk() { - std::size_t index = mask.countr_zero(); + if (rawId >= MaxId - MinId) + { + return false; + } - while (index < ChunkSize) { - objects[index]->decRef(); - index = mask.countr_zero(index + 1); - } - } + const auto chunk = rawId / ChunkSize; + const auto index = rawId % ChunkSize; - std::size_t insert(T *object) { - std::size_t index = mask.countr_one(); - mask.set(index); - objects[index] = object; + std::lock_guard lock(mutex); - return index; - } + if (!m_chunks[chunk].mask.test(index)) + { + return false; + } - T *get(std::size_t index) { return objects[index]; } - - void remove(std::size_t index) { - objects[index]->decRef(); - objects[index] = nullptr; - mask.clear(index); - } - }; - - IdMapChunk m_chunks[ChunkCount]{}; - BitSet m_fullChunks; - -public: - static constexpr auto npos = static_cast(~static_cast(0)); - - shared_mutex mutex; - - struct end_iterator {}; - - class iterator { - const IdMapChunk *chunks = nullptr; - std::size_t chunk = 0; - std::size_t index = 0; - - public: - iterator(const IdMapChunk *chunks) : chunks(chunks) { findNext(); } - - iterator &operator++() { - ++index; - findNext(); - return *this; - } - - std::pair operator*() const { - return {static_cast(chunk * ChunkSize + index + MinId), - chunks[chunk].objects[index]}; - } - - bool operator!=(const end_iterator &) const { return chunk < ChunkCount; } - bool operator==(const end_iterator &) const { return chunk >= ChunkCount; } - - private: - void findNext() { - while (chunk < ChunkCount) { - index = chunks[chunk].mask.countr_zero(index); - - if (index < ChunkSize) { - break; - } - - index = 0; - chunk++; - } - } - }; - - void walk(auto cb) { - std::lock_guard lock(mutex); - - for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) { - std::size_t index = m_chunks[chunk].mask.countr_zero(); - - while (index < ChunkSize) { - cb(static_cast(index + chunk * ChunkSize + MinId), - m_chunks[chunk].objects[index]); - - index = m_chunks[chunk].mask.countr_zero(index + 1); - } - } - } - - iterator begin() const { return iterator{m_chunks}; } - - end_iterator end() const { return {}; } - -private: - IdT insert_impl(T *object) { - std::lock_guard lock(mutex); - - auto page = m_fullChunks.countr_one(); - - if (page == ChunkCount) { - return npos; - } - - auto index = m_chunks[page].insert(object); - - if (m_chunks[page].mask.full()) { - m_fullChunks.set(page); - } - - return {static_cast(page * ChunkSize + index + MinId)}; - } - -public: - IdT insert(T *object) { - auto result = insert_impl(object); - - if (result != npos) { - object->incRef(); - } - - return result; - } - - IdT insert(const Ref &ref) { return insert(ref.get()); } - - IdT insert(Ref &&ref) { - auto object = ref.release(); - auto result = insert_impl(object); - - if (result == npos) { - object->decRef(); - } - - return result; - } - - T *get(IdT id) { - const auto rawId = static_cast(id) - MinId; - - if (rawId >= MaxId - MinId) { - return nullptr; - } - - const auto chunk = rawId / ChunkSize; - const auto index = rawId % ChunkSize; - - std::lock_guard lock(mutex); - - if (!m_chunks[chunk].mask.test(index)) { - return nullptr; - } - - return m_chunks[chunk].get(index); - } - - bool destroy(IdT id) - requires requires(T t) { t.destroy(); } - { - const auto rawId = static_cast(id) - MinId; - - if (rawId >= MaxId - MinId) { - return false; - } - - const auto chunk = rawId / ChunkSize; - const auto index = rawId % ChunkSize; - - std::lock_guard lock(mutex); - - if (!m_chunks[chunk].mask.test(index)) { - return false; - } - - m_chunks[chunk].get(index)->destroy(); - m_chunks[chunk].remove(index); - m_fullChunks.clear(chunk); - return true; - } - - bool close(IdT id) { - const auto rawId = static_cast(id) - MinId; - - if (rawId >= MaxId - MinId) { - return false; - } - - const auto chunk = rawId / ChunkSize; - const auto index = rawId % ChunkSize; - - std::lock_guard lock(mutex); - - if (!m_chunks[chunk].mask.test(index)) { - return false; - } - - m_chunks[chunk].remove(index); - m_fullChunks.clear(chunk); - return true; - } - - [[deprecated("use close()")]] bool remove(IdT id) { return close(id); } -}; - -template - requires(MaxId > MinId) -struct OwningIdMap { - static constexpr auto ChunkSize = std::min(MaxId - MinId, 64); - static constexpr auto ChunkCount = - (MaxId - MinId + ChunkSize - 1) / ChunkSize; - - struct IdMapChunk { - BitSet mask = {}; - alignas(T) std::byte objects[sizeof(T) * ChunkSize]; - - ~IdMapChunk() { - std::size_t pageOffset = 0; - - for (auto page : mask._bits) { - auto tmp = page; - - while (true) { - const auto index = std::countr_zero(tmp); - - if (index >= 64) { - break; - } - - tmp &= ~(static_cast(1) << index); - destroy(pageOffset + index); - } - - pageOffset += 64; - } - } - - template - std::pair emplace_new(ArgsT &&...args) { - std::size_t index = mask.countr_one(); - - if (index >= ChunkSize) { - return {}; - } - - mask.set(index); - - return {index, - std::construct_at(get(index), std::forward(args)...)}; - } - - T *get(std::size_t index) { - return reinterpret_cast(objects + sizeof(T) * index); - } - - void destroy(std::size_t index) { - std::destroy_at(get(index)); - mask.clear(index); - } - }; - - IdMapChunk chunks[ChunkCount]{}; - BitSet fullChunks; - - template - requires(std::is_constructible_v) - std::pair emplace(ArgsT &&...args) { - auto page = fullChunks.countr_one(); - - if (page == ChunkCount) { - return {}; - } - - auto newElem = chunks[page].emplace_new(std::forward(args)...); - - if (chunks[page].mask.full()) { - fullChunks.set(page); - } - - return {static_cast(page * ChunkSize + newElem.first + MinId), - newElem.second}; - } - - T *get(IdT id) { - const auto rawId = static_cast(id) - MinId; - const auto chunk = rawId / ChunkSize; - const auto index = rawId % ChunkSize; - - if (chunk >= ChunkCount) { - return nullptr; - } - - if (!chunks[chunk].mask.test(index)) { - return nullptr; - } - - return chunks[chunk].get(index); - } - - bool destroy(IdT id) { - const auto rawId = static_cast(id) - MinId; - const auto chunk = rawId / ChunkSize; - const auto index = rawId % ChunkSize; - - if (chunk >= ChunkCount) { - return false; - } - - if (!chunks[chunk].mask.test(index)) { - return false; - } - - chunks[chunk].destroy(index); - fullChunks.clear(chunk); - return true; - } - - void walk(auto cb) { - for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) { - std::size_t index = chunks[chunk].mask.countr_zero(); - - while (index < ChunkSize) { - auto id = static_cast(index + chunk * ChunkSize + MinId); - cb(id, chunks[chunk].get(id)); - - index = chunks[chunk].mask.countr_zero(index + 1); - } - } - } -}; -} // namespace utils + m_chunks[chunk].get(index)->destroy(); + m_chunks[chunk].remove(index); + m_fullChunks.clear(chunk); + return true; + } + + bool close(IdT id) + { + const auto rawId = static_cast(id) - MinId; + + if (rawId >= MaxId - MinId) + { + return false; + } + + const auto chunk = rawId / ChunkSize; + const auto index = rawId % ChunkSize; + + std::lock_guard lock(mutex); + + if (!m_chunks[chunk].mask.test(index)) + { + return false; + } + + m_chunks[chunk].remove(index); + m_fullChunks.clear(chunk); + return true; + } + + [[deprecated("use close()")]] bool remove(IdT id) { return close(id); } + }; + + template + requires(MaxId > MinId) struct OwningIdMap + { + static constexpr auto ChunkSize = std::min(MaxId - MinId, 64); + static constexpr auto ChunkCount = + (MaxId - MinId + ChunkSize - 1) / ChunkSize; + + struct IdMapChunk + { + BitSet mask = {}; + alignas(T) std::byte objects[sizeof(T) * ChunkSize]; + + ~IdMapChunk() + { + std::size_t pageOffset = 0; + + for (auto page : mask._bits) + { + auto tmp = page; + + while (true) + { + const auto index = std::countr_zero(tmp); + + if (index >= 64) + { + break; + } + + tmp &= ~(static_cast(1) << index); + destroy(pageOffset + index); + } + + pageOffset += 64; + } + } + + template + std::pair emplace_new(ArgsT&&... args) + { + std::size_t index = mask.countr_one(); + + if (index >= ChunkSize) + { + return {}; + } + + mask.set(index); + + return {index, + std::construct_at(get(index), std::forward(args)...)}; + } + + T* get(std::size_t index) + { + return reinterpret_cast(objects + sizeof(T) * index); + } + + void destroy(std::size_t index) + { + std::destroy_at(get(index)); + mask.clear(index); + } + }; + + IdMapChunk chunks[ChunkCount]{}; + BitSet fullChunks; + + template + requires(std::is_constructible_v) + std::pair emplace(ArgsT&&... args) + { + auto page = fullChunks.countr_one(); + + if (page == ChunkCount) + { + return {}; + } + + auto newElem = chunks[page].emplace_new(std::forward(args)...); + + if (chunks[page].mask.full()) + { + fullChunks.set(page); + } + + return {static_cast(page * ChunkSize + newElem.first + MinId), + newElem.second}; + } + + T* get(IdT id) + { + const auto rawId = static_cast(id) - MinId; + const auto chunk = rawId / ChunkSize; + const auto index = rawId % ChunkSize; + + if (chunk >= ChunkCount) + { + return nullptr; + } + + if (!chunks[chunk].mask.test(index)) + { + return nullptr; + } + + return chunks[chunk].get(index); + } + + bool destroy(IdT id) + { + const auto rawId = static_cast(id) - MinId; + const auto chunk = rawId / ChunkSize; + const auto index = rawId % ChunkSize; + + if (chunk >= ChunkCount) + { + return false; + } + + if (!chunks[chunk].mask.test(index)) + { + return false; + } + + chunks[chunk].destroy(index); + fullChunks.clear(chunk); + return true; + } + + void walk(auto cb) + { + for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) + { + std::size_t index = chunks[chunk].mask.countr_zero(); + + while (index < ChunkSize) + { + auto id = static_cast(index + chunk * ChunkSize + MinId); + cb(id, chunks[chunk].get(id)); + + index = chunks[chunk].mask.countr_zero(index + 1); + } + } + } + }; + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/LinkedNode.hpp b/orbis-kernel/include/orbis/utils/LinkedNode.hpp index f2c005f4..015783ad 100644 --- a/orbis-kernel/include/orbis/utils/LinkedNode.hpp +++ b/orbis-kernel/include/orbis/utils/LinkedNode.hpp @@ -1,48 +1,59 @@ #pragma once -namespace orbis { -inline namespace utils { -template struct LinkedNode final { - T object; - LinkedNode *next = nullptr; - LinkedNode *prev = nullptr; - - void insertNext(LinkedNode &other) { - other.next = next; - other.prev = this; - - if (next != nullptr) { - next->prev = &other; - } - - next = &other; - } - - void insertPrev(LinkedNode &other) { - other.next = this; - other.prev = prev; - - if (prev != nullptr) { - prev->next = &other; - } - - prev = &other; - } - - LinkedNode *erase() { - if (prev != nullptr) { - prev->next = next; - } - - if (next != nullptr) { - next->prev = prev; - } - - prev = nullptr; - auto result = next; - next = nullptr; - return result; - } -}; -} // namespace utils +namespace orbis +{ + inline namespace utils + { + template + struct LinkedNode final + { + T object; + LinkedNode* next = nullptr; + LinkedNode* prev = nullptr; + + void insertNext(LinkedNode& other) + { + other.next = next; + other.prev = this; + + if (next != nullptr) + { + next->prev = &other; + } + + next = &other; + } + + void insertPrev(LinkedNode& other) + { + other.next = this; + other.prev = prev; + + if (prev != nullptr) + { + prev->next = &other; + } + + prev = &other; + } + + LinkedNode* erase() + { + if (prev != nullptr) + { + prev->next = next; + } + + if (next != nullptr) + { + next->prev = prev; + } + + prev = nullptr; + auto result = next; + next = nullptr; + return result; + } + }; + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/Logs.hpp b/orbis-kernel/include/orbis/utils/Logs.hpp index 94217c9a..173e5759 100644 --- a/orbis-kernel/include/orbis/utils/Logs.hpp +++ b/orbis-kernel/include/orbis/utils/Logs.hpp @@ -2,126 +2,160 @@ #include #include -namespace orbis { -inline namespace logs { -enum class LogLevel : unsigned char { - Always, - Fatal, - Error, - Todo, - Success, - Warning, - Notice, - Trace -}; - -// Currently enabled log level -inline std::atomic logs_level = LogLevel::Notice; - -template struct log_class_string { - static const T &get_object(const void *arg) { - return *static_cast(arg); - } - static void format(std::string &out, const void *arg); -}; - -template <> struct log_class_string { - static void format(std::string &out, const void *arg); -}; - -template -struct log_class_string : log_class_string {}; - -template <> struct log_class_string { - static void format_n(std::string &out, const void *str, std::size_t n); - static void format(std::string &out, const void *arg); -}; - -template <> -struct log_class_string : log_class_string {}; - -template struct log_class_string { - static void format(std::string &out, const void *arg) { - log_class_string::format_n(out, arg, N); - } -}; - -template struct log_class_string { - static void format(std::string &out, const void *arg) { - log_class_string::format_n(out, arg, N); - } -}; - -template struct log_class_string { - static void format(std::string &out, const void *arg) { - log_class_string::format_n(out, *(char **)arg, N); - } -}; - -template struct log_class_string { - static void format(std::string &out, const void *arg) { - log_class_string::format_n(out, *(char **)arg, N); - } -}; - -template <> -struct log_class_string : log_class_string {}; - -template <> -struct log_class_string : log_class_string {}; - -template -using log_args_t = const void *(&&)[sizeof...(Args) + 1]; - -struct log_type_info { - decltype(&log_class_string::format) log_string; - - template static constexpr log_type_info make() { - return log_type_info{ - &log_class_string::format, - }; - } -}; - -template -constexpr const log_type_info type_info_v[sizeof...(Args) + 1]{ - log_type_info::make>()...}; - -void _orbis_log_print(LogLevel lvl, std::string_view msg, - std::string_view names, const log_type_info *sup, ...); - -template -void _orbis_log_impl(LogLevel lvl, std::string_view msg, std::string_view names, - const Args &...args) { - // Fast filtering - if (logs_level.load(std::memory_order::relaxed) < lvl) - return; - - _orbis_log_print(lvl, msg, names, type_info_v, - static_cast(&args)...); -} - -} // namespace logs +namespace orbis +{ + inline namespace logs + { + enum class LogLevel : unsigned char + { + Always, + Fatal, + Error, + Todo, + Success, + Warning, + Notice, + Trace + }; + + // Currently enabled log level + inline std::atomic logs_level = LogLevel::Notice; + + template + struct log_class_string + { + static const T& get_object(const void* arg) + { + return *static_cast(arg); + } + static void format(std::string& out, const void* arg); + }; + + template <> + struct log_class_string + { + static void format(std::string& out, const void* arg); + }; + + template + struct log_class_string : log_class_string + { + }; + + template <> + struct log_class_string + { + static void format_n(std::string& out, const void* str, std::size_t n); + static void format(std::string& out, const void* arg); + }; + + template <> + struct log_class_string : log_class_string + { + }; + + template + struct log_class_string + { + static void format(std::string& out, const void* arg) + { + log_class_string::format_n(out, arg, N); + } + }; + + template + struct log_class_string + { + static void format(std::string& out, const void* arg) + { + log_class_string::format_n(out, arg, N); + } + }; + + template + struct log_class_string + { + static void format(std::string& out, const void* arg) + { + log_class_string::format_n(out, *(char**)arg, N); + } + }; + + template + struct log_class_string + { + static void format(std::string& out, const void* arg) + { + log_class_string::format_n(out, *(char**)arg, N); + } + }; + + template <> + struct log_class_string : log_class_string + { + }; + + template <> + struct log_class_string : log_class_string + { + }; + + template + using log_args_t = const void* (&&)[sizeof...(Args) + 1]; + + struct log_type_info + { + decltype(&log_class_string::format) log_string; + + template + static constexpr log_type_info make() + { + return log_type_info{ + &log_class_string::format, + }; + } + }; + + template + constexpr const log_type_info type_info_v[sizeof...(Args) + 1]{ + log_type_info::make>()...}; + + void _orbis_log_print(LogLevel lvl, std::string_view msg, + std::string_view names, const log_type_info* sup, ...); + + template + void _orbis_log_impl(LogLevel lvl, std::string_view msg, std::string_view names, + const Args&... args) + { + // Fast filtering + if (logs_level.load(std::memory_order::relaxed) < lvl) + return; + + _orbis_log_print(lvl, msg, names, type_info_v, + static_cast(&args)...); + } + + } // namespace logs } // namespace orbis -#define ORBIS_LOG_FATAL(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Fatal, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_ERROR(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Error, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_TODO(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Todo, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_SUCCESS(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Success, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_WARNING(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Warning, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_NOTICE(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Notice, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) -#define ORBIS_LOG_TRACE(msg, ...) \ - ::orbis::_orbis_log_impl(::orbis::LogLevel::Trace, (msg), #__VA_ARGS__, \ - ##__VA_ARGS__) +#define ORBIS_LOG_FATAL(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Fatal, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_ERROR(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Error, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_TODO(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Todo, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_SUCCESS(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Success, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_WARNING(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Warning, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_NOTICE(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Notice, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) +#define ORBIS_LOG_TRACE(msg, ...) \ + ::orbis::_orbis_log_impl(::orbis::LogLevel::Trace, (msg), #__VA_ARGS__, \ + ##__VA_ARGS__) diff --git a/orbis-kernel/include/orbis/utils/Rc.hpp b/orbis-kernel/include/orbis/utils/Rc.hpp index f728b849..d6ac8790 100644 --- a/orbis-kernel/include/orbis/utils/Rc.hpp +++ b/orbis-kernel/include/orbis/utils/Rc.hpp @@ -6,130 +6,165 @@ #include #include -namespace orbis { -// template T *knew(Args &&...args); -inline namespace utils { -void kfree(void *ptr, std::size_t size); - -struct RcBase { - std::atomic references{0}; - unsigned _total_size = 0; // Set by knew/kcreate - - virtual ~RcBase() = default; - - void incRef() { - if (!_total_size) - std::abort(); - if (references.fetch_add(1, std::memory_order::relaxed) > 512) { - assert(!"too many references"); - } - } - - // returns true if object was destroyed - bool decRef() { - if (references.fetch_sub(1, std::memory_order::relaxed) == 1) { - auto size = _total_size; - this->~RcBase(); - orbis::utils::kfree(this, size); - return true; - } - - return false; - } -}; - -template -concept WithRc = requires(T t) { - t.incRef(); - t.decRef(); -}; - -template class Ref { - T *m_ref = nullptr; - -public: - Ref() = default; - Ref(std::nullptr_t) {} - - template - requires(std::is_base_of_v) - Ref(OT *ref) : m_ref(ref) { - if (m_ref != nullptr) { - ref->incRef(); - } - } - - template - requires(std::is_base_of_v) - Ref(const Ref &other) : m_ref(other.get()) { - if (m_ref != nullptr) { - m_ref->incRef(); - } - } - - template - requires(std::is_base_of_v) - Ref(Ref &&other) : m_ref(other.release()) {} - - Ref(const Ref &other) : m_ref(other.get()) { - if (m_ref != nullptr) { - m_ref->incRef(); - } - } - Ref(Ref &&other) : m_ref(other.release()) {} - - template - requires(std::is_base_of_v) - Ref &operator=(Ref &&other) { - other.swap(*this); - return *this; - } - - template - requires(std::is_base_of_v) - Ref &operator=(OT *other) { - *this = Ref(other); - return *this; - } - - template - requires(std::is_base_of_v) - Ref &operator=(const Ref &other) { - *this = Ref(other); - return *this; - } - - Ref &operator=(const Ref &other) { - *this = Ref(other); - return *this; - } - - Ref &operator=(Ref &&other) { - other.swap(*this); - return *this; - } - - ~Ref() { - if (m_ref != nullptr) { - m_ref->decRef(); - } - } - - void swap(Ref &other) { std::swap(m_ref, other.m_ref); } - T *get() const { return m_ref; } - T *release() { return std::exchange(m_ref, nullptr); } - T *operator->() const { return m_ref; } - explicit operator bool() const { return m_ref != nullptr; } - bool operator==(const Ref &) const = default; - bool operator==(std::nullptr_t) const { return m_ref == nullptr; } - auto operator<=>(const T *other) const { return m_ref <=> other; } - auto operator<=>(const Ref &other) const = default; -}; - -// template -// requires(std::is_constructible_v) -// Ref kcreate(ArgsT &&...args) { -// return Ref(knew(std::forward(args)...)); -// } -} // namespace utils +namespace orbis +{ + // template T *knew(Args &&...args); + inline namespace utils + { + void kfree(void* ptr, std::size_t size); + + struct RcBase + { + std::atomic references{0}; + unsigned _total_size = 0; // Set by knew/kcreate + + virtual ~RcBase() = default; + + void incRef() + { + if (!_total_size) + std::abort(); + if (references.fetch_add(1, std::memory_order::relaxed) > 512) + { + assert(!"too many references"); + } + } + + // returns true if object was destroyed + bool decRef() + { + if (references.fetch_sub(1, std::memory_order::relaxed) == 1) + { + auto size = _total_size; + this->~RcBase(); + orbis::utils::kfree(this, size); + return true; + } + + return false; + } + }; + + template + concept WithRc = requires(T t) + { + t.incRef(); + t.decRef(); + }; + + template + class Ref + { + T* m_ref = nullptr; + + public: + Ref() = default; + Ref(std::nullptr_t) {} + + template + requires(std::is_base_of_v) + Ref(OT* ref) + : m_ref(ref) + { + if (m_ref != nullptr) + { + ref->incRef(); + } + } + + template + requires(std::is_base_of_v) + Ref(const Ref& other) + : m_ref(other.get()) + { + if (m_ref != nullptr) + { + m_ref->incRef(); + } + } + + template + requires(std::is_base_of_v) + Ref(Ref&& other) + : m_ref(other.release()) + { + } + + Ref(const Ref& other) + : m_ref(other.get()) + { + if (m_ref != nullptr) + { + m_ref->incRef(); + } + } + Ref(Ref&& other) + : m_ref(other.release()) + { + } + + template + requires(std::is_base_of_v) + Ref& + operator=(Ref&& other) + { + other.swap(*this); + return *this; + } + + template + requires(std::is_base_of_v) + Ref& + operator=(OT* other) + { + *this = Ref(other); + return *this; + } + + template + requires(std::is_base_of_v) + Ref& + operator=(const Ref& other) + { + *this = Ref(other); + return *this; + } + + Ref& operator=(const Ref& other) + { + *this = Ref(other); + return *this; + } + + Ref& operator=(Ref&& other) + { + other.swap(*this); + return *this; + } + + ~Ref() + { + if (m_ref != nullptr) + { + m_ref->decRef(); + } + } + + void swap(Ref& other) { std::swap(m_ref, other.m_ref); } + T* get() const { return m_ref; } + T* release() { return std::exchange(m_ref, nullptr); } + T* operator->() const { return m_ref; } + explicit operator bool() const { return m_ref != nullptr; } + bool operator==(const Ref&) const = default; + bool operator==(std::nullptr_t) const { return m_ref == nullptr; } + auto operator<=>(const T* other) const { return m_ref <=> other; } + auto operator<=>(const Ref& other) const = default; + }; + + // template + // requires(std::is_constructible_v) + // Ref kcreate(ArgsT &&...args) { + // return Ref(knew(std::forward(args)...)); + // } + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/SharedCV.hpp b/orbis-kernel/include/orbis/utils/SharedCV.hpp index c75e9048..cd23f3c5 100644 --- a/orbis-kernel/include/orbis/utils/SharedCV.hpp +++ b/orbis-kernel/include/orbis/utils/SharedCV.hpp @@ -4,68 +4,80 @@ #include #include -namespace orbis { -inline namespace utils { -// IPC-ready lightweight condition variable -class shared_cv { - enum : unsigned { - c_waiter_mask = 0xffff, - c_signal_mask = 0x7fff0000, - c_locked_mask = 0x80000000, - c_signal_one = c_waiter_mask + 1, - }; +namespace orbis +{ + inline namespace utils + { + // IPC-ready lightweight condition variable + class shared_cv + { + enum : unsigned + { + c_waiter_mask = 0xffff, + c_signal_mask = 0x7fff0000, + c_locked_mask = 0x80000000, + c_signal_one = c_waiter_mask + 1, + }; - std::atomic m_value{0}; + std::atomic m_value{0}; -protected: - // Increment waiter count - unsigned add_waiter() noexcept { - return atomic_op(m_value, [](unsigned &value) -> unsigned { - if ((value & c_signal_mask) == c_signal_mask || - (value & c_waiter_mask) == c_waiter_mask) { - // Signal or waiter overflow, return immediately - return 0; - } + protected: + // Increment waiter count + unsigned add_waiter() noexcept + { + return atomic_op(m_value, [](unsigned& value) -> unsigned { + if ((value & c_signal_mask) == c_signal_mask || + (value & c_waiter_mask) == c_waiter_mask) + { + // Signal or waiter overflow, return immediately + return 0; + } - // Add waiter (c_waiter_mask) - value += 1; - return value; - }); - } + // Add waiter (c_waiter_mask) + value += 1; + return value; + }); + } - // Internal waiting function - void impl_wait(shared_mutex &mutex, unsigned _val, - std::uint64_t usec_timeout) noexcept; + // Internal waiting function + void impl_wait(shared_mutex& mutex, unsigned _val, + std::uint64_t usec_timeout) noexcept; - // Try to notify up to _count threads - void impl_wake(shared_mutex &mutex, int _count) noexcept; + // Try to notify up to _count threads + void impl_wake(shared_mutex& mutex, int _count) noexcept; -public: - constexpr shared_cv() = default; + public: + constexpr shared_cv() = default; - void wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept { - const unsigned _val = add_waiter(); - if (!_val) { - return; - } + void wait(shared_mutex& mutex, std::uint64_t usec_timeout = -1) noexcept + { + const unsigned _val = add_waiter(); + if (!_val) + { + return; + } - mutex.unlock(); - impl_wait(mutex, _val, usec_timeout); - } + mutex.unlock(); + impl_wait(mutex, _val, usec_timeout); + } - // Wake one thread - void notify_one(shared_mutex &mutex) noexcept { - if (m_value) { - impl_wake(mutex, 1); - } - } + // Wake one thread + void notify_one(shared_mutex& mutex) noexcept + { + if (m_value) + { + impl_wake(mutex, 1); + } + } - // Wake all threads - void notify_all(shared_mutex &mutex) noexcept { - if (m_value) { - impl_wake(mutex, INT_MAX); - } - } -}; -} // namespace utils + // Wake all threads + void notify_all(shared_mutex& mutex) noexcept + { + if (m_value) + { + impl_wake(mutex, INT_MAX); + } + } + }; + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/SharedMutex.hpp b/orbis-kernel/include/orbis/utils/SharedMutex.hpp index d96fa8c8..97e1c94d 100644 --- a/orbis-kernel/include/orbis/utils/SharedMutex.hpp +++ b/orbis-kernel/include/orbis/utils/SharedMutex.hpp @@ -4,147 +4,177 @@ #include #include -namespace orbis { -inline namespace utils { -// IPC-ready shared mutex, using only writer lock is recommended -class shared_mutex final { - friend class shared_cv; - - enum : unsigned { - c_one = 1u << 14, // Fixed-point 1.0 value (one writer) - c_sig = 1u << 30, - c_err = 1u << 31, - }; - - std::atomic m_value{}; - - void impl_lock_shared(unsigned val); - void impl_unlock_shared(unsigned old); - void impl_wait(); - void impl_signal(); - void impl_lock(unsigned val); - void impl_unlock(unsigned old); - void impl_lock_upgrade(); - -public: - constexpr shared_mutex() = default; - - bool try_lock_shared() { - // Conditional increment - unsigned value = m_value.load(); - return value < c_one - 1 && - m_value.compare_exchange_strong(value, value + 1); - } - - // Lock with HLE acquire hint - void lock_shared() { - unsigned value = m_value.load(); - if (value < c_one - 1) [[likely]] { - unsigned old = value; - if (compare_exchange_hle_acq(m_value, old, value + 1)) [[likely]] { - return; - } - } - - impl_lock_shared(value + 1); - } - - // Unlock with HLE release hint - void unlock_shared() { - const unsigned value = fetch_add_hle_rel(m_value, -1u); - if (value >= c_one) [[unlikely]] { - impl_unlock_shared(value); - } - } - - bool try_lock() { - unsigned value = 0; - return m_value.compare_exchange_strong(value, c_one); - } - - // Lock with HLE acquire hint - void lock() { - unsigned value = 0; - if (!compare_exchange_hle_acq(m_value, value, +c_one)) [[unlikely]] { - impl_lock(value); - } - } - - // Unlock with HLE release hint - void unlock() { - const unsigned value = fetch_add_hle_rel(m_value, 0u - c_one); - if (value != c_one) [[unlikely]] { - impl_unlock(value); - } - } - - bool try_lock_upgrade() { - unsigned value = m_value.load(); - - // Conditional increment, try to convert a single reader into a writer, - // ignoring other writers - return (value + c_one - 1) % c_one == 0 && - m_value.compare_exchange_strong(value, value + c_one - 1); - } - - void lock_upgrade() { - if (!try_lock_upgrade()) [[unlikely]] { - impl_lock_upgrade(); - } - } - - void lock_downgrade() { - // Convert to reader lock (can result in broken state) - m_value -= c_one - 1; - } - - // Check whether can immediately obtain an exclusive (writer) lock - bool is_free() const { return m_value.load() == 0; } - - // Check whether can immediately obtain a shared (reader) lock - bool is_lockable() const { return m_value.load() < c_one - 1; } - -private: - // For CV - bool lock_forced(int count = 1); -}; - -// Simplified shared (reader) lock implementation. -class reader_lock final { - shared_mutex &m_mutex; - bool m_upgraded = false; - -public: - reader_lock(const reader_lock &) = delete; - reader_lock &operator=(const reader_lock &) = delete; - explicit reader_lock(shared_mutex &mutex) : m_mutex(mutex) { - m_mutex.lock_shared(); - } - - // One-way lock upgrade; note that the observed state could have been changed - void upgrade() { - if (!m_upgraded) { - m_mutex.lock_upgrade(); - m_upgraded = true; - } - } - - // Try to upgrade; if it succeeds, the observed state has NOT been changed - bool try_upgrade() { - return m_upgraded || (m_upgraded = m_mutex.try_lock_upgrade()); - } - - ~reader_lock() { m_upgraded ? m_mutex.unlock() : m_mutex.unlock_shared(); } -}; - -class writer_lock final { - shared_mutex &m_mutex; - -public: - writer_lock(const writer_lock &) = delete; - writer_lock &operator=(const writer_lock &) = delete; - explicit writer_lock(shared_mutex &mutex) : m_mutex(mutex) { m_mutex.lock(); } - ~writer_lock() { m_mutex.unlock(); } -}; -} // namespace utils +namespace orbis +{ + inline namespace utils + { + // IPC-ready shared mutex, using only writer lock is recommended + class shared_mutex final + { + friend class shared_cv; + + enum : unsigned + { + c_one = 1u << 14, // Fixed-point 1.0 value (one writer) + c_sig = 1u << 30, + c_err = 1u << 31, + }; + + std::atomic m_value{}; + + void impl_lock_shared(unsigned val); + void impl_unlock_shared(unsigned old); + void impl_wait(); + void impl_signal(); + void impl_lock(unsigned val); + void impl_unlock(unsigned old); + void impl_lock_upgrade(); + + public: + constexpr shared_mutex() = default; + + bool try_lock_shared() + { + // Conditional increment + unsigned value = m_value.load(); + return value < c_one - 1 && + m_value.compare_exchange_strong(value, value + 1); + } + + // Lock with HLE acquire hint + void lock_shared() + { + unsigned value = m_value.load(); + if (value < c_one - 1) [[likely]] + { + unsigned old = value; + if (compare_exchange_hle_acq(m_value, old, value + 1)) [[likely]] + { + return; + } + } + + impl_lock_shared(value + 1); + } + + // Unlock with HLE release hint + void unlock_shared() + { + const unsigned value = fetch_add_hle_rel(m_value, -1u); + if (value >= c_one) [[unlikely]] + { + impl_unlock_shared(value); + } + } + + bool try_lock() + { + unsigned value = 0; + return m_value.compare_exchange_strong(value, c_one); + } + + // Lock with HLE acquire hint + void lock() + { + unsigned value = 0; + if (!compare_exchange_hle_acq(m_value, value, +c_one)) [[unlikely]] + { + impl_lock(value); + } + } + + // Unlock with HLE release hint + void unlock() + { + const unsigned value = fetch_add_hle_rel(m_value, 0u - c_one); + if (value != c_one) [[unlikely]] + { + impl_unlock(value); + } + } + + bool try_lock_upgrade() + { + unsigned value = m_value.load(); + + // Conditional increment, try to convert a single reader into a writer, + // ignoring other writers + return (value + c_one - 1) % c_one == 0 && + m_value.compare_exchange_strong(value, value + c_one - 1); + } + + void lock_upgrade() + { + if (!try_lock_upgrade()) [[unlikely]] + { + impl_lock_upgrade(); + } + } + + void lock_downgrade() + { + // Convert to reader lock (can result in broken state) + m_value -= c_one - 1; + } + + // Check whether can immediately obtain an exclusive (writer) lock + bool is_free() const { return m_value.load() == 0; } + + // Check whether can immediately obtain a shared (reader) lock + bool is_lockable() const { return m_value.load() < c_one - 1; } + + private: + // For CV + bool lock_forced(int count = 1); + }; + + // Simplified shared (reader) lock implementation. + class reader_lock final + { + shared_mutex& m_mutex; + bool m_upgraded = false; + + public: + reader_lock(const reader_lock&) = delete; + reader_lock& operator=(const reader_lock&) = delete; + explicit reader_lock(shared_mutex& mutex) + : m_mutex(mutex) + { + m_mutex.lock_shared(); + } + + // One-way lock upgrade; note that the observed state could have been changed + void upgrade() + { + if (!m_upgraded) + { + m_mutex.lock_upgrade(); + m_upgraded = true; + } + } + + // Try to upgrade; if it succeeds, the observed state has NOT been changed + bool try_upgrade() + { + return m_upgraded || (m_upgraded = m_mutex.try_lock_upgrade()); + } + + ~reader_lock() { m_upgraded ? m_mutex.unlock() : m_mutex.unlock_shared(); } + }; + + class writer_lock final + { + shared_mutex& m_mutex; + + public: + writer_lock(const writer_lock&) = delete; + writer_lock& operator=(const writer_lock&) = delete; + explicit writer_lock(shared_mutex& mutex) + : m_mutex(mutex) + { + m_mutex.lock(); + } + ~writer_lock() { m_mutex.unlock(); } + }; + } // namespace utils } // namespace orbis diff --git a/orbis-kernel/include/orbis/vm.hpp b/orbis-kernel/include/orbis/vm.hpp index 8e55bc27..041a4263 100644 --- a/orbis-kernel/include/orbis/vm.hpp +++ b/orbis-kernel/include/orbis/vm.hpp @@ -2,12 +2,14 @@ #include "orbis-config.hpp" -namespace orbis { -struct MemoryProtection { - uint64_t startAddress; - uint64_t endAddress; - int32_t prot; -}; +namespace orbis +{ + struct MemoryProtection + { + uint64_t startAddress; + uint64_t endAddress; + int32_t prot; + }; -static_assert(sizeof(MemoryProtection) == 24); + static_assert(sizeof(MemoryProtection) == 24); } // namespace orbis diff --git a/orbis-kernel/src/KernelContext.cpp b/orbis-kernel/src/KernelContext.cpp index d90e4a29..3d4d7044 100644 --- a/orbis-kernel/src/KernelContext.cpp +++ b/orbis-kernel/src/KernelContext.cpp @@ -5,209 +5,235 @@ #include #include -namespace orbis { -KernelContext &g_context = *[]() -> KernelContext * { - // Allocate global shared kernel memory - // TODO: randomize for hardening and reduce size - auto ptr = mmap(reinterpret_cast(0x200'0000'0000), 0x1'0000'0000, - PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); - if (!ptr) - std::abort(); - - return new (ptr) KernelContext; -}(); - -KernelContext::KernelContext() { - // Initialize recursive heap mutex - pthread_mutexattr_t mtx_attr; - pthread_mutexattr_init(&mtx_attr); - pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutexattr_setpshared(&mtx_attr, PTHREAD_PROCESS_SHARED); - pthread_mutex_init(&m_heap_mtx, &mtx_attr); - pthread_mutexattr_destroy(&mtx_attr); - - std::printf("orbis::KernelContext initialized, addr=%p\n", this); - std::printf("TSC frequency: %lu\n", getTscFreq()); -} -KernelContext::~KernelContext() {} - -Process *KernelContext::createProcess(pid_t pid) { - auto newProcess = knew>(); - newProcess->object.context = this; - newProcess->object.pid = pid; - newProcess->object.state = ProcessState::NEW; - - { - std::lock_guard lock(m_proc_mtx); - if (m_processes != nullptr) { - m_processes->insertPrev(*newProcess); - } - - m_processes = newProcess; - } - - return &newProcess->object; -} - -void KernelContext::deleteProcess(Process *proc) { - auto procNode = reinterpret_cast *>(proc); - auto pid = proc->pid; - - { - std::lock_guard lock(m_proc_mtx); - auto next = procNode->erase(); - - if (procNode == m_processes) { - m_processes = next; - } - } - - kdelete(procNode); -} - -Process *KernelContext::findProcessById(pid_t pid) const { - std::lock_guard lock(m_proc_mtx); - for (auto proc = m_processes; proc != nullptr; proc = proc->next) { - if (proc->object.pid == pid) { - return &proc->object; - } - } - - return nullptr; -} - -long KernelContext::getTscFreq() { - auto cal_tsc = []() -> long { - const long timer_freq = 1'000'000'000; - - // Calibrate TSC - constexpr int samples = 40; - long rdtsc_data[samples]; - long timer_data[samples]; - long error_data[samples]; - - struct ::timespec ts0; - clock_gettime(CLOCK_MONOTONIC, &ts0); - long sec_base = ts0.tv_sec; - - for (int i = 0; i < samples; i++) { - usleep(200); - error_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc()); - struct ::timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - rdtsc_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc()); - timer_data[i] = ts.tv_nsec + (ts.tv_sec - sec_base) * 1'000'000'000; - } - - // Compute average TSC - long acc = 0; - for (int i = 0; i < samples - 1; i++) { - acc += (rdtsc_data[i + 1] - rdtsc_data[i]) * timer_freq / - (timer_data[i + 1] - timer_data[i]); - } - - // Rounding - acc /= (samples - 1); - constexpr long grain = 1'000'000; - return grain * (acc / grain + long{(acc % grain) > (grain / 2)}); - }; - - long freq = m_tsc_freq.load(); - if (freq) - return freq; - m_tsc_freq.compare_exchange_strong(freq, cal_tsc()); - return m_tsc_freq.load(); -} - -void *KernelContext::kalloc(std::size_t size, std::size_t align) { - size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) & - ~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1); - if (!size) - std::abort(); - - pthread_mutex_lock(&m_heap_mtx); - if (!m_heap_is_freeing) { - // Try to reuse previously freed block - for (auto [it, end] = m_free_heap.equal_range(size); it != end; it++) { - auto result = it->second; - if (!(reinterpret_cast(result) & (align - 1))) { - auto node = m_free_heap.extract(it); - node.key() = 0; - node.mapped() = nullptr; - m_used_node.insert(m_used_node.begin(), std::move(node)); - pthread_mutex_unlock(&m_heap_mtx); - return result; - } - } - } - - align = std::max(align, __STDCPP_DEFAULT_NEW_ALIGNMENT__); - auto heap = reinterpret_cast(m_heap_next); - heap = (heap + (align - 1)) & ~(align - 1); - auto result = reinterpret_cast(heap); - m_heap_next = reinterpret_cast(heap + size); - // Check overflow - if (heap + size < heap) - std::abort(); - if (heap + size > (uintptr_t)&g_context + 0x1'0000'0000) - std::abort(); - pthread_mutex_unlock(&m_heap_mtx); - return result; -} - -void KernelContext::kfree(void *ptr, std::size_t size) { - size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) & - ~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1); - if (!size) - std::abort(); - std::memset(ptr, 0xcc, size); - - pthread_mutex_lock(&m_heap_mtx); - if (m_heap_is_freeing) - std::abort(); - m_heap_is_freeing = true; - if (!m_used_node.empty()) { - auto node = m_used_node.extract(m_used_node.begin()); - node.key() = size; - node.mapped() = ptr; - m_free_heap.insert(std::move(node)); - } else { - m_free_heap.emplace(size, ptr); - } - m_heap_is_freeing = false; - pthread_mutex_unlock(&m_heap_mtx); -} - -std::tuple> -KernelContext::getUmtxChainIndexed(int i, Thread *t, uint32_t flags, - void *ptr) { - auto pid = t->tproc->pid; - if (flags & 1) { - pid = 0; // Process shared (TODO) - ORBIS_LOG_WARNING("Using process-shared umtx", t->tid, ptr); - } - auto p = reinterpret_cast(ptr); - auto n = p + pid; - if (flags & 1) - n %= 0x4000; - n = ((n * c_golden_ratio_prime) >> c_umtx_shifts) % c_umtx_chains; - std::unique_lock lock(m_umtx_chains[i][n].mtx); - return {m_umtx_chains[i][n], UmtxKey{p, pid}, std::move(lock)}; -} - -inline namespace utils { -void kfree(void *ptr, std::size_t size) { return g_context.kfree(ptr, size); } -void *kalloc(std::size_t size, std::size_t align) { - return g_context.kalloc(size, align); -} -} // namespace utils - -inline namespace logs { -template <> -void log_class_string::format(std::string &out, const void *arg) { - out += get_object(arg); -} -} // namespace logs - -void Thread::where() { tproc->ops->where(this); } +namespace orbis +{ + KernelContext& g_context = *[]() -> KernelContext* { + // Allocate global shared kernel memory + // TODO: randomize for hardening and reduce size + auto ptr = mmap(reinterpret_cast(0x200'0000'0000), 0x1'0000'0000, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); + if (!ptr) + std::abort(); + + return new (ptr) KernelContext; + }(); + + KernelContext::KernelContext() + { + // Initialize recursive heap mutex + pthread_mutexattr_t mtx_attr; + pthread_mutexattr_init(&mtx_attr); + pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutexattr_setpshared(&mtx_attr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(&m_heap_mtx, &mtx_attr); + pthread_mutexattr_destroy(&mtx_attr); + + std::printf("orbis::KernelContext initialized, addr=%p\n", this); + std::printf("TSC frequency: %lu\n", getTscFreq()); + } + KernelContext::~KernelContext() {} + + Process* KernelContext::createProcess(pid_t pid) + { + auto newProcess = knew>(); + newProcess->object.context = this; + newProcess->object.pid = pid; + newProcess->object.state = ProcessState::NEW; + + { + std::lock_guard lock(m_proc_mtx); + if (m_processes != nullptr) + { + m_processes->insertPrev(*newProcess); + } + + m_processes = newProcess; + } + + return &newProcess->object; + } + + void KernelContext::deleteProcess(Process* proc) + { + auto procNode = reinterpret_cast*>(proc); + auto pid = proc->pid; + + { + std::lock_guard lock(m_proc_mtx); + auto next = procNode->erase(); + + if (procNode == m_processes) + { + m_processes = next; + } + } + + kdelete(procNode); + } + + Process* KernelContext::findProcessById(pid_t pid) const + { + std::lock_guard lock(m_proc_mtx); + for (auto proc = m_processes; proc != nullptr; proc = proc->next) + { + if (proc->object.pid == pid) + { + return &proc->object; + } + } + + return nullptr; + } + + long KernelContext::getTscFreq() + { + auto cal_tsc = []() -> long { + const long timer_freq = 1'000'000'000; + + // Calibrate TSC + constexpr int samples = 40; + long rdtsc_data[samples]; + long timer_data[samples]; + long error_data[samples]; + + struct ::timespec ts0; + clock_gettime(CLOCK_MONOTONIC, &ts0); + long sec_base = ts0.tv_sec; + + for (int i = 0; i < samples; i++) + { + usleep(200); + error_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc()); + struct ::timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + rdtsc_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc()); + timer_data[i] = ts.tv_nsec + (ts.tv_sec - sec_base) * 1'000'000'000; + } + + // Compute average TSC + long acc = 0; + for (int i = 0; i < samples - 1; i++) + { + acc += (rdtsc_data[i + 1] - rdtsc_data[i]) * timer_freq / + (timer_data[i + 1] - timer_data[i]); + } + + // Rounding + acc /= (samples - 1); + constexpr long grain = 1'000'000; + return grain * (acc / grain + long{(acc % grain) > (grain / 2)}); + }; + + long freq = m_tsc_freq.load(); + if (freq) + return freq; + m_tsc_freq.compare_exchange_strong(freq, cal_tsc()); + return m_tsc_freq.load(); + } + + void* KernelContext::kalloc(std::size_t size, std::size_t align) + { + size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) & + ~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1); + if (!size) + std::abort(); + + pthread_mutex_lock(&m_heap_mtx); + if (!m_heap_is_freeing) + { + // Try to reuse previously freed block + for (auto [it, end] = m_free_heap.equal_range(size); it != end; it++) + { + auto result = it->second; + if (!(reinterpret_cast(result) & (align - 1))) + { + auto node = m_free_heap.extract(it); + node.key() = 0; + node.mapped() = nullptr; + m_used_node.insert(m_used_node.begin(), std::move(node)); + pthread_mutex_unlock(&m_heap_mtx); + return result; + } + } + } + + align = std::max(align, __STDCPP_DEFAULT_NEW_ALIGNMENT__); + auto heap = reinterpret_cast(m_heap_next); + heap = (heap + (align - 1)) & ~(align - 1); + auto result = reinterpret_cast(heap); + m_heap_next = reinterpret_cast(heap + size); + // Check overflow + if (heap + size < heap) + std::abort(); + if (heap + size > (uintptr_t)&g_context + 0x1'0000'0000) + std::abort(); + pthread_mutex_unlock(&m_heap_mtx); + return result; + } + + void KernelContext::kfree(void* ptr, std::size_t size) + { + size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) & + ~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1); + if (!size) + std::abort(); + std::memset(ptr, 0xcc, size); + + pthread_mutex_lock(&m_heap_mtx); + if (m_heap_is_freeing) + std::abort(); + m_heap_is_freeing = true; + if (!m_used_node.empty()) + { + auto node = m_used_node.extract(m_used_node.begin()); + node.key() = size; + node.mapped() = ptr; + m_free_heap.insert(std::move(node)); + } + else + { + m_free_heap.emplace(size, ptr); + } + m_heap_is_freeing = false; + pthread_mutex_unlock(&m_heap_mtx); + } + + std::tuple> + KernelContext::getUmtxChainIndexed(int i, Thread* t, uint32_t flags, + void* ptr) + { + auto pid = t->tproc->pid; + if (flags & 1) + { + pid = 0; // Process shared (TODO) + ORBIS_LOG_WARNING("Using process-shared umtx", t->tid, ptr); + } + auto p = reinterpret_cast(ptr); + auto n = p + pid; + if (flags & 1) + n %= 0x4000; + n = ((n * c_golden_ratio_prime) >> c_umtx_shifts) % c_umtx_chains; + std::unique_lock lock(m_umtx_chains[i][n].mtx); + return {m_umtx_chains[i][n], UmtxKey{p, pid}, std::move(lock)}; + } + + inline namespace utils + { + void kfree(void* ptr, std::size_t size) { return g_context.kfree(ptr, size); } + void* kalloc(std::size_t size, std::size_t align) + { + return g_context.kalloc(size, align); + } + } // namespace utils + + inline namespace logs + { + template <> + void log_class_string::format(std::string& out, const void* arg) + { + out += get_object(arg); + } + } // namespace logs + + void Thread::where() { tproc->ops->where(this); } } // namespace orbis diff --git a/orbis-kernel/src/evf.cpp b/orbis-kernel/src/evf.cpp index 063362f4..87895191 100644 --- a/orbis-kernel/src/evf.cpp +++ b/orbis-kernel/src/evf.cpp @@ -4,150 +4,181 @@ #include "utils/SharedCV.hpp" #include -orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode, - std::uint64_t bitPattern, - std::uint32_t *timeout) { - using namespace std::chrono; - - steady_clock::time_point start{}; - uint64_t elapsed = 0; - uint64_t fullTimeout = -1; - if (timeout) { - start = steady_clock::now(); - fullTimeout = *timeout; - } - - auto update_timeout = [&] { - if (!timeout) - return; - auto now = steady_clock::now(); - elapsed = duration_cast(now - start).count(); - if (fullTimeout > elapsed) { - *timeout = fullTimeout - elapsed; - return; - } - *timeout = 0; - }; - - thread->evfResultPattern = 0; - thread->evfIsCancelled = -1; - - std::unique_lock lock(queueMtx); - while (true) { - if (isDeleted) { - if (thread->evfIsCancelled == UINT64_MAX) - thread->evfResultPattern = value.load(); - return ErrorCode::ACCES; - } - if (thread->evfIsCancelled == 1) { - return ErrorCode::CANCELED; - } - if (thread->evfIsCancelled == 0) { - break; - } - - thread->evfResultPattern = 0; - thread->evfIsCancelled = -1; - - auto waitingThread = WaitingThread{ - .thread = thread, .bitPattern = bitPattern, .waitMode = waitMode}; - - if (auto patValue = value.load(std::memory_order::relaxed); - waitingThread.test(patValue)) { - auto resultValue = waitingThread.applyClear(patValue); - value.store(resultValue, std::memory_order::relaxed); - thread->evfResultPattern = patValue; - // Success - break; - } else if (timeout && *timeout == 0) { - thread->evfResultPattern = patValue; - return ErrorCode::TIMEDOUT; - } - - if (attrs & kEvfAttrSingle) { - if (!waitingThreads.empty()) - return ErrorCode::PERM; - } else { - if (attrs & kEvfAttrThFifo) { - } else { - // FIXME: sort waitingThreads by priority - } - } - - waitingThreads.emplace_back(waitingThread); - - if (timeout) { - thread->sync_cv.wait(queueMtx, *timeout); - update_timeout(); - } else { - thread->sync_cv.wait(queueMtx); - } - - if (thread->evfIsCancelled == UINT64_MAX) { - std::erase(waitingThreads, waitingThread); - } - } - - // TODO: update thread state - return {}; +orbis::ErrorCode orbis::EventFlag::wait(Thread* thread, std::uint8_t waitMode, + std::uint64_t bitPattern, + std::uint32_t* timeout) +{ + using namespace std::chrono; + + steady_clock::time_point start{}; + uint64_t elapsed = 0; + uint64_t fullTimeout = -1; + if (timeout) + { + start = steady_clock::now(); + fullTimeout = *timeout; + } + + auto update_timeout = [&] { + if (!timeout) + return; + auto now = steady_clock::now(); + elapsed = duration_cast(now - start).count(); + if (fullTimeout > elapsed) + { + *timeout = fullTimeout - elapsed; + return; + } + *timeout = 0; + }; + + thread->evfResultPattern = 0; + thread->evfIsCancelled = -1; + + std::unique_lock lock(queueMtx); + while (true) + { + if (isDeleted) + { + if (thread->evfIsCancelled == UINT64_MAX) + thread->evfResultPattern = value.load(); + return ErrorCode::ACCES; + } + if (thread->evfIsCancelled == 1) + { + return ErrorCode::CANCELED; + } + if (thread->evfIsCancelled == 0) + { + break; + } + + thread->evfResultPattern = 0; + thread->evfIsCancelled = -1; + + auto waitingThread = WaitingThread{ + .thread = thread, .bitPattern = bitPattern, .waitMode = waitMode}; + + if (auto patValue = value.load(std::memory_order::relaxed); + waitingThread.test(patValue)) + { + auto resultValue = waitingThread.applyClear(patValue); + value.store(resultValue, std::memory_order::relaxed); + thread->evfResultPattern = patValue; + // Success + break; + } + else if (timeout && *timeout == 0) + { + thread->evfResultPattern = patValue; + return ErrorCode::TIMEDOUT; + } + + if (attrs & kEvfAttrSingle) + { + if (!waitingThreads.empty()) + return ErrorCode::PERM; + } + else + { + if (attrs & kEvfAttrThFifo) + { + } + else + { + // FIXME: sort waitingThreads by priority + } + } + + waitingThreads.emplace_back(waitingThread); + + if (timeout) + { + thread->sync_cv.wait(queueMtx, *timeout); + update_timeout(); + } + else + { + thread->sync_cv.wait(queueMtx); + } + + if (thread->evfIsCancelled == UINT64_MAX) + { + std::erase(waitingThreads, waitingThread); + } + } + + // TODO: update thread state + return {}; } -orbis::ErrorCode orbis::EventFlag::tryWait(Thread *thread, - std::uint8_t waitMode, - std::uint64_t bitPattern) { - writer_lock lock(queueMtx); - - if (isDeleted) { - return ErrorCode::ACCES; - } - - auto waitingThread = - WaitingThread{.bitPattern = bitPattern, .waitMode = waitMode}; - - if (auto patValue = value.load(std::memory_order::relaxed); - waitingThread.test(patValue)) { - auto resultValue = waitingThread.applyClear(patValue); - value.store(resultValue, std::memory_order::relaxed); - thread->evfResultPattern = patValue; - return {}; - } - - return ErrorCode::BUSY; +orbis::ErrorCode orbis::EventFlag::tryWait(Thread* thread, + std::uint8_t waitMode, + std::uint64_t bitPattern) +{ + writer_lock lock(queueMtx); + + if (isDeleted) + { + return ErrorCode::ACCES; + } + + auto waitingThread = + WaitingThread{.bitPattern = bitPattern, .waitMode = waitMode}; + + if (auto patValue = value.load(std::memory_order::relaxed); + waitingThread.test(patValue)) + { + auto resultValue = waitingThread.applyClear(patValue); + value.store(resultValue, std::memory_order::relaxed); + thread->evfResultPattern = patValue; + return {}; + } + + return ErrorCode::BUSY; } -std::size_t orbis::EventFlag::notify(NotifyType type, std::uint64_t bits) { - writer_lock lock(queueMtx); - auto patValue = value.load(std::memory_order::relaxed); - - if (type == NotifyType::Destroy) { - isDeleted = true; - } else if (type == NotifyType::Set) { - patValue |= bits; - } - - auto testThread = [&](WaitingThread *thread) { - if (type == NotifyType::Set && !thread->test(patValue)) { - return false; - } - - auto resultValue = thread->applyClear(patValue); - thread->thread->evfResultPattern = patValue; - thread->thread->evfIsCancelled = type == NotifyType::Cancel; - patValue = resultValue; - - // TODO: update thread state - // release wait on waiter thread - thread->thread->sync_cv.notify_one(queueMtx); - return true; - }; - - std::size_t result = std::erase_if( - waitingThreads, [&](auto &thread) { return testThread(&thread); }); - - if (type == NotifyType::Cancel) { - value.store(bits, std::memory_order::relaxed); - } else { - value.store(patValue, std::memory_order::relaxed); - } - return result; +std::size_t orbis::EventFlag::notify(NotifyType type, std::uint64_t bits) +{ + writer_lock lock(queueMtx); + auto patValue = value.load(std::memory_order::relaxed); + + if (type == NotifyType::Destroy) + { + isDeleted = true; + } + else if (type == NotifyType::Set) + { + patValue |= bits; + } + + auto testThread = [&](WaitingThread* thread) { + if (type == NotifyType::Set && !thread->test(patValue)) + { + return false; + } + + auto resultValue = thread->applyClear(patValue); + thread->thread->evfResultPattern = patValue; + thread->thread->evfIsCancelled = type == NotifyType::Cancel; + patValue = resultValue; + + // TODO: update thread state + // release wait on waiter thread + thread->thread->sync_cv.notify_one(queueMtx); + return true; + }; + + std::size_t result = std::erase_if( + waitingThreads, [&](auto& thread) { return testThread(&thread); }); + + if (type == NotifyType::Cancel) + { + value.store(bits, std::memory_order::relaxed); + } + else + { + value.store(patValue, std::memory_order::relaxed); + } + return result; } diff --git a/orbis-kernel/src/module.cpp b/orbis-kernel/src/module.cpp index a3f53228..cee6970e 100644 --- a/orbis-kernel/src/module.cpp +++ b/orbis-kernel/src/module.cpp @@ -7,407 +7,481 @@ #include // TODO: move relocations to the platform specific code -enum RelType { - kRelNone, - kRel64, - kRelPc32, - kRelGot32, - kRelPlt32, - kRelCopy, - kRelGlobDat, - kRelJumpSlot, - kRelRelative, - kRelGotPcRel, - kRel32, - kRel32s, - kRel16, - kRelPc16, - kRel8, - kRelPc8, - kRelDtpMod64, - kRelDtpOff64, - kRelTpOff64, - kRelTlsGd, - kRelTlsLd, - kRelDtpOff32, - kRelGotTpOff, - kRelTpOff32, - kRelPc64, - kRelGotOff64, - kRelGotPc32, - kRelGot64, - kRelGotPcRel64, - kRelGotPc64, - kRelGotPlt64, - kRelPltOff64, - kRelSize32, - kRelSize64, - kRelGotPc32TlsDesc, - kRelTlsDescCall, - kRelTlsDesc, - kRelIRelative, - kRelRelative64, +enum RelType +{ + kRelNone, + kRel64, + kRelPc32, + kRelGot32, + kRelPlt32, + kRelCopy, + kRelGlobDat, + kRelJumpSlot, + kRelRelative, + kRelGotPcRel, + kRel32, + kRel32s, + kRel16, + kRelPc16, + kRel8, + kRelPc8, + kRelDtpMod64, + kRelDtpOff64, + kRelTpOff64, + kRelTlsGd, + kRelTlsLd, + kRelDtpOff32, + kRelGotTpOff, + kRelTpOff32, + kRelPc64, + kRelGotOff64, + kRelGotPc32, + kRelGot64, + kRelGotPcRel64, + kRelGotPc64, + kRelGotPlt64, + kRelPltOff64, + kRelSize32, + kRelSize64, + kRelGotPc32TlsDesc, + kRelTlsDescCall, + kRelTlsDesc, + kRelIRelative, + kRelRelative64, }; static std::uint64_t calculateTlsOffset(std::uint64_t prevOffset, - std::uint64_t size, - std::uint64_t align) { - return (prevOffset + size + align - 1) & ~(align - 1); + std::uint64_t size, + std::uint64_t align) +{ + return (prevOffset + size + align - 1) & ~(align - 1); } -static void allocateTlsOffset(orbis::Process *process, orbis::Module *module) { - if (module->isTlsDone) { - return; - } +static void allocateTlsOffset(orbis::Process* process, orbis::Module* module) +{ + if (module->isTlsDone) + { + return; + } - auto offset = - calculateTlsOffset(module->tlsIndex == 1 ? 0 : process->lastTlsOffset, - module->tlsSize, module->tlsAlign); + auto offset = + calculateTlsOffset(module->tlsIndex == 1 ? 0 : process->lastTlsOffset, + module->tlsSize, module->tlsAlign); - module->tlsOffset = offset; - process->lastTlsOffset = offset; - module->isTlsDone = true; + module->tlsOffset = offset; + process->lastTlsOffset = offset; + module->isTlsDone = true; } -static orbis::SysResult doPltRelocation(orbis::Process *process, - orbis::Module *module, - orbis::Relocation rel) { - auto symbol = module->symbols.at(rel.symbolIndex); - - auto A = rel.addend; - auto B = reinterpret_cast(module->base); - auto where = reinterpret_cast(B + rel.offset); - auto where32 = reinterpret_cast(B + rel.offset); - auto P = reinterpret_cast(where); - - auto findDefModule = [module, - symbol] -> std::pair { - if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) { - return std::pair(module, symbol.address); - } - - auto &defModule = module->importedModules.at(symbol.moduleIndex); - if (!defModule) { - // std::printf( - // "Delaying plt relocation '%s' ('%s'), symbol '%llx' in %s - // module\n", module->moduleName, module->soName, (unsigned long - // long)symbol.id, - // module->neededModules[symbol.moduleIndex].name.c_str()); - - return {}; - } - - auto library = module->neededLibraries.at(symbol.libraryIndex); - - std::vector foundInLibs; - for (auto defSym : defModule->symbols) { - if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { - continue; - } - - if (defSym.visibility == orbis::SymbolVisibility::Hidden) { - std::printf("Ignoring hidden symbol\n"); - continue; - } - - auto defLib = defModule->neededLibraries.at(defSym.libraryIndex); - - if (defLib.name == library.name) { - return std::pair(defModule.get(), defSym.address); - } - - foundInLibs.emplace_back(std::string_view(defLib.name)); - } - - for (auto nsDefModule : defModule->namespaceModules) { - for (auto defSym : nsDefModule->symbols) { - if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { - continue; - } - - if (defSym.visibility == orbis::SymbolVisibility::Hidden) { - std::printf("Ignoring hidden symbol\n"); - continue; - } - - auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex); - - if (defLib.name == library.name) { - return std::pair(nsDefModule.get(), defSym.address); - } - } - } - - std::printf( - "'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n", - module->moduleName, module->soName, (unsigned long long)symbol.id, - defModule->moduleName, defModule->soName); - if (foundInLibs.size() > 0) { - std::printf("Requested library is '%s', exists in libraries: [", - library.name.c_str()); - - for (bool isFirst = true; auto &lib : foundInLibs) { - if (isFirst) { - isFirst = false; - } else { - std::printf(", "); - } - - std::printf("'%s'", lib.c_str()); - } - std::printf("]\n"); - } - return std::pair(module, symbol.address); - }; - - switch (rel.relType) { - case kRelJumpSlot: { - bool isLazyBind = false; // TODO - if (isLazyBind) { - *where += B; - } else { - auto [defObj, S] = findDefModule(); - - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - - *where = reinterpret_cast(defObj->base) + S; - } - return {}; - } - } - - std::fprintf(stderr, "unimplemented relocation type %u\n", - (unsigned)rel.relType); - std::abort(); - return {}; +static orbis::SysResult doPltRelocation(orbis::Process* process, + orbis::Module* module, + orbis::Relocation rel) +{ + auto symbol = module->symbols.at(rel.symbolIndex); + + auto A = rel.addend; + auto B = reinterpret_cast(module->base); + auto where = reinterpret_cast(B + rel.offset); + auto where32 = reinterpret_cast(B + rel.offset); + auto P = reinterpret_cast(where); + + auto findDefModule = [module, + symbol] -> std::pair { + if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) + { + return std::pair(module, symbol.address); + } + + auto& defModule = module->importedModules.at(symbol.moduleIndex); + if (!defModule) + { + // std::printf( + // "Delaying plt relocation '%s' ('%s'), symbol '%llx' in %s + // module\n", module->moduleName, module->soName, (unsigned long + // long)symbol.id, + // module->neededModules[symbol.moduleIndex].name.c_str()); + + return {}; + } + + auto library = module->neededLibraries.at(symbol.libraryIndex); + + std::vector foundInLibs; + for (auto defSym : defModule->symbols) + { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) + { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) + { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = defModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) + { + return std::pair(defModule.get(), defSym.address); + } + + foundInLibs.emplace_back(std::string_view(defLib.name)); + } + + for (auto nsDefModule : defModule->namespaceModules) + { + for (auto defSym : nsDefModule->symbols) + { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) + { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) + { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) + { + return std::pair(nsDefModule.get(), defSym.address); + } + } + } + + std::printf( + "'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n", + module->moduleName, module->soName, (unsigned long long)symbol.id, + defModule->moduleName, defModule->soName); + if (foundInLibs.size() > 0) + { + std::printf("Requested library is '%s', exists in libraries: [", + library.name.c_str()); + + for (bool isFirst = true; auto& lib : foundInLibs) + { + if (isFirst) + { + isFirst = false; + } + else + { + std::printf(", "); + } + + std::printf("'%s'", lib.c_str()); + } + std::printf("]\n"); + } + return std::pair(module, symbol.address); + }; + + switch (rel.relType) + { + case kRelJumpSlot: + { + bool isLazyBind = false; // TODO + if (isLazyBind) + { + *where += B; + } + else + { + auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + + *where = reinterpret_cast(defObj->base) + S; + } + return {}; + } + } + + std::fprintf(stderr, "unimplemented relocation type %u\n", + (unsigned)rel.relType); + std::abort(); + return {}; } -static orbis::SysResult doRelocation(orbis::Process *process, - orbis::Module *module, - orbis::Relocation rel) { - auto symbol = module->symbols.at(rel.symbolIndex); - - auto A = rel.addend; - auto B = reinterpret_cast(module->base); - auto where = reinterpret_cast(B + rel.offset); - auto where32 = reinterpret_cast(B + rel.offset); - auto P = reinterpret_cast(where); - - auto findDefModule = [module, symbol, - rel] -> std::pair { - if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) { - return std::pair(module, symbol.address); - } - - auto &defModule = module->importedModules.at(symbol.moduleIndex); - if (!defModule) { - std::printf("'%s' ('%s') uses undefined symbol '%llx' in unloaded module " - "'%s', rel %u\n", - module->moduleName, module->soName, - (unsigned long long)symbol.id, - module->neededModules.at(symbol.moduleIndex).name.c_str(), - rel.relType); - - return {}; - } - - auto library = module->neededLibraries.at(symbol.libraryIndex); - - std::vector foundInLibs; - for (auto defSym : defModule->symbols) { - if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { - continue; - } - - if (defSym.visibility == orbis::SymbolVisibility::Hidden) { - std::printf("Ignoring hidden symbol\n"); - continue; - } - - auto defLib = defModule->neededLibraries.at(defSym.libraryIndex); - - if (defLib.name == library.name) { - return std::pair(defModule.get(), defSym.address); - } - - foundInLibs.emplace_back(std::string_view(defLib.name)); - } - - for (auto nsDefModule : defModule->namespaceModules) { - for (auto defSym : nsDefModule->symbols) { - if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { - continue; - } - - if (defSym.visibility == orbis::SymbolVisibility::Hidden) { - std::printf("Ignoring hidden symbol\n"); - continue; - } - - auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex); - - if (defLib.name == library.name) { - return std::pair(nsDefModule.get(), defSym.address); - } - } - } - - std::printf( - "'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n", - module->moduleName, module->soName, (unsigned long long)symbol.id, - defModule->moduleName, defModule->soName); - if (foundInLibs.size() > 0) { - std::printf("Requested library is '%s', exists in libraries: [", - library.name.c_str()); - - for (bool isFirst = true; auto &lib : foundInLibs) { - if (isFirst) { - isFirst = false; - } else { - std::printf(", "); - } - - std::printf("'%s'", lib.c_str()); - } - std::printf("]\n"); - } - return std::pair(module, symbol.address); - }; - - switch (rel.relType) { - case kRelNone: - return {}; - case kRel64: { - auto [defObj, S] = findDefModule(); - - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - *where = reinterpret_cast(defObj->base) + S + A; - return {}; - } - return {}; - case kRelPc32: { - auto [defObj, S] = findDefModule(); - - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - *where32 = reinterpret_cast(defObj->base) + S + A - P; - return {}; - } - // case kRelCopy: - // return{}; - case kRelGlobDat: { - auto [defObj, S] = findDefModule(); - - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - *where = reinterpret_cast(defObj->base) + S; - return {}; - } - case kRelRelative: - *where = B + A; - return {}; - case kRelDtpMod64: { - auto [defObj, S] = findDefModule(); - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - *where += defObj->tlsIndex; - return {}; - } - case kRelDtpOff64: { - auto [defObj, S] = findDefModule(); - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - *where += S + A; - return {}; - } - case kRelTpOff64: { - auto [defObj, S] = findDefModule(); - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - if (!defObj->isTlsDone) { - allocateTlsOffset(process, defObj); - } - *where = S - defObj->tlsOffset + A; - return {}; - } - case kRelDtpOff32: { - auto [defObj, S] = findDefModule(); - *where32 += S + A; - return {}; - } - case kRelTpOff32: { - auto [defObj, S] = findDefModule(); - if (defObj == nullptr) { - return orbis::ErrorCode::INVAL; - } - if (!defObj->isTlsDone) { - allocateTlsOffset(process, defObj); - } - *where32 = S - defObj->tlsOffset + A; - return {}; - } - } - - std::fprintf(stderr, "unimplemented relocation type %u\n", - (unsigned)rel.relType); - std::abort(); - return {}; +static orbis::SysResult doRelocation(orbis::Process* process, + orbis::Module* module, + orbis::Relocation rel) +{ + auto symbol = module->symbols.at(rel.symbolIndex); + + auto A = rel.addend; + auto B = reinterpret_cast(module->base); + auto where = reinterpret_cast(B + rel.offset); + auto where32 = reinterpret_cast(B + rel.offset); + auto P = reinterpret_cast(where); + + auto findDefModule = [module, symbol, + rel] -> std::pair { + if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) + { + return std::pair(module, symbol.address); + } + + auto& defModule = module->importedModules.at(symbol.moduleIndex); + if (!defModule) + { + std::printf("'%s' ('%s') uses undefined symbol '%llx' in unloaded module " + "'%s', rel %u\n", + module->moduleName, module->soName, + (unsigned long long)symbol.id, + module->neededModules.at(symbol.moduleIndex).name.c_str(), + rel.relType); + + return {}; + } + + auto library = module->neededLibraries.at(symbol.libraryIndex); + + std::vector foundInLibs; + for (auto defSym : defModule->symbols) + { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) + { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) + { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = defModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) + { + return std::pair(defModule.get(), defSym.address); + } + + foundInLibs.emplace_back(std::string_view(defLib.name)); + } + + for (auto nsDefModule : defModule->namespaceModules) + { + for (auto defSym : nsDefModule->symbols) + { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) + { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) + { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) + { + return std::pair(nsDefModule.get(), defSym.address); + } + } + } + + std::printf( + "'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n", + module->moduleName, module->soName, (unsigned long long)symbol.id, + defModule->moduleName, defModule->soName); + if (foundInLibs.size() > 0) + { + std::printf("Requested library is '%s', exists in libraries: [", + library.name.c_str()); + + for (bool isFirst = true; auto& lib : foundInLibs) + { + if (isFirst) + { + isFirst = false; + } + else + { + std::printf(", "); + } + + std::printf("'%s'", lib.c_str()); + } + std::printf("]\n"); + } + return std::pair(module, symbol.address); + }; + + switch (rel.relType) + { + case kRelNone: + return {}; + case kRel64: + { + auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + *where = reinterpret_cast(defObj->base) + S + A; + return {}; + } + return {}; + case kRelPc32: + { + auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + *where32 = reinterpret_cast(defObj->base) + S + A - P; + return {}; + } + // case kRelCopy: + // return{}; + case kRelGlobDat: + { + auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + *where = reinterpret_cast(defObj->base) + S; + return {}; + } + case kRelRelative: + *where = B + A; + return {}; + case kRelDtpMod64: + { + auto [defObj, S] = findDefModule(); + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + *where += defObj->tlsIndex; + return {}; + } + case kRelDtpOff64: + { + auto [defObj, S] = findDefModule(); + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + *where += S + A; + return {}; + } + case kRelTpOff64: + { + auto [defObj, S] = findDefModule(); + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + if (!defObj->isTlsDone) + { + allocateTlsOffset(process, defObj); + } + *where = S - defObj->tlsOffset + A; + return {}; + } + case kRelDtpOff32: + { + auto [defObj, S] = findDefModule(); + *where32 += S + A; + return {}; + } + case kRelTpOff32: + { + auto [defObj, S] = findDefModule(); + if (defObj == nullptr) + { + return orbis::ErrorCode::INVAL; + } + if (!defObj->isTlsDone) + { + allocateTlsOffset(process, defObj); + } + *where32 = S - defObj->tlsOffset + A; + return {}; + } + } + + std::fprintf(stderr, "unimplemented relocation type %u\n", + (unsigned)rel.relType); + std::abort(); + return {}; } -orbis::SysResult orbis::Module::relocate(Process *process) { - if (!pltRelocations.empty()) { - kvector delayedRelocations; - std::size_t resolved = 0; - std::size_t delayed = 0; - for (auto rel : pltRelocations) { - auto result = doPltRelocation(process, this, rel); - - if (result.isError()) { - delayedRelocations.push_back(rel); - ++delayed; - } else { - ++resolved; - } - } - - std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName, - delayed, resolved); - pltRelocations = std::move(delayedRelocations); - } - - if (!nonPltRelocations.empty()) { - kvector delayedRelocations; - std::size_t resolved = 0; - std::size_t delayed = 0; - for (auto rel : nonPltRelocations) { - auto result = doRelocation(process, this, rel); - - if (result.isError()) { - delayedRelocations.push_back(rel); - ++delayed; - } else { - ++resolved; - } - } - - std::printf("non-plt relocation of %s: delayed/resolved: %zu/%zu\n", - moduleName, delayed, resolved); - nonPltRelocations = std::move(delayedRelocations); - } - - return {}; +orbis::SysResult orbis::Module::relocate(Process* process) +{ + if (!pltRelocations.empty()) + { + kvector delayedRelocations; + std::size_t resolved = 0; + std::size_t delayed = 0; + for (auto rel : pltRelocations) + { + auto result = doPltRelocation(process, this, rel); + + if (result.isError()) + { + delayedRelocations.push_back(rel); + ++delayed; + } + else + { + ++resolved; + } + } + + std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName, + delayed, resolved); + pltRelocations = std::move(delayedRelocations); + } + + if (!nonPltRelocations.empty()) + { + kvector delayedRelocations; + std::size_t resolved = 0; + std::size_t delayed = 0; + for (auto rel : nonPltRelocations) + { + auto result = doRelocation(process, this, rel); + + if (result.isError()) + { + delayedRelocations.push_back(rel); + ++delayed; + } + else + { + ++resolved; + } + } + + std::printf("non-plt relocation of %s: delayed/resolved: %zu/%zu\n", + moduleName, delayed, resolved); + nonPltRelocations = std::move(delayedRelocations); + } + + return {}; } -void orbis::Module::destroy() { - std::lock_guard lock(proc->mtx); - proc->modulesMap.close(id); +void orbis::Module::destroy() +{ + std::lock_guard lock(proc->mtx); + proc->modulesMap.close(id); } diff --git a/orbis-kernel/src/sys/sys_acct.cpp b/orbis-kernel/src/sys/sys_acct.cpp index 32edda6c..9425336f 100644 --- a/orbis-kernel/src/sys/sys_acct.cpp +++ b/orbis-kernel/src/sys/sys_acct.cpp @@ -1,6 +1,7 @@ #include "error.hpp" #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_acct(Thread *thread, ptr path) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_acct(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_audit.cpp b/orbis-kernel/src/sys/sys_audit.cpp index 4a9dd33a..bbb7d7f2 100644 --- a/orbis-kernel/src/sys/sys_audit.cpp +++ b/orbis-kernel/src/sys/sys_audit.cpp @@ -1,35 +1,44 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_audit(Thread *thread, ptr record, - uint length) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_auditon(Thread *thread, sint cmd, ptr data, - uint length) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getauid(Thread *thread, ptr auid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setauid(Thread *thread, ptr auid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getaudit(Thread *thread, - ptr auditinfo) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setaudit(Thread *thread, - ptr auditinfo) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_audit(Thread* thread, ptr record, + uint length) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_auditon(Thread* thread, sint cmd, ptr data, + uint length) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getauid(Thread* thread, ptr auid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setauid(Thread* thread, ptr auid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getaudit(Thread* thread, + ptr auditinfo) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setaudit(Thread* thread, + ptr auditinfo) +{ + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_getaudit_addr( - Thread *thread, ptr auditinfo_addr, uint length) { - return ErrorCode::NOSYS; + Thread* thread, ptr auditinfo_addr, uint length) +{ + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_setaudit_addr( - Thread *thread, ptr auditinfo_addr, uint length) { - return ErrorCode::NOSYS; + Thread* thread, ptr auditinfo_addr, uint length) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_auditctl(Thread *thread, ptr path) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_auditctl(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_capability.cpp b/orbis-kernel/src/sys/sys_capability.cpp index 6f33f57b..694ec3ad 100644 --- a/orbis-kernel/src/sys/sys_capability.cpp +++ b/orbis-kernel/src/sys/sys_capability.cpp @@ -1,15 +1,19 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_cap_enter(Thread *thread) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_enter(Thread* thread) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_getmode(Thread *thread, ptr modep) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_getmode(Thread* thread, ptr modep) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_new(Thread *thread, sint fd, uint64_t rights) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_new(Thread* thread, sint fd, uint64_t rights) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_getrights(Thread *thread, sint fd, - ptr rights) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_getrights(Thread* thread, sint fd, + ptr rights) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_context.cpp b/orbis-kernel/src/sys/sys_context.cpp index dd16c861..ec1748f6 100644 --- a/orbis-kernel/src/sys/sys_context.cpp +++ b/orbis-kernel/src/sys/sys_context.cpp @@ -1,15 +1,18 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_getcontext(Thread *thread, - ptr ucp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getcontext(Thread* thread, + ptr ucp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_setcontext(Thread *thread, - ptr ucp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setcontext(Thread* thread, + ptr ucp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_swapcontext(Thread *thread, - ptr oucp, - ptr ucp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_swapcontext(Thread* thread, + ptr oucp, + ptr ucp) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_cpuset.cpp b/orbis-kernel/src/sys/sys_cpuset.cpp index bbb8cbfb..6d93c86e 100644 --- a/orbis-kernel/src/sys/sys_cpuset.cpp +++ b/orbis-kernel/src/sys/sys_cpuset.cpp @@ -1,26 +1,31 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_cpuset(Thread *thread, ptr setid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cpuset(Thread* thread, ptr setid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cpuset_setid(Thread *thread, cpuwhich_t which, - id_t id, cpusetid_t setid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cpuset_setid(Thread* thread, cpuwhich_t which, + id_t id, cpusetid_t setid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cpuset_getid(Thread *thread, cpulevel_t level, - cpuwhich_t which, id_t id, - ptr setid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cpuset_getid(Thread* thread, cpulevel_t level, + cpuwhich_t which, id_t id, + ptr setid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level, - cpuwhich_t which, id_t id, - size_t cpusetsize, - ptr mask) { - return {}; +orbis::SysResult orbis::sys_cpuset_getaffinity(Thread* thread, cpulevel_t level, + cpuwhich_t which, id_t id, + size_t cpusetsize, + ptr mask) +{ + return {}; } -orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level, - cpuwhich_t which, id_t id, - size_t cpusetsize, - ptr mask) { - return {}; +orbis::SysResult orbis::sys_cpuset_setaffinity(Thread* thread, cpulevel_t level, + cpuwhich_t which, id_t id, + size_t cpusetsize, + ptr mask) +{ + return {}; } diff --git a/orbis-kernel/src/sys/sys_descrip.cpp b/orbis-kernel/src/sys/sys_descrip.cpp index e1576807..13952c30 100644 --- a/orbis-kernel/src/sys/sys_descrip.cpp +++ b/orbis-kernel/src/sys/sys_descrip.cpp @@ -2,62 +2,77 @@ #include "stat.hpp" #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_getdtablesize(Thread *thread) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getdtablesize(Thread* thread) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_dup2(Thread *thread, uint from, uint to) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_dup2(Thread* thread, uint from, uint to) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_dup(Thread *thread, uint fd) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_dup(Thread* thread, uint fd) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fcntl(Thread *thread, sint fd, sint cmd, - slong arg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fcntl(Thread* thread, sint fd, sint cmd, + slong arg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_close(Thread *thread, sint fd) { - ORBIS_LOG_NOTICE(__FUNCTION__, fd); - if (thread->tproc->fileDescriptors.close(fd)) { - return {}; - } +orbis::SysResult orbis::sys_close(Thread* thread, sint fd) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, fd); + if (thread->tproc->fileDescriptors.close(fd)) + { + return {}; + } - return ErrorCode::BADF; + return ErrorCode::BADF; } -orbis::SysResult orbis::sys_closefrom(Thread *thread, sint lowfd) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_closefrom(Thread* thread, sint lowfd) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fstat(Thread *thread, sint fd, ptr ub) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } +orbis::SysResult orbis::sys_fstat(Thread* thread, sint fd, ptr ub) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } - auto stat = file->ops->stat; - if (stat == nullptr) { - return ErrorCode::NOTSUP; - } + auto stat = file->ops->stat; + if (stat == nullptr) + { + return ErrorCode::NOTSUP; + } - std::lock_guard lock(file->mtx); - Stat _ub; - auto result = uread(_ub, ub); - if (result != ErrorCode{}) { - return result; - } + std::lock_guard lock(file->mtx); + Stat _ub; + auto result = uread(_ub, ub); + if (result != ErrorCode{}) + { + return result; + } - result = stat(file.get(), &_ub, thread); - if (result != ErrorCode{}) { - return result; - } + result = stat(file.get(), &_ub, thread); + if (result != ErrorCode{}) + { + return result; + } - return uwrite(ub, _ub); + return uwrite(ub, _ub); } -orbis::SysResult orbis::sys_nfstat(Thread *thread, sint fd, - ptr sb) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_nfstat(Thread* thread, sint fd, + ptr sb) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fpathconf(Thread *thread, sint fd, sint name) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fpathconf(Thread* thread, sint fd, sint name) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_flock(Thread *thread, sint fd, sint how) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_flock(Thread* thread, sint fd, sint how) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_environment.cpp b/orbis-kernel/src/sys/sys_environment.cpp index 8b394e2a..1fbed785 100644 --- a/orbis-kernel/src/sys/sys_environment.cpp +++ b/orbis-kernel/src/sys/sys_environment.cpp @@ -1,7 +1,8 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_kenv(Thread *thread, sint what, - ptr name, ptr value, - sint len) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kenv(Thread* thread, sint what, + ptr name, ptr value, + sint len) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_event.cpp b/orbis-kernel/src/sys/sys_event.cpp index a53df8f8..d0632816 100644 --- a/orbis-kernel/src/sys/sys_event.cpp +++ b/orbis-kernel/src/sys/sys_event.cpp @@ -3,24 +3,29 @@ #include "thread/Process.hpp" #include "utils/Logs.hpp" -struct KQueue : orbis::File {}; +struct KQueue : orbis::File +{ +}; -orbis::SysResult orbis::sys_kqueue(Thread *thread) { - ORBIS_LOG_TODO(__FUNCTION__); - auto queue = knew(); - if (queue == nullptr) { - return ErrorCode::NOMEM; - } +orbis::SysResult orbis::sys_kqueue(Thread* thread) +{ + ORBIS_LOG_TODO(__FUNCTION__); + auto queue = knew(); + if (queue == nullptr) + { + return ErrorCode::NOMEM; + } - thread->retval[0] = thread->tproc->fileDescriptors.insert(queue); - return {}; + thread->retval[0] = thread->tproc->fileDescriptors.insert(queue); + return {}; } -orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, - ptr changelist, sint nchanges, - ptr eventlist, sint nevents, - ptr timeout) { - // ORBIS_LOG_TODO(__FUNCTION__, fd); - thread->retval[0] = 1; - return {}; +orbis::SysResult orbis::sys_kevent(Thread* thread, sint fd, + ptr changelist, sint nchanges, + ptr eventlist, sint nevents, + ptr timeout) +{ + // ORBIS_LOG_TODO(__FUNCTION__, fd); + thread->retval[0] = 1; + return {}; } diff --git a/orbis-kernel/src/sys/sys_exec.cpp b/orbis-kernel/src/sys/sys_exec.cpp index 29f9ca43..5953c7ae 100644 --- a/orbis-kernel/src/sys/sys_exec.cpp +++ b/orbis-kernel/src/sys/sys_exec.cpp @@ -1,16 +1,19 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_execve(Thread *thread, ptr fname, - ptr> argv, ptr> envv) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_execve(Thread* thread, ptr fname, + ptr> argv, ptr> envv) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fexecve(Thread *thread, sint fd, - ptr> argv, ptr> envv) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fexecve(Thread* thread, sint fd, + ptr> argv, ptr> envv) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys___mac_execve(Thread *thread, ptr fname, - ptr> argv, - ptr> envv, - ptr mac_p) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys___mac_execve(Thread* thread, ptr fname, + ptr> argv, + ptr> envv, + ptr mac_p) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_exit.cpp b/orbis-kernel/src/sys/sys_exit.cpp index d025e92b..742ef473 100644 --- a/orbis-kernel/src/sys/sys_exit.cpp +++ b/orbis-kernel/src/sys/sys_exit.cpp @@ -1,17 +1,21 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_exit(Thread *thread, sint status) { - if (auto exit = thread->tproc->ops->exit) { - return exit(thread, status); - } +orbis::SysResult orbis::sys_exit(Thread* thread, sint status) +{ + if (auto exit = thread->tproc->ops->exit) + { + return exit(thread, status); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_abort2(Thread *thread, ptr why, - sint narg, ptr> args) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_abort2(Thread* thread, ptr why, + sint narg, ptr> args) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_wait4(Thread *thread, sint pid, ptr status, - sint options, ptr rusage) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_wait4(Thread* thread, sint pid, ptr status, + sint options, ptr rusage) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_fork.cpp b/orbis-kernel/src/sys/sys_fork.cpp index 52b0c472..e666ac9a 100644 --- a/orbis-kernel/src/sys/sys_fork.cpp +++ b/orbis-kernel/src/sys/sys_fork.cpp @@ -1,10 +1,12 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_fork(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_pdfork(Thread *thread, ptr fdp, sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fork(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_pdfork(Thread* thread, ptr fdp, sint flags) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_vfork(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rfork(Thread *thread, sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_vfork(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_rfork(Thread* thread, sint flags) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_generic.cpp b/orbis-kernel/src/sys/sys_generic.cpp index 970dcb28..2ebeafb8 100644 --- a/orbis-kernel/src/sys/sys_generic.cpp +++ b/orbis-kernel/src/sys/sys_generic.cpp @@ -3,295 +3,333 @@ #include "uio.hpp" #include -orbis::SysResult orbis::sys_read(Thread *thread, sint fd, ptr buf, - size_t nbyte) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto read = file->ops->read; - if (read == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - IoVec vec{.base = (void *)buf, .len = nbyte}; - - Uio io{ - .offset = file->nextOff, - .iov = &vec, - .iovcnt = 1, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Read, - .td = thread, - }; - - auto error = read(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - auto cnt = io.offset - file->nextOff; - file->nextOff = io.offset; - - thread->retval[0] = cnt; - return {}; +orbis::SysResult orbis::sys_read(Thread* thread, sint fd, ptr buf, + size_t nbyte) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto read = file->ops->read; + if (read == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + IoVec vec{.base = (void*)buf, .len = nbyte}; + + Uio io{ + .offset = file->nextOff, + .iov = &vec, + .iovcnt = 1, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Read, + .td = thread, + }; + + auto error = read(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + auto cnt = io.offset - file->nextOff; + file->nextOff = io.offset; + + thread->retval[0] = cnt; + return {}; } -orbis::SysResult orbis::sys_pread(Thread *thread, sint fd, ptr buf, - size_t nbyte, off_t offset) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto read = file->ops->read; - if (read == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - IoVec vec{.base = (void *)buf, .len = nbyte}; - - Uio io{ - .offset = static_cast(offset), - .iov = &vec, - .iovcnt = 1, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Read, - .td = thread, - }; - - auto error = read(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - thread->retval[0] = io.offset - offset; - return {}; +orbis::SysResult orbis::sys_pread(Thread* thread, sint fd, ptr buf, + size_t nbyte, off_t offset) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto read = file->ops->read; + if (read == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + IoVec vec{.base = (void*)buf, .len = nbyte}; + + Uio io{ + .offset = static_cast(offset), + .iov = &vec, + .iovcnt = 1, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Read, + .td = thread, + }; + + auto error = read(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + thread->retval[0] = io.offset - offset; + return {}; } -orbis::SysResult orbis::sys_freebsd6_pread(Thread *thread, sint fd, - ptr buf, size_t nbyte, sint, - off_t offset) { - return sys_pread(thread, fd, buf, nbyte, offset); +orbis::SysResult orbis::sys_freebsd6_pread(Thread* thread, sint fd, + ptr buf, size_t nbyte, sint, + off_t offset) +{ + return sys_pread(thread, fd, buf, nbyte, offset); } -orbis::SysResult orbis::sys_readv(Thread *thread, sint fd, ptr iovp, - uint iovcnt) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto read = file->ops->read; - if (read == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - - Uio io{ - .offset = file->nextOff, - .iov = iovp, - .iovcnt = iovcnt, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Read, - .td = thread, - }; - - auto error = read(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - auto cnt = io.offset - file->nextOff; - file->nextOff = io.offset; - thread->retval[0] = cnt; - return {}; +orbis::SysResult orbis::sys_readv(Thread* thread, sint fd, ptr iovp, + uint iovcnt) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto read = file->ops->read; + if (read == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + + Uio io{ + .offset = file->nextOff, + .iov = iovp, + .iovcnt = iovcnt, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Read, + .td = thread, + }; + + auto error = read(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + auto cnt = io.offset - file->nextOff; + file->nextOff = io.offset; + thread->retval[0] = cnt; + return {}; } -orbis::SysResult orbis::sys_preadv(Thread *thread, sint fd, ptr iovp, - uint iovcnt, off_t offset) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto read = file->ops->read; - if (read == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - - Uio io{ - .offset = static_cast(offset), - .iov = iovp, - .iovcnt = iovcnt, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Read, - .td = thread, - }; - - auto error = read(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - thread->retval[0] = io.offset - offset; - return {}; +orbis::SysResult orbis::sys_preadv(Thread* thread, sint fd, ptr iovp, + uint iovcnt, off_t offset) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto read = file->ops->read; + if (read == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + + Uio io{ + .offset = static_cast(offset), + .iov = iovp, + .iovcnt = iovcnt, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Read, + .td = thread, + }; + + auto error = read(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + thread->retval[0] = io.offset - offset; + return {}; } -orbis::SysResult orbis::sys_write(Thread *thread, sint fd, ptr buf, - size_t nbyte) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto write = file->ops->write; - if (write == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - IoVec vec{.base = (void *)buf, .len = nbyte}; - - Uio io{ - .offset = file->nextOff, - .iov = &vec, - .iovcnt = 1, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Write, - .td = thread, - }; - - auto error = write(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - auto cnt = io.offset - file->nextOff; - file->nextOff = io.offset; - - thread->retval[0] = cnt; - return {}; +orbis::SysResult orbis::sys_write(Thread* thread, sint fd, ptr buf, + size_t nbyte) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto write = file->ops->write; + if (write == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + IoVec vec{.base = (void*)buf, .len = nbyte}; + + Uio io{ + .offset = file->nextOff, + .iov = &vec, + .iovcnt = 1, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Write, + .td = thread, + }; + + auto error = write(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + auto cnt = io.offset - file->nextOff; + file->nextOff = io.offset; + + thread->retval[0] = cnt; + return {}; } -orbis::SysResult orbis::sys_pwrite(Thread *thread, sint fd, ptr buf, - size_t nbyte, off_t offset) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto write = file->ops->write; - if (write == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - IoVec vec{.base = (void *)buf, .len = nbyte}; - - Uio io{ - .offset = static_cast(offset), - .iov = &vec, - .iovcnt = 1, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Write, - .td = thread, - }; - - auto error = write(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - thread->retval[0] = io.offset - offset; - return {}; +orbis::SysResult orbis::sys_pwrite(Thread* thread, sint fd, ptr buf, + size_t nbyte, off_t offset) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto write = file->ops->write; + if (write == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + IoVec vec{.base = (void*)buf, .len = nbyte}; + + Uio io{ + .offset = static_cast(offset), + .iov = &vec, + .iovcnt = 1, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Write, + .td = thread, + }; + + auto error = write(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + thread->retval[0] = io.offset - offset; + return {}; } -orbis::SysResult orbis::sys_freebsd6_pwrite(Thread *thread, sint fd, - ptr buf, size_t nbyte, - sint, off_t offset) { - return sys_pwrite(thread, fd, buf, nbyte, offset); +orbis::SysResult orbis::sys_freebsd6_pwrite(Thread* thread, sint fd, + ptr buf, size_t nbyte, + sint, off_t offset) +{ + return sys_pwrite(thread, fd, buf, nbyte, offset); } -orbis::SysResult orbis::sys_writev(Thread *thread, sint fd, ptr iovp, - uint iovcnt) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto write = file->ops->write; - if (write == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - - Uio io{ - .offset = file->nextOff, - .iov = iovp, - .iovcnt = iovcnt, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Write, - .td = thread, - }; - - auto error = write(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - auto cnt = io.offset - file->nextOff; - file->nextOff = io.offset; - - thread->retval[0] = cnt; - return {}; +orbis::SysResult orbis::sys_writev(Thread* thread, sint fd, ptr iovp, + uint iovcnt) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto write = file->ops->write; + if (write == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + + Uio io{ + .offset = file->nextOff, + .iov = iovp, + .iovcnt = iovcnt, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Write, + .td = thread, + }; + + auto error = write(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + auto cnt = io.offset - file->nextOff; + file->nextOff = io.offset; + + thread->retval[0] = cnt; + return {}; } -orbis::SysResult orbis::sys_pwritev(Thread *thread, sint fd, ptr iovp, - uint iovcnt, off_t offset) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto write = file->ops->write; - if (write == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - - Uio io{ - .offset = static_cast(offset), - .iov = iovp, - .iovcnt = iovcnt, - .segflg = UioSeg::UserSpace, - .rw = UioRw::Write, - .td = thread, - }; - auto error = write(file.get(), &io, thread); - if (error != ErrorCode{} && error != ErrorCode::AGAIN) { - return error; - } - - thread->retval[0] = io.offset - offset; - return {}; +orbis::SysResult orbis::sys_pwritev(Thread* thread, sint fd, ptr iovp, + uint iovcnt, off_t offset) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto write = file->ops->write; + if (write == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + + Uio io{ + .offset = static_cast(offset), + .iov = iovp, + .iovcnt = iovcnt, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Write, + .td = thread, + }; + auto error = write(file.get(), &io, thread); + if (error != ErrorCode{} && error != ErrorCode::AGAIN) + { + return error; + } + + thread->retval[0] = io.offset - offset; + return {}; } -orbis::SysResult orbis::sys_ftruncate(Thread *thread, sint fd, off_t length) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto truncate = file->ops->truncate; - if (truncate == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - return truncate(file.get(), length, thread); +orbis::SysResult orbis::sys_ftruncate(Thread* thread, sint fd, off_t length) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto truncate = file->ops->truncate; + if (truncate == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + return truncate(file.get(), length, thread); } -orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread *thread, sint fd, sint, - off_t length) { - return sys_ftruncate(thread, fd, length); +orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread* thread, sint fd, sint, + off_t length) +{ + return sys_ftruncate(thread, fd, length); } // clang-format off #define IOCPARM_SHIFT 13 /* number of bits for ioctl size */ @@ -318,172 +356,196 @@ orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread *thread, sint fd, sint, #define _IOWR(g, n, t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) // clang-format on -static std::string iocGroupToString(unsigned iocGroup) { - if (iocGroup >= 128) { - const char *sceGroups[] = { - "DEV", - "DMEM", - "GC", - "DCE", - "UVD", - "VCE", - "DBGGC", - "TWSI", - "MDBG", - "DEVENV", - "AJM", - "TRACE", - "IBS", - "MBUS", - "HDMI", - "CAMERA", - "FAN", - "THERMAL", - "PFS", - "ICC_CONFIG", - "IPC", - "IOSCHED", - "ICC_INDICATOR", - "EXFATFS", - "ICC_NVS", - "DVE", - "ICC_POWER", - "AV_CONTROL", - "ICC_SC_CONFIGURATION", - "ICC_DEVICE_POWER", - "SSHOT", - "DCE_SCANIN", - "FSCTRL", - "HMD", - "SHM", - "PHYSHM", - "HMDDFU", - "BLUETOOTH_HID", - "SBI", - "S3DA", - "SPM", - "BLOCKPOOL", - "SDK_EVENTLOG", - }; - - if (iocGroup - 127 >= std::size(sceGroups)) { - return "'?'"; - } - - return sceGroups[iocGroup - 127]; - } - - if (isprint(iocGroup)) { - return "'" + std::string(1, (char)iocGroup) + "'"; - } - - return "'?'"; +static std::string iocGroupToString(unsigned iocGroup) +{ + if (iocGroup >= 128) + { + const char* sceGroups[] = { + "DEV", + "DMEM", + "GC", + "DCE", + "UVD", + "VCE", + "DBGGC", + "TWSI", + "MDBG", + "DEVENV", + "AJM", + "TRACE", + "IBS", + "MBUS", + "HDMI", + "CAMERA", + "FAN", + "THERMAL", + "PFS", + "ICC_CONFIG", + "IPC", + "IOSCHED", + "ICC_INDICATOR", + "EXFATFS", + "ICC_NVS", + "DVE", + "ICC_POWER", + "AV_CONTROL", + "ICC_SC_CONFIGURATION", + "ICC_DEVICE_POWER", + "SSHOT", + "DCE_SCANIN", + "FSCTRL", + "HMD", + "SHM", + "PHYSHM", + "HMDDFU", + "BLUETOOTH_HID", + "SBI", + "S3DA", + "SPM", + "BLOCKPOOL", + "SDK_EVENTLOG", + }; + + if (iocGroup - 127 >= std::size(sceGroups)) + { + return "'?'"; + } + + return sceGroups[iocGroup - 127]; + } + + if (isprint(iocGroup)) + { + return "'" + std::string(1, (char)iocGroup) + "'"; + } + + return "'?'"; } -static void printIoctl(unsigned long arg) { - std::printf("0x%lx { IO%s%s %lu(%s), %lu, %lu }\n", arg, - arg & IOC_OUT ? "R" : "", arg & IOC_IN ? "W" : "", IOCGROUP(arg), - iocGroupToString(IOCGROUP(arg)).c_str(), arg & 0xFF, - IOCPARM_LEN(arg)); +static void printIoctl(unsigned long arg) +{ + std::printf("0x%lx { IO%s%s %lu(%s), %lu, %lu }\n", arg, + arg & IOC_OUT ? "R" : "", arg & IOC_IN ? "W" : "", IOCGROUP(arg), + iocGroupToString(IOCGROUP(arg)).c_str(), arg & 0xFF, + IOCPARM_LEN(arg)); } -static void ioctlToStream(std::ostream &stream, unsigned long arg) { - stream << "0x" << std::hex << arg << " { IO"; - - if ((arg & IOC_OUT) != 0) { - stream << 'R'; - } - - if ((arg & IOC_IN) != 0) { - stream << 'W'; - } - if ((arg & IOC_VOID) != 0) { - stream << 'i'; - } - - stream << " 0x" << IOCGROUP(arg); - stream << "('" << iocGroupToString(IOCGROUP(arg)) << "'), "; - stream << std::dec << (arg & 0xFF) << ", " << IOCPARM_LEN(arg) << " }"; +static void ioctlToStream(std::ostream& stream, unsigned long arg) +{ + stream << "0x" << std::hex << arg << " { IO"; + + if ((arg & IOC_OUT) != 0) + { + stream << 'R'; + } + + if ((arg & IOC_IN) != 0) + { + stream << 'W'; + } + if ((arg & IOC_VOID) != 0) + { + stream << 'i'; + } + + stream << " 0x" << IOCGROUP(arg); + stream << "('" << iocGroupToString(IOCGROUP(arg)) << "'), "; + stream << std::dec << (arg & 0xFF) << ", " << IOCPARM_LEN(arg) << " }"; } -static std::string ioctlToString(unsigned long arg) { - std::ostringstream stream; - ioctlToStream(stream, arg); - return std::move(stream).str(); +static std::string ioctlToString(unsigned long arg) +{ + std::ostringstream stream; + ioctlToStream(stream, arg); + return std::move(stream).str(); } -orbis::SysResult orbis::sys_ioctl(Thread *thread, sint fd, ulong com, - caddr_t data) { - auto str = ioctlToString(com); - ORBIS_LOG_WARNING(__FUNCTION__, fd, com, str); - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - auto ioctl = file->ops->ioctl; - if (ioctl == nullptr) { - return ErrorCode::NOTSUP; - } - - std::lock_guard lock(file->mtx); - return ioctl(file.get(), com, data, thread); +orbis::SysResult orbis::sys_ioctl(Thread* thread, sint fd, ulong com, + caddr_t data) +{ + auto str = ioctlToString(com); + ORBIS_LOG_WARNING(__FUNCTION__, fd, com, str); + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + auto ioctl = file->ops->ioctl; + if (ioctl == nullptr) + { + return ErrorCode::NOTSUP; + } + + std::lock_guard lock(file->mtx); + return ioctl(file.get(), com, data, thread); } -orbis::SysResult orbis::sys_pselect(Thread *thread, sint nd, ptr in, - ptr ou, ptr ex, - ptr ts, - ptr sm) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_pselect(Thread* thread, sint nd, ptr in, + ptr ou, ptr ex, + ptr ts, + ptr sm) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_select(Thread *thread, sint nd, - ptr in, - ptr out, - ptr ex, - ptr tv) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_select(Thread* thread, sint nd, + ptr in, + ptr out, + ptr ex, + ptr tv) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_poll(Thread *thread, ptr fds, - uint nfds, sint timeout) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_poll(Thread* thread, ptr fds, + uint nfds, sint timeout) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_openbsd_poll(Thread *thread, ptr fds, - uint nfds, sint timeout) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_openbsd_poll(Thread* thread, ptr fds, + uint nfds, sint timeout) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_nlm_syscall(Thread *thread, sint debug_level, - sint grace_period, sint addr_count, - ptr> addrs) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_nlm_syscall(Thread* thread, sint debug_level, + sint grace_period, sint addr_count, + ptr> addrs) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_nfssvc(Thread *thread, sint flag, caddr_t argp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_nfssvc(Thread* thread, sint flag, caddr_t argp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sysarch(Thread *thread, sint op, ptr parms) { - if (op == 129) { - uint64_t fs; - if (auto error = uread(fs, (ptr)parms); error != ErrorCode{}) - return error; - ORBIS_LOG_WARNING("sys_sysarch: set FS", (std::size_t)fs); - thread->fsBase = fs; - return {}; - } - - ORBIS_LOG_WARNING(__FUNCTION__, op, parms); - return {}; +orbis::SysResult orbis::sys_sysarch(Thread* thread, sint op, ptr parms) +{ + if (op == 129) + { + uint64_t fs; + if (auto error = uread(fs, (ptr)parms); error != ErrorCode{}) + return error; + ORBIS_LOG_WARNING("sys_sysarch: set FS", (std::size_t)fs); + thread->fsBase = fs; + return {}; + } + + ORBIS_LOG_WARNING(__FUNCTION__, op, parms); + return {}; } -orbis::SysResult orbis::sys_nnpfs_syscall(Thread *thread, sint operation, - ptr a_pathP, sint opcode, - ptr a_paramsP, - sint a_followSymlinks) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_nnpfs_syscall(Thread* thread, sint operation, + ptr a_pathP, sint opcode, + ptr a_paramsP, + sint a_followSymlinks) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_afs3_syscall(Thread *thread, slong syscall, - slong param1, slong param2, - slong param3, slong param4, - slong param5, slong param6) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_afs3_syscall(Thread* thread, slong syscall, + slong param1, slong param2, + slong param3, slong param4, + slong param5, slong param6) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_gssd_syscall(Thread *thread, ptr path) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_gssd_syscall(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_jail.cpp b/orbis-kernel/src/sys/sys_jail.cpp index 74261d63..82b466eb 100644 --- a/orbis-kernel/src/sys/sys_jail.cpp +++ b/orbis-kernel/src/sys/sys_jail.cpp @@ -1,19 +1,24 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_jail(Thread *thread, ptr jail) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_jail(Thread* thread, ptr jail) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_jail_set(Thread *thread, ptr iovp, - uint iovcnt, sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_jail_set(Thread* thread, ptr iovp, + uint iovcnt, sint flags) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_jail_get(Thread *thread, ptr iovp, - uint iovcnt, sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_jail_get(Thread* thread, ptr iovp, + uint iovcnt, sint flags) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_jail_remove(Thread *thread, sint jid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_jail_remove(Thread* thread, sint jid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_jail_attach(Thread *thread, sint jid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_jail_attach(Thread* thread, sint jid) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_ktrace.cpp b/orbis-kernel/src/sys/sys_ktrace.cpp index 7d28e0bf..af4d5156 100644 --- a/orbis-kernel/src/sys/sys_ktrace.cpp +++ b/orbis-kernel/src/sys/sys_ktrace.cpp @@ -1,10 +1,12 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_ktrace(Thread *thread, ptr fname, - sint ops, sint facs, sint pit) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktrace(Thread* thread, ptr fname, + sint ops, sint facs, sint pit) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_utrace(Thread *thread, ptr addr, - size_t len) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_utrace(Thread* thread, ptr addr, + size_t len) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_linker.cpp b/orbis-kernel/src/sys/sys_linker.cpp index 8f9b6703..aecc7551 100644 --- a/orbis-kernel/src/sys/sys_linker.cpp +++ b/orbis-kernel/src/sys/sys_linker.cpp @@ -1,29 +1,37 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_kldload(Thread *thread, ptr file) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldunload(Thread *thread, sint fileid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldunloadf(Thread *thread, slong fileid, - sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldfind(Thread *thread, ptr name) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldnext(Thread *thread, sint fileid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldstat(Thread *thread, sint fileid, - ptr stat) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldfirstmod(Thread *thread, sint fileid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kldsym(Thread *thread, sint fileid, sint cmd, - ptr data) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kldload(Thread* thread, ptr file) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldunload(Thread* thread, sint fileid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldunloadf(Thread* thread, slong fileid, + sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldfind(Thread* thread, ptr name) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldnext(Thread* thread, sint fileid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldstat(Thread* thread, sint fileid, + ptr stat) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldfirstmod(Thread* thread, sint fileid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kldsym(Thread* thread, sint fileid, sint cmd, + ptr data) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_loginclass.cpp b/orbis-kernel/src/sys/sys_loginclass.cpp index 00d1e655..3113a634 100644 --- a/orbis-kernel/src/sys/sys_loginclass.cpp +++ b/orbis-kernel/src/sys/sys_loginclass.cpp @@ -1,9 +1,11 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_getloginclass(Thread *thread, ptr namebuf, - size_t namelen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getloginclass(Thread* thread, ptr namebuf, + size_t namelen) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_setloginclass(Thread *thread, ptr namebuf) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setloginclass(Thread* thread, ptr namebuf) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_mac.cpp b/orbis-kernel/src/sys/sys_mac.cpp index 1f4c501c..5cdd3d78 100644 --- a/orbis-kernel/src/sys/sys_mac.cpp +++ b/orbis-kernel/src/sys/sys_mac.cpp @@ -1,44 +1,54 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys___mac_get_pid(Thread *thread, pid_t pid, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_get_proc(Thread *thread, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_set_proc(Thread *thread, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_get_fd(Thread *thread, sint fd, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_get_file(Thread *thread, ptr path, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_set_fd(Thread *thread, sint fd, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_set_file(Thread *thread, ptr path, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_get_link(Thread *thread, - ptr path_p, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___mac_set_link(Thread *thread, - ptr path_p, - ptr mac_p) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mac_syscall(Thread *thread, ptr policy, - sint call, ptr arg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys___mac_get_pid(Thread* thread, pid_t pid, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_get_proc(Thread* thread, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_set_proc(Thread* thread, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_get_fd(Thread* thread, sint fd, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_get_file(Thread* thread, ptr path, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_set_fd(Thread* thread, sint fd, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_set_file(Thread* thread, ptr path, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_get_link(Thread* thread, + ptr path_p, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___mac_set_link(Thread* thread, + ptr path_p, + ptr mac_p) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mac_syscall(Thread* thread, ptr policy, + sint call, ptr arg) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_module.cpp b/orbis-kernel/src/sys/sys_module.cpp index 84b74a0d..ee532869 100644 --- a/orbis-kernel/src/sys/sys_module.cpp +++ b/orbis-kernel/src/sys/sys_module.cpp @@ -1,15 +1,19 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_modnext(Thread *thread, sint modid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_modnext(Thread* thread, sint modid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_modfnext(Thread *thread, sint modid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_modfnext(Thread* thread, sint modid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_modstat(Thread *thread, sint modid, - ptr stat) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_modstat(Thread* thread, sint modid, + ptr stat) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_modfind(Thread *thread, ptr name) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_modfind(Thread* thread, ptr name) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_msg.cpp b/orbis-kernel/src/sys/sys_msg.cpp index 2a3c7b9b..ab67b6be 100644 --- a/orbis-kernel/src/sys/sys_msg.cpp +++ b/orbis-kernel/src/sys/sys_msg.cpp @@ -1,22 +1,27 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_msgctl(Thread *thread, sint msqid, sint cmd, - ptr buf) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_msgctl(Thread* thread, sint msqid, sint cmd, + ptr buf) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_msgget(Thread *thread, key_t key, sint msgflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_msgget(Thread* thread, key_t key, sint msgflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_msgsnd(Thread *thread, sint msqid, - ptr msgp, size_t msgsz, - sint msgflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_msgsnd(Thread* thread, sint msqid, + ptr msgp, size_t msgsz, + sint msgflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_msgrcv(Thread *thread, sint msqid, ptr msgp, - size_t msgsz, slong msgtyp, sint msgflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_msgrcv(Thread* thread, sint msqid, ptr msgp, + size_t msgsz, slong msgtyp, sint msgflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_msgsys(Thread *thread, sint which, sint a2, sint a3, - sint a4, sint a5, sint a6) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_msgsys(Thread* thread, sint which, sint a2, sint a3, + sint a4, sint a5, sint a6) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_ntptime.cpp b/orbis-kernel/src/sys/sys_ntptime.cpp index 5a5d6dce..e9d9f54b 100644 --- a/orbis-kernel/src/sys/sys_ntptime.cpp +++ b/orbis-kernel/src/sys/sys_ntptime.cpp @@ -1,13 +1,16 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_ntp_gettime(Thread *thread, - ptr ntvp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ntp_gettime(Thread* thread, + ptr ntvp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ntp_adjtime(Thread *thread, ptr tp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ntp_adjtime(Thread* thread, ptr tp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_adjtime(Thread *thread, ptr delta, - ptr olddelta) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_adjtime(Thread* thread, ptr delta, + ptr olddelta) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_p1003_1b.cpp b/orbis-kernel/src/sys/sys_p1003_1b.cpp index e54ef652..1d277064 100644 --- a/orbis-kernel/src/sys/sys_p1003_1b.cpp +++ b/orbis-kernel/src/sys/sys_p1003_1b.cpp @@ -2,35 +2,43 @@ #include orbis::SysResult -orbis::sys_sched_setparam(Thread *thread, pid_t pid, - ptr param) { - return ErrorCode::NOSYS; +orbis::sys_sched_setparam(Thread* thread, pid_t pid, + ptr param) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sched_getparam(Thread *thread, pid_t pid, - ptr param) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sched_getparam(Thread* thread, pid_t pid, + ptr param) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_sched_setscheduler(Thread *thread, pid_t pid, sint policy, - ptr param) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sched_getscheduler(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sched_yield(Thread *thread) { - std::this_thread::yield(); - return {}; -} -orbis::SysResult orbis::sys_sched_get_priority_max(Thread *thread, - sint policy) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sched_get_priority_min(Thread *thread, - sint policy) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sched_rr_get_interval(Thread *thread, pid_t pid, - ptr interval) { - return ErrorCode::NOSYS; +orbis::sys_sched_setscheduler(Thread* thread, pid_t pid, sint policy, + ptr param) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sched_getscheduler(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sched_yield(Thread* thread) +{ + std::this_thread::yield(); + return {}; +} +orbis::SysResult orbis::sys_sched_get_priority_max(Thread* thread, + sint policy) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sched_get_priority_min(Thread* thread, + sint policy) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sched_rr_get_interval(Thread* thread, pid_t pid, + ptr interval) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_pipe.cpp b/orbis-kernel/src/sys/sys_pipe.cpp index 411b3215..c59d09fc 100644 --- a/orbis-kernel/src/sys/sys_pipe.cpp +++ b/orbis-kernel/src/sys/sys_pipe.cpp @@ -1,3 +1,3 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_pipe(Thread *thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_pipe(Thread* thread) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_procdesc.cpp b/orbis-kernel/src/sys/sys_procdesc.cpp index 0ddd003f..65065193 100644 --- a/orbis-kernel/src/sys/sys_procdesc.cpp +++ b/orbis-kernel/src/sys/sys_procdesc.cpp @@ -1,5 +1,6 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_pdgetpid(Thread *thread, sint fd, ptr pidp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_pdgetpid(Thread* thread, sint fd, ptr pidp) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_process.cpp b/orbis-kernel/src/sys/sys_process.cpp index cf3223fd..a080d2d6 100644 --- a/orbis-kernel/src/sys/sys_process.cpp +++ b/orbis-kernel/src/sys/sys_process.cpp @@ -1,6 +1,7 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_ptrace(Thread *thread, sint req, pid_t pid, - caddr_t addr, sint data) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ptrace(Thread* thread, sint req, pid_t pid, + caddr_t addr, sint data) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_prot.cpp b/orbis-kernel/src/sys/sys_prot.cpp index 5b8decee..b9e0db09 100644 --- a/orbis-kernel/src/sys/sys_prot.cpp +++ b/orbis-kernel/src/sys/sys_prot.cpp @@ -1,82 +1,103 @@ #include "sys/sysproto.hpp" #include "utils/Logs.hpp" -orbis::SysResult orbis::sys_getpid(Thread *thread) { - thread->retval[0] = thread->tid; - return {}; -} -orbis::SysResult orbis::sys_getppid(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getpgrp(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getpgid(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getsid(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getuid(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_geteuid(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getgid(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getegid(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getgroups(Thread *thread, uint gidsetsize, - ptr gidset) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setsid(Thread *thread) { - ORBIS_LOG_WARNING(__FUNCTION__); - return {}; -} -orbis::SysResult orbis::sys_setpgid(Thread *thread, sint pid, sint pgid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setuid(Thread *thread, uid_t uid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_seteuid(Thread *thread, uid_t euid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setgid(Thread *thread, gid_t gid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setegid(Thread *thread, gid_t egid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setgroups(Thread *thread, uint gidsetsize, - ptr gidset) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setreuid(Thread *thread, sint ruid, sint euid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setregid(Thread *thread, sint rgid, sint egid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setresuid(Thread *thread, uid_t ruid, uid_t euid, - uid_t suid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setresgid(Thread *thread, gid_t rgid, gid_t egid, - gid_t sgid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getresuid(Thread *thread, ptr ruid, - ptr euid, ptr suid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getresgid(Thread *thread, ptr rgid, - ptr egid, ptr sgid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_issetugid(Thread *thread) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___setugid(Thread *thread, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getlogin(Thread *thread, ptr namebuf, - uint namelen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setlogin(Thread *thread, ptr namebuf) { - ORBIS_LOG_WARNING(__FUNCTION__, namebuf); - return {}; +orbis::SysResult orbis::sys_getpid(Thread* thread) +{ + thread->retval[0] = thread->tid; + return {}; +} +orbis::SysResult orbis::sys_getppid(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getpgrp(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getpgid(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getsid(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getuid(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_geteuid(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getgid(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getegid(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getgroups(Thread* thread, uint gidsetsize, + ptr gidset) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setsid(Thread* thread) +{ + ORBIS_LOG_WARNING(__FUNCTION__); + return {}; +} +orbis::SysResult orbis::sys_setpgid(Thread* thread, sint pid, sint pgid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setuid(Thread* thread, uid_t uid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_seteuid(Thread* thread, uid_t euid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setgid(Thread* thread, gid_t gid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setegid(Thread* thread, gid_t egid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setgroups(Thread* thread, uint gidsetsize, + ptr gidset) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setreuid(Thread* thread, sint ruid, sint euid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setregid(Thread* thread, sint rgid, sint egid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setresuid(Thread* thread, uid_t ruid, uid_t euid, + uid_t suid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setresgid(Thread* thread, gid_t rgid, gid_t egid, + gid_t sgid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getresuid(Thread* thread, ptr ruid, + ptr euid, ptr suid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getresgid(Thread* thread, ptr rgid, + ptr egid, ptr sgid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_issetugid(Thread* thread) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___setugid(Thread* thread, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getlogin(Thread* thread, ptr namebuf, + uint namelen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setlogin(Thread* thread, ptr namebuf) +{ + ORBIS_LOG_WARNING(__FUNCTION__, namebuf); + return {}; } diff --git a/orbis-kernel/src/sys/sys_pty_pts.cpp b/orbis-kernel/src/sys/sys_pty_pts.cpp index 65b6246a..b10196fc 100644 --- a/orbis-kernel/src/sys/sys_pty_pts.cpp +++ b/orbis-kernel/src/sys/sys_pty_pts.cpp @@ -1,5 +1,6 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_posix_openpt(Thread *thread, sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_posix_openpt(Thread* thread, sint flags) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_rctl.cpp b/orbis-kernel/src/sys/sys_rctl.cpp index a8215e20..2714a0c1 100644 --- a/orbis-kernel/src/sys/sys_rctl.cpp +++ b/orbis-kernel/src/sys/sys_rctl.cpp @@ -1,32 +1,37 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_rctl_get_racct(Thread *thread, - ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rctl_get_racct(Thread* thread, + ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rctl_get_rules(Thread *thread, - ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rctl_get_rules(Thread* thread, + ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rctl_get_limits(Thread *thread, - ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rctl_get_limits(Thread* thread, + ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rctl_add_rule(Thread *thread, - ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rctl_add_rule(Thread* thread, + ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rctl_remove_rule(Thread *thread, - ptr inbufp, - size_t inbuflen, ptr outbuf, - size_t outbuflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rctl_remove_rule(Thread* thread, + ptr inbufp, + size_t inbuflen, ptr outbuf, + size_t outbuflen) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_resource.cpp b/orbis-kernel/src/sys/sys_resource.cpp index d8942bcc..43210cbb 100644 --- a/orbis-kernel/src/sys/sys_resource.cpp +++ b/orbis-kernel/src/sys/sys_resource.cpp @@ -1,31 +1,38 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_getpriority(Thread *thread, sint which, sint who) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getpriority(Thread* thread, sint which, sint who) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_setpriority(Thread *thread, sint which, sint who, - sint prio) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setpriority(Thread* thread, sint which, sint who, + sint prio) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_rtprio_thread(Thread *thread, sint function, - lwpid_t lwpid, - ptr rtp) { - std::printf("sys_rtprio_thread: unimplemented\n"); - return {}; +orbis::SysResult orbis::sys_rtprio_thread(Thread* thread, sint function, + lwpid_t lwpid, + ptr rtp) +{ + std::printf("sys_rtprio_thread: unimplemented\n"); + return {}; } -orbis::SysResult orbis::sys_rtprio(Thread *thread, sint function, pid_t pid, - ptr rtp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_rtprio(Thread* thread, sint function, pid_t pid, + ptr rtp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_setrlimit(Thread *thread, uint which, - ptr rlp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setrlimit(Thread* thread, uint which, + ptr rlp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getrlimit(Thread *thread, uint which, - ptr rlp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getrlimit(Thread* thread, uint which, + ptr rlp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getrusage(Thread *thread, sint who, - ptr rusage) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getrusage(Thread* thread, sint who, + ptr rusage) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_route.cpp b/orbis-kernel/src/sys/sys_route.cpp index a19427e8..a0ce8b2d 100644 --- a/orbis-kernel/src/sys/sys_route.cpp +++ b/orbis-kernel/src/sys/sys_route.cpp @@ -1,5 +1,6 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_setfib(Thread *thread, sint fib) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setfib(Thread* thread, sint fib) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index d1db1679..97f95ddd 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -13,1785 +13,2159 @@ #include #include -orbis::SysResult orbis::sys_netcontrol(Thread *thread, sint fd, uint op, - ptr buf, uint nbuf) { - return {}; -} -orbis::SysResult orbis::sys_netabort(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_netgetsockinfo(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_socketex(Thread *thread, ptr name, - sint domain, sint type, sint protocol) { - ORBIS_LOG_TODO(__FUNCTION__, name, domain, type, protocol); - if (auto socket = thread->tproc->ops->socket) { - Ref file; - auto result = socket(thread, name, domain, type, protocol, &file); - - if (result.isError()) { - return result; - } - - auto fd = thread->tproc->fileDescriptors.insert(file); - ORBIS_LOG_WARNING("Socket opened", name, fd); - thread->retval[0] = fd; - return {}; - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_socketclose(Thread *thread, sint fd) { - // This syscall is identical to sys_close - ORBIS_LOG_NOTICE(__FUNCTION__, fd); - if (thread->tproc->fileDescriptors.close(fd)) { - return {}; - } - - return ErrorCode::BADF; -} -orbis::SysResult orbis::sys_netgetiflist(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_kqueueex(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mtypeprotect(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, - uint32_t id, ptr result, - ptr value, uint64_t type) { - if (op == 25) { - struct nonsys_int { - union { - uint64_t encoded_id; - struct { - uint8_t data[4]; - uint8_t table; - uint8_t index; - uint16_t checksum; - } encoded_id_parts; - }; - uint32_t unk; - uint32_t value; - }; - - auto int_value = reinterpret_cast(value); - ORBIS_LOG_TODO( - __FUNCTION__, int_value->encoded_id, - int_value->encoded_id_parts.data[0], - int_value->encoded_id_parts.data[1], - int_value->encoded_id_parts.data[2], - int_value->encoded_id_parts.data[3], int_value->encoded_id_parts.table, - int_value->encoded_id_parts.index, int_value->encoded_id_parts.checksum, - int_value->unk, int_value->value); - - // HACK: set default system language and gamepad layout to US/EU region - // 0x12356328ECF5617B -> language where is 0 is Japanese, 1 is English - // 0x22666251FE7BECFF -> confirm button layout, 0 is Circle, 1 is Cross - if (int_value->encoded_id == 0x12356328ECF5617B || - int_value->encoded_id == 0x22666251FE7BECFF) { - int_value->value = 1; - return {}; - } - - int_value->value = 0; - } - - return {}; -} -orbis::SysResult orbis::sys_jitshm_create(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_jitshm_alias(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dl_get_list(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dl_get_info(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dl_notify_event(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_evf_create(Thread *thread, ptr name, - sint attrs, uint64_t initPattern) { - ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initPattern); - if (name == nullptr) { - return ErrorCode::INVAL; - } - - if (attrs & ~(kEvfAttrSingle | kEvfAttrMulti | kEvfAttrThPrio | - kEvfAttrThFifo | kEvfAttrShared)) { - return ErrorCode::INVAL; - } - - switch (attrs & (kEvfAttrSingle | kEvfAttrMulti)) { - case kEvfAttrSingle | kEvfAttrMulti: - return ErrorCode::INVAL; - case 0: - attrs |= kEvfAttrSingle; - break; - - default: - break; - } - - switch (attrs & (kEvfAttrThPrio | kEvfAttrThFifo)) { - case kEvfAttrThPrio | kEvfAttrThFifo: - return ErrorCode::INVAL; - case 0: - attrs |= kEvfAttrThFifo; - break; - - default: - break; - } - - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - - EventFlag *eventFlag; - if (attrs & kEvfAttrShared) { - auto [insertedEvf, inserted] = - thread->tproc->context->createEventFlag(_name, attrs, initPattern); - - if (!inserted) { - return ErrorCode::EXIST; // FIXME: verify - } - - eventFlag = insertedEvf; - } else { - eventFlag = knew(attrs, initPattern); - std::strncpy(eventFlag->name, _name, 32); - } - - thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); - return {}; -} -orbis::SysResult orbis::sys_evf_delete(Thread *thread, sint id) { - ORBIS_LOG_WARNING(__FUNCTION__, id); - Ref evf = thread->tproc->evfMap.get(id); - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - thread->tproc->evfMap.destroy(id); - return {}; -} -orbis::SysResult orbis::sys_evf_open(Thread *thread, ptr name) { - ORBIS_LOG_WARNING(__FUNCTION__, name); - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - - auto eventFlag = thread->tproc->context->findEventFlag(_name); - - if (eventFlag == nullptr) { - // HACK :) - if (std::string_view(_name).starts_with("SceAppMessaging")) { - // change pattern on system window open - return sys_evf_create(thread, name, kEvfAttrShared, 1); - } - return sys_evf_create(thread, name, kEvfAttrShared, 0); - return ErrorCode::SRCH; - } - - thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); - return {}; -} -orbis::SysResult orbis::sys_evf_close(Thread *thread, sint id) { - ORBIS_LOG_WARNING(__FUNCTION__, thread->tid, id); - if (!thread->tproc->evfMap.close(id)) { - return ErrorCode::SRCH; - } - - return {}; -} -orbis::SysResult orbis::sys_evf_wait(Thread *thread, sint id, - uint64_t patternSet, uint64_t mode, - ptr pPatternSet, - ptr pTimeout) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, patternSet, mode, pPatternSet, - pTimeout); - if ((mode & (kEvfWaitModeAnd | kEvfWaitModeOr)) == 0 || - (mode & ~(kEvfWaitModeAnd | kEvfWaitModeOr | kEvfWaitModeClearAll | - kEvfWaitModeClearPat)) != 0 || - patternSet == 0) { - return ErrorCode::INVAL; - } - - Ref evf = thread->tproc->evfMap.get(id); - - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - std::uint32_t resultTimeout{}; - auto result = evf->wait(thread, mode, patternSet, - pTimeout != nullptr ? &resultTimeout : nullptr); - - ORBIS_LOG_TRACE("sys_evf_wait wakeup", thread->tid, thread->evfResultPattern); - - if (pPatternSet != nullptr) { - uwrite(pPatternSet, thread->evfResultPattern); - } - - if (pTimeout != nullptr) { - uwrite(pTimeout, resultTimeout); - } - - if (result == ErrorCode::TIMEDOUT) - return SysResult::notAnError(result); - - return result; -} - -orbis::SysResult orbis::sys_evf_trywait(Thread *thread, sint id, - uint64_t patternSet, uint64_t mode, - ptr pPatternSet) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, patternSet, mode, pPatternSet); - if ((mode & (kEvfWaitModeAnd | kEvfWaitModeOr)) == 0 || - (mode & ~(kEvfWaitModeAnd | kEvfWaitModeOr | kEvfWaitModeClearAll | - kEvfWaitModeClearPat)) != 0 || - patternSet == 0) { - return ErrorCode::INVAL; - } - - Ref evf = thread->tproc->evfMap.get(id); - - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - auto result = evf->tryWait(thread, mode, patternSet); - - if (pPatternSet != nullptr) { - uwrite(pPatternSet, thread->evfResultPattern); - } - - if (result == ErrorCode::BUSY) { - return SysResult::notAnError(result); - } - return result; -} -orbis::SysResult orbis::sys_evf_set(Thread *thread, sint id, uint64_t value) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value); - Ref evf = thread->tproc->evfMap.get(id); - - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - evf->set(value); - return {}; -} -orbis::SysResult orbis::sys_evf_clear(Thread *thread, sint id, uint64_t value) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value); - Ref evf = thread->tproc->evfMap.get(id); - - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - evf->clear(value); - return {}; -} -orbis::SysResult orbis::sys_evf_cancel(Thread *thread, sint id, uint64_t value, - ptr pNumWaitThreads) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value, pNumWaitThreads); - Ref evf = thread->tproc->evfMap.get(id); - - if (evf == nullptr) { - return ErrorCode::SRCH; - } - - auto numWaitThreads = evf->cancel(value); - if (pNumWaitThreads != nullptr) { - return uwrite(pNumWaitThreads, static_cast(numWaitThreads)); - } - return {}; +orbis::SysResult orbis::sys_netcontrol(Thread* thread, sint fd, uint op, + ptr buf, uint nbuf) +{ + return {}; +} +orbis::SysResult orbis::sys_netabort(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_netgetsockinfo(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_socketex(Thread* thread, ptr name, + sint domain, sint type, sint protocol) +{ + ORBIS_LOG_TODO(__FUNCTION__, name, domain, type, protocol); + if (auto socket = thread->tproc->ops->socket) + { + Ref file; + auto result = socket(thread, name, domain, type, protocol, &file); + + if (result.isError()) + { + return result; + } + + auto fd = thread->tproc->fileDescriptors.insert(file); + ORBIS_LOG_WARNING("Socket opened", name, fd); + thread->retval[0] = fd; + return {}; + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_socketclose(Thread* thread, sint fd) +{ + // This syscall is identical to sys_close + ORBIS_LOG_NOTICE(__FUNCTION__, fd); + if (thread->tproc->fileDescriptors.close(fd)) + { + return {}; + } + + return ErrorCode::BADF; +} +orbis::SysResult orbis::sys_netgetiflist(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_kqueueex(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mtypeprotect(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_regmgr_call(Thread* thread, uint32_t op, + uint32_t id, ptr result, + ptr value, uint64_t type) +{ + if (op == 25) + { + struct nonsys_int + { + union + { + uint64_t encoded_id; + struct + { + uint8_t data[4]; + uint8_t table; + uint8_t index; + uint16_t checksum; + } encoded_id_parts; + }; + uint32_t unk; + uint32_t value; + }; + + auto int_value = reinterpret_cast(value); + ORBIS_LOG_TODO( + __FUNCTION__, int_value->encoded_id, + int_value->encoded_id_parts.data[0], + int_value->encoded_id_parts.data[1], + int_value->encoded_id_parts.data[2], + int_value->encoded_id_parts.data[3], int_value->encoded_id_parts.table, + int_value->encoded_id_parts.index, int_value->encoded_id_parts.checksum, + int_value->unk, int_value->value); + + // HACK: set default system language and gamepad layout to US/EU region + // 0x12356328ECF5617B -> language where is 0 is Japanese, 1 is English + // 0x22666251FE7BECFF -> confirm button layout, 0 is Circle, 1 is Cross + if (int_value->encoded_id == 0x12356328ECF5617B || + int_value->encoded_id == 0x22666251FE7BECFF) + { + int_value->value = 1; + return {}; + } + + int_value->value = 0; + } + + return {}; +} +orbis::SysResult orbis::sys_jitshm_create(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_jitshm_alias(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dl_get_list(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dl_get_info(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dl_notify_event(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_evf_create(Thread* thread, ptr name, + sint attrs, uint64_t initPattern) +{ + ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initPattern); + if (name == nullptr) + { + return ErrorCode::INVAL; + } + + if (attrs & ~(kEvfAttrSingle | kEvfAttrMulti | kEvfAttrThPrio | + kEvfAttrThFifo | kEvfAttrShared)) + { + return ErrorCode::INVAL; + } + + switch (attrs & (kEvfAttrSingle | kEvfAttrMulti)) + { + case kEvfAttrSingle | kEvfAttrMulti: + return ErrorCode::INVAL; + case 0: + attrs |= kEvfAttrSingle; + break; + + default: + break; + } + + switch (attrs & (kEvfAttrThPrio | kEvfAttrThFifo)) + { + case kEvfAttrThPrio | kEvfAttrThFifo: + return ErrorCode::INVAL; + case 0: + attrs |= kEvfAttrThFifo; + break; + + default: + break; + } + + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + + EventFlag* eventFlag; + if (attrs & kEvfAttrShared) + { + auto [insertedEvf, inserted] = + thread->tproc->context->createEventFlag(_name, attrs, initPattern); + + if (!inserted) + { + return ErrorCode::EXIST; // FIXME: verify + } + + eventFlag = insertedEvf; + } + else + { + eventFlag = knew(attrs, initPattern); + std::strncpy(eventFlag->name, _name, 32); + } + + thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); + return {}; +} +orbis::SysResult orbis::sys_evf_delete(Thread* thread, sint id) +{ + ORBIS_LOG_WARNING(__FUNCTION__, id); + Ref evf = thread->tproc->evfMap.get(id); + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + thread->tproc->evfMap.destroy(id); + return {}; +} +orbis::SysResult orbis::sys_evf_open(Thread* thread, ptr name) +{ + ORBIS_LOG_WARNING(__FUNCTION__, name); + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + + auto eventFlag = thread->tproc->context->findEventFlag(_name); + + if (eventFlag == nullptr) + { + // HACK :) + if (std::string_view(_name).starts_with("SceAppMessaging")) + { + // change pattern on system window open + return sys_evf_create(thread, name, kEvfAttrShared, 1); + } + return sys_evf_create(thread, name, kEvfAttrShared, 0); + return ErrorCode::SRCH; + } + + thread->retval[0] = thread->tproc->evfMap.insert(eventFlag); + return {}; +} +orbis::SysResult orbis::sys_evf_close(Thread* thread, sint id) +{ + ORBIS_LOG_WARNING(__FUNCTION__, thread->tid, id); + if (!thread->tproc->evfMap.close(id)) + { + return ErrorCode::SRCH; + } + + return {}; +} +orbis::SysResult orbis::sys_evf_wait(Thread* thread, sint id, + uint64_t patternSet, uint64_t mode, + ptr pPatternSet, + ptr pTimeout) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, patternSet, mode, pPatternSet, + pTimeout); + if ((mode & (kEvfWaitModeAnd | kEvfWaitModeOr)) == 0 || + (mode & ~(kEvfWaitModeAnd | kEvfWaitModeOr | kEvfWaitModeClearAll | + kEvfWaitModeClearPat)) != 0 || + patternSet == 0) + { + return ErrorCode::INVAL; + } + + Ref evf = thread->tproc->evfMap.get(id); + + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + std::uint32_t resultTimeout{}; + auto result = evf->wait(thread, mode, patternSet, + pTimeout != nullptr ? &resultTimeout : nullptr); + + ORBIS_LOG_TRACE("sys_evf_wait wakeup", thread->tid, thread->evfResultPattern); + + if (pPatternSet != nullptr) + { + uwrite(pPatternSet, thread->evfResultPattern); + } + + if (pTimeout != nullptr) + { + uwrite(pTimeout, resultTimeout); + } + + if (result == ErrorCode::TIMEDOUT) + return SysResult::notAnError(result); + + return result; +} + +orbis::SysResult orbis::sys_evf_trywait(Thread* thread, sint id, + uint64_t patternSet, uint64_t mode, + ptr pPatternSet) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, patternSet, mode, pPatternSet); + if ((mode & (kEvfWaitModeAnd | kEvfWaitModeOr)) == 0 || + (mode & ~(kEvfWaitModeAnd | kEvfWaitModeOr | kEvfWaitModeClearAll | + kEvfWaitModeClearPat)) != 0 || + patternSet == 0) + { + return ErrorCode::INVAL; + } + + Ref evf = thread->tproc->evfMap.get(id); + + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + auto result = evf->tryWait(thread, mode, patternSet); + + if (pPatternSet != nullptr) + { + uwrite(pPatternSet, thread->evfResultPattern); + } + + if (result == ErrorCode::BUSY) + { + return SysResult::notAnError(result); + } + return result; +} +orbis::SysResult orbis::sys_evf_set(Thread* thread, sint id, uint64_t value) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value); + Ref evf = thread->tproc->evfMap.get(id); + + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + evf->set(value); + return {}; +} +orbis::SysResult orbis::sys_evf_clear(Thread* thread, sint id, uint64_t value) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value); + Ref evf = thread->tproc->evfMap.get(id); + + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + evf->clear(value); + return {}; +} +orbis::SysResult orbis::sys_evf_cancel(Thread* thread, sint id, uint64_t value, + ptr pNumWaitThreads) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, id, value, pNumWaitThreads); + Ref evf = thread->tproc->evfMap.get(id); + + if (evf == nullptr) + { + return ErrorCode::SRCH; + } + + auto numWaitThreads = evf->cancel(value); + if (pNumWaitThreads != nullptr) + { + return uwrite(pNumWaitThreads, static_cast(numWaitThreads)); + } + return {}; } orbis::SysResult -orbis::sys_query_memory_protection(Thread *thread, ptr address, - ptr protection) { - if (auto query_memory_protection = - thread->tproc->ops->query_memory_protection) { - return query_memory_protection(thread, address, protection); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_batch_map(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_osem_create(Thread *thread, - ptr name, uint attrs, - sint initCount, sint maxCount) { - ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initCount, maxCount); - if (name == nullptr) { - return ErrorCode::INVAL; - } - - if (attrs & ~(kSemaAttrThPrio | kSemaAttrThFifo | kSemaAttrShared)) { - return ErrorCode::INVAL; - } - - switch (attrs & (kSemaAttrThPrio | kSemaAttrThFifo)) { - case kSemaAttrThPrio | kSemaAttrThFifo: - return ErrorCode::INVAL; - case 0: - attrs |= kSemaAttrThFifo; - break; - - default: - break; - } - - if (maxCount <= 0 || initCount < 0 || maxCount < initCount) - return ErrorCode::INVAL; - - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - - Semaphore *sem; - if (attrs & kSemaAttrShared) { - auto [insertedSem, ok] = thread->tproc->context->createSemaphore( - _name, attrs, initCount, maxCount); - - if (!ok) { - return ErrorCode::EXIST; // FIXME: verify - } - - sem = insertedSem; - } else { - sem = knew(attrs, initCount, maxCount); - } - - thread->retval[0] = thread->tproc->semMap.insert(sem); - return {}; -} -orbis::SysResult orbis::sys_osem_delete(Thread *thread, sint id) { - ORBIS_LOG_WARNING(__FUNCTION__, id); - Ref sem = thread->tproc->semMap.get(id); - if (sem == nullptr) { - return ErrorCode::SRCH; - } - - thread->tproc->semMap.destroy(id); - return {}; -} -orbis::SysResult orbis::sys_osem_open(Thread *thread, - ptr name) { - ORBIS_LOG_WARNING(__FUNCTION__, name); - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - - auto sem = thread->tproc->context->findSemaphore(_name); - if (sem == nullptr) { - // FIXME: hack :) - if (std::string_view(_name).starts_with("SceLncSuspendBlock")) { - auto result = sys_osem_create(thread, name, kSemaAttrShared, 1, 10000); - ORBIS_LOG_WARNING(__FUNCTION__, _name, result.value(), thread->retval[0]); - return result; - } else { - auto result = sys_osem_create(thread, name, kSemaAttrShared, 0, 10000); - ORBIS_LOG_WARNING(__FUNCTION__, _name, result.value(), thread->retval[0]); - return result; - } - return ErrorCode::SRCH; - } - - thread->retval[0] = thread->tproc->semMap.insert(sem); - return {}; -} -orbis::SysResult orbis::sys_osem_close(Thread *thread, sint id) { - ORBIS_LOG_WARNING(__FUNCTION__, id); - if (!thread->tproc->semMap.close(id)) { - return ErrorCode::SRCH; - } - - return {}; -} -orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need, - ptr pTimeout) { - ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need, pTimeout); - Ref sem = thread->tproc->semMap.get(id); - if (pTimeout) - ORBIS_LOG_FATAL("sys_osem_wait timeout is not implemented!"); - if (need < 1 || need > sem->maxValue) - return ErrorCode::INVAL; - - std::lock_guard lock(sem->mtx); - while (true) { - if (sem->isDeleted) - return ErrorCode::ACCES; - if (sem->value >= need) { - sem->value -= need; - break; - } - sem->cond.wait(sem->mtx); - } - return {}; -} -orbis::SysResult orbis::sys_osem_trywait(Thread *thread, sint id, sint need) { - ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need); - Ref sem = thread->tproc->semMap.get(id); - if (need < 1 || need > sem->maxValue) - return ErrorCode::INVAL; - - std::lock_guard lock(sem->mtx); - if (sem->isDeleted || sem->value < need) - return orbis::SysResult::notAnError(ErrorCode::BUSY); - sem->value -= need; - return {}; -} -orbis::SysResult orbis::sys_osem_post(Thread *thread, sint id, sint count) { - ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, count); - Ref sem = thread->tproc->semMap.get(id); - if (count < 1 || count > sem->maxValue - sem->value) - return ErrorCode::INVAL; - - std::lock_guard lock(sem->mtx); - if (sem->isDeleted) - return {}; - sem->value += count; - sem->cond.notify_all(sem->mtx); - return {}; -} -orbis::SysResult orbis::sys_osem_cancel(Thread *thread, sint id, sint set, - ptr pNumWaitThreads) { - ORBIS_LOG_TODO(__FUNCTION__, thread, id, set, pNumWaitThreads); - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_namedobj_create(Thread *thread, - ptr name, - ptr object, uint16_t type) { - ORBIS_LOG_NOTICE(__FUNCTION__, name, object, type); - if (!name) - return ErrorCode::INVAL; - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - if (type < 0x101 || type > 0x104) { - if (type != 0x107) - ORBIS_LOG_ERROR(__FUNCTION__, name, object, type); - } - - std::lock_guard lock(thread->tproc->namedObjMutex); - auto [id, obj] = thread->tproc->namedObjIds.emplace(object, type); - if (!obj) { - return ErrorCode::AGAIN; - } - if (!thread->tproc->namedObjNames.try_emplace(object, _name).second) { - ORBIS_LOG_ERROR("Named object: pointer colflict", type, object); - } - - thread->retval[0] = id; - return {}; -} -orbis::SysResult orbis::sys_namedobj_delete(Thread *thread, uint id, - uint16_t type) { - ORBIS_LOG_NOTICE(__FUNCTION__, id, type); - if (type < 0x101 || type > 0x104) { - if (type != 0x107) - ORBIS_LOG_ERROR(__FUNCTION__, id, type); - } - - std::lock_guard lock(thread->tproc->namedObjMutex); - if (!thread->tproc->namedObjIds.get(id)) - return ErrorCode::SRCH; - auto [object, ty] = *thread->tproc->namedObjIds.get(id); - if (ty != type) { - ORBIS_LOG_ERROR("Named object: found with incorrect type", ty, type); - } - - if (!thread->tproc->namedObjNames.erase(object)) { - ORBIS_LOG_ERROR("Named object: pointer not found", type, object); - } - - thread->tproc->namedObjIds.destroy(id); - return {}; -} -orbis::SysResult orbis::sys_set_vm_container(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_debug_init(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_suspend_process(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_resume_process(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_enable(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_disable(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_set_ctl(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_set_ctr(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_get_ctr(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_budget_create(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_budget_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_budget_get(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_budget_set(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_virtual_query(Thread *thread, ptr addr, - uint64_t unk, ptr info, - size_t infosz) { - if (auto virtual_query = thread->tproc->ops->virtual_query) { - return virtual_query(thread, addr, unk, info, infosz); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mdbg_call(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_create(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_enter(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_exit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_xenter(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_sblock_xexit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_eport_create(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_eport_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_eport_trigger(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_eport_open(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_obs_eport_close(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_is_in_sandbox(Thread *thread /* TODO */) { - std::printf("sys_is_in_sandbox() -> 0\n"); - return {}; -} -orbis::SysResult orbis::sys_dmem_container(Thread *thread, uint id) { - ORBIS_LOG_NOTICE(__FUNCTION__, id); - thread->retval[0] = 1; // returns default direct memory device - if (id + 1) - return ErrorCode::PERM; - return {}; -} -orbis::SysResult orbis::sys_get_authinfo(Thread *thread, pid_t pid, - ptr info) { - struct authinfo { - uint64_t unk0; - uint64_t caps[4]; - uint64_t attrs[4]; - uint64_t unk[8]; - }; - static_assert(sizeof(authinfo) == 136); - - authinfo result { - .unk0 = 0x3100000000000001, - .caps = { - 0x2000038000000000, - 0x000000000000FF00, - 0x0000000000000000, - 0x0000000000000000, - }, - .attrs = { - 0x4000400040000000, - 0x4000000000000000, - 0x0080000000000002, - 0xF0000000FFFF4000, - }, - }; - - return uwrite((ptr)info, result); -} -orbis::SysResult orbis::sys_mname(Thread *thread, uint64_t addr, uint64_t len, - ptr name) { - ORBIS_LOG_NOTICE(__FUNCTION__, addr, len, name); - if (addr < 0x40000 || addr >= 0x100'0000'0000 || 0x100'0000'0000 - addr < len) - return ErrorCode::INVAL; - char _name[32]; - if (auto result = ureadString(_name, sizeof(_name), (const char *)name); - result != ErrorCode{}) { - return result; - } - - NamedMemoryRange range; - range.begin = addr & ~0x3fffull; - range.end = range.begin; - range.end += ((addr & 0x3fff) + 0x3fff + len) & ~0x3fffull; - - std::lock_guard lock(thread->tproc->namedMemMutex); - auto [it, end] = thread->tproc->namedMem.equal_range(range); - while (it != end) { - auto [addr2, end2] = it->first; - auto len2 = end2 - addr2; - ORBIS_LOG_NOTICE("sys_mname: removed overlapped", it->second, addr2, len2); - it = thread->tproc->namedMem.erase(it); - } - if (!thread->tproc->namedMem.try_emplace(range, _name).second) - std::abort(); - if (!thread->tproc->namedMem.count(addr)) - std::abort(); - - return {}; -} -orbis::SysResult orbis::sys_dynlib_dlopen(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_dlclose(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_dlsym(Thread *thread, SceKernelModule handle, - ptr symbol, - ptr> addrp) { - ORBIS_LOG_WARNING(__FUNCTION__, symbol); - if (thread->tproc->ops->dynlib_dlsym) { - return thread->tproc->ops->dynlib_dlsym(thread, handle, symbol, addrp); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_get_list(Thread *thread, - ptr pArray, - size_t numArray, - ptr pActualNum) { - std::size_t actualNum = 0; - for (auto [id, module] : thread->tproc->modulesMap) { - if (actualNum >= numArray) { - break; - } - pArray[actualNum++] = id; - } - return uwrite(pActualNum, actualNum); -} -orbis::SysResult orbis::sys_dynlib_get_info(Thread *thread, - SceKernelModule handle, - ptr pInfo) { - auto module = thread->tproc->modulesMap.get(handle); - - if (module == nullptr) { - return ErrorCode::SRCH; - } - - if (pInfo->size != sizeof(ModuleInfo)) { - return ErrorCode::INVAL; - } - - ModuleInfo result = {}; - result.size = sizeof(ModuleInfo); - std::strncpy(result.name, module->moduleName, sizeof(result.name)); - std::memcpy(result.segments, module->segments, - sizeof(ModuleSegment) * module->segmentCount); - result.segmentCount = module->segmentCount; - std::memcpy(result.fingerprint, module->fingerprint, - sizeof(result.fingerprint)); - uwrite(pInfo, result); - return {}; -} -orbis::SysResult orbis::sys_dynlib_load_prx(Thread *thread, - ptr name, uint64_t arg1, - ptr pHandle, - uint64_t arg3) { - if (auto dynlib_load_prx = thread->tproc->ops->dynlib_load_prx) { - return dynlib_load_prx(thread, name, arg1, pHandle, arg3); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_unload_prx(Thread *thread, - SceKernelModule handle) { - if (auto dynlib_unload_prx = thread->tproc->ops->dynlib_unload_prx) { - return dynlib_unload_prx(thread, handle); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_do_copy_relocations(Thread *thread) { - if (auto dynlib_do_copy_relocations = - thread->tproc->ops->dynlib_do_copy_relocations) { - return dynlib_do_copy_relocations(thread); - } - - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_prepare_dlclose(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} - -orbis::SysResult orbis::sys_dynlib_get_proc_param(Thread *thread, - ptr> procParam, - ptr procParamSize) { - auto proc = thread->tproc; - *procParam = proc->processParam; - *procParamSize = proc->processParamSize; - return {}; -} -orbis::SysResult orbis::sys_dynlib_process_needed_and_relocate(Thread *thread) { - ORBIS_LOG_NOTICE(__FUNCTION__); - if (auto processNeeded = thread->tproc->ops->processNeeded) { - auto result = processNeeded(thread); - - if (result.value() != 0) { - return result; - } - } - - for (auto [id, module] : thread->tproc->modulesMap) { - auto result = module->relocate(thread->tproc); - if (result.isError()) { - return result; - } - } - - if (auto registerEhFrames = thread->tproc->ops->registerEhFrames) { - auto result = registerEhFrames(thread); - - if (result.value() != 0) { - return result; - } - } - - ORBIS_LOG_WARNING(__FUNCTION__); - return {}; -} -orbis::SysResult orbis::sys_sandbox_path(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} - -struct mdbg_property { - orbis::int32_t unk; - orbis::int32_t unk2; - orbis::uint64_t addr_ptr; - orbis::uint64_t areaSize; - orbis::int64_t unk3; - orbis::int64_t unk4; - char name[32]; +orbis::sys_query_memory_protection(Thread* thread, ptr address, + ptr protection) +{ + if (auto query_memory_protection = + thread->tproc->ops->query_memory_protection) + { + return query_memory_protection(thread, address, protection); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_batch_map(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_osem_create(Thread* thread, + ptr name, uint attrs, + sint initCount, sint maxCount) +{ + ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initCount, maxCount); + if (name == nullptr) + { + return ErrorCode::INVAL; + } + + if (attrs & ~(kSemaAttrThPrio | kSemaAttrThFifo | kSemaAttrShared)) + { + return ErrorCode::INVAL; + } + + switch (attrs & (kSemaAttrThPrio | kSemaAttrThFifo)) + { + case kSemaAttrThPrio | kSemaAttrThFifo: + return ErrorCode::INVAL; + case 0: + attrs |= kSemaAttrThFifo; + break; + + default: + break; + } + + if (maxCount <= 0 || initCount < 0 || maxCount < initCount) + return ErrorCode::INVAL; + + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + + Semaphore* sem; + if (attrs & kSemaAttrShared) + { + auto [insertedSem, ok] = thread->tproc->context->createSemaphore( + _name, attrs, initCount, maxCount); + + if (!ok) + { + return ErrorCode::EXIST; // FIXME: verify + } + + sem = insertedSem; + } + else + { + sem = knew(attrs, initCount, maxCount); + } + + thread->retval[0] = thread->tproc->semMap.insert(sem); + return {}; +} +orbis::SysResult orbis::sys_osem_delete(Thread* thread, sint id) +{ + ORBIS_LOG_WARNING(__FUNCTION__, id); + Ref sem = thread->tproc->semMap.get(id); + if (sem == nullptr) + { + return ErrorCode::SRCH; + } + + thread->tproc->semMap.destroy(id); + return {}; +} +orbis::SysResult orbis::sys_osem_open(Thread* thread, + ptr name) +{ + ORBIS_LOG_WARNING(__FUNCTION__, name); + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + + auto sem = thread->tproc->context->findSemaphore(_name); + if (sem == nullptr) + { + // FIXME: hack :) + if (std::string_view(_name).starts_with("SceLncSuspendBlock")) + { + auto result = sys_osem_create(thread, name, kSemaAttrShared, 1, 10000); + ORBIS_LOG_WARNING(__FUNCTION__, _name, result.value(), thread->retval[0]); + return result; + } + else + { + auto result = sys_osem_create(thread, name, kSemaAttrShared, 0, 10000); + ORBIS_LOG_WARNING(__FUNCTION__, _name, result.value(), thread->retval[0]); + return result; + } + return ErrorCode::SRCH; + } + + thread->retval[0] = thread->tproc->semMap.insert(sem); + return {}; +} +orbis::SysResult orbis::sys_osem_close(Thread* thread, sint id) +{ + ORBIS_LOG_WARNING(__FUNCTION__, id); + if (!thread->tproc->semMap.close(id)) + { + return ErrorCode::SRCH; + } + + return {}; +} +orbis::SysResult orbis::sys_osem_wait(Thread* thread, sint id, sint need, + ptr pTimeout) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need, pTimeout); + Ref sem = thread->tproc->semMap.get(id); + if (pTimeout) + ORBIS_LOG_FATAL("sys_osem_wait timeout is not implemented!"); + if (need < 1 || need > sem->maxValue) + return ErrorCode::INVAL; + + std::lock_guard lock(sem->mtx); + while (true) + { + if (sem->isDeleted) + return ErrorCode::ACCES; + if (sem->value >= need) + { + sem->value -= need; + break; + } + sem->cond.wait(sem->mtx); + } + return {}; +} +orbis::SysResult orbis::sys_osem_trywait(Thread* thread, sint id, sint need) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need); + Ref sem = thread->tproc->semMap.get(id); + if (need < 1 || need > sem->maxValue) + return ErrorCode::INVAL; + + std::lock_guard lock(sem->mtx); + if (sem->isDeleted || sem->value < need) + return orbis::SysResult::notAnError(ErrorCode::BUSY); + sem->value -= need; + return {}; +} +orbis::SysResult orbis::sys_osem_post(Thread* thread, sint id, sint count) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, count); + Ref sem = thread->tproc->semMap.get(id); + if (count < 1 || count > sem->maxValue - sem->value) + return ErrorCode::INVAL; + + std::lock_guard lock(sem->mtx); + if (sem->isDeleted) + return {}; + sem->value += count; + sem->cond.notify_all(sem->mtx); + return {}; +} +orbis::SysResult orbis::sys_osem_cancel(Thread* thread, sint id, sint set, + ptr pNumWaitThreads) +{ + ORBIS_LOG_TODO(__FUNCTION__, thread, id, set, pNumWaitThreads); + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_namedobj_create(Thread* thread, + ptr name, + ptr object, uint16_t type) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, name, object, type); + if (!name) + return ErrorCode::INVAL; + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + if (type < 0x101 || type > 0x104) + { + if (type != 0x107) + ORBIS_LOG_ERROR(__FUNCTION__, name, object, type); + } + + std::lock_guard lock(thread->tproc->namedObjMutex); + auto [id, obj] = thread->tproc->namedObjIds.emplace(object, type); + if (!obj) + { + return ErrorCode::AGAIN; + } + if (!thread->tproc->namedObjNames.try_emplace(object, _name).second) + { + ORBIS_LOG_ERROR("Named object: pointer colflict", type, object); + } + + thread->retval[0] = id; + return {}; +} +orbis::SysResult orbis::sys_namedobj_delete(Thread* thread, uint id, + uint16_t type) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, id, type); + if (type < 0x101 || type > 0x104) + { + if (type != 0x107) + ORBIS_LOG_ERROR(__FUNCTION__, id, type); + } + + std::lock_guard lock(thread->tproc->namedObjMutex); + if (!thread->tproc->namedObjIds.get(id)) + return ErrorCode::SRCH; + auto [object, ty] = *thread->tproc->namedObjIds.get(id); + if (ty != type) + { + ORBIS_LOG_ERROR("Named object: found with incorrect type", ty, type); + } + + if (!thread->tproc->namedObjNames.erase(object)) + { + ORBIS_LOG_ERROR("Named object: pointer not found", type, object); + } + + thread->tproc->namedObjIds.destroy(id); + return {}; +} +orbis::SysResult orbis::sys_set_vm_container(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_debug_init(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_suspend_process(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_resume_process(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_enable(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_disable(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_set_ctl(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_set_ctr(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_get_ctr(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_budget_create(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_budget_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_budget_get(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_budget_set(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_virtual_query(Thread* thread, ptr addr, + uint64_t unk, ptr info, + size_t infosz) +{ + if (auto virtual_query = thread->tproc->ops->virtual_query) + { + return virtual_query(thread, addr, unk, info, infosz); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mdbg_call(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_create(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_enter(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_exit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_xenter(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_sblock_xexit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_eport_create(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_eport_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_eport_trigger(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_eport_open(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_obs_eport_close(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_is_in_sandbox(Thread* thread /* TODO */) +{ + std::printf("sys_is_in_sandbox() -> 0\n"); + return {}; +} +orbis::SysResult orbis::sys_dmem_container(Thread* thread, uint id) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, id); + thread->retval[0] = 1; // returns default direct memory device + if (id + 1) + return ErrorCode::PERM; + return {}; +} +orbis::SysResult orbis::sys_get_authinfo(Thread* thread, pid_t pid, + ptr info) +{ + struct authinfo + { + uint64_t unk0; + uint64_t caps[4]; + uint64_t attrs[4]; + uint64_t unk[8]; + }; + static_assert(sizeof(authinfo) == 136); + + authinfo result{ + .unk0 = 0x3100000000000001, + .caps = { + 0x2000038000000000, + 0x000000000000FF00, + 0x0000000000000000, + 0x0000000000000000, + }, + .attrs = { + 0x4000400040000000, + 0x4000000000000000, + 0x0080000000000002, + 0xF0000000FFFF4000, + }, + }; + + return uwrite((ptr)info, result); +} +orbis::SysResult orbis::sys_mname(Thread* thread, uint64_t addr, uint64_t len, + ptr name) +{ + ORBIS_LOG_NOTICE(__FUNCTION__, addr, len, name); + if (addr < 0x40000 || addr >= 0x100'0000'0000 || 0x100'0000'0000 - addr < len) + return ErrorCode::INVAL; + char _name[32]; + if (auto result = ureadString(_name, sizeof(_name), (const char*)name); + result != ErrorCode{}) + { + return result; + } + + NamedMemoryRange range; + range.begin = addr & ~0x3fffull; + range.end = range.begin; + range.end += ((addr & 0x3fff) + 0x3fff + len) & ~0x3fffull; + + std::lock_guard lock(thread->tproc->namedMemMutex); + auto [it, end] = thread->tproc->namedMem.equal_range(range); + while (it != end) + { + auto [addr2, end2] = it->first; + auto len2 = end2 - addr2; + ORBIS_LOG_NOTICE("sys_mname: removed overlapped", it->second, addr2, len2); + it = thread->tproc->namedMem.erase(it); + } + if (!thread->tproc->namedMem.try_emplace(range, _name).second) + std::abort(); + if (!thread->tproc->namedMem.count(addr)) + std::abort(); + + return {}; +} +orbis::SysResult orbis::sys_dynlib_dlopen(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_dlclose(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_dlsym(Thread* thread, SceKernelModule handle, + ptr symbol, + ptr> addrp) +{ + ORBIS_LOG_WARNING(__FUNCTION__, symbol); + if (thread->tproc->ops->dynlib_dlsym) + { + return thread->tproc->ops->dynlib_dlsym(thread, handle, symbol, addrp); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_get_list(Thread* thread, + ptr pArray, + size_t numArray, + ptr pActualNum) +{ + std::size_t actualNum = 0; + for (auto [id, module] : thread->tproc->modulesMap) + { + if (actualNum >= numArray) + { + break; + } + pArray[actualNum++] = id; + } + return uwrite(pActualNum, actualNum); +} +orbis::SysResult orbis::sys_dynlib_get_info(Thread* thread, + SceKernelModule handle, + ptr pInfo) +{ + auto module = thread->tproc->modulesMap.get(handle); + + if (module == nullptr) + { + return ErrorCode::SRCH; + } + + if (pInfo->size != sizeof(ModuleInfo)) + { + return ErrorCode::INVAL; + } + + ModuleInfo result = {}; + result.size = sizeof(ModuleInfo); + std::strncpy(result.name, module->moduleName, sizeof(result.name)); + std::memcpy(result.segments, module->segments, + sizeof(ModuleSegment) * module->segmentCount); + result.segmentCount = module->segmentCount; + std::memcpy(result.fingerprint, module->fingerprint, + sizeof(result.fingerprint)); + uwrite(pInfo, result); + return {}; +} +orbis::SysResult orbis::sys_dynlib_load_prx(Thread* thread, + ptr name, uint64_t arg1, + ptr pHandle, + uint64_t arg3) +{ + if (auto dynlib_load_prx = thread->tproc->ops->dynlib_load_prx) + { + return dynlib_load_prx(thread, name, arg1, pHandle, arg3); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_unload_prx(Thread* thread, + SceKernelModule handle) +{ + if (auto dynlib_unload_prx = thread->tproc->ops->dynlib_unload_prx) + { + return dynlib_unload_prx(thread, handle); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_do_copy_relocations(Thread* thread) +{ + if (auto dynlib_do_copy_relocations = + thread->tproc->ops->dynlib_do_copy_relocations) + { + return dynlib_do_copy_relocations(thread); + } + + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_prepare_dlclose(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} + +orbis::SysResult orbis::sys_dynlib_get_proc_param(Thread* thread, + ptr> procParam, + ptr procParamSize) +{ + auto proc = thread->tproc; + *procParam = proc->processParam; + *procParamSize = proc->processParamSize; + return {}; +} +orbis::SysResult orbis::sys_dynlib_process_needed_and_relocate(Thread* thread) +{ + ORBIS_LOG_NOTICE(__FUNCTION__); + if (auto processNeeded = thread->tproc->ops->processNeeded) + { + auto result = processNeeded(thread); + + if (result.value() != 0) + { + return result; + } + } + + for (auto [id, module] : thread->tproc->modulesMap) + { + auto result = module->relocate(thread->tproc); + if (result.isError()) + { + return result; + } + } + + if (auto registerEhFrames = thread->tproc->ops->registerEhFrames) + { + auto result = registerEhFrames(thread); + + if (result.value() != 0) + { + return result; + } + } + + ORBIS_LOG_WARNING(__FUNCTION__); + return {}; +} +orbis::SysResult orbis::sys_sandbox_path(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} + +struct mdbg_property +{ + orbis::int32_t unk; + orbis::int32_t unk2; + orbis::uint64_t addr_ptr; + orbis::uint64_t areaSize; + orbis::int64_t unk3; + orbis::int64_t unk4; + char name[32]; }; -orbis::SysResult orbis::sys_mdbg_service(Thread *thread, uint32_t op, - ptr arg0, ptr arg1) { - ORBIS_LOG_NOTICE("sys_mdbg_service", thread->tid, op, arg0, arg1); - thread->where(); - - switch (op) { - case 1: { - mdbg_property prop; - if (auto error = uread(prop, (ptr)arg0); - error != ErrorCode{}) - return error; - ORBIS_LOG_WARNING(__FUNCTION__, prop.name, prop.addr_ptr, prop.areaSize); - break; - } - - case 3: { - auto errorCode = (unsigned)(uint64_t)(arg0); - ORBIS_LOG_ERROR("sys_mdbg_service: ERROR CODE", errorCode); - break; - } - - case 7: { - // TODO: read string from userspace - ORBIS_LOG_NOTICE("sys_mdbg_service", (char *)arg0); - break; - } - - case 0x14: { - std::this_thread::sleep_for(std::chrono::years(1)); - break; - } - - default: - break; - } - - return {}; -} -orbis::SysResult orbis::sys_randomized_path(Thread *thread /* TODO */) { - std::printf("TODO: sys_randomized_path()\n"); - return {}; -} -orbis::SysResult orbis::sys_rdup(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dl_get_metadata(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_workaround8849(Thread *thread /* TODO */) { - thread->retval[0] = 1; - return {}; -} -orbis::SysResult orbis::sys_is_development_mode(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_self_auth_info(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_mdbg_service(Thread* thread, uint32_t op, + ptr arg0, ptr arg1) +{ + ORBIS_LOG_NOTICE("sys_mdbg_service", thread->tid, op, arg0, arg1); + thread->where(); + + switch (op) + { + case 1: + { + mdbg_property prop; + if (auto error = uread(prop, (ptr)arg0); + error != ErrorCode{}) + return error; + ORBIS_LOG_WARNING(__FUNCTION__, prop.name, prop.addr_ptr, prop.areaSize); + break; + } + + case 3: + { + auto errorCode = (unsigned)(uint64_t)(arg0); + ORBIS_LOG_ERROR("sys_mdbg_service: ERROR CODE", errorCode); + break; + } + + case 7: + { + // TODO: read string from userspace + ORBIS_LOG_NOTICE("sys_mdbg_service", (char*)arg0); + break; + } + + case 0x14: + { + std::this_thread::sleep_for(std::chrono::years(1)); + break; + } + + default: + break; + } + + return {}; +} +orbis::SysResult orbis::sys_randomized_path(Thread* thread /* TODO */) +{ + std::printf("TODO: sys_randomized_path()\n"); + return {}; +} +orbis::SysResult orbis::sys_rdup(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dl_get_metadata(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_workaround8849(Thread* thread /* TODO */) +{ + thread->retval[0] = 1; + return {}; +} +orbis::SysResult orbis::sys_is_development_mode(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_self_auth_info(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_dynlib_get_info_ex(Thread *thread, SceKernelModule handle, - ptr unk, - ptr destModuleInfoEx) { - auto module = thread->tproc->modulesMap.get(handle); - if (module == nullptr) { - return ErrorCode::SRCH; - } - - if (destModuleInfoEx->size != sizeof(ModuleInfoEx)) { - return ErrorCode::INVAL; - } - - ModuleInfoEx result = {}; - result.size = sizeof(ModuleInfoEx); - std::strncpy(result.name, module->moduleName, sizeof(result.name)); - result.id = std::to_underlying(handle); - result.tlsIndex = module->tlsIndex; - result.tlsInit = module->tlsInit; - result.tlsInitSize = module->tlsInitSize; - result.tlsSize = module->tlsSize; - result.tlsOffset = module->tlsOffset; - result.tlsAlign = module->tlsAlign; - result.initProc = module->initProc; - result.finiProc = module->finiProc; - result.ehFrameHdr = module->ehFrameHdr; - result.ehFrame = module->ehFrame; - result.ehFrameHdrSize = module->ehFrameHdrSize; - result.ehFrameSize = module->ehFrameSize; - std::memcpy(result.segments, module->segments, - sizeof(ModuleSegment) * module->segmentCount); - result.segmentCount = module->segmentCount; - result.refCount = 1; - ORBIS_LOG_WARNING(__FUNCTION__, result.id, result.name, result.tlsIndex, - result.tlsInit, result.tlsInitSize, result.tlsSize, - result.tlsOffset, result.tlsAlign, result.initProc, - result.finiProc, result.ehFrameHdr, result.ehFrame, - result.ehFrameHdrSize, result.ehFrameSize, result.segmentCount, result.refCount); - return uwrite(destModuleInfoEx, result); -} -orbis::SysResult orbis::sys_budget_getid(Thread *thread) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_budget_get_ptype(Thread *thread, sint budgetId) { - thread->retval[0] = 1; - return {}; +orbis::sys_dynlib_get_info_ex(Thread* thread, SceKernelModule handle, + ptr unk, + ptr destModuleInfoEx) +{ + auto module = thread->tproc->modulesMap.get(handle); + if (module == nullptr) + { + return ErrorCode::SRCH; + } + + if (destModuleInfoEx->size != sizeof(ModuleInfoEx)) + { + return ErrorCode::INVAL; + } + + ModuleInfoEx result = {}; + result.size = sizeof(ModuleInfoEx); + std::strncpy(result.name, module->moduleName, sizeof(result.name)); + result.id = std::to_underlying(handle); + result.tlsIndex = module->tlsIndex; + result.tlsInit = module->tlsInit; + result.tlsInitSize = module->tlsInitSize; + result.tlsSize = module->tlsSize; + result.tlsOffset = module->tlsOffset; + result.tlsAlign = module->tlsAlign; + result.initProc = module->initProc; + result.finiProc = module->finiProc; + result.ehFrameHdr = module->ehFrameHdr; + result.ehFrame = module->ehFrame; + result.ehFrameHdrSize = module->ehFrameHdrSize; + result.ehFrameSize = module->ehFrameSize; + std::memcpy(result.segments, module->segments, + sizeof(ModuleSegment) * module->segmentCount); + result.segmentCount = module->segmentCount; + result.refCount = 1; + ORBIS_LOG_WARNING(__FUNCTION__, result.id, result.name, result.tlsIndex, + result.tlsInit, result.tlsInitSize, result.tlsSize, + result.tlsOffset, result.tlsAlign, result.initProc, + result.finiProc, result.ehFrameHdr, result.ehFrame, + result.ehFrameHdrSize, result.ehFrameSize, result.segmentCount, result.refCount); + return uwrite(destModuleInfoEx, result); +} +orbis::SysResult orbis::sys_budget_getid(Thread* thread) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_budget_get_ptype(Thread* thread, sint budgetId) +{ + thread->retval[0] = 1; + return {}; } orbis::SysResult -orbis::sys_get_paging_stats_of_all_threads(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_proc_type_info(Thread *thread, - ptr destProcessInfo) { - std::printf("TODO: sys_get_proc_type_info\n"); - - struct dargs { - uint64_t size = sizeof(dargs); - uint32_t ptype; - uint32_t pflags; - } args = {.ptype = 1, .pflags = 0}; - - uwrite((ptr)destProcessInfo, args); - return {}; -} -orbis::SysResult orbis::sys_get_resident_count(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_prepare_to_suspend_process(Thread *thread, - pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_resident_fmem_count(Thread *thread, pid_t pid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_set_gpo(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_get_paging_stats_of_all_threads(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_proc_type_info(Thread* thread, + ptr destProcessInfo) +{ + std::printf("TODO: sys_get_proc_type_info\n"); + + struct dargs + { + uint64_t size = sizeof(dargs); + uint32_t ptype; + uint32_t pflags; + } args = {.ptype = 1, .pflags = 0}; + + uwrite((ptr)destProcessInfo, args); + return {}; +} +orbis::SysResult orbis::sys_get_resident_count(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_prepare_to_suspend_process(Thread* thread, + pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_resident_fmem_count(Thread* thread, pid_t pid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_thr_get_name(Thread* thread, lwpid_t lwpid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_set_gpo(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_get_paging_stats_of_all_objects(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_test_debug_rwmem(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_free_stack(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_suspend_system(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} - -enum ImpiOpcode { - kImpiCreateServer = 0, - kImpiDestroyServer = 1, - kIpmiCreateClient = 2, - kImpiDestroyClient = 3, - kImpiCreateSession = 4, - kImpiDestroySession = 5, +orbis::sys_get_paging_stats_of_all_objects(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_test_debug_rwmem(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_free_stack(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_suspend_system(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} + +enum ImpiOpcode +{ + kImpiCreateServer = 0, + kImpiDestroyServer = 1, + kIpmiCreateClient = 2, + kImpiDestroyClient = 3, + kImpiCreateSession = 4, + kImpiDestroySession = 5, }; -struct IpmiCreateClientParams { - orbis::ptr arg0; - orbis::ptr name; - orbis::ptr arg2; +struct IpmiCreateClientParams +{ + orbis::ptr arg0; + orbis::ptr name; + orbis::ptr arg2; }; static_assert(sizeof(IpmiCreateClientParams) == 0x18); -struct IpmiBufferInfo { - orbis::ptr data; - orbis::uint64_t size; +struct IpmiBufferInfo +{ + orbis::ptr data; + orbis::uint64_t size; }; -struct IpmiDataInfo { - orbis::ptr data; - orbis::uint64_t size; +struct IpmiDataInfo +{ + orbis::ptr data; + orbis::uint64_t size; }; -struct IpmiSyncCallParams { - orbis::uint32_t method; - orbis::uint32_t dataCount; - orbis::uint64_t flags; // ? - orbis::ptr pData; - orbis::ptr pBuffers; - orbis::ptr pResult; - orbis::uint32_t resultCount; +struct IpmiSyncCallParams +{ + orbis::uint32_t method; + orbis::uint32_t dataCount; + orbis::uint64_t flags; // ? + orbis::ptr pData; + orbis::ptr pBuffers; + orbis::ptr pResult; + orbis::uint32_t resultCount; }; -struct IpmiCreateServerParams { - orbis::uint64_t arg0; - orbis::ptr name; - orbis::uint64_t arg2; +struct IpmiCreateServerParams +{ + orbis::uint64_t arg0; + orbis::ptr name; + orbis::uint64_t arg2; }; -struct IpmiClientConnectParams { - orbis::ptr arg0; - orbis::ptr name; - orbis::ptr arg2; - orbis::ptr arg3; +struct IpmiClientConnectParams +{ + orbis::ptr arg0; + orbis::ptr name; + orbis::ptr arg2; + orbis::ptr arg3; }; static_assert(sizeof(IpmiSyncCallParams) == 0x30); -orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, - ptr result, ptr params, - uint64_t paramsSz, uint64_t arg6) { - ORBIS_LOG_TODO("sys_ipmimgr_call", op, kid, result, params, paramsSz, arg6); - thread->where(); - - if (op == kImpiCreateServer) { - if (paramsSz != sizeof(IpmiCreateServerParams)) { - return ErrorCode::INVAL; - } - - auto createParams = (ptr)params; - - ORBIS_LOG_TODO("IPMI: create server", createParams->arg0, - createParams->name, createParams->arg2); - - auto [server, inserted] = g_context.createIpmiServer(createParams->name); - if (!inserted) { - return ErrorCode::EXIST; - } - - auto id = thread->tproc->ipmiServerMap.insert(server); - return uwrite(result, id); - } - - if (op == 0x10) { - // IPMI server start? - - return uwrite(result, 0); - } - - if (op == 0x201) { - // IPMI server receive packet? - return uwrite(result, 0x80020023); - } - - if (op == kIpmiCreateClient) { - if (paramsSz != sizeof(IpmiCreateClientParams)) { - return ErrorCode::INVAL; - } - - auto createParams = (ptr)params; - - ORBIS_LOG_TODO("IPMI: create client", createParams->arg0, - createParams->name, createParams->arg2); - // auto server = g_context.findIpmiServer(createParams->name); - - // if (server == nullptr) { - // ORBIS_LOG_TODO("IPMI: failed to find server", createParams->name); - // } - - auto ipmiClient = knew(createParams->name); - // ipmiClient->connection = server; - auto id = thread->tproc->ipmiClientMap.insert(ipmiClient); - return uwrite(result, id); - } - - if (op == kImpiDestroyClient) { - ORBIS_LOG_TODO("IPMI: destroy client"); - thread->tproc->ipmiClientMap.close(kid); - if (result) { - return uwrite(result, 0); - } - - return {}; - } - - auto client = thread->tproc->ipmiClientMap.get(kid); - - if (client == nullptr) { - return ErrorCode::INVAL; - } - - if (op == 0x241) { - if (result) { - return uwrite(result, 0); - } - } - - if (op == 0x400) { - if (paramsSz != sizeof(IpmiClientConnectParams)) { - return ErrorCode::INVAL; - } - - auto connectParams = (ptr)params; - ORBIS_LOG_TODO("IMPI: connect?", connectParams->arg0, connectParams->name, - connectParams->arg2, connectParams->arg3); - if (result) { - return uwrite(result, 0); - } - } - - if (op == 0x320) { - ORBIS_LOG_TODO("IMPI: invoke sync method"); - - if (paramsSz != sizeof(IpmiSyncCallParams)) { - return ErrorCode::INVAL; - } - - IpmiSyncCallParams syncCallParams; - auto errorCode = uread(syncCallParams, (ptr)params); - if (errorCode != ErrorCode{}) { - return errorCode; - } - - ORBIS_LOG_TODO("impi: invokeSyncMethod", client->name, - syncCallParams.method, syncCallParams.dataCount, - syncCallParams.flags, syncCallParams.pData, - syncCallParams.pBuffers, syncCallParams.pResult, - syncCallParams.resultCount); - - IpmiDataInfo dataInfo; - uread(dataInfo, syncCallParams.pData); - - ORBIS_LOG_TODO("", dataInfo.data, dataInfo.size); - - if (client->name == "SceMbusIpc") { - if (syncCallParams.method == 0xce110007) { // SceMbusIpcAddHandleByUserId - struct SceMbusIpcAddHandleByUserIdMethodArgs { - uint32_t unk; // 0 - uint32_t deviceId; - uint32_t userId; - uint32_t type; - uint32_t index; - uint32_t reserved; - uint32_t pid; - }; - - static_assert(sizeof(SceMbusIpcAddHandleByUserIdMethodArgs) == 0x1c); - - if (dataInfo.size != sizeof(SceMbusIpcAddHandleByUserIdMethodArgs)) { - return ErrorCode::INVAL; - } - - SceMbusIpcAddHandleByUserIdMethodArgs args; - uread(args, ptr(dataInfo.data)); - - ORBIS_LOG_TODO("impi: SceMbusIpcAddHandleByUserId", args.unk, - args.deviceId, args.userId, args.type, args.index, - args.reserved, args.pid); - } - - return uwrite(result, 1); - } else if (client->name == "SceUserService") { - ORBIS_LOG_TODO("SceUserService"); - if (syncCallParams.method == 0x30011) { // get initial user id - ORBIS_LOG_TODO("SceUserService: get_initial_user_id"); - auto err = uwrite(syncCallParams.pResult, 0); - if (err != ErrorCode{}) { - return err; - } - IpmiBufferInfo bufferInfo; - err = uread(bufferInfo, syncCallParams.pBuffers); - if (err != ErrorCode{}) { - return err; - } - - if (bufferInfo.size != sizeof(uint32_t)) { - return uwrite(result, -1); - } - - err = uwrite((ptr)bufferInfo.data, 1u); // initial user id - if (err != ErrorCode{}) { - return err; - } - return uwrite(result, 0); - } - } else if (client->name == "SceLncService") { - if (syncCallParams.method == 0x30010) { // get app status - // returns pending system events - ORBIS_LOG_TODO("SceUserService: get_app_status"); - auto err = uwrite(syncCallParams.pResult, 0); - if (err != ErrorCode{}) { - return err; - } - IpmiBufferInfo bufferInfo; - err = uread(bufferInfo, syncCallParams.pBuffers); - if (err != ErrorCode{}) { - return err; - } - - struct Result { - std::uint32_t unk0; - std::uint32_t unk1; - std::uint32_t unk2; - }; - - static_assert(sizeof(Result) == 0xc); - - if (bufferInfo.size != sizeof(Result)) { - return uwrite(result, -1); - } - - Result bufferResult{ - .unk0 = 1, - .unk1 = 1, - .unk2 = 1, - }; - - err = uwrite((ptr)bufferInfo.data, bufferResult); - if (err != ErrorCode{}) { - return err; - } - return uwrite(result, 0); - } - } else if (client->name == "SceSysAudioSystemIpc") { - if (syncCallParams.method == 0x12340000) { // check shared memory control - struct SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs { - uint32_t channelId; - }; - - static_assert( - sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs) == - 0x4); - - if (dataInfo.size != - sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs)) { - return ErrorCode::INVAL; - } - - SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs args; - uread(args, ptr( - dataInfo.data)); - - ORBIS_LOG_TODO( - "impi: SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs", - args.channelId); - if (auto audioOut = g_context.audioOut) { - audioOut->channelInfo.idControl = args.channelId; - } - } else if (syncCallParams.method == 0x1234000f) { // create event flag - struct SceSysAudioSystemIpcCreateEventFlagMethodArgs { - uint32_t channelId; - }; - - static_assert(sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs) == - 0x4); - - if (dataInfo.size != - sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs)) { - return ErrorCode::INVAL; - } - - SceSysAudioSystemIpcCreateEventFlagMethodArgs args; - uread(args, ptr( - dataInfo.data)); - - if (auto audioOut = g_context.audioOut) { - // very bad - char buffer[32]; - std::snprintf(buffer, sizeof(buffer), "sceAudioOutMix%x", - args.channelId); - // const char* eventName = &buffer; - auto [eventFlag, inserted] = thread->tproc->context->createEventFlag( - buffer, kEvfAttrShared, 0); - - if (!inserted) { - return ErrorCode::EXIST; // FIXME: verify - } - - audioOut->channelInfo.evf = eventFlag; - } - } else if (syncCallParams.method == - 0x12340001) { // check shared memory audio - struct SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs { - uint32_t audioPort; - uint32_t channelId; - }; - - static_assert( - sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs) == - 0x8); - - if (dataInfo.size != - sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs)) { - return ErrorCode::INVAL; - } - - SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs args; - uread(args, ptr( - dataInfo.data)); - - ORBIS_LOG_TODO( - "impi: SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs", - args.audioPort, args.channelId); - if (auto audioOut = g_context.audioOut) { - audioOut->channelInfo.port = args.audioPort; - audioOut->channelInfo.channel = args.channelId; - } - } else if (syncCallParams.method == 0x12340002) { // something like open - struct SceSysAudioSystemIpcSomethingMethodArgs { - uint32_t audioPort; - uint32_t channelId; - }; - - static_assert(sizeof(SceSysAudioSystemIpcSomethingMethodArgs) == 0x8); - - if (dataInfo.size != sizeof(SceSysAudioSystemIpcSomethingMethodArgs)) { - return ErrorCode::INVAL; - } - - SceSysAudioSystemIpcSomethingMethodArgs args; - uread(args, - ptr(dataInfo.data)); - - ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs", - args.audioPort, args.channelId); - - if (auto audioOut = g_context.audioOut) { - // here startToListen - audioOut->start(); - } - } else if (syncCallParams.method == 0x12340006) { // close port - struct SceSysAudioSystemIpcCloseAudioMethodArgs { - uint32_t audioPort; - uint32_t channelId; - }; - - static_assert(sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs) == 0x8); - - if (dataInfo.size != sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs)) { - return ErrorCode::INVAL; - } - - SceSysAudioSystemIpcCloseAudioMethodArgs args; - uread(args, - ptr(dataInfo.data)); - - ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcCloseAudioMethodArgs", - args.audioPort, args.channelId); - } - } - - if (result != nullptr) { - return uwrite(result, 0); - } - - return {}; - } - - if (op == 0x310) { - ORBIS_LOG_TODO("IMPI: disconnect?"); - if (result) { - return uwrite(result, 0); - } - - return {}; - } - - if (op == 0x252) { - ORBIS_LOG_TODO("IMPI: client:tryGet", client->name); - thread->where(); - - struct SceIpmiClientTryGetArgs { - uint32_t unk; // 0 - uint32_t padding; - ptr message; - ptr pSize; - uint64_t maxSize; - }; - - static_assert(sizeof(SceIpmiClientTryGetArgs) == 0x20); - - if (paramsSz != sizeof(SceIpmiClientTryGetArgs)) { - return ErrorCode::INVAL; - } - - SceIpmiClientTryGetArgs tryGetParams; - auto errorCode = uread(tryGetParams, (ptr)params); - if (errorCode != ErrorCode{}) { - return errorCode; - } - - ORBIS_LOG_WARNING("IMPI: client: tryGet", tryGetParams.unk, - tryGetParams.message, tryGetParams.pSize, - tryGetParams.maxSize); - - if (client->name == "SceUserService") { - static bool isFirst = true; // TODO: implement ipmi hooks at os side - - if (isFirst) { - isFirst = false; - - struct SceUserServiceEvent { - std::uint32_t eventType; // 0 - login, 1 - logout - std::uint32_t user; - }; - - if (tryGetParams.maxSize < sizeof(SceUserServiceEvent)) { - return uwrite(result, 0x80020003); - } - - errorCode = uwrite(tryGetParams.pSize, sizeof(SceUserServiceEvent)); - if (errorCode != ErrorCode{}) { - return errorCode; - } - - errorCode = uwrite((ptr)tryGetParams.message, - {.eventType = 0, .user = 1}); - - if (errorCode != ErrorCode{}) { - return errorCode; - } - - return uwrite(result, 0); - } else { - return uwrite(result, 0x80020003); - } - } - if (result) { - return uwrite(result, 0x80020003); - } - return {}; - } - - if (op == 0x46b) { - thread->retval[0] = -0x40004; // HACK - return {}; - } - - if (op == 0x243) { - return uwrite(result, 0); - } - - return {}; -} -orbis::SysResult orbis::sys_get_gpo(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_vm_map_timestamp(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_set_hw(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_opmc_get_hw(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_cpu_usage_all(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mmap_dmem(Thread *thread, caddr_t addr, size_t len, - sint memoryType, sint prot, sint flags, - off_t directMemoryStart) { - if (auto dmem_mmap = thread->tproc->ops->dmem_mmap) { - return dmem_mmap(thread, addr, len, memoryType, prot, flags, - directMemoryStart); - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_physhm_open(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_physhm_unlink(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_resume_internal_hdd(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_thr_suspend_ucontext(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_thr_resume_ucontext(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_thr_get_ucontext(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_thr_set_ucontext(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_set_timezone_info(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_set_phys_fmem_limit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_utc_to_localtime(Thread *thread, int64_t time, - int64_t *localtime, - orbis::timesec *_sec, - int *_dst_sec) { - ORBIS_LOG_TRACE(__FUNCTION__, time, localtime, _sec, _dst_sec); - // Disabled for now - return SysResult::notAnError(ErrorCode::RANGE); - - struct ::tm tp; - auto result = ::mktime(::localtime_r(&time, &tp)); - if (auto e = uwrite(localtime, result); e != ErrorCode{}) - return e; - uwrite(_sec, {}); - uwrite(_dst_sec, 0); - return {}; -} -orbis::SysResult orbis::sys_localtime_to_utc(Thread *thread, int64_t time, - uint unk, int64_t *ptime, - orbis::timesec *_sec, - int *_dst_sec) { - ORBIS_LOG_TRACE(__FUNCTION__, time, unk, ptime, _sec, _dst_sec); - // Disabled for now - return SysResult::notAnError(ErrorCode::RANGE); - - struct ::tm tp; - ::time_t timez = 0; - auto result = time - ::mktime(::localtime_r(&timez, &tp)); - if (auto e = uwrite(ptime, result); e != ErrorCode{}) - return e; - uwrite(_sec, {}); - uwrite(_dst_sec, 0); - return {}; -} -orbis::SysResult orbis::sys_set_uevt(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_cpu_usage_proc(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_get_map_statistics(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_set_chicken_switches(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_extend_page_table_pool(Thread *thread) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_extend_page_table_pool2(Thread *thread) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ipmimgr_call(Thread* thread, uint op, uint kid, + ptr result, ptr params, + uint64_t paramsSz, uint64_t arg6) +{ + ORBIS_LOG_TODO("sys_ipmimgr_call", op, kid, result, params, paramsSz, arg6); + thread->where(); + + if (op == kImpiCreateServer) + { + if (paramsSz != sizeof(IpmiCreateServerParams)) + { + return ErrorCode::INVAL; + } + + auto createParams = (ptr)params; + + ORBIS_LOG_TODO("IPMI: create server", createParams->arg0, + createParams->name, createParams->arg2); + + auto [server, inserted] = g_context.createIpmiServer(createParams->name); + if (!inserted) + { + return ErrorCode::EXIST; + } + + auto id = thread->tproc->ipmiServerMap.insert(server); + return uwrite(result, id); + } + + if (op == 0x10) + { + // IPMI server start? + + return uwrite(result, 0); + } + + if (op == 0x201) + { + // IPMI server receive packet? + return uwrite(result, 0x80020023); + } + + if (op == kIpmiCreateClient) + { + if (paramsSz != sizeof(IpmiCreateClientParams)) + { + return ErrorCode::INVAL; + } + + auto createParams = (ptr)params; + + ORBIS_LOG_TODO("IPMI: create client", createParams->arg0, + createParams->name, createParams->arg2); + // auto server = g_context.findIpmiServer(createParams->name); + + // if (server == nullptr) { + // ORBIS_LOG_TODO("IPMI: failed to find server", createParams->name); + // } + + auto ipmiClient = knew(createParams->name); + // ipmiClient->connection = server; + auto id = thread->tproc->ipmiClientMap.insert(ipmiClient); + return uwrite(result, id); + } + + if (op == kImpiDestroyClient) + { + ORBIS_LOG_TODO("IPMI: destroy client"); + thread->tproc->ipmiClientMap.close(kid); + if (result) + { + return uwrite(result, 0); + } + + return {}; + } + + auto client = thread->tproc->ipmiClientMap.get(kid); + + if (client == nullptr) + { + return ErrorCode::INVAL; + } + + if (op == 0x241) + { + if (result) + { + return uwrite(result, 0); + } + } + + if (op == 0x400) + { + if (paramsSz != sizeof(IpmiClientConnectParams)) + { + return ErrorCode::INVAL; + } + + auto connectParams = (ptr)params; + ORBIS_LOG_TODO("IMPI: connect?", connectParams->arg0, connectParams->name, + connectParams->arg2, connectParams->arg3); + if (result) + { + return uwrite(result, 0); + } + } + + if (op == 0x320) + { + ORBIS_LOG_TODO("IMPI: invoke sync method"); + + if (paramsSz != sizeof(IpmiSyncCallParams)) + { + return ErrorCode::INVAL; + } + + IpmiSyncCallParams syncCallParams; + auto errorCode = uread(syncCallParams, (ptr)params); + if (errorCode != ErrorCode{}) + { + return errorCode; + } + + ORBIS_LOG_TODO("impi: invokeSyncMethod", client->name, + syncCallParams.method, syncCallParams.dataCount, + syncCallParams.flags, syncCallParams.pData, + syncCallParams.pBuffers, syncCallParams.pResult, + syncCallParams.resultCount); + + IpmiDataInfo dataInfo; + uread(dataInfo, syncCallParams.pData); + + ORBIS_LOG_TODO("", dataInfo.data, dataInfo.size); + + if (client->name == "SceMbusIpc") + { + if (syncCallParams.method == 0xce110007) + { // SceMbusIpcAddHandleByUserId + struct SceMbusIpcAddHandleByUserIdMethodArgs + { + uint32_t unk; // 0 + uint32_t deviceId; + uint32_t userId; + uint32_t type; + uint32_t index; + uint32_t reserved; + uint32_t pid; + }; + + static_assert(sizeof(SceMbusIpcAddHandleByUserIdMethodArgs) == 0x1c); + + if (dataInfo.size != sizeof(SceMbusIpcAddHandleByUserIdMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceMbusIpcAddHandleByUserIdMethodArgs args; + uread(args, ptr(dataInfo.data)); + + ORBIS_LOG_TODO("impi: SceMbusIpcAddHandleByUserId", args.unk, + args.deviceId, args.userId, args.type, args.index, + args.reserved, args.pid); + } + + return uwrite(result, 1); + } + else if (client->name == "SceUserService") + { + ORBIS_LOG_TODO("SceUserService"); + if (syncCallParams.method == 0x30011) + { // get initial user id + ORBIS_LOG_TODO("SceUserService: get_initial_user_id"); + auto err = uwrite(syncCallParams.pResult, 0); + if (err != ErrorCode{}) + { + return err; + } + IpmiBufferInfo bufferInfo; + err = uread(bufferInfo, syncCallParams.pBuffers); + if (err != ErrorCode{}) + { + return err; + } + + if (bufferInfo.size != sizeof(uint32_t)) + { + return uwrite(result, -1); + } + + err = uwrite((ptr)bufferInfo.data, 1u); // initial user id + if (err != ErrorCode{}) + { + return err; + } + return uwrite(result, 0); + } + } + else if (client->name == "SceLncService") + { + if (syncCallParams.method == 0x30010) + { // get app status + // returns pending system events + ORBIS_LOG_TODO("SceUserService: get_app_status"); + auto err = uwrite(syncCallParams.pResult, 0); + if (err != ErrorCode{}) + { + return err; + } + IpmiBufferInfo bufferInfo; + err = uread(bufferInfo, syncCallParams.pBuffers); + if (err != ErrorCode{}) + { + return err; + } + + struct Result + { + std::uint32_t unk0; + std::uint32_t unk1; + std::uint32_t unk2; + }; + + static_assert(sizeof(Result) == 0xc); + + if (bufferInfo.size != sizeof(Result)) + { + return uwrite(result, -1); + } + + Result bufferResult{ + .unk0 = 1, + .unk1 = 1, + .unk2 = 1, + }; + + err = uwrite((ptr)bufferInfo.data, bufferResult); + if (err != ErrorCode{}) + { + return err; + } + return uwrite(result, 0); + } + } + else if (client->name == "SceSysAudioSystemIpc") + { + if (syncCallParams.method == 0x12340000) + { // check shared memory control + struct SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs + { + uint32_t channelId; + }; + + static_assert( + sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs) == + 0x4); + + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs args; + uread(args, ptr( + dataInfo.data)); + + ORBIS_LOG_TODO( + "impi: SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs", + args.channelId); + if (auto audioOut = g_context.audioOut) + { + audioOut->channelInfo.idControl = args.channelId; + } + } + else if (syncCallParams.method == 0x1234000f) + { // create event flag + struct SceSysAudioSystemIpcCreateEventFlagMethodArgs + { + uint32_t channelId; + }; + + static_assert(sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs) == + 0x4); + + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceSysAudioSystemIpcCreateEventFlagMethodArgs args; + uread(args, ptr( + dataInfo.data)); + + if (auto audioOut = g_context.audioOut) + { + // very bad + char buffer[32]; + std::snprintf(buffer, sizeof(buffer), "sceAudioOutMix%x", + args.channelId); + // const char* eventName = &buffer; + auto [eventFlag, inserted] = thread->tproc->context->createEventFlag( + buffer, kEvfAttrShared, 0); + + if (!inserted) + { + return ErrorCode::EXIST; // FIXME: verify + } + + audioOut->channelInfo.evf = eventFlag; + } + } + else if (syncCallParams.method == + 0x12340001) + { // check shared memory audio + struct SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs + { + uint32_t audioPort; + uint32_t channelId; + }; + + static_assert( + sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs) == + 0x8); + + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs args; + uread(args, ptr( + dataInfo.data)); + + ORBIS_LOG_TODO( + "impi: SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs", + args.audioPort, args.channelId); + if (auto audioOut = g_context.audioOut) + { + audioOut->channelInfo.port = args.audioPort; + audioOut->channelInfo.channel = args.channelId; + } + } + else if (syncCallParams.method == 0x12340002) + { // something like open + struct SceSysAudioSystemIpcSomethingMethodArgs + { + uint32_t audioPort; + uint32_t channelId; + }; + + static_assert(sizeof(SceSysAudioSystemIpcSomethingMethodArgs) == 0x8); + + if (dataInfo.size != sizeof(SceSysAudioSystemIpcSomethingMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceSysAudioSystemIpcSomethingMethodArgs args; + uread(args, + ptr(dataInfo.data)); + + ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs", + args.audioPort, args.channelId); + + if (auto audioOut = g_context.audioOut) + { + // here startToListen + audioOut->start(); + } + } + else if (syncCallParams.method == 0x12340006) + { // close port + struct SceSysAudioSystemIpcCloseAudioMethodArgs + { + uint32_t audioPort; + uint32_t channelId; + }; + + static_assert(sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs) == 0x8); + + if (dataInfo.size != sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs)) + { + return ErrorCode::INVAL; + } + + SceSysAudioSystemIpcCloseAudioMethodArgs args; + uread(args, + ptr(dataInfo.data)); + + ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcCloseAudioMethodArgs", + args.audioPort, args.channelId); + } + } + + if (result != nullptr) + { + return uwrite(result, 0); + } + + return {}; + } + + if (op == 0x310) + { + ORBIS_LOG_TODO("IMPI: disconnect?"); + if (result) + { + return uwrite(result, 0); + } + + return {}; + } + + if (op == 0x252) + { + ORBIS_LOG_TODO("IMPI: client:tryGet", client->name); + thread->where(); + + struct SceIpmiClientTryGetArgs + { + uint32_t unk; // 0 + uint32_t padding; + ptr message; + ptr pSize; + uint64_t maxSize; + }; + + static_assert(sizeof(SceIpmiClientTryGetArgs) == 0x20); + + if (paramsSz != sizeof(SceIpmiClientTryGetArgs)) + { + return ErrorCode::INVAL; + } + + SceIpmiClientTryGetArgs tryGetParams; + auto errorCode = uread(tryGetParams, (ptr)params); + if (errorCode != ErrorCode{}) + { + return errorCode; + } + + ORBIS_LOG_WARNING("IMPI: client: tryGet", tryGetParams.unk, + tryGetParams.message, tryGetParams.pSize, + tryGetParams.maxSize); + + if (client->name == "SceUserService") + { + static bool isFirst = true; // TODO: implement ipmi hooks at os side + + if (isFirst) + { + isFirst = false; + + struct SceUserServiceEvent + { + std::uint32_t eventType; // 0 - login, 1 - logout + std::uint32_t user; + }; + + if (tryGetParams.maxSize < sizeof(SceUserServiceEvent)) + { + return uwrite(result, 0x80020003); + } + + errorCode = uwrite(tryGetParams.pSize, sizeof(SceUserServiceEvent)); + if (errorCode != ErrorCode{}) + { + return errorCode; + } + + errorCode = uwrite((ptr)tryGetParams.message, + {.eventType = 0, .user = 1}); + + if (errorCode != ErrorCode{}) + { + return errorCode; + } + + return uwrite(result, 0); + } + else + { + return uwrite(result, 0x80020003); + } + } + if (result) + { + return uwrite(result, 0x80020003); + } + return {}; + } + + if (op == 0x46b) + { + thread->retval[0] = -0x40004; // HACK + return {}; + } + + if (op == 0x243) + { + return uwrite(result, 0); + } + + return {}; +} +orbis::SysResult orbis::sys_get_gpo(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_vm_map_timestamp(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_set_hw(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_opmc_get_hw(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_cpu_usage_all(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mmap_dmem(Thread* thread, caddr_t addr, size_t len, + sint memoryType, sint prot, sint flags, + off_t directMemoryStart) +{ + if (auto dmem_mmap = thread->tproc->ops->dmem_mmap) + { + return dmem_mmap(thread, addr, len, memoryType, prot, flags, + directMemoryStart); + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_physhm_open(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_physhm_unlink(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_resume_internal_hdd(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_thr_suspend_ucontext(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_thr_resume_ucontext(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_thr_get_ucontext(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_thr_set_ucontext(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_set_timezone_info(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_set_phys_fmem_limit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_utc_to_localtime(Thread* thread, int64_t time, + int64_t* localtime, + orbis::timesec* _sec, + int* _dst_sec) +{ + ORBIS_LOG_TRACE(__FUNCTION__, time, localtime, _sec, _dst_sec); + // Disabled for now + return SysResult::notAnError(ErrorCode::RANGE); + + struct ::tm tp; + auto result = ::mktime(::localtime_r(&time, &tp)); + if (auto e = uwrite(localtime, result); e != ErrorCode{}) + return e; + uwrite(_sec, {}); + uwrite(_dst_sec, 0); + return {}; +} +orbis::SysResult orbis::sys_localtime_to_utc(Thread* thread, int64_t time, + uint unk, int64_t* ptime, + orbis::timesec* _sec, + int* _dst_sec) +{ + ORBIS_LOG_TRACE(__FUNCTION__, time, unk, ptime, _sec, _dst_sec); + // Disabled for now + return SysResult::notAnError(ErrorCode::RANGE); + + struct ::tm tp; + ::time_t timez = 0; + auto result = time - ::mktime(::localtime_r(&timez, &tp)); + if (auto e = uwrite(ptime, result); e != ErrorCode{}) + return e; + uwrite(_sec, {}); + uwrite(_dst_sec, 0); + return {}; +} +orbis::SysResult orbis::sys_set_uevt(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_cpu_usage_proc(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_get_map_statistics(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_set_chicken_switches(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_extend_page_table_pool(Thread* thread) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_extend_page_table_pool2(Thread* thread) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_get_kernel_mem_statistics(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_get_kernel_mem_statistics(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_get_sdk_compiled_version(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_app_state_change(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_dynlib_get_obj_member(Thread *thread, - SceKernelModule handle, - uint64_t index, - ptr> addrp) { - if (auto dynlib_get_obj_member = thread->tproc->ops->dynlib_get_obj_member) { - return dynlib_get_obj_member(thread, handle, index, addrp); - } - - return ErrorCode::NOSYS; +orbis::sys_get_sdk_compiled_version(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_app_state_change(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_dynlib_get_obj_member(Thread* thread, + SceKernelModule handle, + uint64_t index, + ptr> addrp) +{ + if (auto dynlib_get_obj_member = thread->tproc->ops->dynlib_get_obj_member) + { + return dynlib_get_obj_member(thread, handle, index, addrp); + } + + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_budget_get_ptype_of_budget(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_budget_get_ptype_of_budget(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_prepare_to_resume_process(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_process_terminate(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_blockpool_open(Thread *thread) { - if (auto blockpool_open = thread->tproc->ops->blockpool_open) { - Ref file; - auto result = blockpool_open(thread, &file); - if (result.isError()) { - return result; - } - - thread->retval[0] = thread->tproc->fileDescriptors.insert(file); - return {}; - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_blockpool_map(Thread *thread, caddr_t addr, - size_t len, sint prot, sint flags) { - if (auto blockpool_map = thread->tproc->ops->blockpool_map) { - return blockpool_map(thread, addr, len, prot, flags); - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_blockpool_unmap(Thread *thread, caddr_t addr, - size_t len, sint flags) { - if (auto blockpool_unmap = thread->tproc->ops->blockpool_unmap) { - return blockpool_unmap(thread, addr, len); - } - return ErrorCode::NOSYS; +orbis::sys_prepare_to_resume_process(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_process_terminate(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_blockpool_open(Thread* thread) +{ + if (auto blockpool_open = thread->tproc->ops->blockpool_open) + { + Ref file; + auto result = blockpool_open(thread, &file); + if (result.isError()) + { + return result; + } + + thread->retval[0] = thread->tproc->fileDescriptors.insert(file); + return {}; + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_blockpool_map(Thread* thread, caddr_t addr, + size_t len, sint prot, sint flags) +{ + if (auto blockpool_map = thread->tproc->ops->blockpool_map) + { + return blockpool_map(thread, addr, len, prot, flags); + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_blockpool_unmap(Thread* thread, caddr_t addr, + size_t len, sint flags) +{ + if (auto blockpool_unmap = thread->tproc->ops->blockpool_unmap) + { + return blockpool_unmap(thread, addr, len); + } + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_dynlib_get_info_for_libdbg(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_dynlib_get_info_for_libdbg(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_blockpool_batch(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_blockpool_batch(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fdatasync(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fdatasync(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_dynlib_get_list2(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_dynlib_get_list2(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_dynlib_get_info2(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_dynlib_get_info2(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_submit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_submit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_multi_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_multi_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_multi_wait(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_multi_wait(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_multi_poll(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_multi_poll(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_get_data(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_get_data(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_multi_cancel(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_multi_cancel(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_get_bio_usage_all(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_get_bio_usage_all(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_create(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_create(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_submit_cmd(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_submit_cmd(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_init(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_init(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_get_page_table_stats(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_get_page_table_stats(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_dynlib_get_list_for_libdbg(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_dynlib_get_list_for_libdbg(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_blockpool_move(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_blockpool_move(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_virtual_query_all(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_virtual_query_all(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_reserve_2mb_page(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_reserve_2mb_page(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cpumode_yield(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cpumode_yield(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_wait6(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_wait6(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_rights_limit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_rights_limit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_ioctls_limit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_ioctls_limit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_ioctls_get(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_ioctls_get(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_fcntls_limit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_fcntls_limit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_cap_fcntls_get(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_cap_fcntls_get(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_bindat(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_bindat(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_connectat(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_connectat(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_chflagsat(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_chflagsat(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_accept4(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_accept4(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_pipe2(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_pipe2(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_aio_mlock(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_mlock(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_procctl(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_procctl(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ppoll(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ppoll(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_futimens(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_futimens(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_utimensat(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_utimensat(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_numa_getaffinity(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_numa_getaffinity(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_numa_setaffinity(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_numa_setaffinity(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_apr_submit(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_apr_submit(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_apr_resolve(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_apr_resolve(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_apr_stat(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_apr_stat(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_apr_wait(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_apr_wait(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_apr_ctrl(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_apr_ctrl(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_get_phys_page_size(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_get_phys_page_size(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_begin_app_mount(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_begin_app_mount(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_end_app_mount(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_end_app_mount(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_fsc2h_ctrl(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_fsc2h_ctrl(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_streamwrite(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_streamwrite(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_app_save(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_app_save(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_app_restore(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_app_restore(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_saved_app_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_saved_app_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_get_ppr_sdk_compiled_version(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_get_ppr_sdk_compiled_version(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_notify_app_event(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_notify_app_event(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ioreq(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ioreq(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_openintr(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_openintr(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_dl_get_info_2(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_dl_get_info_2(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_acinfo_add(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_acinfo_add(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_acinfo_delete(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_acinfo_delete(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_acinfo_get_all_for_coredump(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::sys_acinfo_get_all_for_coredump(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ampr_ctrl_debug(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ampr_ctrl_debug(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_workspace_ctrl(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_workspace_ctrl(Thread* thread /* TODO */) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_sem.cpp b/orbis-kernel/src/sys/sys_sem.cpp index 039e10ea..aa1f06f4 100644 --- a/orbis-kernel/src/sys/sys_sem.cpp +++ b/orbis-kernel/src/sys/sys_sem.cpp @@ -1,18 +1,22 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys___semctl(Thread *thread, sint semid, sint semnum, - sint cmd, ptr arg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys___semctl(Thread* thread, sint semid, sint semnum, + sint cmd, ptr arg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_semget(Thread *thread, key_t key, sint nsems, - sint semflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_semget(Thread* thread, key_t key, sint nsems, + sint semflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_semop(Thread *thread, sint semid, - ptr sops, size_t nspos) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_semop(Thread* thread, sint semid, + ptr sops, size_t nspos) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_semsys(Thread *thread, sint which, sint a2, sint a3, - sint a4, sint a5) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_semsys(Thread* thread, sint which, sint a2, sint a3, + sint a4, sint a5) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_shm.cpp b/orbis-kernel/src/sys/sys_shm.cpp index c7061554..8ad35433 100644 --- a/orbis-kernel/src/sys/sys_shm.cpp +++ b/orbis-kernel/src/sys/sys_shm.cpp @@ -1,21 +1,26 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_shmdt(Thread *thread, ptr shmaddr) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_shmdt(Thread* thread, ptr shmaddr) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_shmat(Thread *thread, sint shmid, - ptr shmaddr, sint shmflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_shmat(Thread* thread, sint shmid, + ptr shmaddr, sint shmflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_shmctl(Thread *thread, sint shmid, sint cmd, - ptr buf) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_shmctl(Thread* thread, sint shmid, sint cmd, + ptr buf) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_shmget(Thread *thread, key_t key, size_t size, - sint shmflg) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_shmget(Thread* thread, key_t key, size_t size, + sint shmflg) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_shmsys(Thread *thread, sint which, sint a2, sint a3, - sint a4) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_shmsys(Thread* thread, sint which, sint a2, sint a3, + sint a4) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_shutdown.cpp b/orbis-kernel/src/sys/sys_shutdown.cpp index 496a0905..75f31669 100644 --- a/orbis-kernel/src/sys/sys_shutdown.cpp +++ b/orbis-kernel/src/sys/sys_shutdown.cpp @@ -1,5 +1,6 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_reboot(Thread *thread, sint opt) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_reboot(Thread* thread, sint opt) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_sig.cpp b/orbis-kernel/src/sys/sys_sig.cpp index cabea89d..2b04033d 100644 --- a/orbis-kernel/src/sys/sys_sig.cpp +++ b/orbis-kernel/src/sys/sys_sig.cpp @@ -1,83 +1,102 @@ #include "sys/sysproto.hpp" #include "utils/Logs.hpp" -orbis::SysResult orbis::sys_sigaction(Thread *thread, sint sig, - ptr act, - ptr oact) { - return {}; +orbis::SysResult orbis::sys_sigaction(Thread* thread, sint sig, + ptr act, + ptr oact) +{ + return {}; } -orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how, - ptr set, ptr oset) { - if (oset) { - for (std::size_t i = 0; i < 2; ++i) { - oset[i] = thread->sigMask[i]; - } - } +orbis::SysResult orbis::sys_sigprocmask(Thread* thread, sint how, + ptr set, ptr oset) +{ + if (oset) + { + for (std::size_t i = 0; i < 2; ++i) + { + oset[i] = thread->sigMask[i]; + } + } - if (set) { - switch (how) { - case 0: // unblock - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] &= ~set[i]; - } - case 1: // block - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] |= set[i]; - } - break; - case 3: // set - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] = set[i]; - } - break; + if (set) + { + switch (how) + { + case 0: // unblock + for (std::size_t i = 0; i < 2; ++i) + { + thread->sigMask[i] &= ~set[i]; + } + case 1: // block + for (std::size_t i = 0; i < 2; ++i) + { + thread->sigMask[i] |= set[i]; + } + break; + case 3: // set + for (std::size_t i = 0; i < 2; ++i) + { + thread->sigMask[i] = set[i]; + } + break; - default: - ORBIS_LOG_ERROR("sys_sigprocmask: unimplemented how", how); - thread->where(); - return {}; - } - } - return {}; + default: + ORBIS_LOG_ERROR("sys_sigprocmask: unimplemented how", how); + thread->where(); + return {}; + } + } + return {}; } -orbis::SysResult orbis::sys_sigwait(Thread *thread, - ptr set, - ptr sig) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigwait(Thread* thread, + ptr set, + ptr sig) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigtimedwait(Thread *thread, - ptr set, - ptr info, - ptr timeout) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigtimedwait(Thread* thread, + ptr set, + ptr info, + ptr timeout) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigwaitinfo(Thread *thread, - ptr set, - ptr info) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigwaitinfo(Thread* thread, + ptr set, + ptr info) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigpending(Thread *thread, ptr set) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigpending(Thread* thread, ptr set) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigsuspend(Thread *thread, - ptr set) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigsuspend(Thread* thread, + ptr set) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigaltstack(Thread *thread, ptr ss, - ptr oss) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigaltstack(Thread* thread, ptr ss, + ptr oss) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kill(Thread* thread, sint pid, sint signum) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_pdkill(Thread *thread, sint fd, sint signum) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_pdkill(Thread* thread, sint fd, sint signum) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigqueue(Thread *thread, pid_t pid, sint signum, - ptr value) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigqueue(Thread* thread, pid_t pid, sint signum, + ptr value) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigreturn(Thread *thread, - ptr sigcntxp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigreturn(Thread* thread, + ptr sigcntxp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::nosys(Thread *thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::nosys(Thread* thread) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_subr_prof.cpp b/orbis-kernel/src/sys/sys_subr_prof.cpp index 37ac4996..d0d31f70 100644 --- a/orbis-kernel/src/sys/sys_subr_prof.cpp +++ b/orbis-kernel/src/sys/sys_subr_prof.cpp @@ -1,6 +1,7 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_profil(Thread *thread, caddr_t samples, size_t size, - size_t offset, uint scale) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_profil(Thread* thread, caddr_t samples, size_t size, + size_t offset, uint scale) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_swap_pager.cpp b/orbis-kernel/src/sys/sys_swap_pager.cpp index 1313f8fe..355a82dc 100644 --- a/orbis-kernel/src/sys/sys_swap_pager.cpp +++ b/orbis-kernel/src/sys/sys_swap_pager.cpp @@ -1,8 +1,10 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_swapon(Thread *thread, ptr name) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_swapon(Thread* thread, ptr name) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_swapoff(Thread *thread, ptr name) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_swapoff(Thread* thread, ptr name) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_synch.cpp b/orbis-kernel/src/sys/sys_synch.cpp index 6d46ef02..a87fc0d5 100644 --- a/orbis-kernel/src/sys/sys_synch.cpp +++ b/orbis-kernel/src/sys/sys_synch.cpp @@ -1,3 +1,3 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_yield(Thread *thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_yield(Thread* thread) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_sysctl.cpp b/orbis-kernel/src/sys/sys_sysctl.cpp index b202064f..b0a55dc3 100644 --- a/orbis-kernel/src/sys/sys_sysctl.cpp +++ b/orbis-kernel/src/sys/sys_sysctl.cpp @@ -1,320 +1,393 @@ #include "KernelContext.hpp" #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, - uint namelen, ptr old, - ptr oldlenp, ptr new_, - size_t newlen) { - enum sysctl_ctl { unspec, kern, vm, vfs, net, debug, hw, machdep, user }; - - // machdep.tsc_freq - - enum sysctl_kern { - usrstack = 33, - kern_14 = 14, - kern_37 = 37, - - // FIXME - smp_cpus = 1000, - sdk_version, - sched_cpusetsize, - proc_ptc, - cpu_mode, - rng_pseudo, - }; - - enum sysctl_hw { - pagesize = 7, - }; - - enum sysctl_machdep { - // FIXME - tsc_freq = 1000 - }; - - // for (unsigned int i = 0; i < namelen; ++i) { - // std::fprintf(stderr, " name[%u] = %u\n", i, name[i]); - // } - - if (namelen == 3) { - // 1 - 14 - 41 - debug flags? - - if (name[0] == 1 && name[1] == 14 && name[2] == 41) { - // std::printf(" kern.14.41\n"); - - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(uint32_t *)old = 0; - return {}; - } - } - - if (namelen == 4) { - // 1 - 14 - 35 - 2 - - // sceKernelGetAppInfo - struct app_info { - char unk[72]; - }; - - if (name[0] == 1 && name[1] == 14 && name[2] == 35) { - // std::printf(" kern.14.35.%u\n", name[3]); - memset(old, 0, sizeof(app_info)); - return {}; - } - - if (name[0] == 1 && name[1] == 14 && name[2] == 44) { - // GetLibkernelTextLocation - if (*oldlenp != 16) { - return ErrorCode::INVAL; - } - - auto *dest = (uint64_t *)old; - - for (auto [id, mod] : thread->tproc->modulesMap) { - if (std::string_view("libkernel") == mod->moduleName) { - dest[0] = (uint64_t)mod->segments[0].addr; - dest[1] = mod->segments[0].size; - return{}; - } - } - } - } - - if (namelen == 2) { - switch (name[0]) { - case sysctl_ctl::unspec: { - switch (name[1]) { - case 3: { - std::fprintf(stderr, " unspec - get name of '%s'\n", - std::string((char *)new_, newlen).c_str()); - auto searchName = std::string_view((char *)new_, newlen); - auto *dest = (std::uint32_t *)old; - std::uint32_t count = 0; - - if (searchName == "kern.smp.cpus") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = smp_cpus; - } else if (searchName == "machdep.tsc_freq") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = machdep; - dest[count++] = tsc_freq; - } else if (searchName == "kern.sdk_version") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = sdk_version; - } else if (searchName == "kern.rng_pseudo") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = rng_pseudo; - } else if (searchName == "kern.sched.cpusetsize") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = sched_cpusetsize; - } else if (searchName == "kern.proc.ptc") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = proc_ptc; - } else if (searchName == "kern.cpumode") { - if (*oldlenp < 2 * sizeof(uint32_t)) { - std::fprintf(stderr, " %s error\n", searchName.data()); - return ErrorCode::INVAL; - } - - dest[count++] = kern; - dest[count++] = cpu_mode; - } - - if (count == 0) { - std::fprintf(stderr, " %s is unknown\n", searchName.data()); - return ErrorCode::SRCH; - } - - *oldlenp = count * sizeof(uint32_t); - return {}; - } - - default: - break; - } - std::printf(" unspec_%u\n", name[1]); - return {}; - } - - case sysctl_ctl::kern: - switch (name[1]) { - case sysctl_kern::usrstack: { - if (*oldlenp != 8 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - std::printf("Reporting stack at %p\n", thread->stackEnd); - *(ptr *)old = thread->stackEnd; - return {}; - } - - case sysctl_kern::smp_cpus: - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(uint32_t *)old = 1; - return{}; - - case sysctl_kern::sdk_version: { - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - auto processParam = - reinterpret_cast(thread->tproc->processParam); - - auto sdkVersion = processParam // - + sizeof(uint64_t) // size - + sizeof(uint32_t) // magic - + sizeof(uint32_t); // entryCount - - std::printf("Reporting SDK version %x\n", - *reinterpret_cast(sdkVersion)); - *(uint32_t *)old = *reinterpret_cast(sdkVersion); - return{}; - } - - case sysctl_kern::sched_cpusetsize: - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(std::uint32_t *)old = 4; - return{}; - - case sysctl_kern::rng_pseudo: - if (*oldlenp != 0x40 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - - std::memset(old, 0, 0x40); - return{}; - - case sysctl_kern::kern_37: { - struct kern37_value { - std::uint64_t size; - std::uint64_t unk[7]; - }; - - if (*oldlenp != sizeof(kern37_value) || new_ != nullptr || - newlen != 0) { - return ErrorCode::INVAL; - } - - auto value = (kern37_value *)old; - value->size = sizeof(kern37_value); - return{}; - } - - case sysctl_kern::proc_ptc: { - if (*oldlenp != 8 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(std::uint64_t *)old = 1357; - return{}; - } - - case sysctl_kern::cpu_mode: { - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - // 0 - 6 cpu - // 1 - 7 cpu, low power - // 5 - 7 cpu, normal - *(std::uint32_t *)old = 5; - return{}; - } - - default: - return ErrorCode::INVAL; - } - break; - - case sysctl_ctl::vm: - case sysctl_ctl::vfs: - case sysctl_ctl::net: - case sysctl_ctl::debug: - return ErrorCode::INVAL; - - case sysctl_ctl::hw: - switch (name[1]) { - case sysctl_hw::pagesize: - if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(uint32_t *)old = 0x4000; - return{}; - - default: - break; - } - break; - - case sysctl_ctl::machdep: - switch (name[1]) { - case sysctl_machdep::tsc_freq: { - if (*oldlenp != 8 || new_ != nullptr || newlen != 0) { - return ErrorCode::INVAL; - } - - *(uint64_t *)old = g_context.getTscFreq(); - return {}; - - default: - return ErrorCode::INVAL; - } - } - case sysctl_ctl::user: - return ErrorCode::INVAL; - } - } - - std::string concatName; - for (unsigned int i = 0; i < namelen; ++i) { - if (i != 0) { - concatName += '.'; - } - - concatName += std::to_string(name[i]); - } - - ORBIS_LOG_TODO(__FUNCTION__, concatName); - return {}; +orbis::SysResult orbis::sys___sysctl(Thread* thread, ptr name, + uint namelen, ptr old, + ptr oldlenp, ptr new_, + size_t newlen) +{ + enum sysctl_ctl + { + unspec, + kern, + vm, + vfs, + net, + debug, + hw, + machdep, + user + }; + + // machdep.tsc_freq + + enum sysctl_kern + { + usrstack = 33, + kern_14 = 14, + kern_37 = 37, + + // FIXME + smp_cpus = 1000, + sdk_version, + sched_cpusetsize, + proc_ptc, + cpu_mode, + rng_pseudo, + }; + + enum sysctl_hw + { + pagesize = 7, + }; + + enum sysctl_machdep + { + // FIXME + tsc_freq = 1000 + }; + + // for (unsigned int i = 0; i < namelen; ++i) { + // std::fprintf(stderr, " name[%u] = %u\n", i, name[i]); + // } + + if (namelen == 3) + { + // 1 - 14 - 41 - debug flags? + + if (name[0] == 1 && name[1] == 14 && name[2] == 41) + { + // std::printf(" kern.14.41\n"); + + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(uint32_t*)old = 0; + return {}; + } + } + + if (namelen == 4) + { + // 1 - 14 - 35 - 2 + + // sceKernelGetAppInfo + struct app_info + { + char unk[72]; + }; + + if (name[0] == 1 && name[1] == 14 && name[2] == 35) + { + // std::printf(" kern.14.35.%u\n", name[3]); + memset(old, 0, sizeof(app_info)); + return {}; + } + + if (name[0] == 1 && name[1] == 14 && name[2] == 44) + { + // GetLibkernelTextLocation + if (*oldlenp != 16) + { + return ErrorCode::INVAL; + } + + auto* dest = (uint64_t*)old; + + for (auto [id, mod] : thread->tproc->modulesMap) + { + if (std::string_view("libkernel") == mod->moduleName) + { + dest[0] = (uint64_t)mod->segments[0].addr; + dest[1] = mod->segments[0].size; + return {}; + } + } + } + } + + if (namelen == 2) + { + switch (name[0]) + { + case sysctl_ctl::unspec: + { + switch (name[1]) + { + case 3: + { + std::fprintf(stderr, " unspec - get name of '%s'\n", + std::string((char*)new_, newlen).c_str()); + auto searchName = std::string_view((char*)new_, newlen); + auto* dest = (std::uint32_t*)old; + std::uint32_t count = 0; + + if (searchName == "kern.smp.cpus") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = smp_cpus; + } + else if (searchName == "machdep.tsc_freq") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = machdep; + dest[count++] = tsc_freq; + } + else if (searchName == "kern.sdk_version") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = sdk_version; + } + else if (searchName == "kern.rng_pseudo") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = rng_pseudo; + } + else if (searchName == "kern.sched.cpusetsize") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = sched_cpusetsize; + } + else if (searchName == "kern.proc.ptc") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = proc_ptc; + } + else if (searchName == "kern.cpumode") + { + if (*oldlenp < 2 * sizeof(uint32_t)) + { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = cpu_mode; + } + + if (count == 0) + { + std::fprintf(stderr, " %s is unknown\n", searchName.data()); + return ErrorCode::SRCH; + } + + *oldlenp = count * sizeof(uint32_t); + return {}; + } + + default: + break; + } + std::printf(" unspec_%u\n", name[1]); + return {}; + } + + case sysctl_ctl::kern: + switch (name[1]) + { + case sysctl_kern::usrstack: + { + if (*oldlenp != 8 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + std::printf("Reporting stack at %p\n", thread->stackEnd); + *(ptr*)old = thread->stackEnd; + return {}; + } + + case sysctl_kern::smp_cpus: + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(uint32_t*)old = 1; + return {}; + + case sysctl_kern::sdk_version: + { + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + auto processParam = + reinterpret_cast(thread->tproc->processParam); + + auto sdkVersion = processParam // + + sizeof(uint64_t) // size + + sizeof(uint32_t) // magic + + sizeof(uint32_t); // entryCount + + std::printf("Reporting SDK version %x\n", + *reinterpret_cast(sdkVersion)); + *(uint32_t*)old = *reinterpret_cast(sdkVersion); + return {}; + } + + case sysctl_kern::sched_cpusetsize: + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(std::uint32_t*)old = 4; + return {}; + + case sysctl_kern::rng_pseudo: + if (*oldlenp != 0x40 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + + std::memset(old, 0, 0x40); + return {}; + + case sysctl_kern::kern_37: + { + struct kern37_value + { + std::uint64_t size; + std::uint64_t unk[7]; + }; + + if (*oldlenp != sizeof(kern37_value) || new_ != nullptr || + newlen != 0) + { + return ErrorCode::INVAL; + } + + auto value = (kern37_value*)old; + value->size = sizeof(kern37_value); + return {}; + } + + case sysctl_kern::proc_ptc: + { + if (*oldlenp != 8 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(std::uint64_t*)old = 1357; + return {}; + } + + case sysctl_kern::cpu_mode: + { + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + // 0 - 6 cpu + // 1 - 7 cpu, low power + // 5 - 7 cpu, normal + *(std::uint32_t*)old = 5; + return {}; + } + + default: + return ErrorCode::INVAL; + } + break; + + case sysctl_ctl::vm: + case sysctl_ctl::vfs: + case sysctl_ctl::net: + case sysctl_ctl::debug: + return ErrorCode::INVAL; + + case sysctl_ctl::hw: + switch (name[1]) + { + case sysctl_hw::pagesize: + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(uint32_t*)old = 0x4000; + return {}; + + default: + break; + } + break; + + case sysctl_ctl::machdep: + switch (name[1]) + { + case sysctl_machdep::tsc_freq: + { + if (*oldlenp != 8 || new_ != nullptr || newlen != 0) + { + return ErrorCode::INVAL; + } + + *(uint64_t*)old = g_context.getTscFreq(); + return {}; + + default: + return ErrorCode::INVAL; + } + } + case sysctl_ctl::user: + return ErrorCode::INVAL; + } + } + + std::string concatName; + for (unsigned int i = 0; i < namelen; ++i) + { + if (i != 0) + { + concatName += '.'; + } + + concatName += std::to_string(name[i]); + } + + ORBIS_LOG_TODO(__FUNCTION__, concatName); + return {}; } diff --git a/orbis-kernel/src/sys/sys_thr.cpp b/orbis-kernel/src/sys/sys_thr.cpp index d377f4b5..8f516ba0 100644 --- a/orbis-kernel/src/sys/sys_thr.cpp +++ b/orbis-kernel/src/sys/sys_thr.cpp @@ -1,74 +1,91 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_thr_create(Thread *thread, - ptr ctxt, - ptr arg, sint flags) { - if (auto thr_create = thread->tproc->ops->thr_create) { - return thr_create(thread, ctxt, arg, flags); - } - - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_thr_create(Thread* thread, + ptr ctxt, + ptr arg, sint flags) +{ + if (auto thr_create = thread->tproc->ops->thr_create) + { + return thr_create(thread, ctxt, arg, flags); + } + + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_new(Thread *thread, ptr param, - sint param_size) { - if (auto thr_new = thread->tproc->ops->thr_new) { - return thr_new(thread, param, param_size); - } +orbis::SysResult orbis::sys_thr_new(Thread* thread, ptr param, + sint param_size) +{ + if (auto thr_new = thread->tproc->ops->thr_new) + { + return thr_new(thread, param, param_size); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_self(Thread *thread, ptr id) { - return uwrite(id, (slong)thread->tid); +orbis::SysResult orbis::sys_thr_self(Thread* thread, ptr id) +{ + return uwrite(id, (slong)thread->tid); } -orbis::SysResult orbis::sys_thr_exit(Thread *thread, ptr state) { - if (auto thr_exit = thread->tproc->ops->thr_exit) { - return thr_exit(thread, state); - } - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_thr_exit(Thread* thread, ptr state) +{ + if (auto thr_exit = thread->tproc->ops->thr_exit) + { + return thr_exit(thread, state); + } + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_kill(Thread *thread, slong id, sint sig) { - if (auto thr_kill = thread->tproc->ops->thr_kill) { - return thr_kill(thread, id, sig); - } +orbis::SysResult orbis::sys_thr_kill(Thread* thread, slong id, sint sig) +{ + if (auto thr_kill = thread->tproc->ops->thr_kill) + { + return thr_kill(thread, id, sig); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_kill2(Thread *thread, pid_t pid, slong id, - sint sig) { - if (auto thr_kill2 = thread->tproc->ops->thr_kill2) { - return thr_kill2(thread, pid, id, sig); - } +orbis::SysResult orbis::sys_thr_kill2(Thread* thread, pid_t pid, slong id, + sint sig) +{ + if (auto thr_kill2 = thread->tproc->ops->thr_kill2) + { + return thr_kill2(thread, pid, id, sig); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_suspend(Thread *thread, - ptr timeout) { - if (auto thr_suspend = thread->tproc->ops->thr_suspend) { - return thr_suspend(thread, timeout); - } +orbis::SysResult orbis::sys_thr_suspend(Thread* thread, + ptr timeout) +{ + if (auto thr_suspend = thread->tproc->ops->thr_suspend) + { + return thr_suspend(thread, timeout); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_wake(Thread *thread, slong id) { - if (auto thr_wake = thread->tproc->ops->thr_wake) { - return thr_wake(thread, id); - } +orbis::SysResult orbis::sys_thr_wake(Thread* thread, slong id) +{ + if (auto thr_wake = thread->tproc->ops->thr_wake) + { + return thr_wake(thread, id); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_thr_set_name(Thread *thread, slong id, - ptr name) { - if (auto thr_set_name = thread->tproc->ops->thr_set_name) { - return thr_set_name(thread, id, name); - } +orbis::SysResult orbis::sys_thr_set_name(Thread* thread, slong id, + ptr name) +{ + if (auto thr_set_name = thread->tproc->ops->thr_set_name) + { + return thr_set_name(thread, id, name); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_time.cpp b/orbis-kernel/src/sys/sys_time.cpp index 29e7c658..fe14a702 100644 --- a/orbis-kernel/src/sys/sys_time.cpp +++ b/orbis-kernel/src/sys/sys_time.cpp @@ -3,189 +3,211 @@ #include "utils/Logs.hpp" #include -enum class ClockId { - Realtime = 0, - Virtual = 1, - Prof = 2, - Monotonic = 4, - Uptime = 5, // FreeBSD-specific - UptimePrecise = 7, // FreeBSD-specific - UptimeFast = 8, // FreeBSD-specific - RealtimePrecise = 9, // FreeBSD-specific - RealtimeFast = 10, // FreeBSD-specific - MonotonicPrecise = 11, // FreeBSD-specific - MonotonicFast = 12, // FreeBSD-specific - Second = 13, // FreeBSD-specific - ThreadCputimeId = 14, +enum class ClockId +{ + Realtime = 0, + Virtual = 1, + Prof = 2, + Monotonic = 4, + Uptime = 5, // FreeBSD-specific + UptimePrecise = 7, // FreeBSD-specific + UptimeFast = 8, // FreeBSD-specific + RealtimePrecise = 9, // FreeBSD-specific + RealtimeFast = 10, // FreeBSD-specific + MonotonicPrecise = 11, // FreeBSD-specific + MonotonicFast = 12, // FreeBSD-specific + Second = 13, // FreeBSD-specific + ThreadCputimeId = 14, - // orbis extension - Proctime = 15, - Network = 16, - DebugNetwork = 17, - AdNetwork = 18, - RawNetwork = 19, + // orbis extension + Proctime = 15, + Network = 16, + DebugNetwork = 17, + AdNetwork = 18, + RawNetwork = 19, }; -orbis::SysResult orbis::sys_clock_gettime(Thread *, clockid_t clock_id, - ptr tp) { - timespec result{}; +orbis::SysResult orbis::sys_clock_gettime(Thread*, clockid_t clock_id, + ptr tp) +{ + timespec result{}; - auto getHostClock = [](clockid_t clock_id) { - ::timespec hostClock; - ::clock_gettime(clock_id, &hostClock); + auto getHostClock = [](clockid_t clock_id) { + ::timespec hostClock; + ::clock_gettime(clock_id, &hostClock); - timespec result; - result.sec = hostClock.tv_sec; - result.nsec = hostClock.tv_nsec; - return result; - }; + timespec result; + result.sec = hostClock.tv_sec; + result.nsec = hostClock.tv_nsec; + return result; + }; - switch (static_cast(clock_id)) { - case ClockId::Realtime: - case ClockId::RealtimePrecise: - result = getHostClock(CLOCK_REALTIME); - break; + switch (static_cast(clock_id)) + { + case ClockId::Realtime: + case ClockId::RealtimePrecise: + result = getHostClock(CLOCK_REALTIME); + break; - case ClockId::RealtimeFast: { - result = getHostClock(CLOCK_REALTIME); // FIXME - break; - } - case ClockId::Virtual: - ORBIS_LOG_ERROR("Unimplemented ClockId::Virtual\n"); - break; - case ClockId::Prof: - ORBIS_LOG_ERROR("Unimplemented ClockId::Prof\n"); - break; + case ClockId::RealtimeFast: + { + result = getHostClock(CLOCK_REALTIME); // FIXME + break; + } + case ClockId::Virtual: + ORBIS_LOG_ERROR("Unimplemented ClockId::Virtual\n"); + break; + case ClockId::Prof: + ORBIS_LOG_ERROR("Unimplemented ClockId::Prof\n"); + break; - case ClockId::Monotonic: - case ClockId::MonotonicPrecise: - case ClockId::Uptime: - case ClockId::UptimePrecise: { - result = getHostClock(CLOCK_MONOTONIC); - break; - } + case ClockId::Monotonic: + case ClockId::MonotonicPrecise: + case ClockId::Uptime: + case ClockId::UptimePrecise: + { + result = getHostClock(CLOCK_MONOTONIC); + break; + } - case ClockId::UptimeFast: - case ClockId::MonotonicFast: - result = getHostClock(CLOCK_MONOTONIC); // FIXME - break; + case ClockId::UptimeFast: + case ClockId::MonotonicFast: + result = getHostClock(CLOCK_MONOTONIC); // FIXME + break; - case ClockId::Second: { - result = getHostClock(CLOCK_MONOTONIC); // FIXME - result.nsec = 0; - break; - } - case ClockId::ThreadCputimeId: - result = getHostClock(CLOCK_THREAD_CPUTIME_ID); - break; - case ClockId::Proctime: - result = getHostClock(CLOCK_PROCESS_CPUTIME_ID); - break; - case ClockId::Network: - ORBIS_LOG_ERROR("Unimplemented ClockId::Network\n"); - break; - case ClockId::DebugNetwork: - ORBIS_LOG_ERROR("Unimplemented ClockId::DebugNetwork\n"); - break; - case ClockId::AdNetwork: - ORBIS_LOG_ERROR("Unimplemented ClockId::AdNetwork\n"); - break; - case ClockId::RawNetwork: - ORBIS_LOG_ERROR("Unimplemented ClockId::RawNetwork\n"); - break; + case ClockId::Second: + { + result = getHostClock(CLOCK_MONOTONIC); // FIXME + result.nsec = 0; + break; + } + case ClockId::ThreadCputimeId: + result = getHostClock(CLOCK_THREAD_CPUTIME_ID); + break; + case ClockId::Proctime: + result = getHostClock(CLOCK_PROCESS_CPUTIME_ID); + break; + case ClockId::Network: + ORBIS_LOG_ERROR("Unimplemented ClockId::Network\n"); + break; + case ClockId::DebugNetwork: + ORBIS_LOG_ERROR("Unimplemented ClockId::DebugNetwork\n"); + break; + case ClockId::AdNetwork: + ORBIS_LOG_ERROR("Unimplemented ClockId::AdNetwork\n"); + break; + case ClockId::RawNetwork: + ORBIS_LOG_ERROR("Unimplemented ClockId::RawNetwork\n"); + break; - default: - return ErrorCode::INVAL; - } + default: + return ErrorCode::INVAL; + } - return uwrite(tp, result); + return uwrite(tp, result); } -orbis::SysResult orbis::sys_clock_settime(Thread *thread, clockid_t clock_id, - ptr tp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_clock_settime(Thread* thread, clockid_t clock_id, + ptr tp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_clock_getres(Thread *thread, clockid_t clock_id, - ptr tp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_clock_getres(Thread* thread, clockid_t clock_id, + ptr tp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_nanosleep(Thread *thread, - cptr rqtp, - ptr rmtp) { - ORBIS_LOG_TRACE(__FUNCTION__, rqtp, rmtp); - struct ::timespec rq; - struct ::timespec rm; - orbis::timespec value; - if (auto e = uread(value, rqtp); e != ErrorCode{}) - return e; - rq.tv_sec = value.sec; - rq.tv_nsec = value.nsec; - if (::nanosleep(&rq, &rm) == EINTR) { - if (rmtp) { - value.sec = rm.tv_sec; - value.nsec = rm.tv_nsec; - if (auto e = uwrite(rmtp, value); e != ErrorCode{}) - return e; - } - return ErrorCode::INTR; - } - return {}; +orbis::SysResult orbis::sys_nanosleep(Thread* thread, + cptr rqtp, + ptr rmtp) +{ + ORBIS_LOG_TRACE(__FUNCTION__, rqtp, rmtp); + struct ::timespec rq; + struct ::timespec rm; + orbis::timespec value; + if (auto e = uread(value, rqtp); e != ErrorCode{}) + return e; + rq.tv_sec = value.sec; + rq.tv_nsec = value.nsec; + if (::nanosleep(&rq, &rm) == EINTR) + { + if (rmtp) + { + value.sec = rm.tv_sec; + value.nsec = rm.tv_nsec; + if (auto e = uwrite(rmtp, value); e != ErrorCode{}) + return e; + } + return ErrorCode::INTR; + } + return {}; } -orbis::SysResult orbis::sys_gettimeofday(Thread *thread, ptr tp, - ptr tzp) { - ORBIS_LOG_TRACE(__FUNCTION__, tp, tzp); - struct ::timeval tv; - if (::gettimeofday(&tv, nullptr) != 0) - std::abort(); - if (tp) { - orbis::timeval value; - value.tv_sec = tv.tv_sec; - value.tv_usec = tv.tv_usec; - if (auto e = uwrite(tp, value); e != ErrorCode{}) - return e; - } - if (tzp) { - struct ::tm tp; - if (localtime_r(&tv.tv_sec, &tp) != &tp) - std::abort(); - orbis::timezone value; - value.tz_dsttime = 0; // TODO - value.tz_mineast = tp.tm_gmtoff / 60; - if (auto e = uwrite(tzp, value); e != ErrorCode{}) - return e; - } - return {}; +orbis::SysResult orbis::sys_gettimeofday(Thread* thread, ptr tp, + ptr tzp) +{ + ORBIS_LOG_TRACE(__FUNCTION__, tp, tzp); + struct ::timeval tv; + if (::gettimeofday(&tv, nullptr) != 0) + std::abort(); + if (tp) + { + orbis::timeval value; + value.tv_sec = tv.tv_sec; + value.tv_usec = tv.tv_usec; + if (auto e = uwrite(tp, value); e != ErrorCode{}) + return e; + } + if (tzp) + { + struct ::tm tp; + if (localtime_r(&tv.tv_sec, &tp) != &tp) + std::abort(); + orbis::timezone value; + value.tz_dsttime = 0; // TODO + value.tz_mineast = tp.tm_gmtoff / 60; + if (auto e = uwrite(tzp, value); e != ErrorCode{}) + return e; + } + return {}; } -orbis::SysResult orbis::sys_settimeofday(Thread *thread, ptr tp, - ptr tzp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_settimeofday(Thread* thread, ptr tp, + ptr tzp) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_getitimer(Thread *thread, uint which, - ptr itv) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_getitimer(Thread* thread, uint which, + ptr itv) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_setitimer(Thread *thread, uint which, - ptr itv, - ptr oitv) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_setitimer(Thread* thread, uint which, + ptr itv, + ptr oitv) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ktimer_create(Thread *thread, clockid_t clock_id, - ptr evp, - ptr timerid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktimer_create(Thread* thread, clockid_t clock_id, + ptr evp, + ptr timerid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ktimer_delete(Thread *thread, sint timerid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktimer_delete(Thread* thread, sint timerid) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ktimer_settime(Thread *thread, sint timerid, - sint flags, - ptr value, - ptr ovalue) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktimer_settime(Thread* thread, sint timerid, + sint flags, + ptr value, + ptr ovalue) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ktimer_gettime(Thread *thread, sint timerid, - ptr value) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktimer_gettime(Thread* thread, sint timerid, + ptr value) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ktimer_getoverrun(Thread *thread, sint timerid) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ktimer_getoverrun(Thread* thread, sint timerid) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_uipc.cpp b/orbis-kernel/src/sys/sys_uipc.cpp index a87c04d9..57283934 100644 --- a/orbis-kernel/src/sys/sys_uipc.cpp +++ b/orbis-kernel/src/sys/sys_uipc.cpp @@ -1,94 +1,114 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_socket(Thread *thread, sint domain, sint type, - sint protocol) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_bind(Thread *thread, sint s, caddr_t name, - sint namelen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_listen(Thread *thread, sint s, sint backlog) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_accept(Thread *thread, sint s, - ptr from, - ptr fromlenaddr) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_connect(Thread *thread, sint s, caddr_t name, - sint namelen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_socketpair(Thread *thread, sint domain, sint type, - sint protocol, ptr rsv) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sendto(Thread *thread, sint s, caddr_t buf, - size_t len, sint flags, caddr_t to, - sint tolen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sendmsg(Thread *thread, sint s, - ptr msg, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_recvfrom(Thread *thread, sint s, caddr_t buf, - size_t len, sint flags, - ptr from, - ptr fromlenaddr) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_recvmsg(Thread *thread, sint s, - ptr msg, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_shutdown(Thread *thread, sint s, sint how) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_setsockopt(Thread *thread, sint s, sint level, - sint name, caddr_t val, sint valsize) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getsockopt(Thread *thread, sint s, sint level, - sint name, caddr_t val, - ptr avalsize) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getsockname(Thread *thread, sint fdes, - ptr asa, - ptr alen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getpeername(Thread *thread, sint fdes, - ptr asa, - ptr alen) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sendfile(Thread *thread, sint fd, sint s, - off_t offset, size_t nbytes, - ptr hdtr, - ptr sbytes, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_sctp_peeloff(Thread *thread, sint sd, - uint32_t name) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_socket(Thread* thread, sint domain, sint type, + sint protocol) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_bind(Thread* thread, sint s, caddr_t name, + sint namelen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_listen(Thread* thread, sint s, sint backlog) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_accept(Thread* thread, sint s, + ptr from, + ptr fromlenaddr) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_connect(Thread* thread, sint s, caddr_t name, + sint namelen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_socketpair(Thread* thread, sint domain, sint type, + sint protocol, ptr rsv) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sendto(Thread* thread, sint s, caddr_t buf, + size_t len, sint flags, caddr_t to, + sint tolen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sendmsg(Thread* thread, sint s, + ptr msg, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_recvfrom(Thread* thread, sint s, caddr_t buf, + size_t len, sint flags, + ptr from, + ptr fromlenaddr) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_recvmsg(Thread* thread, sint s, + ptr msg, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_shutdown(Thread* thread, sint s, sint how) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_setsockopt(Thread* thread, sint s, sint level, + sint name, caddr_t val, sint valsize) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getsockopt(Thread* thread, sint s, sint level, + sint name, caddr_t val, + ptr avalsize) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getsockname(Thread* thread, sint fdes, + ptr asa, + ptr alen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getpeername(Thread* thread, sint fdes, + ptr asa, + ptr alen) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sendfile(Thread* thread, sint fd, sint s, + off_t offset, size_t nbytes, + ptr hdtr, + ptr sbytes, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_sctp_peeloff(Thread* thread, sint sd, + uint32_t name) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_sctp_generic_sendmsg(Thread *thread, sint sd, caddr_t msg, sint mlen, - caddr_t to, __socklen_t tolen, - ptr sinfo, sint flags) { - return ErrorCode::NOSYS; +orbis::sys_sctp_generic_sendmsg(Thread* thread, sint sd, caddr_t msg, sint mlen, + caddr_t to, __socklen_t tolen, + ptr sinfo, sint flags) +{ + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_sctp_generic_sendmsg_iov( - Thread *thread, sint sd, ptr iov, sint iovlen, caddr_t to, - __socklen_t tolen, ptr sinfo, sint flags) { - return ErrorCode::NOSYS; + Thread* thread, sint sd, ptr iov, sint iovlen, caddr_t to, + __socklen_t tolen, ptr sinfo, sint flags) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr iov, - sint iovlen, caddr_t from, __socklen_t fromlen, - ptr sinfo, sint flags) { - return ErrorCode::NOSYS; +orbis::sys_sctp_generic_recvmsg(Thread* thread, sint sd, ptr iov, + sint iovlen, caddr_t from, __socklen_t fromlen, + ptr sinfo, sint flags) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_uipc_mqueue.cpp b/orbis-kernel/src/sys/sys_uipc_mqueue.cpp index 7ab4b965..7dc72460 100644 --- a/orbis-kernel/src/sys/sys_uipc_mqueue.cpp +++ b/orbis-kernel/src/sys/sys_uipc_mqueue.cpp @@ -1,31 +1,37 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_kmq_open(Thread *thread, ptr path, - sint flags, mode_t mode, - ptr attr) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_open(Thread* thread, ptr path, + sint flags, mode_t mode, + ptr attr) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kmq_unlink(Thread *thread, ptr path) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_unlink(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kmq_setattr(Thread *thread, sint mqd, - ptr attr, - ptr oattr) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_setattr(Thread* thread, sint mqd, + ptr attr, + ptr oattr) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kmq_timedreceive(Thread *thread, sint mqd, - ptr msg_ptr, - size_t msg_len, ptr msg_prio, - ptr abstimeout) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_timedreceive(Thread* thread, sint mqd, + ptr msg_ptr, + size_t msg_len, ptr msg_prio, + ptr abstimeout) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kmq_timedsend(Thread *thread, sint mqd, - ptr msg_ptr, size_t msg_len, - ptr msg_prio, - ptr abstimeout) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_timedsend(Thread* thread, sint mqd, + ptr msg_ptr, size_t msg_len, + ptr msg_prio, + ptr abstimeout) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_kmq_notify(Thread *thread, sint mqd, - ptr sigev) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_kmq_notify(Thread* thread, sint mqd, + ptr sigev) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_uipc_sem.cpp b/orbis-kernel/src/sys/sys_uipc_sem.cpp index 1ecc4e94..8ae20701 100644 --- a/orbis-kernel/src/sys/sys_uipc_sem.cpp +++ b/orbis-kernel/src/sys/sys_uipc_sem.cpp @@ -1,37 +1,47 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_ksem_init(Thread *thread, ptr idp, - uint value) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_open(Thread *thread, ptr idp, - ptr name, sint oflag, - mode_t mode, uint value) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_unlink(Thread *thread, ptr name) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_close(Thread *thread, semid_t id) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_post(Thread *thread, semid_t id) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_wait(Thread *thread, semid_t id) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_timedwait(Thread *thread, semid_t id, - ptr abstime) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_trywait(Thread *thread, semid_t id) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_getvalue(Thread *thread, semid_t id, - ptr value) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_ksem_destroy(Thread *thread, semid_t id) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ksem_init(Thread* thread, ptr idp, + uint value) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_open(Thread* thread, ptr idp, + ptr name, sint oflag, + mode_t mode, uint value) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_unlink(Thread* thread, ptr name) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_close(Thread* thread, semid_t id) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_post(Thread* thread, semid_t id) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_wait(Thread* thread, semid_t id) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_timedwait(Thread* thread, semid_t id, + ptr abstime) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_trywait(Thread* thread, semid_t id) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_getvalue(Thread* thread, semid_t id, + ptr value) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_ksem_destroy(Thread* thread, semid_t id) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_uipc_shm.cpp b/orbis-kernel/src/sys/sys_uipc_shm.cpp index 1c44b3e6..dea4e3d2 100644 --- a/orbis-kernel/src/sys/sys_uipc_shm.cpp +++ b/orbis-kernel/src/sys/sys_uipc_shm.cpp @@ -1,44 +1,52 @@ #include "orbis-config.hpp" #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_shm_open(Thread *thread, ptr path, - sint flags, mode_t mode) { - char _name[256]; - if (auto result = ureadString(_name, sizeof(_name), path); - result != ErrorCode{}) { - return result; - } +orbis::SysResult orbis::sys_shm_open(Thread* thread, ptr path, + sint flags, mode_t mode) +{ + char _name[256]; + if (auto result = ureadString(_name, sizeof(_name), path); + result != ErrorCode{}) + { + return result; + } - if (auto shm_open = thread->tproc->ops->shm_open) { - Ref file; - auto result = shm_open(thread, path, flags, mode, &file); - if (result.isError()) { - return result; - } + if (auto shm_open = thread->tproc->ops->shm_open) + { + Ref file; + auto result = shm_open(thread, path, flags, mode, &file); + if (result.isError()) + { + return result; + } - thread->retval[0] = thread->tproc->fileDescriptors.insert(file); - return {}; - } - return ErrorCode::NOSYS; + thread->retval[0] = thread->tproc->fileDescriptors.insert(file); + return {}; + } + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_shm_unlink(Thread *thread, ptr path) { - char _name[256]; - if (auto result = ureadString(_name, sizeof(_name), path); - result != ErrorCode{}) { - return result; - } +orbis::SysResult orbis::sys_shm_unlink(Thread* thread, ptr path) +{ + char _name[256]; + if (auto result = ureadString(_name, sizeof(_name), path); + result != ErrorCode{}) + { + return result; + } - if (auto shm_unlink = thread->tproc->ops->shm_unlink) { - Ref file; - auto result = shm_unlink(thread, path); - if (result.isError()) { - return result; - } + if (auto shm_unlink = thread->tproc->ops->shm_unlink) + { + Ref file; + auto result = shm_unlink(thread, path); + if (result.isError()) + { + return result; + } - thread->retval[0] = thread->tproc->fileDescriptors.insert(file); - return {}; - } + thread->retval[0] = thread->tproc->fileDescriptors.insert(file); + return {}; + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_umtx.cpp b/orbis-kernel/src/sys/sys_umtx.cpp index 0e8d6a93..495e1087 100644 --- a/orbis-kernel/src/sys/sys_umtx.cpp +++ b/orbis-kernel/src/sys/sys_umtx.cpp @@ -4,162 +4,182 @@ #include "umtx.hpp" #include -static orbis::ErrorCode ureadTimespec(orbis::timespec &ts, - orbis::ptr addr) { - orbis::ErrorCode error = uread(ts, addr); - if (error != orbis::ErrorCode{}) - return error; - if (ts.sec < 0 || ts.nsec < 0 || ts.nsec > 1000000000) { - return orbis::ErrorCode::INVAL; - } +static orbis::ErrorCode ureadTimespec(orbis::timespec& ts, + orbis::ptr addr) +{ + orbis::ErrorCode error = uread(ts, addr); + if (error != orbis::ErrorCode{}) + return error; + if (ts.sec < 0 || ts.nsec < 0 || ts.nsec > 1000000000) + { + return orbis::ErrorCode::INVAL; + } - return {}; + return {}; } -orbis::SysResult orbis::sys__umtx_lock(Thread *thread, ptr umtx) { - ORBIS_LOG_TRACE(__FUNCTION__, umtx); - if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) - return ErrorCode::FAULT; - return umtx_lock_umtx(thread, umtx, thread->tid, -1); +orbis::SysResult orbis::sys__umtx_lock(Thread* thread, ptr umtx) +{ + ORBIS_LOG_TRACE(__FUNCTION__, umtx); + if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) + return ErrorCode::FAULT; + return umtx_lock_umtx(thread, umtx, thread->tid, -1); } -orbis::SysResult orbis::sys__umtx_unlock(Thread *thread, ptr umtx) { - ORBIS_LOG_TRACE(__FUNCTION__, umtx); - if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) - return ErrorCode::FAULT; - return umtx_unlock_umtx(thread, umtx, thread->tid); +orbis::SysResult orbis::sys__umtx_unlock(Thread* thread, ptr umtx) +{ + ORBIS_LOG_TRACE(__FUNCTION__, umtx); + if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) + return ErrorCode::FAULT; + return umtx_unlock_umtx(thread, umtx, thread->tid); } -orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr obj, sint op, - ulong val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TRACE(__FUNCTION__, obj, op, val, uaddr1, uaddr2); - if (reinterpret_cast(obj) - 0x10000 > 0xff'fffe'ffff) - return ErrorCode::FAULT; - auto with_timeout = [&](auto op, bool loop = true) -> orbis::ErrorCode { - timespec *ts = nullptr; - timespec timeout{}; - if (uaddr2 != nullptr) { - auto result = ureadTimespec(timeout, (ptr)uaddr2); - if (result != ErrorCode{}) { - return result; - } +orbis::SysResult orbis::sys__umtx_op(Thread* thread, ptr obj, sint op, + ulong val, ptr uaddr1, + ptr uaddr2) +{ + ORBIS_LOG_TRACE(__FUNCTION__, obj, op, val, uaddr1, uaddr2); + if (reinterpret_cast(obj) - 0x10000 > 0xff'fffe'ffff) + return ErrorCode::FAULT; + auto with_timeout = [&](auto op, bool loop = true) -> orbis::ErrorCode { + timespec* ts = nullptr; + timespec timeout{}; + if (uaddr2 != nullptr) + { + auto result = ureadTimespec(timeout, (ptr)uaddr2); + if (result != ErrorCode{}) + { + return result; + } - ts = &timeout; - } + ts = &timeout; + } - if (!ts) { - if (!loop) - return op(-1); - while (true) { - if (auto r = op(-1); r != ErrorCode::TIMEDOUT) - return r; - } - } else { - __uint128_t usec = timeout.sec; - usec *= 1000'000; - usec += (timeout.nsec + 999) / 1000; - if (usec >= UINT64_MAX) - usec = -2; - if (!loop) - return op(usec); - auto start = std::chrono::steady_clock::now(); - std::uint64_t udiff = 0; - while (true) { - if (auto r = op(usec - udiff); r != ErrorCode::TIMEDOUT) - return r; - udiff = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count(); - if (udiff >= usec) - return ErrorCode::TIMEDOUT; - } - } - }; + if (!ts) + { + if (!loop) + return op(-1); + while (true) + { + if (auto r = op(-1); r != ErrorCode::TIMEDOUT) + return r; + } + } + else + { + __uint128_t usec = timeout.sec; + usec *= 1000'000; + usec += (timeout.nsec + 999) / 1000; + if (usec >= UINT64_MAX) + usec = -2; + if (!loop) + return op(usec); + auto start = std::chrono::steady_clock::now(); + std::uint64_t udiff = 0; + while (true) + { + if (auto r = op(usec - udiff); r != ErrorCode::TIMEDOUT) + return r; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (udiff >= usec) + return ErrorCode::TIMEDOUT; + } + } + }; - switch (op) { - case 0: { - return with_timeout([&](std::uint64_t ut) { - return umtx_lock_umtx(thread, (ptr)obj, val, ut); - }); - } - case 1: - return umtx_unlock_umtx(thread, (ptr)obj, val); - case 2: { - return with_timeout( - [&](std::uint64_t ut) { - return umtx_wait(thread, obj, val, ut, false, true); - }, - false); - } - case 3: - return umtx_wake(thread, obj, val); - case 4: - return umtx_trylock_umutex(thread, (ptr)obj); - case 5: { - return with_timeout([&](std::uint64_t ut) { - return umtx_lock_umutex(thread, (ptr)obj, ut); - }); - } - case 6: - return umtx_unlock_umutex(thread, (ptr)obj); - case 7: - return umtx_set_ceiling(thread, (ptr)obj, val, - (ptr)uaddr1); + switch (op) + { + case 0: + { + return with_timeout([&](std::uint64_t ut) { + return umtx_lock_umtx(thread, (ptr)obj, val, ut); + }); + } + case 1: + return umtx_unlock_umtx(thread, (ptr)obj, val); + case 2: + { + return with_timeout( + [&](std::uint64_t ut) { + return umtx_wait(thread, obj, val, ut, false, true); + }, + false); + } + case 3: + return umtx_wake(thread, obj, val); + case 4: + return umtx_trylock_umutex(thread, (ptr)obj); + case 5: + { + return with_timeout([&](std::uint64_t ut) { + return umtx_lock_umutex(thread, (ptr)obj, ut); + }); + } + case 6: + return umtx_unlock_umutex(thread, (ptr)obj); + case 7: + return umtx_set_ceiling(thread, (ptr)obj, val, + (ptr)uaddr1); - case 8: { - return with_timeout( - [&](std::uint64_t ut) { - return umtx_cv_wait(thread, (ptr)obj, (ptr)uaddr1, ut, - val); - }, - false); - } + case 8: + { + return with_timeout( + [&](std::uint64_t ut) { + return umtx_cv_wait(thread, (ptr)obj, (ptr)uaddr1, ut, + val); + }, + false); + } - case 9: - return umtx_cv_signal(thread, (ptr)obj); - case 10: - return umtx_cv_broadcast(thread, (ptr)obj); - case 11: { - return with_timeout( - [&](std::uint64_t ut) { - return umtx_wait(thread, obj, val, ut, true, true); - }, - false); - } - case 12: - return umtx_rw_rdlock(thread, obj, val, uaddr1, uaddr2); - case 13: - return umtx_rw_wrlock(thread, obj, val, uaddr1, uaddr2); - case 14: - return umtx_rw_unlock(thread, obj, val, uaddr1, uaddr2); - case 15: { - return with_timeout( - [&](std::uint64_t ut) { - return umtx_wait(thread, obj, val, ut, true, false); - }, - false); - } - case 16: - return umtx_wake_private(thread, obj, val); - case 17: { - return with_timeout([&](std::uint64_t ut) { - return umtx_wait_umutex(thread, (ptr)obj, ut); - }); - } - case 18: - return umtx_wake_umutex(thread, (ptr)obj); - case 19: - return with_timeout( - [&](std::uint64_t ut) { - return umtx_sem_wait(thread, (ptr)obj, ut); - }, - false); - case 20: - return umtx_sem_wake(thread, (ptr)obj); - case 21: - return umtx_nwake_private(thread, (ptr)obj, val); - case 22: - return umtx_wake2_umutex(thread, obj, val, uaddr1, uaddr2); - } + case 9: + return umtx_cv_signal(thread, (ptr)obj); + case 10: + return umtx_cv_broadcast(thread, (ptr)obj); + case 11: + { + return with_timeout( + [&](std::uint64_t ut) { + return umtx_wait(thread, obj, val, ut, true, true); + }, + false); + } + case 12: + return umtx_rw_rdlock(thread, obj, val, uaddr1, uaddr2); + case 13: + return umtx_rw_wrlock(thread, obj, val, uaddr1, uaddr2); + case 14: + return umtx_rw_unlock(thread, obj, val, uaddr1, uaddr2); + case 15: + { + return with_timeout( + [&](std::uint64_t ut) { + return umtx_wait(thread, obj, val, ut, true, false); + }, + false); + } + case 16: + return umtx_wake_private(thread, obj, val); + case 17: + { + return with_timeout([&](std::uint64_t ut) { + return umtx_wait_umutex(thread, (ptr)obj, ut); + }); + } + case 18: + return umtx_wake_umutex(thread, (ptr)obj); + case 19: + return with_timeout( + [&](std::uint64_t ut) { + return umtx_sem_wait(thread, (ptr)obj, ut); + }, + false); + case 20: + return umtx_sem_wake(thread, (ptr)obj); + case 21: + return umtx_nwake_private(thread, (ptr)obj, val); + case 22: + return umtx_wake2_umutex(thread, obj, val, uaddr1, uaddr2); + } - return ErrorCode::INVAL; + return ErrorCode::INVAL; } diff --git a/orbis-kernel/src/sys/sys_uuid.cpp b/orbis-kernel/src/sys/sys_uuid.cpp index f0a24766..d5ee9022 100644 --- a/orbis-kernel/src/sys/sys_uuid.cpp +++ b/orbis-kernel/src/sys/sys_uuid.cpp @@ -1,6 +1,7 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_uuidgen(Thread *thread, ptr store, - sint count) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_uuidgen(Thread* thread, ptr store, + sint count) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs.cpp b/orbis-kernel/src/sys/sys_vfs.cpp index 4a00bad2..04c88864 100644 --- a/orbis-kernel/src/sys/sys_vfs.cpp +++ b/orbis-kernel/src/sys/sys_vfs.cpp @@ -2,395 +2,482 @@ #include "sys/sysproto.hpp" #include "utils/Logs.hpp" -orbis::SysResult orbis::sys_sync(Thread *thread) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_quotactl(Thread *thread, ptr path, sint cmd, - sint uid, caddr_t arg) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_statfs(Thread *thread, ptr path, - ptr buf) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fstatfs(Thread *thread, sint fd, - ptr buf) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getfsstat(Thread *thread, ptr buf, - slong bufsize, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchdir(Thread *thread, sint fd) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_chdir(Thread *thread, ptr path) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_chroot(Thread *thread, ptr path) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_open(Thread *thread, ptr path, sint flags, - sint mode) { - ORBIS_LOG_NOTICE("sys_open", path, flags, mode); - if (auto open = thread->tproc->ops->open) { - Ref file; - auto result = open(thread, path, flags, mode, &file); - if (result.isError()) { - return result; - } +orbis::SysResult orbis::sys_sync(Thread* thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_quotactl(Thread* thread, ptr path, sint cmd, + sint uid, caddr_t arg) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_statfs(Thread* thread, ptr path, + ptr buf) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fstatfs(Thread* thread, sint fd, + ptr buf) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getfsstat(Thread* thread, ptr buf, + slong bufsize, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchdir(Thread* thread, sint fd) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_chdir(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_chroot(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_open(Thread* thread, ptr path, sint flags, + sint mode) +{ + ORBIS_LOG_NOTICE("sys_open", path, flags, mode); + if (auto open = thread->tproc->ops->open) + { + Ref file; + auto result = open(thread, path, flags, mode, &file); + if (result.isError()) + { + return result; + } - thread->retval[0] = thread->tproc->fileDescriptors.insert(file); - return {}; - } + thread->retval[0] = thread->tproc->fileDescriptors.insert(file); + return {}; + } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_openat(Thread *thread, sint fd, ptr path, - sint flag, mode_t mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mknod(Thread *thread, ptr path, sint mode, - sint dev) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mknodat(Thread *thread, sint fd, ptr path, - mode_t mode, dev_t dev) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mkfifo(Thread *thread, ptr path, sint mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mkfifoat(Thread *thread, sint fd, ptr path, - mode_t mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_link(Thread *thread, ptr path, - ptr link) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_linkat(Thread *thread, sint fd1, ptr path1, - sint fd2, ptr path2, sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_symlink(Thread *thread, ptr path, - ptr link) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_symlinkat(Thread *thread, ptr path1, sint fd, - ptr path2) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_undelete(Thread *thread, ptr path) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_unlink(Thread *thread, ptr path) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_unlinkat(Thread *thread, sint fd, ptr path, - sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lseek(Thread *thread, sint fd, off_t offset, - sint whence) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_openat(Thread* thread, sint fd, ptr path, + sint flag, mode_t mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mknod(Thread* thread, ptr path, sint mode, + sint dev) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mknodat(Thread* thread, sint fd, ptr path, + mode_t mode, dev_t dev) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mkfifo(Thread* thread, ptr path, sint mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mkfifoat(Thread* thread, sint fd, ptr path, + mode_t mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_link(Thread* thread, ptr path, + ptr link) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_linkat(Thread* thread, sint fd1, ptr path1, + sint fd2, ptr path2, sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_symlink(Thread* thread, ptr path, + ptr link) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_symlinkat(Thread* thread, ptr path1, sint fd, + ptr path2) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_undelete(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_unlink(Thread* thread, ptr path) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_unlinkat(Thread* thread, sint fd, ptr path, + sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lseek(Thread* thread, sint fd, off_t offset, + sint whence) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } - std::lock_guard lock(file->mtx); + std::lock_guard lock(file->mtx); - // TODO: use ioctl? - switch (whence) { - case SEEK_SET: - file->nextOff = offset; - break; + // TODO: use ioctl? + switch (whence) + { + case SEEK_SET: + file->nextOff = offset; + break; - case SEEK_CUR: - file->nextOff += offset; - break; + case SEEK_CUR: + file->nextOff += offset; + break; - case SEEK_END: { - if (file->ops->stat == nullptr) { - ORBIS_LOG_ERROR("seek with end whence: unimplemented stat"); - return ErrorCode::NOTSUP; - } + case SEEK_END: + { + if (file->ops->stat == nullptr) + { + ORBIS_LOG_ERROR("seek with end whence: unimplemented stat"); + return ErrorCode::NOTSUP; + } - orbis::Stat stat; - auto result = file->ops->stat(file.get(), &stat, thread); - if (result != ErrorCode{}) { - return result; - } + orbis::Stat stat; + auto result = file->ops->stat(file.get(), &stat, thread); + if (result != ErrorCode{}) + { + return result; + } - file->nextOff = stat.size + offset; - break; - } + file->nextOff = stat.size + offset; + break; + } - default: - ORBIS_LOG_ERROR("sys_lseek: unimplemented whence", whence); - return ErrorCode::NOSYS; - } + default: + ORBIS_LOG_ERROR("sys_lseek: unimplemented whence", whence); + return ErrorCode::NOSYS; + } - thread->retval[0] = file->nextOff; - return {}; -} -orbis::SysResult orbis::sys_freebsd6_lseek(Thread *thread, sint fd, sint, - off_t offset, sint whence) { - return sys_lseek(thread, fd, offset, whence); -} -orbis::SysResult orbis::sys_access(Thread *thread, ptr path, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_faccessat(Thread *thread, sint fd, ptr path, - sint mode, sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_eaccess(Thread *thread, ptr path, - sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_stat(Thread *thread, ptr path, ptr ub) { - Ref file; - auto result = thread->tproc->ops->open(thread, path, 0, 0, &file); - if (result.isError()) { - return result; - } + thread->retval[0] = file->nextOff; + return {}; +} +orbis::SysResult orbis::sys_freebsd6_lseek(Thread* thread, sint fd, sint, + off_t offset, sint whence) +{ + return sys_lseek(thread, fd, offset, whence); +} +orbis::SysResult orbis::sys_access(Thread* thread, ptr path, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_faccessat(Thread* thread, sint fd, ptr path, + sint mode, sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_eaccess(Thread* thread, ptr path, + sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_stat(Thread* thread, ptr path, ptr ub) +{ + Ref file; + auto result = thread->tproc->ops->open(thread, path, 0, 0, &file); + if (result.isError()) + { + return result; + } - auto stat = file->ops->stat; - if (stat == nullptr) { - return ErrorCode::NOTSUP; - } + auto stat = file->ops->stat; + if (stat == nullptr) + { + return ErrorCode::NOTSUP; + } - std::lock_guard lock(file->mtx); - Stat _ub; - result = uread(_ub, ub); - if (result.isError()) { - return result; - } + std::lock_guard lock(file->mtx); + Stat _ub; + result = uread(_ub, ub); + if (result.isError()) + { + return result; + } - result = stat(file.get(), &_ub, thread); - if (result.isError()) { - return result; - } + result = stat(file.get(), &_ub, thread); + if (result.isError()) + { + return result; + } - return uwrite(ub, _ub); -} -orbis::SysResult orbis::sys_fstatat(Thread *thread, sint fd, ptr path, - ptr buf, sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lstat(Thread *thread, ptr path, - ptr ub) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_nstat(Thread *thread, ptr path, - ptr ub) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_nlstat(Thread *thread, ptr path, - ptr ub) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_pathconf(Thread *thread, ptr path, - sint name) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lpathconf(Thread *thread, ptr path, - sint name) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_readlink(Thread *thread, ptr path, - ptr buf, size_t count) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_readlinkat(Thread *thread, sint fd, ptr path, - ptr buf, size_t bufsize) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_chflags(Thread *thread, ptr path, - sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lchflags(Thread *thread, ptr path, - sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchflags(Thread *thread, sint fd, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_chmod(Thread *thread, ptr path, sint mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchmodat(Thread *thread, sint fd, ptr path, - mode_t mode, sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lchmod(Thread *thread, ptr path, - mode_t mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchmod(Thread *thread, sint fd, sint mode) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_chown(Thread *thread, ptr path, sint uid, - sint gid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchownat(Thread *thread, sint fd, ptr path, - uid_t uid, gid_t gid, sint flag) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lchown(Thread *thread, ptr path, sint uid, - sint gid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fchown(Thread *thread, sint fd, sint uid, - sint gid) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_utimes(Thread *thread, ptr path, - ptr tptr) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_futimesat(Thread *thread, sint fd, ptr path, - ptr times) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lutimes(Thread *thread, ptr path, - ptr tptr) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_futimes(Thread *thread, sint fd, - ptr tptr) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_truncate(Thread *thread, ptr path, - off_t length) { - Ref file; - auto result = thread->tproc->ops->open(thread, path, 0, 0, &file); - if (result.isError()) { - return result; - } + return uwrite(ub, _ub); +} +orbis::SysResult orbis::sys_fstatat(Thread* thread, sint fd, ptr path, + ptr buf, sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lstat(Thread* thread, ptr path, + ptr ub) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_nstat(Thread* thread, ptr path, + ptr ub) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_nlstat(Thread* thread, ptr path, + ptr ub) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_pathconf(Thread* thread, ptr path, + sint name) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lpathconf(Thread* thread, ptr path, + sint name) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_readlink(Thread* thread, ptr path, + ptr buf, size_t count) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_readlinkat(Thread* thread, sint fd, ptr path, + ptr buf, size_t bufsize) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_chflags(Thread* thread, ptr path, + sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lchflags(Thread* thread, ptr path, + sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchflags(Thread* thread, sint fd, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_chmod(Thread* thread, ptr path, sint mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchmodat(Thread* thread, sint fd, ptr path, + mode_t mode, sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lchmod(Thread* thread, ptr path, + mode_t mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchmod(Thread* thread, sint fd, sint mode) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_chown(Thread* thread, ptr path, sint uid, + sint gid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchownat(Thread* thread, sint fd, ptr path, + uid_t uid, gid_t gid, sint flag) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lchown(Thread* thread, ptr path, sint uid, + sint gid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fchown(Thread* thread, sint fd, sint uid, + sint gid) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_utimes(Thread* thread, ptr path, + ptr tptr) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_futimesat(Thread* thread, sint fd, ptr path, + ptr times) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lutimes(Thread* thread, ptr path, + ptr tptr) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_futimes(Thread* thread, sint fd, + ptr tptr) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_truncate(Thread* thread, ptr path, + off_t length) +{ + Ref file; + auto result = thread->tproc->ops->open(thread, path, 0, 0, &file); + if (result.isError()) + { + return result; + } - auto truncate = file->ops->truncate; - if (truncate == nullptr) { - return ErrorCode::NOTSUP; - } + auto truncate = file->ops->truncate; + if (truncate == nullptr) + { + return ErrorCode::NOTSUP; + } - std::lock_guard lock(file->mtx); - return truncate(file.get(), length, thread); -} -orbis::SysResult orbis::sys_freebsd6_truncate(Thread *thread, ptr path, - sint, off_t length) { - return sys_truncate(thread, path, length); -} -orbis::SysResult orbis::sys_fsync(Thread *thread, sint fd) { return {}; } -orbis::SysResult orbis::sys_rename(Thread *thread, ptr from, - ptr to) { - if (auto rename = thread->tproc->ops->rename) { - return rename(thread, from, to); - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_renameat(Thread *thread, sint oldfd, ptr old, - sint newfd, ptr new_) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mkdir(Thread *thread, ptr path, sint mode) { - if (auto mkdir = thread->tproc->ops->mkdir) { - return mkdir(thread, path, mode); - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_mkdirat(Thread *thread, sint fd, ptr path, - mode_t mode) { - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } + std::lock_guard lock(file->mtx); + return truncate(file.get(), length, thread); +} +orbis::SysResult orbis::sys_freebsd6_truncate(Thread* thread, ptr path, + sint, off_t length) +{ + return sys_truncate(thread, path, length); +} +orbis::SysResult orbis::sys_fsync(Thread* thread, sint fd) { return {}; } +orbis::SysResult orbis::sys_rename(Thread* thread, ptr from, + ptr to) +{ + if (auto rename = thread->tproc->ops->rename) + { + return rename(thread, from, to); + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_renameat(Thread* thread, sint oldfd, ptr old, + sint newfd, ptr new_) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mkdir(Thread* thread, ptr path, sint mode) +{ + if (auto mkdir = thread->tproc->ops->mkdir) + { + return mkdir(thread, path, mode); + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_mkdirat(Thread* thread, sint fd, ptr path, + mode_t mode) +{ + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } - auto mkdir = file->ops->mkdir; + auto mkdir = file->ops->mkdir; - if (mkdir == nullptr) { - return ErrorCode::NOTSUP; - } - std::lock_guard lock(file->mtx); + if (mkdir == nullptr) + { + return ErrorCode::NOTSUP; + } + std::lock_guard lock(file->mtx); - return mkdir(file.get(), path, mode); + return mkdir(file.get(), path, mode); } -orbis::SysResult orbis::sys_rmdir(Thread *thread, ptr path) { - if (auto rmdir = thread->tproc->ops->rmdir) { - return rmdir(thread, path); - } - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd, - ptr buf, uint count, - ptr basep) { - ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count, basep); - Ref file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } +orbis::SysResult orbis::sys_rmdir(Thread* thread, ptr path) +{ + if (auto rmdir = thread->tproc->ops->rmdir) + { + return rmdir(thread, path); + } + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getdirentries(Thread* thread, sint fd, + ptr buf, uint count, + ptr basep) +{ + ORBIS_LOG_WARNING(__FUNCTION__, fd, (void*)buf, count, basep); + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } - std::lock_guard lock(file->mtx); - const orbis::Dirent *entries = file->dirEntries.data(); - auto pos = file->nextOff / sizeof(orbis::Dirent); // TODO - auto rmax = count / sizeof(orbis::Dirent); - auto next = std::min(file->dirEntries.size(), pos + rmax); - file->nextOff = next * sizeof(orbis::Dirent); - SysResult result{}; - result = uwrite((orbis::Dirent *)buf, entries + pos, next - pos); - if (result.isError()) - return result; + std::lock_guard lock(file->mtx); + const orbis::Dirent* entries = file->dirEntries.data(); + auto pos = file->nextOff / sizeof(orbis::Dirent); // TODO + auto rmax = count / sizeof(orbis::Dirent); + auto next = std::min(file->dirEntries.size(), pos + rmax); + file->nextOff = next * sizeof(orbis::Dirent); + SysResult result{}; + result = uwrite((orbis::Dirent*)buf, entries + pos, next - pos); + if (result.isError()) + return result; - if (basep) { - result = uwrite(basep, slong(file->nextOff)); - if (result.isError()) - return result; - } + if (basep) + { + result = uwrite(basep, slong(file->nextOff)); + if (result.isError()) + return result; + } - thread->retval[0] = (next - pos) * sizeof(orbis::Dirent); - return {}; -} -orbis::SysResult orbis::sys_getdents(Thread *thread, sint fd, ptr buf, - size_t count) { - ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count); - return orbis::sys_getdirentries(thread, fd, buf, count, nullptr); -} -orbis::SysResult orbis::sys_umask(Thread *thread, sint newmask) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_revoke(Thread *thread, ptr path) { - ORBIS_LOG_WARNING(__FUNCTION__); - return {}; -} -orbis::SysResult orbis::sys_lgetfh(Thread *thread, ptr fname, - ptr fhp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_getfh(Thread *thread, ptr fname, - ptr fhp) { - return ErrorCode::NOSYS; + thread->retval[0] = (next - pos) * sizeof(orbis::Dirent); + return {}; +} +orbis::SysResult orbis::sys_getdents(Thread* thread, sint fd, ptr buf, + size_t count) +{ + ORBIS_LOG_WARNING(__FUNCTION__, fd, (void*)buf, count); + return orbis::sys_getdirentries(thread, fd, buf, count, nullptr); +} +orbis::SysResult orbis::sys_umask(Thread* thread, sint newmask) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_revoke(Thread* thread, ptr path) +{ + ORBIS_LOG_WARNING(__FUNCTION__); + return {}; +} +orbis::SysResult orbis::sys_lgetfh(Thread* thread, ptr fname, + ptr fhp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_getfh(Thread* thread, ptr fname, + ptr fhp) +{ + return ErrorCode::NOSYS; } orbis::SysResult -orbis::sys_fhopen(Thread *thread, ptr u_fhp, sint flags) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fhstat(Thread *thread, - ptr u_fhp, - ptr sb) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_fhstatfs(Thread *thread, - ptr u_fhp, - ptr buf) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_posix_fallocate(Thread *thread, sint fd, - off_t offset, off_t len) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_posix_fadvise(Thread *thread, sint fd, off_t offset, - off_t len, sint advice) { - return ErrorCode::NOSYS; +orbis::sys_fhopen(Thread* thread, ptr u_fhp, sint flags) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fhstat(Thread* thread, + ptr u_fhp, + ptr sb) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_fhstatfs(Thread* thread, + ptr u_fhp, + ptr buf) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_posix_fallocate(Thread* thread, sint fd, + off_t offset, off_t len) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_posix_fadvise(Thread* thread, sint fd, off_t offset, + off_t len, sint advice) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs_acl.cpp b/orbis-kernel/src/sys/sys_vfs_acl.cpp index 9f61dbe3..ac1cc549 100644 --- a/orbis-kernel/src/sys/sys_vfs_acl.cpp +++ b/orbis-kernel/src/sys/sys_vfs_acl.cpp @@ -1,61 +1,73 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys___acl_get_file(Thread *thread, ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_get_link(Thread *thread, ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_set_file(Thread *thread, ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_set_link(Thread *thread, ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_get_fd(Thread *thread, sint filedes, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_set_fd(Thread *thread, sint filedes, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_delete_link(Thread *thread, - ptr path, - acl_type_t type) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_delete_file(Thread *thread, ptr path, - acl_type_t type) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_delete_fd(Thread *thread, sint filedes, - acl_type_t type) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_aclcheck_file(Thread *thread, ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_aclcheck_link(Thread *thread, - ptr path, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys___acl_aclcheck_fd(Thread *thread, sint filedes, - acl_type_t type, - ptr aclp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys___acl_get_file(Thread* thread, ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_get_link(Thread* thread, ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_set_file(Thread* thread, ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_set_link(Thread* thread, ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_get_fd(Thread* thread, sint filedes, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_set_fd(Thread* thread, sint filedes, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_delete_link(Thread* thread, + ptr path, + acl_type_t type) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_delete_file(Thread* thread, ptr path, + acl_type_t type) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_delete_fd(Thread* thread, sint filedes, + acl_type_t type) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_aclcheck_file(Thread* thread, ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_aclcheck_link(Thread* thread, + ptr path, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys___acl_aclcheck_fd(Thread* thread, sint filedes, + acl_type_t type, + ptr aclp) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs_aio.cpp b/orbis-kernel/src/sys/sys_vfs_aio.cpp index 74c40292..1e55206e 100644 --- a/orbis-kernel/src/sys/sys_vfs_aio.cpp +++ b/orbis-kernel/src/sys/sys_vfs_aio.cpp @@ -1,53 +1,65 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_aio_return(Thread *thread, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_suspend(Thread *thread, - ptr aiocbp, sint nent, - ptr timeout) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_cancel(Thread *thread, sint fd, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_error(Thread *thread, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_oaio_read(Thread *thread, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_read(Thread *thread, ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_oaio_write(Thread *thread, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_write(Thread *thread, - ptr aiocbp) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_olio_listio(Thread *thread, sint mode, - ptr> acb_list, - sint nent, ptr sig) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_lio_listio(Thread *thread, sint mode, - ptr> aiocbp, - sint nent, ptr sig) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_waitcomplete(Thread *thread, - ptr> aiocbp, - ptr timeout) { - return ErrorCode::NOSYS; -} -orbis::SysResult orbis::sys_aio_fsync(Thread *thread, sint op, - ptr aiocbp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_aio_return(Thread* thread, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_suspend(Thread* thread, + ptr aiocbp, sint nent, + ptr timeout) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_cancel(Thread* thread, sint fd, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_error(Thread* thread, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_oaio_read(Thread* thread, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_read(Thread* thread, ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_oaio_write(Thread* thread, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_write(Thread* thread, + ptr aiocbp) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_olio_listio(Thread* thread, sint mode, + ptr> acb_list, + sint nent, ptr sig) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_lio_listio(Thread* thread, sint mode, + ptr> aiocbp, + sint nent, ptr sig) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_waitcomplete(Thread* thread, + ptr> aiocbp, + ptr timeout) +{ + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sys_aio_fsync(Thread* thread, sint op, + ptr aiocbp) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs_cache.cpp b/orbis-kernel/src/sys/sys_vfs_cache.cpp index b4aa4a71..dea19e4c 100644 --- a/orbis-kernel/src/sys/sys_vfs_cache.cpp +++ b/orbis-kernel/src/sys/sys_vfs_cache.cpp @@ -1,6 +1,7 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys___getcwd(Thread *thread, ptr buf, - uint buflen) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys___getcwd(Thread* thread, ptr buf, + uint buflen) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs_extattr.cpp b/orbis-kernel/src/sys/sys_vfs_extattr.cpp index 460e28a6..6d6b689c 100644 --- a/orbis-kernel/src/sys/sys_vfs_extattr.cpp +++ b/orbis-kernel/src/sys/sys_vfs_extattr.cpp @@ -1,79 +1,92 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_extattrctl(Thread *thread, ptr path, char cmd, - ptr filename, - sint attrnamespace, - ptr attrname) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattrctl(Thread* thread, ptr path, char cmd, + ptr filename, + sint attrnamespace, + ptr attrname) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_set_fd(Thread *thread, sint fd, - sint attrnamespace, - ptr attrname, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_set_fd(Thread* thread, sint fd, + sint attrnamespace, + ptr attrname, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_set_file(Thread *thread, ptr path, - sint attrnamespace, - ptr filename, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_set_file(Thread* thread, ptr path, + sint attrnamespace, + ptr filename, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_set_link(Thread *thread, - ptr path, - sint attrnamespace, - ptr attrname, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_set_link(Thread* thread, + ptr path, + sint attrnamespace, + ptr attrname, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_get_fd(Thread *thread, sint fd, - sint attrnamespace, - ptr attrname, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_get_fd(Thread* thread, sint fd, + sint attrnamespace, + ptr attrname, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_get_file(Thread *thread, ptr path, - sint attrnamespace, - ptr filename, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_get_file(Thread* thread, ptr path, + sint attrnamespace, + ptr filename, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_get_link(Thread *thread, - ptr path, - sint attrnamespace, - ptr attrname, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_get_link(Thread* thread, + ptr path, + sint attrnamespace, + ptr attrname, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_delete_fd(Thread *thread, sint fd, - sint attrnamespace, - ptr attrname) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_delete_fd(Thread* thread, sint fd, + sint attrnamespace, + ptr attrname) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_delete_file(Thread *thread, ptr path, - sint attrnamespace, - ptr attrname) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_delete_file(Thread* thread, ptr path, + sint attrnamespace, + ptr attrname) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_delete_link(Thread *thread, - ptr path, - sint attrnamespace, - ptr attrname) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_delete_link(Thread* thread, + ptr path, + sint attrnamespace, + ptr attrname) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_list_fd(Thread *thread, sint fd, - sint attrnamespace, ptr data, - size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_list_fd(Thread* thread, sint fd, + sint attrnamespace, ptr data, + size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_list_file(Thread *thread, - ptr path, - sint attrnamespace, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_list_file(Thread* thread, + ptr path, + sint attrnamespace, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_extattr_list_link(Thread *thread, - ptr path, - sint attrnamespace, - ptr data, size_t nbytes) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_extattr_list_link(Thread* thread, + ptr path, + sint attrnamespace, + ptr data, size_t nbytes) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vfs_mount.cpp b/orbis-kernel/src/sys/sys_vfs_mount.cpp index 3f80cc10..0e4b731c 100644 --- a/orbis-kernel/src/sys/sys_vfs_mount.cpp +++ b/orbis-kernel/src/sys/sys_vfs_mount.cpp @@ -1,14 +1,17 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_mount(Thread *thread, ptr type, - ptr path, sint flags, caddr_t data) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_mount(Thread* thread, ptr type, + ptr path, sint flags, caddr_t data) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_unmount(Thread *thread, ptr path, - sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_unmount(Thread* thread, ptr path, + sint flags) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_nmount(Thread *thread, ptr iovp, uint iovcnt, - sint flags) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_nmount(Thread* thread, ptr iovp, uint iovcnt, + sint flags) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vm_mmap.cpp b/orbis-kernel/src/sys/sys_vm_mmap.cpp index fa074841..468342a5 100644 --- a/orbis-kernel/src/sys/sys_vm_mmap.cpp +++ b/orbis-kernel/src/sys/sys_vm_mmap.cpp @@ -1,105 +1,131 @@ #include "error.hpp" #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_sbrk(Thread *, sint) { - return ErrorCode::OPNOTSUPP; +orbis::SysResult orbis::sys_sbrk(Thread*, sint) +{ + return ErrorCode::OPNOTSUPP; } -orbis::SysResult orbis::sys_sstk(Thread *, sint) { - return ErrorCode::OPNOTSUPP; +orbis::SysResult orbis::sys_sstk(Thread*, sint) +{ + return ErrorCode::OPNOTSUPP; } -orbis::SysResult orbis::sys_mmap(Thread *thread, caddr_t addr, size_t len, - sint prot, sint flags, sint fd, off_t pos) { - if (auto impl = thread->tproc->ops->mmap) { - // hack for audio control shared memory - if (len == 3880) { - return impl(thread, addr, 0x10000, prot, flags, fd, pos); - } - return impl(thread, addr, len, prot, flags, fd, pos); - } +orbis::SysResult orbis::sys_mmap(Thread* thread, caddr_t addr, size_t len, + sint prot, sint flags, sint fd, off_t pos) +{ + if (auto impl = thread->tproc->ops->mmap) + { + // hack for audio control shared memory + if (len == 3880) + { + return impl(thread, addr, 0x10000, prot, flags, fd, pos); + } + return impl(thread, addr, len, prot, flags, fd, pos); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_freebsd6_mmap(Thread *thread, caddr_t addr, - size_t len, sint prot, sint flags, - sint fd, sint, off_t pos) { - return sys_mmap(thread, addr, len, prot, flags, fd, pos); +orbis::SysResult orbis::sys_freebsd6_mmap(Thread* thread, caddr_t addr, + size_t len, sint prot, sint flags, + sint fd, sint, off_t pos) +{ + return sys_mmap(thread, addr, len, prot, flags, fd, pos); } -orbis::SysResult orbis::sys_msync(Thread *thread, ptr addr, size_t len, - sint flags) { - if (auto impl = thread->tproc->ops->msync) { - return impl(thread, addr, len, flags); - } +orbis::SysResult orbis::sys_msync(Thread* thread, ptr addr, size_t len, + sint flags) +{ + if (auto impl = thread->tproc->ops->msync) + { + return impl(thread, addr, len, flags); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_munmap(Thread *thread, ptr addr, size_t len) { - if (auto impl = thread->tproc->ops->munmap) { - return impl(thread, addr, len); - } +orbis::SysResult orbis::sys_munmap(Thread* thread, ptr addr, size_t len) +{ + if (auto impl = thread->tproc->ops->munmap) + { + return impl(thread, addr, len); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_mprotect(Thread *thread, ptr addr, - size_t len, sint prot) { - if (auto impl = thread->tproc->ops->mprotect) { - return impl(thread, addr, len, prot); - } +orbis::SysResult orbis::sys_mprotect(Thread* thread, ptr addr, + size_t len, sint prot) +{ + if (auto impl = thread->tproc->ops->mprotect) + { + return impl(thread, addr, len, prot); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_minherit(Thread *thread, ptr addr, size_t len, - sint inherit) { - if (auto impl = thread->tproc->ops->minherit) { - return impl(thread, addr, len, inherit); - } +orbis::SysResult orbis::sys_minherit(Thread* thread, ptr addr, size_t len, + sint inherit) +{ + if (auto impl = thread->tproc->ops->minherit) + { + return impl(thread, addr, len, inherit); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_madvise(Thread *thread, ptr addr, size_t len, - sint behav) { - if (auto impl = thread->tproc->ops->madvise) { - return impl(thread, addr, len, behav); - } +orbis::SysResult orbis::sys_madvise(Thread* thread, ptr addr, size_t len, + sint behav) +{ + if (auto impl = thread->tproc->ops->madvise) + { + return impl(thread, addr, len, behav); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_mincore(Thread *thread, ptr addr, - size_t len, ptr vec) { - if (auto impl = thread->tproc->ops->mincore) { - return impl(thread, addr, len, vec); - } +orbis::SysResult orbis::sys_mincore(Thread* thread, ptr addr, + size_t len, ptr vec) +{ + if (auto impl = thread->tproc->ops->mincore) + { + return impl(thread, addr, len, vec); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_mlock(Thread *thread, ptr addr, - size_t len) { - if (auto impl = thread->tproc->ops->mlock) { - return impl(thread, addr, len); - } +orbis::SysResult orbis::sys_mlock(Thread* thread, ptr addr, + size_t len) +{ + if (auto impl = thread->tproc->ops->mlock) + { + return impl(thread, addr, len); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_mlockall(Thread *thread, sint how) { - if (auto impl = thread->tproc->ops->mlockall) { - return impl(thread, how); - } +orbis::SysResult orbis::sys_mlockall(Thread* thread, sint how) +{ + if (auto impl = thread->tproc->ops->mlockall) + { + return impl(thread, how); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_munlockall(Thread *thread) { - if (auto impl = thread->tproc->ops->munlockall) { - return impl(thread); - } +orbis::SysResult orbis::sys_munlockall(Thread* thread) +{ + if (auto impl = thread->tproc->ops->munlockall) + { + return impl(thread); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_munlock(Thread *thread, ptr addr, - size_t len) { - if (auto impl = thread->tproc->ops->munlock) { - return impl(thread, addr, len); - } +orbis::SysResult orbis::sys_munlock(Thread* thread, ptr addr, + size_t len) +{ + if (auto impl = thread->tproc->ops->munlock) + { + return impl(thread, addr, len); + } - return ErrorCode::NOSYS; + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_vm_unix.cpp b/orbis-kernel/src/sys/sys_vm_unix.cpp index 88a3a599..1f128f23 100644 --- a/orbis-kernel/src/sys/sys_vm_unix.cpp +++ b/orbis-kernel/src/sys/sys_vm_unix.cpp @@ -1,8 +1,10 @@ #include "sys/sysproto.hpp" -orbis::SysResult orbis::sys_obreak(Thread *thread, ptr nsize) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_obreak(Thread* thread, ptr nsize) +{ + return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_ovadvise(Thread *thread, sint anom) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_ovadvise(Thread* thread, sint anom) +{ + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sysvec.cpp b/orbis-kernel/src/sysvec.cpp index 5bc1a364..b601b406 100644 --- a/orbis-kernel/src/sysvec.cpp +++ b/orbis-kernel/src/sysvec.cpp @@ -4,2495 +4,2522 @@ #include #include -enum { PSL_C = 0x1 }; +enum +{ + PSL_C = 0x1 +}; -void orbis::syscall_entry(Thread *thread) { - uint64_t regstbl[] = { - readRegister(thread->context, RegisterId::rdi), - readRegister(thread->context, RegisterId::rsi), - readRegister(thread->context, RegisterId::rdx), - readRegister(thread->context, RegisterId::r10), - readRegister(thread->context, RegisterId::r8), - readRegister(thread->context, RegisterId::r9), - }; +void orbis::syscall_entry(Thread* thread) +{ + uint64_t regstbl[] = { + readRegister(thread->context, RegisterId::rdi), + readRegister(thread->context, RegisterId::rsi), + readRegister(thread->context, RegisterId::rdx), + readRegister(thread->context, RegisterId::r10), + readRegister(thread->context, RegisterId::r8), + readRegister(thread->context, RegisterId::r9), + }; - uint64_t *regsptr = regstbl; - sint regcnt = 6; + uint64_t* regsptr = regstbl; + sint regcnt = 6; - int syscall_num = readRegister(thread->context, RegisterId::rax); - if (syscall_num == kSYS_syscall || syscall_num == kSYS___syscall) { - syscall_num = *regsptr++; - --regcnt; - } + int syscall_num = readRegister(thread->context, RegisterId::rax); + if (syscall_num == kSYS_syscall || syscall_num == kSYS___syscall) + { + syscall_num = *regsptr++; + --regcnt; + } - thread->retval[0] = 0; - thread->retval[1] = readRegister(thread->context, RegisterId::rdx); + thread->retval[0] = 0; + thread->retval[1] = readRegister(thread->context, RegisterId::rdx); - int error = 0; - auto p = thread->tproc; + int error = 0; + auto p = thread->tproc; - if (syscall_num >= p->sysent->size) { - error = int(ErrorCode::NOSYS); - } else { - auto sysent = p->sysent->table[syscall_num]; - uint64_t args[8]; - std::memcpy(args, regsptr, - std::min(regcnt, sysent.narg) * sizeof(uint64_t)); - if (sysent.narg > regcnt) { - if (sysent.narg > std::ssize(args)) { - std::abort(); - } + if (syscall_num >= p->sysent->size) + { + error = int(ErrorCode::NOSYS); + } + else + { + auto sysent = p->sysent->table[syscall_num]; + uint64_t args[8]; + std::memcpy(args, regsptr, + std::min(regcnt, sysent.narg) * sizeof(uint64_t)); + if (sysent.narg > regcnt) + { + if (sysent.narg > std::ssize(args)) + { + std::abort(); + } - error = int( - ureadRaw(args + regcnt, - ptr(readRegister(thread->context, RegisterId::rsp) + - sizeof(uint64_t)), - (sysent.narg - regcnt) * sizeof(uint64_t))); - } + error = int( + ureadRaw(args + regcnt, + ptr(readRegister(thread->context, RegisterId::rsp) + + sizeof(uint64_t)), + (sysent.narg - regcnt) * sizeof(uint64_t))); + } - if (error == 0) { - if (thread->tproc->onSysEnter != nullptr) { - thread->tproc->onSysEnter(thread, syscall_num, args, sysent.narg); - } + if (error == 0) + { + if (thread->tproc->onSysEnter != nullptr) + { + thread->tproc->onSysEnter(thread, syscall_num, args, sysent.narg); + } - auto result = sysent.call(thread, args); + auto result = sysent.call(thread, args); - if (thread->tproc->onSysExit != nullptr) { - thread->tproc->onSysExit(thread, syscall_num, args, sysent.narg, - result); - } + if (thread->tproc->onSysExit != nullptr) + { + thread->tproc->onSysExit(thread, syscall_num, args, sysent.narg, + result); + } - error = result.value(); - } - } + error = result.value(); + } + } - auto rflags = readRegister(thread->context, RegisterId::rflags); + auto rflags = readRegister(thread->context, RegisterId::rflags); - if (error == 0) { - writeRegister(thread->context, RegisterId::rax, thread->retval[0]); - writeRegister(thread->context, RegisterId::rdx, thread->retval[1]); - writeRegister(thread->context, RegisterId::rflags, rflags & ~PSL_C); - } else { - writeRegister(thread->context, RegisterId::rax, error); - writeRegister(thread->context, RegisterId::rflags, rflags | PSL_C); - } + if (error == 0) + { + writeRegister(thread->context, RegisterId::rax, thread->retval[0]); + writeRegister(thread->context, RegisterId::rdx, thread->retval[1]); + writeRegister(thread->context, RegisterId::rflags, rflags & ~PSL_C); + } + else + { + writeRegister(thread->context, RegisterId::rax, error); + writeRegister(thread->context, RegisterId::rflags, rflags | PSL_C); + } } -namespace orbis { -namespace detail { -template struct WrapImpl; +namespace orbis +{ + namespace detail + { + template + struct WrapImpl; -template - requires(sizeof...(Args) < 8) -struct WrapImpl { - constexpr sysent operator()() { - sysent result; - result.narg = sizeof...(Args); - result.call = &WrapImpl::call; + template + requires(sizeof...(Args) < 8) struct WrapImpl + { + constexpr sysent operator()() + { + sysent result; + result.narg = sizeof...(Args); + result.call = &WrapImpl::call; - return result; - } + return result; + } -private: - static SysResult call(Thread *thread, uint64_t *args) { - return callImpl(thread, args, std::index_sequence_for{}); - } + private: + static SysResult call(Thread* thread, uint64_t* args) + { + return callImpl(thread, args, std::index_sequence_for{}); + } - template - static SysResult callImpl(Thread *thread, uint64_t *args, - std::index_sequence) { - return Fn(thread, Args(args[I])...); - } -}; -} // namespace detail + template + static SysResult callImpl(Thread* thread, uint64_t* args, + std::index_sequence) + { + return Fn(thread, Args(args[I])...); + } + }; + } // namespace detail -template constexpr auto wrap() -> decltype(detail::WrapImpl()()) { - return detail::WrapImpl()(); -} + template + constexpr auto wrap() -> decltype(detail::WrapImpl()()) + { + return detail::WrapImpl()(); + } -template -constexpr auto sysImplPointer() -> SysResult (*)(Thread *, uint64_t *) { - return wrap().call; -} + template + constexpr auto sysImplPointer() -> SysResult (*)(Thread*, uint64_t*) + { + return wrap().call; + } -static constexpr std::pair - gImplToName[] = { - {sysImplPointer(), "nosys"}, - {sysImplPointer(), "sys_exit"}, - {sysImplPointer(), "sys_fork"}, - {sysImplPointer(), "sys_read"}, - {sysImplPointer(), "sys_write"}, - {sysImplPointer(), "sys_open"}, - {sysImplPointer(), "sys_close"}, - {sysImplPointer(), "sys_wait4"}, - {sysImplPointer(), "sys_link"}, - {sysImplPointer(), "sys_unlink"}, - {sysImplPointer(), "sys_chdir"}, - {sysImplPointer(), "sys_fchdir"}, - {sysImplPointer(), "sys_mknod"}, - {sysImplPointer(), "sys_chmod"}, - {sysImplPointer(), "sys_chown"}, - {sysImplPointer(), "sys_obreak"}, - {sysImplPointer(), "sys_getpid"}, - {sysImplPointer(), "sys_mount"}, - {sysImplPointer(), "sys_unmount"}, - {sysImplPointer(), "sys_setuid"}, - {sysImplPointer(), "sys_getuid"}, - {sysImplPointer(), "sys_geteuid"}, - {sysImplPointer(), "sys_ptrace"}, - {sysImplPointer(), "sys_recvmsg"}, - {sysImplPointer(), "sys_sendmsg"}, - {sysImplPointer(), "sys_recvfrom"}, - {sysImplPointer(), "sys_accept"}, - {sysImplPointer(), "sys_getpeername"}, - {sysImplPointer(), "sys_getsockname"}, - {sysImplPointer(), "sys_access"}, - {sysImplPointer(), "sys_chflags"}, - {sysImplPointer(), "sys_fchflags"}, - {sysImplPointer(), "sys_sync"}, - {sysImplPointer(), "sys_kill"}, - {sysImplPointer(), "sys_getppid"}, - {sysImplPointer(), "sys_dup"}, - {sysImplPointer(), "sys_pipe"}, - {sysImplPointer(), "sys_getegid"}, - {sysImplPointer(), "sys_profil"}, - {sysImplPointer(), "sys_ktrace"}, - {sysImplPointer(), "sys_getgid"}, - {sysImplPointer(), "sys_getlogin"}, - {sysImplPointer(), "sys_setlogin"}, - {sysImplPointer(), "sys_acct"}, - {sysImplPointer(), "sys_sigaltstack"}, - {sysImplPointer(), "sys_ioctl"}, - {sysImplPointer(), "sys_reboot"}, - {sysImplPointer(), "sys_revoke"}, - {sysImplPointer(), "sys_symlink"}, - {sysImplPointer(), "sys_readlink"}, - {sysImplPointer(), "sys_execve"}, - {sysImplPointer(), "sys_umask"}, - {sysImplPointer(), "sys_chroot"}, - {sysImplPointer(), "sys_msync"}, - {sysImplPointer(), "sys_vfork"}, - {sysImplPointer(), "sys_sbrk"}, - {sysImplPointer(), "sys_sstk"}, - {sysImplPointer(), "sys_ovadvise"}, - {sysImplPointer(), "sys_munmap"}, - {sysImplPointer(), "sys_mprotect"}, - {sysImplPointer(), "sys_madvise"}, - {sysImplPointer(), "sys_mincore"}, - {sysImplPointer(), "sys_getgroups"}, - {sysImplPointer(), "sys_setgroups"}, - {sysImplPointer(), "sys_getpgrp"}, - {sysImplPointer(), "sys_setpgid"}, - {sysImplPointer(), "sys_setitimer"}, - {sysImplPointer(), "sys_swapon"}, - {sysImplPointer(), "sys_getitimer"}, - {sysImplPointer(), "sys_getdtablesize"}, - {sysImplPointer(), "sys_dup2"}, - {sysImplPointer(), "sys_fcntl"}, - {sysImplPointer(), "sys_select"}, - {sysImplPointer(), "sys_fsync"}, - {sysImplPointer(), "sys_setpriority"}, - {sysImplPointer(), "sys_socket"}, - {sysImplPointer(), "sys_connect"}, - {sysImplPointer(), "sys_getpriority"}, - {sysImplPointer(), "sys_bind"}, - {sysImplPointer(), "sys_setsockopt"}, - {sysImplPointer(), "sys_listen"}, - {sysImplPointer(), "sys_gettimeofday"}, - {sysImplPointer(), "sys_getrusage"}, - {sysImplPointer(), "sys_getsockopt"}, - {sysImplPointer(), "sys_readv"}, - {sysImplPointer(), "sys_writev"}, - {sysImplPointer(), "sys_settimeofday"}, - {sysImplPointer(), "sys_fchown"}, - {sysImplPointer(), "sys_fchmod"}, - {sysImplPointer(), "sys_setreuid"}, - {sysImplPointer(), "sys_setregid"}, - {sysImplPointer(), "sys_rename"}, - {sysImplPointer(), "sys_flock"}, - {sysImplPointer(), "sys_mkfifo"}, - {sysImplPointer(), "sys_sendto"}, - {sysImplPointer(), "sys_shutdown"}, - {sysImplPointer(), "sys_socketpair"}, - {sysImplPointer(), "sys_mkdir"}, - {sysImplPointer(), "sys_rmdir"}, - {sysImplPointer(), "sys_utimes"}, - {sysImplPointer(), "sys_adjtime"}, - {sysImplPointer(), "sys_setsid"}, - {sysImplPointer(), "sys_quotactl"}, - {sysImplPointer(), "sys_nlm_syscall"}, - {sysImplPointer(), "sys_nfssvc"}, - {sysImplPointer(), "sys_lgetfh"}, - {sysImplPointer(), "sys_getfh"}, - {sysImplPointer(), "sys_sysarch"}, - {sysImplPointer(), "sys_rtprio"}, - {sysImplPointer(), "sys_semsys"}, - {sysImplPointer(), "sys_msgsys"}, - {sysImplPointer(), "sys_shmsys"}, - {sysImplPointer(), "sys_freebsd6_pread"}, - {sysImplPointer(), "sys_freebsd6_pwrite"}, - {sysImplPointer(), "sys_setfib"}, - {sysImplPointer(), "sys_ntp_adjtime"}, - {sysImplPointer(), "sys_setgid"}, - {sysImplPointer(), "sys_setegid"}, - {sysImplPointer(), "sys_seteuid"}, - {sysImplPointer(), "sys_stat"}, - {sysImplPointer(), "sys_fstat"}, - {sysImplPointer(), "sys_lstat"}, - {sysImplPointer(), "sys_pathconf"}, - {sysImplPointer(), "sys_fpathconf"}, - {sysImplPointer(), "sys_getrlimit"}, - {sysImplPointer(), "sys_setrlimit"}, - {sysImplPointer(), "sys_getdirentries"}, - {sysImplPointer(), "sys_freebsd6_mmap"}, - {sysImplPointer(), "sys_freebsd6_lseek"}, - {sysImplPointer(), "sys_freebsd6_truncate"}, - {sysImplPointer(), "sys_freebsd6_ftruncate"}, - {sysImplPointer(), "sys___sysctl"}, - {sysImplPointer(), "sys_mlock"}, - {sysImplPointer(), "sys_munlock"}, - {sysImplPointer(), "sys_undelete"}, - {sysImplPointer(), "sys_futimes"}, - {sysImplPointer(), "sys_getpgid"}, - {sysImplPointer(), "sys_poll"}, - {sysImplPointer(), "sys_semget"}, - {sysImplPointer(), "sys_semop"}, - {sysImplPointer(), "sys_msgget"}, - {sysImplPointer(), "sys_msgsnd"}, - {sysImplPointer(), "sys_msgrcv"}, - {sysImplPointer(), "sys_shmat"}, - {sysImplPointer(), "sys_shmdt"}, - {sysImplPointer(), "sys_shmget"}, - {sysImplPointer(), "sys_clock_gettime"}, - {sysImplPointer(), "sys_clock_settime"}, - {sysImplPointer(), "sys_clock_getres"}, - {sysImplPointer(), "sys_ktimer_create"}, - {sysImplPointer(), "sys_ktimer_delete"}, - {sysImplPointer(), "sys_ktimer_settime"}, - {sysImplPointer(), "sys_ktimer_gettime"}, - {sysImplPointer(), "sys_ktimer_getoverrun"}, - {sysImplPointer(), "sys_nanosleep"}, - {sysImplPointer(), "sys_ntp_gettime"}, - {sysImplPointer(), "sys_minherit"}, - {sysImplPointer(), "sys_rfork"}, - {sysImplPointer(), "sys_openbsd_poll"}, - {sysImplPointer(), "sys_issetugid"}, - {sysImplPointer(), "sys_lchown"}, - {sysImplPointer(), "sys_aio_read"}, - {sysImplPointer(), "sys_aio_write"}, - {sysImplPointer(), "sys_lio_listio"}, - {sysImplPointer(), "sys_getdents"}, - {sysImplPointer(), "sys_lchmod"}, - {sysImplPointer(), "sys_lutimes"}, - {sysImplPointer(), "sys_nstat"}, - {sysImplPointer(), "sys_nfstat"}, - {sysImplPointer(), "sys_nlstat"}, - {sysImplPointer(), "sys_preadv"}, - {sysImplPointer(), "sys_pwritev"}, - {sysImplPointer(), "sys_fhopen"}, - {sysImplPointer(), "sys_fhstat"}, - {sysImplPointer(), "sys_modnext"}, - {sysImplPointer(), "sys_modstat"}, - {sysImplPointer(), "sys_modfnext"}, - {sysImplPointer(), "sys_modfind"}, - {sysImplPointer(), "sys_kldload"}, - {sysImplPointer(), "sys_kldunload"}, - {sysImplPointer(), "sys_kldfind"}, - {sysImplPointer(), "sys_kldnext"}, - {sysImplPointer(), "sys_kldstat"}, - {sysImplPointer(), "sys_kldfirstmod"}, - {sysImplPointer(), "sys_getsid"}, - {sysImplPointer(), "sys_setresuid"}, - {sysImplPointer(), "sys_setresgid"}, - {sysImplPointer(), "sys_aio_return"}, - {sysImplPointer(), "sys_aio_suspend"}, - {sysImplPointer(), "sys_aio_cancel"}, - {sysImplPointer(), "sys_aio_error"}, - {sysImplPointer(), "sys_oaio_read"}, - {sysImplPointer(), "sys_oaio_write"}, - {sysImplPointer(), "sys_olio_listio"}, - {sysImplPointer(), "sys_yield"}, - {sysImplPointer(), "sys_mlockall"}, - {sysImplPointer(), "sys_munlockall"}, - {sysImplPointer(), "sys___getcwd"}, - {sysImplPointer(), "sys_sched_setparam"}, - {sysImplPointer(), "sys_sched_getparam"}, - {sysImplPointer(), "sys_sched_setscheduler"}, - {sysImplPointer(), "sys_sched_getscheduler"}, - {sysImplPointer(), "sys_sched_yield"}, - {sysImplPointer(), - "sys_sched_get_priority_max"}, - {sysImplPointer(), - "sys_sched_get_priority_min"}, - {sysImplPointer(), - "sys_sched_rr_get_interval"}, - {sysImplPointer(), "sys_utrace"}, - {sysImplPointer(), "sys_kldsym"}, - {sysImplPointer(), "sys_jail"}, - {sysImplPointer(), "sys_nnpfs_syscall"}, - {sysImplPointer(), "sys_sigprocmask"}, - {sysImplPointer(), "sys_sigsuspend"}, - {sysImplPointer(), "sys_sigpending"}, - {sysImplPointer(), "sys_sigtimedwait"}, - {sysImplPointer(), "sys_sigwaitinfo"}, - {sysImplPointer(), "sys___acl_get_file"}, - {sysImplPointer(), "sys___acl_set_file"}, - {sysImplPointer(), "sys___acl_get_fd"}, - {sysImplPointer(), "sys___acl_set_fd"}, - {sysImplPointer(), "sys___acl_delete_file"}, - {sysImplPointer(), "sys___acl_delete_fd"}, - {sysImplPointer(), "sys___acl_aclcheck_file"}, - {sysImplPointer(), "sys___acl_aclcheck_fd"}, - {sysImplPointer(), "sys_extattrctl"}, - {sysImplPointer(), "sys_extattr_set_file"}, - {sysImplPointer(), "sys_extattr_get_file"}, - {sysImplPointer(), "sys_extattr_delete_file"}, - {sysImplPointer(), "sys_aio_waitcomplete"}, - {sysImplPointer(), "sys_getresuid"}, - {sysImplPointer(), "sys_getresgid"}, - {sysImplPointer(), "sys_kqueue"}, - {sysImplPointer(), "sys_kevent"}, - {sysImplPointer(), "sys_extattr_set_fd"}, - {sysImplPointer(), "sys_extattr_get_fd"}, - {sysImplPointer(), "sys_extattr_delete_fd"}, - {sysImplPointer(), "sys___setugid"}, - {sysImplPointer(), "sys_eaccess"}, - {sysImplPointer(), "sys_afs3_syscall"}, - {sysImplPointer(), "sys_nmount"}, - {sysImplPointer(), "sys___mac_get_proc"}, - {sysImplPointer(), "sys___mac_set_proc"}, - {sysImplPointer(), "sys___mac_get_fd"}, - {sysImplPointer(), "sys___mac_get_file"}, - {sysImplPointer(), "sys___mac_set_fd"}, - {sysImplPointer(), "sys___mac_set_file"}, - {sysImplPointer(), "sys_kenv"}, - {sysImplPointer(), "sys_lchflags"}, - {sysImplPointer(), "sys_uuidgen"}, - {sysImplPointer(), "sys_sendfile"}, - {sysImplPointer(), "sys_mac_syscall"}, - {sysImplPointer(), "sys_getfsstat"}, - {sysImplPointer(), "sys_statfs"}, - {sysImplPointer(), "sys_fstatfs"}, - {sysImplPointer(), "sys_fhstatfs"}, - {sysImplPointer(), "sys_ksem_close"}, - {sysImplPointer(), "sys_ksem_post"}, - {sysImplPointer(), "sys_ksem_wait"}, - {sysImplPointer(), "sys_ksem_trywait"}, - {sysImplPointer(), "sys_ksem_init"}, - {sysImplPointer(), "sys_ksem_open"}, - {sysImplPointer(), "sys_ksem_unlink"}, - {sysImplPointer(), "sys_ksem_getvalue"}, - {sysImplPointer(), "sys_ksem_destroy"}, - {sysImplPointer(), "sys___mac_get_pid"}, - {sysImplPointer(), "sys___mac_get_link"}, - {sysImplPointer(), "sys___mac_set_link"}, - {sysImplPointer(), "sys_extattr_set_link"}, - {sysImplPointer(), "sys_extattr_get_link"}, - {sysImplPointer(), "sys_extattr_delete_link"}, - {sysImplPointer(), "sys___mac_execve"}, - {sysImplPointer(), "sys_sigaction"}, - {sysImplPointer(), "sys_sigreturn"}, - {sysImplPointer(), "sys_getcontext"}, - {sysImplPointer(), "sys_setcontext"}, - {sysImplPointer(), "sys_swapcontext"}, - {sysImplPointer(), "sys_swapoff"}, - {sysImplPointer(), "sys___acl_get_link"}, - {sysImplPointer(), "sys___acl_set_link"}, - {sysImplPointer(), "sys___acl_delete_link"}, - {sysImplPointer(), "sys___acl_aclcheck_link"}, - {sysImplPointer(), "sys_sigwait"}, - {sysImplPointer(), "sys_thr_create"}, - {sysImplPointer(), "sys_thr_exit"}, - {sysImplPointer(), "sys_thr_self"}, - {sysImplPointer(), "sys_thr_kill"}, - {sysImplPointer(), "sys__umtx_lock"}, - {sysImplPointer(), "sys__umtx_unlock"}, - {sysImplPointer(), "sys_jail_attach"}, - {sysImplPointer(), "sys_extattr_list_fd"}, - {sysImplPointer(), "sys_extattr_list_file"}, - {sysImplPointer(), "sys_extattr_list_link"}, - {sysImplPointer(), "sys_ksem_timedwait"}, - {sysImplPointer(), "sys_thr_suspend"}, - {sysImplPointer(), "sys_thr_wake"}, - {sysImplPointer(), "sys_kldunloadf"}, - {sysImplPointer(), "sys_audit"}, - {sysImplPointer(), "sys_auditon"}, - {sysImplPointer(), "sys_getauid"}, - {sysImplPointer(), "sys_setauid"}, - {sysImplPointer(), "sys_getaudit"}, - {sysImplPointer(), "sys_setaudit"}, - {sysImplPointer(), "sys_getaudit_addr"}, - {sysImplPointer(), "sys_setaudit_addr"}, - {sysImplPointer(), "sys_auditctl"}, - {sysImplPointer(), "sys__umtx_op"}, - {sysImplPointer(), "sys_thr_new"}, - {sysImplPointer(), "sys_sigqueue"}, - {sysImplPointer(), "sys_kmq_open"}, - {sysImplPointer(), "sys_kmq_setattr"}, - {sysImplPointer(), "sys_kmq_timedreceive"}, - {sysImplPointer(), "sys_kmq_timedsend"}, - {sysImplPointer(), "sys_kmq_notify"}, - {sysImplPointer(), "sys_kmq_unlink"}, - {sysImplPointer(), "sys_abort2"}, - {sysImplPointer(), "sys_thr_set_name"}, - {sysImplPointer(), "sys_aio_fsync"}, - {sysImplPointer(), "sys_rtprio_thread"}, - {sysImplPointer(), "sys_sctp_peeloff"}, - {sysImplPointer(), - "sys_sctp_generic_sendmsg"}, - {sysImplPointer(), - "sys_sctp_generic_sendmsg_iov"}, - {sysImplPointer(), - "sys_sctp_generic_recvmsg"}, - {sysImplPointer(), "sys_pread"}, - {sysImplPointer(), "sys_pwrite"}, - {sysImplPointer(), "sys_mmap"}, - {sysImplPointer(), "sys_lseek"}, - {sysImplPointer(), "sys_truncate"}, - {sysImplPointer(), "sys_ftruncate"}, - {sysImplPointer(), "sys_thr_kill2"}, - {sysImplPointer(), "sys_shm_open"}, - {sysImplPointer(), "sys_shm_unlink"}, - {sysImplPointer(), "sys_cpuset"}, - {sysImplPointer(), "sys_cpuset_setid"}, - {sysImplPointer(), "sys_cpuset_getid"}, - {sysImplPointer(), "sys_cpuset_getaffinity"}, - {sysImplPointer(), "sys_cpuset_setaffinity"}, - {sysImplPointer(), "sys_faccessat"}, - {sysImplPointer(), "sys_fchmodat"}, - {sysImplPointer(), "sys_fchownat"}, - {sysImplPointer(), "sys_fexecve"}, - {sysImplPointer(), "sys_fstatat"}, - {sysImplPointer(), "sys_futimesat"}, - {sysImplPointer(), "sys_linkat"}, - {sysImplPointer(), "sys_mkdirat"}, - {sysImplPointer(), "sys_mkfifoat"}, - {sysImplPointer(), "sys_mknodat"}, - {sysImplPointer(), "sys_openat"}, - {sysImplPointer(), "sys_readlinkat"}, - {sysImplPointer(), "sys_renameat"}, - {sysImplPointer(), "sys_symlinkat"}, - {sysImplPointer(), "sys_unlinkat"}, - {sysImplPointer(), "sys_posix_openpt"}, - {sysImplPointer(), "sys_gssd_syscall"}, - {sysImplPointer(), "sys_jail_get"}, - {sysImplPointer(), "sys_jail_set"}, - {sysImplPointer(), "sys_jail_remove"}, - {sysImplPointer(), "sys_closefrom"}, - {sysImplPointer(), "sys___semctl"}, - {sysImplPointer(), "sys_msgctl"}, - {sysImplPointer(), "sys_shmctl"}, - {sysImplPointer(), "sys_lpathconf"}, - {sysImplPointer(), "sys_cap_new"}, - {sysImplPointer(), "sys_cap_getrights"}, - {sysImplPointer(), "sys_cap_enter"}, - {sysImplPointer(), "sys_cap_getmode"}, - {sysImplPointer(), "sys_pdfork"}, - {sysImplPointer(), "sys_pdkill"}, - {sysImplPointer(), "sys_pdgetpid"}, - {sysImplPointer(), "sys_pselect"}, - {sysImplPointer(), "sys_getloginclass"}, - {sysImplPointer(), "sys_setloginclass"}, - {sysImplPointer(), "sys_rctl_get_racct"}, - {sysImplPointer(), "sys_rctl_get_rules"}, - {sysImplPointer(), "sys_rctl_get_limits"}, - {sysImplPointer(), "sys_rctl_add_rule"}, - {sysImplPointer(), "sys_rctl_remove_rule"}, - {sysImplPointer(), "sys_posix_fallocate"}, - {sysImplPointer(), "sys_posix_fadvise"}, - {sysImplPointer(), "sys_netcontrol"}, - {sysImplPointer(), "sys_netabort"}, - {sysImplPointer(), "sys_netgetsockinfo"}, - {sysImplPointer(), "sys_socketex"}, - {sysImplPointer(), "sys_socketclose"}, - {sysImplPointer(), "sys_netgetiflist"}, - {sysImplPointer(), "sys_kqueueex"}, - {sysImplPointer(), "sys_mtypeprotect"}, - {sysImplPointer(), "sys_regmgr_call"}, - {sysImplPointer(), "sys_jitshm_create"}, - {sysImplPointer(), "sys_jitshm_alias"}, - {sysImplPointer(), "sys_dl_get_list"}, - {sysImplPointer(), "sys_dl_get_info"}, - {sysImplPointer(), "sys_dl_notify_event"}, - {sysImplPointer(), "sys_evf_create"}, - {sysImplPointer(), "sys_evf_delete"}, - {sysImplPointer(), "sys_evf_open"}, - {sysImplPointer(), "sys_evf_close"}, - {sysImplPointer(), "sys_evf_wait"}, - {sysImplPointer(), "sys_evf_trywait"}, - {sysImplPointer(), "sys_evf_set"}, - {sysImplPointer(), "sys_evf_clear"}, - {sysImplPointer(), "sys_evf_cancel"}, - {sysImplPointer(), - "sys_query_memory_protection"}, - {sysImplPointer(), "sys_batch_map"}, - {sysImplPointer(), "sys_osem_create"}, - {sysImplPointer(), "sys_osem_delete"}, - {sysImplPointer(), "sys_osem_open"}, - {sysImplPointer(), "sys_osem_close"}, - {sysImplPointer(), "sys_osem_wait"}, - {sysImplPointer(), "sys_osem_trywait"}, - {sysImplPointer(), "sys_osem_post"}, - {sysImplPointer(), "sys_osem_cancel"}, - {sysImplPointer(), "sys_namedobj_create"}, - {sysImplPointer(), "sys_namedobj_delete"}, - {sysImplPointer(), "sys_set_vm_container"}, - {sysImplPointer(), "sys_debug_init"}, - {sysImplPointer(), "sys_suspend_process"}, - {sysImplPointer(), "sys_resume_process"}, - {sysImplPointer(), "sys_opmc_enable"}, - {sysImplPointer(), "sys_opmc_disable"}, - {sysImplPointer(), "sys_opmc_set_ctl"}, - {sysImplPointer(), "sys_opmc_set_ctr"}, - {sysImplPointer(), "sys_opmc_get_ctr"}, - {sysImplPointer(), "sys_budget_create"}, - {sysImplPointer(), "sys_budget_delete"}, - {sysImplPointer(), "sys_budget_get"}, - {sysImplPointer(), "sys_budget_set"}, - {sysImplPointer(), "sys_virtual_query"}, - {sysImplPointer(), "sys_mdbg_call"}, - {sysImplPointer(), "sys_obs_sblock_create"}, - {sysImplPointer(), "sys_obs_sblock_delete"}, - {sysImplPointer(), "sys_obs_sblock_enter"}, - {sysImplPointer(), "sys_obs_sblock_exit"}, - {sysImplPointer(), "sys_obs_sblock_xenter"}, - {sysImplPointer(), "sys_obs_sblock_xexit"}, - {sysImplPointer(), "sys_obs_eport_create"}, - {sysImplPointer(), "sys_obs_eport_delete"}, - {sysImplPointer(), "sys_obs_eport_trigger"}, - {sysImplPointer(), "sys_obs_eport_open"}, - {sysImplPointer(), "sys_obs_eport_close"}, - {sysImplPointer(), "sys_is_in_sandbox"}, - {sysImplPointer(), "sys_dmem_container"}, - {sysImplPointer(), "sys_get_authinfo"}, - {sysImplPointer(), "sys_mname"}, - {sysImplPointer(), "sys_dynlib_dlopen"}, - {sysImplPointer(), "sys_dynlib_dlclose"}, - {sysImplPointer(), "sys_dynlib_dlsym"}, - {sysImplPointer(), "sys_dynlib_get_list"}, - {sysImplPointer(), "sys_dynlib_get_info"}, - {sysImplPointer(), "sys_dynlib_load_prx"}, - {sysImplPointer(), "sys_dynlib_unload_prx"}, - {sysImplPointer(), - "sys_dynlib_do_copy_relocations"}, - {sysImplPointer(), - "sys_dynlib_prepare_dlclose"}, - {sysImplPointer(), - "sys_dynlib_get_proc_param"}, - {sysImplPointer(), - "sys_dynlib_process_needed_and_relocate"}, - {sysImplPointer(), "sys_sandbox_path"}, - {sysImplPointer(), "sys_mdbg_service"}, - {sysImplPointer(), "sys_randomized_path"}, - {sysImplPointer(), "sys_rdup"}, - {sysImplPointer(), "sys_dl_get_metadata"}, - {sysImplPointer(), "sys_workaround8849"}, - {sysImplPointer(), "sys_is_development_mode"}, - {sysImplPointer(), "sys_get_self_auth_info"}, - {sysImplPointer(), "sys_dynlib_get_info_ex"}, - {sysImplPointer(), "sys_budget_getid"}, - {sysImplPointer(), "sys_budget_get_ptype"}, - {sysImplPointer(), - "sys_get_paging_stats_of_all_threads"}, - {sysImplPointer(), "sys_get_proc_type_info"}, - {sysImplPointer(), "sys_get_resident_count"}, - {sysImplPointer(), - "sys_prepare_to_suspend_process"}, - {sysImplPointer(), - "sys_get_resident_fmem_count"}, - {sysImplPointer(), "sys_thr_get_name"}, - {sysImplPointer(), "sys_set_gpo"}, - {sysImplPointer(), - "sys_get_paging_stats_of_all_objects"}, - {sysImplPointer(), "sys_test_debug_rwmem"}, - {sysImplPointer(), "sys_free_stack"}, - {sysImplPointer(), "sys_suspend_system"}, - {sysImplPointer(), "sys_ipmimgr_call"}, - {sysImplPointer(), "sys_get_gpo"}, - {sysImplPointer(), - "sys_get_vm_map_timestamp"}, - {sysImplPointer(), "sys_opmc_set_hw"}, - {sysImplPointer(), "sys_opmc_get_hw"}, - {sysImplPointer(), "sys_get_cpu_usage_all"}, - {sysImplPointer(), "sys_mmap_dmem"}, - {sysImplPointer(), "sys_physhm_open"}, - {sysImplPointer(), "sys_physhm_unlink"}, - {sysImplPointer(), "sys_resume_internal_hdd"}, - {sysImplPointer(), - "sys_thr_suspend_ucontext"}, - {sysImplPointer(), "sys_thr_resume_ucontext"}, - {sysImplPointer(), "sys_thr_get_ucontext"}, - {sysImplPointer(), "sys_thr_set_ucontext"}, - {sysImplPointer(), "sys_set_timezone_info"}, - {sysImplPointer(), "sys_set_phys_fmem_limit"}, - {sysImplPointer(), "sys_utc_to_localtime"}, - {sysImplPointer(), "sys_localtime_to_utc"}, - {sysImplPointer(), "sys_set_uevt"}, - {sysImplPointer(), "sys_get_cpu_usage_proc"}, - {sysImplPointer(), "sys_get_map_statistics"}, - {sysImplPointer(), - "sys_set_chicken_switches"}, - {sysImplPointer(), - "sys_extend_page_table_pool"}, - {sysImplPointer(), - "sys_extend_page_table_pool2"}, - {sysImplPointer(), - "sys_get_kernel_mem_statistics"}, - {sysImplPointer(), - "sys_get_sdk_compiled_version"}, - {sysImplPointer(), "sys_app_state_change"}, - {sysImplPointer(), - "sys_dynlib_get_obj_member"}, - {sysImplPointer(), - "sys_budget_get_ptype_of_budget"}, - {sysImplPointer(), - "sys_prepare_to_resume_process"}, - {sysImplPointer(), "sys_process_terminate"}, - {sysImplPointer(), "sys_blockpool_open"}, - {sysImplPointer(), "sys_blockpool_map"}, - {sysImplPointer(), "sys_blockpool_unmap"}, - {sysImplPointer(), - "sys_dynlib_get_info_for_libdbg"}, - {sysImplPointer(), "sys_blockpool_batch"}, - {sysImplPointer(), "sys_fdatasync"}, - {sysImplPointer(), "sys_dynlib_get_list2"}, - {sysImplPointer(), "sys_dynlib_get_info2"}, - {sysImplPointer(), "sys_aio_submit"}, - {sysImplPointer(), "sys_aio_multi_delete"}, - {sysImplPointer(), "sys_aio_multi_wait"}, - {sysImplPointer(), "sys_aio_multi_poll"}, - {sysImplPointer(), "sys_aio_get_data"}, - {sysImplPointer(), "sys_aio_multi_cancel"}, - {sysImplPointer(), "sys_get_bio_usage_all"}, - {sysImplPointer(), "sys_aio_create"}, - {sysImplPointer(), "sys_aio_submit_cmd"}, - {sysImplPointer(), "sys_aio_init"}, - {sysImplPointer(), - "sys_get_page_table_stats"}, - {sysImplPointer(), - "sys_dynlib_get_list_for_libdbg"}, - {sysImplPointer(), "sys_blockpool_move"}, - {sysImplPointer(), "sys_virtual_query_all"}, - {sysImplPointer(), "sys_reserve_2mb_page"}, - {sysImplPointer(), "sys_cpumode_yield"}, - {sysImplPointer(), "sys_wait6"}, - {sysImplPointer(), "sys_cap_rights_limit"}, - {sysImplPointer(), "sys_cap_ioctls_limit"}, - {sysImplPointer(), "sys_cap_ioctls_get"}, - {sysImplPointer(), "sys_cap_fcntls_limit"}, - {sysImplPointer(), "sys_cap_fcntls_get"}, - {sysImplPointer(), "sys_bindat"}, - {sysImplPointer(), "sys_connectat"}, - {sysImplPointer(), "sys_chflagsat"}, - {sysImplPointer(), "sys_accept4"}, - {sysImplPointer(), "sys_pipe2"}, - {sysImplPointer(), "sys_aio_mlock"}, - {sysImplPointer(), "sys_procctl"}, - {sysImplPointer(), "sys_ppoll"}, - {sysImplPointer(), "sys_futimens"}, - {sysImplPointer(), "sys_utimensat"}, - {sysImplPointer(), "sys_numa_getaffinity"}, - {sysImplPointer(), "sys_numa_setaffinity"}, - {sysImplPointer(), "sys_apr_submit"}, - {sysImplPointer(), "sys_apr_resolve"}, - {sysImplPointer(), "sys_apr_stat"}, - {sysImplPointer(), "sys_apr_wait"}, - {sysImplPointer(), "sys_apr_ctrl"}, - {sysImplPointer(), "sys_get_phys_page_size"}, - {sysImplPointer(), "sys_begin_app_mount"}, - {sysImplPointer(), "sys_end_app_mount"}, - {sysImplPointer(), "sys_fsc2h_ctrl"}, - {sysImplPointer(), "sys_streamwrite"}, - {sysImplPointer(), "sys_app_save"}, - {sysImplPointer(), "sys_app_restore"}, - {sysImplPointer(), "sys_saved_app_delete"}, - {sysImplPointer(), - "sys_get_ppr_sdk_compiled_version"}, - {sysImplPointer(), "sys_notify_app_event"}, - {sysImplPointer(), "sys_ioreq"}, - {sysImplPointer(), "sys_openintr"}, - {sysImplPointer(), "sys_dl_get_info_2"}, - {sysImplPointer(), "sys_acinfo_add"}, - {sysImplPointer(), "sys_acinfo_delete"}, - {sysImplPointer(), - "sys_acinfo_get_all_for_coredump"}, - {sysImplPointer(), "sys_ampr_ctrl_debug"}, - {sysImplPointer(), "sys_workspace_ctrl"}, -}; + static constexpr std::pair + gImplToName[] = { + {sysImplPointer(), "nosys"}, + {sysImplPointer(), "sys_exit"}, + {sysImplPointer(), "sys_fork"}, + {sysImplPointer(), "sys_read"}, + {sysImplPointer(), "sys_write"}, + {sysImplPointer(), "sys_open"}, + {sysImplPointer(), "sys_close"}, + {sysImplPointer(), "sys_wait4"}, + {sysImplPointer(), "sys_link"}, + {sysImplPointer(), "sys_unlink"}, + {sysImplPointer(), "sys_chdir"}, + {sysImplPointer(), "sys_fchdir"}, + {sysImplPointer(), "sys_mknod"}, + {sysImplPointer(), "sys_chmod"}, + {sysImplPointer(), "sys_chown"}, + {sysImplPointer(), "sys_obreak"}, + {sysImplPointer(), "sys_getpid"}, + {sysImplPointer(), "sys_mount"}, + {sysImplPointer(), "sys_unmount"}, + {sysImplPointer(), "sys_setuid"}, + {sysImplPointer(), "sys_getuid"}, + {sysImplPointer(), "sys_geteuid"}, + {sysImplPointer(), "sys_ptrace"}, + {sysImplPointer(), "sys_recvmsg"}, + {sysImplPointer(), "sys_sendmsg"}, + {sysImplPointer(), "sys_recvfrom"}, + {sysImplPointer(), "sys_accept"}, + {sysImplPointer(), "sys_getpeername"}, + {sysImplPointer(), "sys_getsockname"}, + {sysImplPointer(), "sys_access"}, + {sysImplPointer(), "sys_chflags"}, + {sysImplPointer(), "sys_fchflags"}, + {sysImplPointer(), "sys_sync"}, + {sysImplPointer(), "sys_kill"}, + {sysImplPointer(), "sys_getppid"}, + {sysImplPointer(), "sys_dup"}, + {sysImplPointer(), "sys_pipe"}, + {sysImplPointer(), "sys_getegid"}, + {sysImplPointer(), "sys_profil"}, + {sysImplPointer(), "sys_ktrace"}, + {sysImplPointer(), "sys_getgid"}, + {sysImplPointer(), "sys_getlogin"}, + {sysImplPointer(), "sys_setlogin"}, + {sysImplPointer(), "sys_acct"}, + {sysImplPointer(), "sys_sigaltstack"}, + {sysImplPointer(), "sys_ioctl"}, + {sysImplPointer(), "sys_reboot"}, + {sysImplPointer(), "sys_revoke"}, + {sysImplPointer(), "sys_symlink"}, + {sysImplPointer(), "sys_readlink"}, + {sysImplPointer(), "sys_execve"}, + {sysImplPointer(), "sys_umask"}, + {sysImplPointer(), "sys_chroot"}, + {sysImplPointer(), "sys_msync"}, + {sysImplPointer(), "sys_vfork"}, + {sysImplPointer(), "sys_sbrk"}, + {sysImplPointer(), "sys_sstk"}, + {sysImplPointer(), "sys_ovadvise"}, + {sysImplPointer(), "sys_munmap"}, + {sysImplPointer(), "sys_mprotect"}, + {sysImplPointer(), "sys_madvise"}, + {sysImplPointer(), "sys_mincore"}, + {sysImplPointer(), "sys_getgroups"}, + {sysImplPointer(), "sys_setgroups"}, + {sysImplPointer(), "sys_getpgrp"}, + {sysImplPointer(), "sys_setpgid"}, + {sysImplPointer(), "sys_setitimer"}, + {sysImplPointer(), "sys_swapon"}, + {sysImplPointer(), "sys_getitimer"}, + {sysImplPointer(), "sys_getdtablesize"}, + {sysImplPointer(), "sys_dup2"}, + {sysImplPointer(), "sys_fcntl"}, + {sysImplPointer(), "sys_select"}, + {sysImplPointer(), "sys_fsync"}, + {sysImplPointer(), "sys_setpriority"}, + {sysImplPointer(), "sys_socket"}, + {sysImplPointer(), "sys_connect"}, + {sysImplPointer(), "sys_getpriority"}, + {sysImplPointer(), "sys_bind"}, + {sysImplPointer(), "sys_setsockopt"}, + {sysImplPointer(), "sys_listen"}, + {sysImplPointer(), "sys_gettimeofday"}, + {sysImplPointer(), "sys_getrusage"}, + {sysImplPointer(), "sys_getsockopt"}, + {sysImplPointer(), "sys_readv"}, + {sysImplPointer(), "sys_writev"}, + {sysImplPointer(), "sys_settimeofday"}, + {sysImplPointer(), "sys_fchown"}, + {sysImplPointer(), "sys_fchmod"}, + {sysImplPointer(), "sys_setreuid"}, + {sysImplPointer(), "sys_setregid"}, + {sysImplPointer(), "sys_rename"}, + {sysImplPointer(), "sys_flock"}, + {sysImplPointer(), "sys_mkfifo"}, + {sysImplPointer(), "sys_sendto"}, + {sysImplPointer(), "sys_shutdown"}, + {sysImplPointer(), "sys_socketpair"}, + {sysImplPointer(), "sys_mkdir"}, + {sysImplPointer(), "sys_rmdir"}, + {sysImplPointer(), "sys_utimes"}, + {sysImplPointer(), "sys_adjtime"}, + {sysImplPointer(), "sys_setsid"}, + {sysImplPointer(), "sys_quotactl"}, + {sysImplPointer(), "sys_nlm_syscall"}, + {sysImplPointer(), "sys_nfssvc"}, + {sysImplPointer(), "sys_lgetfh"}, + {sysImplPointer(), "sys_getfh"}, + {sysImplPointer(), "sys_sysarch"}, + {sysImplPointer(), "sys_rtprio"}, + {sysImplPointer(), "sys_semsys"}, + {sysImplPointer(), "sys_msgsys"}, + {sysImplPointer(), "sys_shmsys"}, + {sysImplPointer(), "sys_freebsd6_pread"}, + {sysImplPointer(), "sys_freebsd6_pwrite"}, + {sysImplPointer(), "sys_setfib"}, + {sysImplPointer(), "sys_ntp_adjtime"}, + {sysImplPointer(), "sys_setgid"}, + {sysImplPointer(), "sys_setegid"}, + {sysImplPointer(), "sys_seteuid"}, + {sysImplPointer(), "sys_stat"}, + {sysImplPointer(), "sys_fstat"}, + {sysImplPointer(), "sys_lstat"}, + {sysImplPointer(), "sys_pathconf"}, + {sysImplPointer(), "sys_fpathconf"}, + {sysImplPointer(), "sys_getrlimit"}, + {sysImplPointer(), "sys_setrlimit"}, + {sysImplPointer(), "sys_getdirentries"}, + {sysImplPointer(), "sys_freebsd6_mmap"}, + {sysImplPointer(), "sys_freebsd6_lseek"}, + {sysImplPointer(), "sys_freebsd6_truncate"}, + {sysImplPointer(), "sys_freebsd6_ftruncate"}, + {sysImplPointer(), "sys___sysctl"}, + {sysImplPointer(), "sys_mlock"}, + {sysImplPointer(), "sys_munlock"}, + {sysImplPointer(), "sys_undelete"}, + {sysImplPointer(), "sys_futimes"}, + {sysImplPointer(), "sys_getpgid"}, + {sysImplPointer(), "sys_poll"}, + {sysImplPointer(), "sys_semget"}, + {sysImplPointer(), "sys_semop"}, + {sysImplPointer(), "sys_msgget"}, + {sysImplPointer(), "sys_msgsnd"}, + {sysImplPointer(), "sys_msgrcv"}, + {sysImplPointer(), "sys_shmat"}, + {sysImplPointer(), "sys_shmdt"}, + {sysImplPointer(), "sys_shmget"}, + {sysImplPointer(), "sys_clock_gettime"}, + {sysImplPointer(), "sys_clock_settime"}, + {sysImplPointer(), "sys_clock_getres"}, + {sysImplPointer(), "sys_ktimer_create"}, + {sysImplPointer(), "sys_ktimer_delete"}, + {sysImplPointer(), "sys_ktimer_settime"}, + {sysImplPointer(), "sys_ktimer_gettime"}, + {sysImplPointer(), "sys_ktimer_getoverrun"}, + {sysImplPointer(), "sys_nanosleep"}, + {sysImplPointer(), "sys_ntp_gettime"}, + {sysImplPointer(), "sys_minherit"}, + {sysImplPointer(), "sys_rfork"}, + {sysImplPointer(), "sys_openbsd_poll"}, + {sysImplPointer(), "sys_issetugid"}, + {sysImplPointer(), "sys_lchown"}, + {sysImplPointer(), "sys_aio_read"}, + {sysImplPointer(), "sys_aio_write"}, + {sysImplPointer(), "sys_lio_listio"}, + {sysImplPointer(), "sys_getdents"}, + {sysImplPointer(), "sys_lchmod"}, + {sysImplPointer(), "sys_lutimes"}, + {sysImplPointer(), "sys_nstat"}, + {sysImplPointer(), "sys_nfstat"}, + {sysImplPointer(), "sys_nlstat"}, + {sysImplPointer(), "sys_preadv"}, + {sysImplPointer(), "sys_pwritev"}, + {sysImplPointer(), "sys_fhopen"}, + {sysImplPointer(), "sys_fhstat"}, + {sysImplPointer(), "sys_modnext"}, + {sysImplPointer(), "sys_modstat"}, + {sysImplPointer(), "sys_modfnext"}, + {sysImplPointer(), "sys_modfind"}, + {sysImplPointer(), "sys_kldload"}, + {sysImplPointer(), "sys_kldunload"}, + {sysImplPointer(), "sys_kldfind"}, + {sysImplPointer(), "sys_kldnext"}, + {sysImplPointer(), "sys_kldstat"}, + {sysImplPointer(), "sys_kldfirstmod"}, + {sysImplPointer(), "sys_getsid"}, + {sysImplPointer(), "sys_setresuid"}, + {sysImplPointer(), "sys_setresgid"}, + {sysImplPointer(), "sys_aio_return"}, + {sysImplPointer(), "sys_aio_suspend"}, + {sysImplPointer(), "sys_aio_cancel"}, + {sysImplPointer(), "sys_aio_error"}, + {sysImplPointer(), "sys_oaio_read"}, + {sysImplPointer(), "sys_oaio_write"}, + {sysImplPointer(), "sys_olio_listio"}, + {sysImplPointer(), "sys_yield"}, + {sysImplPointer(), "sys_mlockall"}, + {sysImplPointer(), "sys_munlockall"}, + {sysImplPointer(), "sys___getcwd"}, + {sysImplPointer(), "sys_sched_setparam"}, + {sysImplPointer(), "sys_sched_getparam"}, + {sysImplPointer(), "sys_sched_setscheduler"}, + {sysImplPointer(), "sys_sched_getscheduler"}, + {sysImplPointer(), "sys_sched_yield"}, + {sysImplPointer(), + "sys_sched_get_priority_max"}, + {sysImplPointer(), + "sys_sched_get_priority_min"}, + {sysImplPointer(), + "sys_sched_rr_get_interval"}, + {sysImplPointer(), "sys_utrace"}, + {sysImplPointer(), "sys_kldsym"}, + {sysImplPointer(), "sys_jail"}, + {sysImplPointer(), "sys_nnpfs_syscall"}, + {sysImplPointer(), "sys_sigprocmask"}, + {sysImplPointer(), "sys_sigsuspend"}, + {sysImplPointer(), "sys_sigpending"}, + {sysImplPointer(), "sys_sigtimedwait"}, + {sysImplPointer(), "sys_sigwaitinfo"}, + {sysImplPointer(), "sys___acl_get_file"}, + {sysImplPointer(), "sys___acl_set_file"}, + {sysImplPointer(), "sys___acl_get_fd"}, + {sysImplPointer(), "sys___acl_set_fd"}, + {sysImplPointer(), "sys___acl_delete_file"}, + {sysImplPointer(), "sys___acl_delete_fd"}, + {sysImplPointer(), "sys___acl_aclcheck_file"}, + {sysImplPointer(), "sys___acl_aclcheck_fd"}, + {sysImplPointer(), "sys_extattrctl"}, + {sysImplPointer(), "sys_extattr_set_file"}, + {sysImplPointer(), "sys_extattr_get_file"}, + {sysImplPointer(), "sys_extattr_delete_file"}, + {sysImplPointer(), "sys_aio_waitcomplete"}, + {sysImplPointer(), "sys_getresuid"}, + {sysImplPointer(), "sys_getresgid"}, + {sysImplPointer(), "sys_kqueue"}, + {sysImplPointer(), "sys_kevent"}, + {sysImplPointer(), "sys_extattr_set_fd"}, + {sysImplPointer(), "sys_extattr_get_fd"}, + {sysImplPointer(), "sys_extattr_delete_fd"}, + {sysImplPointer(), "sys___setugid"}, + {sysImplPointer(), "sys_eaccess"}, + {sysImplPointer(), "sys_afs3_syscall"}, + {sysImplPointer(), "sys_nmount"}, + {sysImplPointer(), "sys___mac_get_proc"}, + {sysImplPointer(), "sys___mac_set_proc"}, + {sysImplPointer(), "sys___mac_get_fd"}, + {sysImplPointer(), "sys___mac_get_file"}, + {sysImplPointer(), "sys___mac_set_fd"}, + {sysImplPointer(), "sys___mac_set_file"}, + {sysImplPointer(), "sys_kenv"}, + {sysImplPointer(), "sys_lchflags"}, + {sysImplPointer(), "sys_uuidgen"}, + {sysImplPointer(), "sys_sendfile"}, + {sysImplPointer(), "sys_mac_syscall"}, + {sysImplPointer(), "sys_getfsstat"}, + {sysImplPointer(), "sys_statfs"}, + {sysImplPointer(), "sys_fstatfs"}, + {sysImplPointer(), "sys_fhstatfs"}, + {sysImplPointer(), "sys_ksem_close"}, + {sysImplPointer(), "sys_ksem_post"}, + {sysImplPointer(), "sys_ksem_wait"}, + {sysImplPointer(), "sys_ksem_trywait"}, + {sysImplPointer(), "sys_ksem_init"}, + {sysImplPointer(), "sys_ksem_open"}, + {sysImplPointer(), "sys_ksem_unlink"}, + {sysImplPointer(), "sys_ksem_getvalue"}, + {sysImplPointer(), "sys_ksem_destroy"}, + {sysImplPointer(), "sys___mac_get_pid"}, + {sysImplPointer(), "sys___mac_get_link"}, + {sysImplPointer(), "sys___mac_set_link"}, + {sysImplPointer(), "sys_extattr_set_link"}, + {sysImplPointer(), "sys_extattr_get_link"}, + {sysImplPointer(), "sys_extattr_delete_link"}, + {sysImplPointer(), "sys___mac_execve"}, + {sysImplPointer(), "sys_sigaction"}, + {sysImplPointer(), "sys_sigreturn"}, + {sysImplPointer(), "sys_getcontext"}, + {sysImplPointer(), "sys_setcontext"}, + {sysImplPointer(), "sys_swapcontext"}, + {sysImplPointer(), "sys_swapoff"}, + {sysImplPointer(), "sys___acl_get_link"}, + {sysImplPointer(), "sys___acl_set_link"}, + {sysImplPointer(), "sys___acl_delete_link"}, + {sysImplPointer(), "sys___acl_aclcheck_link"}, + {sysImplPointer(), "sys_sigwait"}, + {sysImplPointer(), "sys_thr_create"}, + {sysImplPointer(), "sys_thr_exit"}, + {sysImplPointer(), "sys_thr_self"}, + {sysImplPointer(), "sys_thr_kill"}, + {sysImplPointer(), "sys__umtx_lock"}, + {sysImplPointer(), "sys__umtx_unlock"}, + {sysImplPointer(), "sys_jail_attach"}, + {sysImplPointer(), "sys_extattr_list_fd"}, + {sysImplPointer(), "sys_extattr_list_file"}, + {sysImplPointer(), "sys_extattr_list_link"}, + {sysImplPointer(), "sys_ksem_timedwait"}, + {sysImplPointer(), "sys_thr_suspend"}, + {sysImplPointer(), "sys_thr_wake"}, + {sysImplPointer(), "sys_kldunloadf"}, + {sysImplPointer(), "sys_audit"}, + {sysImplPointer(), "sys_auditon"}, + {sysImplPointer(), "sys_getauid"}, + {sysImplPointer(), "sys_setauid"}, + {sysImplPointer(), "sys_getaudit"}, + {sysImplPointer(), "sys_setaudit"}, + {sysImplPointer(), "sys_getaudit_addr"}, + {sysImplPointer(), "sys_setaudit_addr"}, + {sysImplPointer(), "sys_auditctl"}, + {sysImplPointer(), "sys__umtx_op"}, + {sysImplPointer(), "sys_thr_new"}, + {sysImplPointer(), "sys_sigqueue"}, + {sysImplPointer(), "sys_kmq_open"}, + {sysImplPointer(), "sys_kmq_setattr"}, + {sysImplPointer(), "sys_kmq_timedreceive"}, + {sysImplPointer(), "sys_kmq_timedsend"}, + {sysImplPointer(), "sys_kmq_notify"}, + {sysImplPointer(), "sys_kmq_unlink"}, + {sysImplPointer(), "sys_abort2"}, + {sysImplPointer(), "sys_thr_set_name"}, + {sysImplPointer(), "sys_aio_fsync"}, + {sysImplPointer(), "sys_rtprio_thread"}, + {sysImplPointer(), "sys_sctp_peeloff"}, + {sysImplPointer(), + "sys_sctp_generic_sendmsg"}, + {sysImplPointer(), + "sys_sctp_generic_sendmsg_iov"}, + {sysImplPointer(), + "sys_sctp_generic_recvmsg"}, + {sysImplPointer(), "sys_pread"}, + {sysImplPointer(), "sys_pwrite"}, + {sysImplPointer(), "sys_mmap"}, + {sysImplPointer(), "sys_lseek"}, + {sysImplPointer(), "sys_truncate"}, + {sysImplPointer(), "sys_ftruncate"}, + {sysImplPointer(), "sys_thr_kill2"}, + {sysImplPointer(), "sys_shm_open"}, + {sysImplPointer(), "sys_shm_unlink"}, + {sysImplPointer(), "sys_cpuset"}, + {sysImplPointer(), "sys_cpuset_setid"}, + {sysImplPointer(), "sys_cpuset_getid"}, + {sysImplPointer(), "sys_cpuset_getaffinity"}, + {sysImplPointer(), "sys_cpuset_setaffinity"}, + {sysImplPointer(), "sys_faccessat"}, + {sysImplPointer(), "sys_fchmodat"}, + {sysImplPointer(), "sys_fchownat"}, + {sysImplPointer(), "sys_fexecve"}, + {sysImplPointer(), "sys_fstatat"}, + {sysImplPointer(), "sys_futimesat"}, + {sysImplPointer(), "sys_linkat"}, + {sysImplPointer(), "sys_mkdirat"}, + {sysImplPointer(), "sys_mkfifoat"}, + {sysImplPointer(), "sys_mknodat"}, + {sysImplPointer(), "sys_openat"}, + {sysImplPointer(), "sys_readlinkat"}, + {sysImplPointer(), "sys_renameat"}, + {sysImplPointer(), "sys_symlinkat"}, + {sysImplPointer(), "sys_unlinkat"}, + {sysImplPointer(), "sys_posix_openpt"}, + {sysImplPointer(), "sys_gssd_syscall"}, + {sysImplPointer(), "sys_jail_get"}, + {sysImplPointer(), "sys_jail_set"}, + {sysImplPointer(), "sys_jail_remove"}, + {sysImplPointer(), "sys_closefrom"}, + {sysImplPointer(), "sys___semctl"}, + {sysImplPointer(), "sys_msgctl"}, + {sysImplPointer(), "sys_shmctl"}, + {sysImplPointer(), "sys_lpathconf"}, + {sysImplPointer(), "sys_cap_new"}, + {sysImplPointer(), "sys_cap_getrights"}, + {sysImplPointer(), "sys_cap_enter"}, + {sysImplPointer(), "sys_cap_getmode"}, + {sysImplPointer(), "sys_pdfork"}, + {sysImplPointer(), "sys_pdkill"}, + {sysImplPointer(), "sys_pdgetpid"}, + {sysImplPointer(), "sys_pselect"}, + {sysImplPointer(), "sys_getloginclass"}, + {sysImplPointer(), "sys_setloginclass"}, + {sysImplPointer(), "sys_rctl_get_racct"}, + {sysImplPointer(), "sys_rctl_get_rules"}, + {sysImplPointer(), "sys_rctl_get_limits"}, + {sysImplPointer(), "sys_rctl_add_rule"}, + {sysImplPointer(), "sys_rctl_remove_rule"}, + {sysImplPointer(), "sys_posix_fallocate"}, + {sysImplPointer(), "sys_posix_fadvise"}, + {sysImplPointer(), "sys_netcontrol"}, + {sysImplPointer(), "sys_netabort"}, + {sysImplPointer(), "sys_netgetsockinfo"}, + {sysImplPointer(), "sys_socketex"}, + {sysImplPointer(), "sys_socketclose"}, + {sysImplPointer(), "sys_netgetiflist"}, + {sysImplPointer(), "sys_kqueueex"}, + {sysImplPointer(), "sys_mtypeprotect"}, + {sysImplPointer(), "sys_regmgr_call"}, + {sysImplPointer(), "sys_jitshm_create"}, + {sysImplPointer(), "sys_jitshm_alias"}, + {sysImplPointer(), "sys_dl_get_list"}, + {sysImplPointer(), "sys_dl_get_info"}, + {sysImplPointer(), "sys_dl_notify_event"}, + {sysImplPointer(), "sys_evf_create"}, + {sysImplPointer(), "sys_evf_delete"}, + {sysImplPointer(), "sys_evf_open"}, + {sysImplPointer(), "sys_evf_close"}, + {sysImplPointer(), "sys_evf_wait"}, + {sysImplPointer(), "sys_evf_trywait"}, + {sysImplPointer(), "sys_evf_set"}, + {sysImplPointer(), "sys_evf_clear"}, + {sysImplPointer(), "sys_evf_cancel"}, + {sysImplPointer(), + "sys_query_memory_protection"}, + {sysImplPointer(), "sys_batch_map"}, + {sysImplPointer(), "sys_osem_create"}, + {sysImplPointer(), "sys_osem_delete"}, + {sysImplPointer(), "sys_osem_open"}, + {sysImplPointer(), "sys_osem_close"}, + {sysImplPointer(), "sys_osem_wait"}, + {sysImplPointer(), "sys_osem_trywait"}, + {sysImplPointer(), "sys_osem_post"}, + {sysImplPointer(), "sys_osem_cancel"}, + {sysImplPointer(), "sys_namedobj_create"}, + {sysImplPointer(), "sys_namedobj_delete"}, + {sysImplPointer(), "sys_set_vm_container"}, + {sysImplPointer(), "sys_debug_init"}, + {sysImplPointer(), "sys_suspend_process"}, + {sysImplPointer(), "sys_resume_process"}, + {sysImplPointer(), "sys_opmc_enable"}, + {sysImplPointer(), "sys_opmc_disable"}, + {sysImplPointer(), "sys_opmc_set_ctl"}, + {sysImplPointer(), "sys_opmc_set_ctr"}, + {sysImplPointer(), "sys_opmc_get_ctr"}, + {sysImplPointer(), "sys_budget_create"}, + {sysImplPointer(), "sys_budget_delete"}, + {sysImplPointer(), "sys_budget_get"}, + {sysImplPointer(), "sys_budget_set"}, + {sysImplPointer(), "sys_virtual_query"}, + {sysImplPointer(), "sys_mdbg_call"}, + {sysImplPointer(), "sys_obs_sblock_create"}, + {sysImplPointer(), "sys_obs_sblock_delete"}, + {sysImplPointer(), "sys_obs_sblock_enter"}, + {sysImplPointer(), "sys_obs_sblock_exit"}, + {sysImplPointer(), "sys_obs_sblock_xenter"}, + {sysImplPointer(), "sys_obs_sblock_xexit"}, + {sysImplPointer(), "sys_obs_eport_create"}, + {sysImplPointer(), "sys_obs_eport_delete"}, + {sysImplPointer(), "sys_obs_eport_trigger"}, + {sysImplPointer(), "sys_obs_eport_open"}, + {sysImplPointer(), "sys_obs_eport_close"}, + {sysImplPointer(), "sys_is_in_sandbox"}, + {sysImplPointer(), "sys_dmem_container"}, + {sysImplPointer(), "sys_get_authinfo"}, + {sysImplPointer(), "sys_mname"}, + {sysImplPointer(), "sys_dynlib_dlopen"}, + {sysImplPointer(), "sys_dynlib_dlclose"}, + {sysImplPointer(), "sys_dynlib_dlsym"}, + {sysImplPointer(), "sys_dynlib_get_list"}, + {sysImplPointer(), "sys_dynlib_get_info"}, + {sysImplPointer(), "sys_dynlib_load_prx"}, + {sysImplPointer(), "sys_dynlib_unload_prx"}, + {sysImplPointer(), + "sys_dynlib_do_copy_relocations"}, + {sysImplPointer(), + "sys_dynlib_prepare_dlclose"}, + {sysImplPointer(), + "sys_dynlib_get_proc_param"}, + {sysImplPointer(), + "sys_dynlib_process_needed_and_relocate"}, + {sysImplPointer(), "sys_sandbox_path"}, + {sysImplPointer(), "sys_mdbg_service"}, + {sysImplPointer(), "sys_randomized_path"}, + {sysImplPointer(), "sys_rdup"}, + {sysImplPointer(), "sys_dl_get_metadata"}, + {sysImplPointer(), "sys_workaround8849"}, + {sysImplPointer(), "sys_is_development_mode"}, + {sysImplPointer(), "sys_get_self_auth_info"}, + {sysImplPointer(), "sys_dynlib_get_info_ex"}, + {sysImplPointer(), "sys_budget_getid"}, + {sysImplPointer(), "sys_budget_get_ptype"}, + {sysImplPointer(), + "sys_get_paging_stats_of_all_threads"}, + {sysImplPointer(), "sys_get_proc_type_info"}, + {sysImplPointer(), "sys_get_resident_count"}, + {sysImplPointer(), + "sys_prepare_to_suspend_process"}, + {sysImplPointer(), + "sys_get_resident_fmem_count"}, + {sysImplPointer(), "sys_thr_get_name"}, + {sysImplPointer(), "sys_set_gpo"}, + {sysImplPointer(), + "sys_get_paging_stats_of_all_objects"}, + {sysImplPointer(), "sys_test_debug_rwmem"}, + {sysImplPointer(), "sys_free_stack"}, + {sysImplPointer(), "sys_suspend_system"}, + {sysImplPointer(), "sys_ipmimgr_call"}, + {sysImplPointer(), "sys_get_gpo"}, + {sysImplPointer(), + "sys_get_vm_map_timestamp"}, + {sysImplPointer(), "sys_opmc_set_hw"}, + {sysImplPointer(), "sys_opmc_get_hw"}, + {sysImplPointer(), "sys_get_cpu_usage_all"}, + {sysImplPointer(), "sys_mmap_dmem"}, + {sysImplPointer(), "sys_physhm_open"}, + {sysImplPointer(), "sys_physhm_unlink"}, + {sysImplPointer(), "sys_resume_internal_hdd"}, + {sysImplPointer(), + "sys_thr_suspend_ucontext"}, + {sysImplPointer(), "sys_thr_resume_ucontext"}, + {sysImplPointer(), "sys_thr_get_ucontext"}, + {sysImplPointer(), "sys_thr_set_ucontext"}, + {sysImplPointer(), "sys_set_timezone_info"}, + {sysImplPointer(), "sys_set_phys_fmem_limit"}, + {sysImplPointer(), "sys_utc_to_localtime"}, + {sysImplPointer(), "sys_localtime_to_utc"}, + {sysImplPointer(), "sys_set_uevt"}, + {sysImplPointer(), "sys_get_cpu_usage_proc"}, + {sysImplPointer(), "sys_get_map_statistics"}, + {sysImplPointer(), + "sys_set_chicken_switches"}, + {sysImplPointer(), + "sys_extend_page_table_pool"}, + {sysImplPointer(), + "sys_extend_page_table_pool2"}, + {sysImplPointer(), + "sys_get_kernel_mem_statistics"}, + {sysImplPointer(), + "sys_get_sdk_compiled_version"}, + {sysImplPointer(), "sys_app_state_change"}, + {sysImplPointer(), + "sys_dynlib_get_obj_member"}, + {sysImplPointer(), + "sys_budget_get_ptype_of_budget"}, + {sysImplPointer(), + "sys_prepare_to_resume_process"}, + {sysImplPointer(), "sys_process_terminate"}, + {sysImplPointer(), "sys_blockpool_open"}, + {sysImplPointer(), "sys_blockpool_map"}, + {sysImplPointer(), "sys_blockpool_unmap"}, + {sysImplPointer(), + "sys_dynlib_get_info_for_libdbg"}, + {sysImplPointer(), "sys_blockpool_batch"}, + {sysImplPointer(), "sys_fdatasync"}, + {sysImplPointer(), "sys_dynlib_get_list2"}, + {sysImplPointer(), "sys_dynlib_get_info2"}, + {sysImplPointer(), "sys_aio_submit"}, + {sysImplPointer(), "sys_aio_multi_delete"}, + {sysImplPointer(), "sys_aio_multi_wait"}, + {sysImplPointer(), "sys_aio_multi_poll"}, + {sysImplPointer(), "sys_aio_get_data"}, + {sysImplPointer(), "sys_aio_multi_cancel"}, + {sysImplPointer(), "sys_get_bio_usage_all"}, + {sysImplPointer(), "sys_aio_create"}, + {sysImplPointer(), "sys_aio_submit_cmd"}, + {sysImplPointer(), "sys_aio_init"}, + {sysImplPointer(), + "sys_get_page_table_stats"}, + {sysImplPointer(), + "sys_dynlib_get_list_for_libdbg"}, + {sysImplPointer(), "sys_blockpool_move"}, + {sysImplPointer(), "sys_virtual_query_all"}, + {sysImplPointer(), "sys_reserve_2mb_page"}, + {sysImplPointer(), "sys_cpumode_yield"}, + {sysImplPointer(), "sys_wait6"}, + {sysImplPointer(), "sys_cap_rights_limit"}, + {sysImplPointer(), "sys_cap_ioctls_limit"}, + {sysImplPointer(), "sys_cap_ioctls_get"}, + {sysImplPointer(), "sys_cap_fcntls_limit"}, + {sysImplPointer(), "sys_cap_fcntls_get"}, + {sysImplPointer(), "sys_bindat"}, + {sysImplPointer(), "sys_connectat"}, + {sysImplPointer(), "sys_chflagsat"}, + {sysImplPointer(), "sys_accept4"}, + {sysImplPointer(), "sys_pipe2"}, + {sysImplPointer(), "sys_aio_mlock"}, + {sysImplPointer(), "sys_procctl"}, + {sysImplPointer(), "sys_ppoll"}, + {sysImplPointer(), "sys_futimens"}, + {sysImplPointer(), "sys_utimensat"}, + {sysImplPointer(), "sys_numa_getaffinity"}, + {sysImplPointer(), "sys_numa_setaffinity"}, + {sysImplPointer(), "sys_apr_submit"}, + {sysImplPointer(), "sys_apr_resolve"}, + {sysImplPointer(), "sys_apr_stat"}, + {sysImplPointer(), "sys_apr_wait"}, + {sysImplPointer(), "sys_apr_ctrl"}, + {sysImplPointer(), "sys_get_phys_page_size"}, + {sysImplPointer(), "sys_begin_app_mount"}, + {sysImplPointer(), "sys_end_app_mount"}, + {sysImplPointer(), "sys_fsc2h_ctrl"}, + {sysImplPointer(), "sys_streamwrite"}, + {sysImplPointer(), "sys_app_save"}, + {sysImplPointer(), "sys_app_restore"}, + {sysImplPointer(), "sys_saved_app_delete"}, + {sysImplPointer(), + "sys_get_ppr_sdk_compiled_version"}, + {sysImplPointer(), "sys_notify_app_event"}, + {sysImplPointer(), "sys_ioreq"}, + {sysImplPointer(), "sys_openintr"}, + {sysImplPointer(), "sys_dl_get_info_2"}, + {sysImplPointer(), "sys_acinfo_add"}, + {sysImplPointer(), "sys_acinfo_delete"}, + {sysImplPointer(), + "sys_acinfo_get_all_for_coredump"}, + {sysImplPointer(), "sys_ampr_ctrl_debug"}, + {sysImplPointer(), "sys_workspace_ctrl"}, + }; -const char *getSysentName(SysResult (*sysent)(Thread *, uint64_t *)) { - auto it = std::find_if( - std::begin(gImplToName), std::end(gImplToName), - [=](std::pair elem) { - return sysent == elem.first; - }); + const char* getSysentName(SysResult (*sysent)(Thread*, uint64_t*)) + { + auto it = std::find_if( + std::begin(gImplToName), std::end(gImplToName), + [=](std::pair elem) { + return sysent == elem.first; + }); - if (it == std::end(gImplToName)) { - return nullptr; - } + if (it == std::end(gImplToName)) + { + return nullptr; + } - return it->second; -} + return it->second; + } -static constexpr sysent freebsd9_sysent[] = { - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), -}; + static constexpr sysent freebsd9_sysent[] = { + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + }; -// TODO -static constexpr sysent freebsd11_sysent[] = { - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), -}; + // TODO + static constexpr sysent freebsd11_sysent[] = { + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + }; -static constexpr sysent ps4_sysent[] = { - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), - wrap(), -}; + static constexpr sysent ps4_sysent[] = { + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + wrap(), + }; -constinit sysentvec freebsd9_sysvec = {.size = std::size(freebsd9_sysent), - .table = freebsd9_sysent}; + constinit sysentvec freebsd9_sysvec = {.size = std::size(freebsd9_sysent), + .table = freebsd9_sysent}; -constinit sysentvec freebsd11_sysvec = {.size = std::size(freebsd11_sysent), - .table = freebsd11_sysent}; + constinit sysentvec freebsd11_sysvec = {.size = std::size(freebsd11_sysent), + .table = freebsd11_sysent}; -constinit sysentvec ps4_sysvec = {.size = std::size(ps4_sysent), - .table = ps4_sysent}; + constinit sysentvec ps4_sysvec = {.size = std::size(ps4_sysent), + .table = ps4_sysent}; -constinit sysentvec ps5_sysvec = {.size = 0, .table = nullptr}; + constinit sysentvec ps5_sysvec = {.size = 0, .table = nullptr}; } // namespace orbis diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index 624b6537..a6750e55 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -5,522 +5,611 @@ #include "orbis/utils/Logs.hpp" #include "time.hpp" -namespace orbis { -std::pair *UmtxChain::enqueue(UmtxKey &key, - Thread *thr) { - if (!spare_queue.empty()) { - auto node = spare_queue.extract(spare_queue.begin()); - node.key() = key; - node.mapped().thr = thr; - return &*sleep_queue.insert(std::move(node)); - } - return &*sleep_queue.emplace(key, thr); -} - -void UmtxChain::erase(std::pair *obj) { - for (auto [it, e] = sleep_queue.equal_range(obj->first); it != e; it++) { - if (&*it == obj) { - auto node = sleep_queue.extract(it); - node.key() = {}; - spare_queue.insert(spare_queue.begin(), std::move(node)); - return; - } - } -} - -uint UmtxChain::notify_one(const UmtxKey &key) { - auto it = sleep_queue.find(key); - if (it == sleep_queue.end()) - return 0; - it->second.thr = nullptr; - it->second.cv.notify_one(mtx); - this->erase(&*it); - return 1; -} - -uint UmtxChain::notify_all(const UmtxKey &key) { - uint n = 0; - while (notify_one(key)) - n++; - return n; -} +namespace orbis +{ + std::pair* UmtxChain::enqueue(UmtxKey& key, + Thread* thr) + { + if (!spare_queue.empty()) + { + auto node = spare_queue.extract(spare_queue.begin()); + node.key() = key; + node.mapped().thr = thr; + return &*sleep_queue.insert(std::move(node)); + } + return &*sleep_queue.emplace(key, thr); + } + + void UmtxChain::erase(std::pair* obj) + { + for (auto [it, e] = sleep_queue.equal_range(obj->first); it != e; it++) + { + if (&*it == obj) + { + auto node = sleep_queue.extract(it); + node.key() = {}; + spare_queue.insert(spare_queue.begin(), std::move(node)); + return; + } + } + } + + uint UmtxChain::notify_one(const UmtxKey& key) + { + auto it = sleep_queue.find(key); + if (it == sleep_queue.end()) + return 0; + it->second.thr = nullptr; + it->second.cv.notify_one(mtx); + this->erase(&*it); + return 1; + } + + uint UmtxChain::notify_all(const UmtxKey& key) + { + uint n = 0; + while (notify_one(key)) + n++; + return n; + } } // namespace orbis -orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr umtx, ulong id, - std::uint64_t ut) { - ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id, ut); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr umtx, - ulong id) { - ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr addr, ulong id, - std::uint64_t ut, bool is32, bool ipc) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, id, ut, is32); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, ipc, addr); - auto node = chain.enqueue(key, thread); - ErrorCode result = {}; - ulong val = 0; - if (is32) - val = reinterpret_cast>>(addr)->load(); - else - val = reinterpret_cast>>(addr)->load(); - if (val == id) { - if (ut + 1 == 0) { - while (true) { - node->second.cv.wait(chain.mtx); - if (node->second.thr != thread) - break; - } - } else { - auto start = std::chrono::steady_clock::now(); - std::uint64_t udiff = 0; - while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); - if (node->second.thr != thread) - break; - udiff = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count(); - if (udiff >= ut) { - result = ErrorCode::TIMEDOUT; - break; - } - } - } - } - if (node->second.thr == thread) - chain.erase(node); - return result; -} - -orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr addr, sint n_wake) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, true, addr); - std::size_t count = chain.sleep_queue.count(key); - if (key.pid == 0) { - // IPC workaround (TODO) - chain.notify_all(key); - return {}; - } - // TODO: check this - while (count--) { - chain.notify_one(key); - if (n_wake-- <= 1) - break; - } - return {}; -} - -namespace orbis { -enum class umutex_lock_mode { - lock, - try_, - wait, -}; -template <> -void log_class_string::format(std::string &out, - const void *arg) { - switch (get_object(arg)) { - case umutex_lock_mode::lock: - out += "lock"; - break; - case umutex_lock_mode::try_: - out += "try"; - break; - case umutex_lock_mode::wait: - out += "wait"; - break; - } -} -static ErrorCode do_lock_normal(Thread *thread, ptr m, uint flags, - std::uint64_t ut, umutex_lock_mode mode) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags, ut, mode); - - ErrorCode error = {}; - while (true) { - int owner = m->owner.load(std::memory_order_acquire); - if (mode == umutex_lock_mode::wait) { - if (owner == kUmutexUnowned || owner == kUmutexContested) - return {}; - } else { - owner = kUmutexUnowned; - if (m->owner.compare_exchange_strong(owner, thread->tid)) - return {}; - if (owner == kUmutexContested) { - if (m->owner.compare_exchange_strong(owner, - thread->tid | kUmutexContested)) - return {}; - continue; - } - } - - if ((flags & kUmutexErrorCheck) != 0 && - (owner & ~kUmutexContested) == thread->tid) - return ErrorCode::DEADLK; - - if (mode == umutex_lock_mode::try_) - return ErrorCode::BUSY; - - if (error != ErrorCode{}) - return error; - - auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); - auto node = chain.enqueue(key, thread); - if (m->owner.compare_exchange_strong(owner, owner | kUmutexContested)) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr == thread) { - error = ErrorCode::TIMEDOUT; - } - } - if (node->second.thr == thread) - chain.erase(node); - } - - return {}; -} -static ErrorCode do_lock_pi(Thread *thread, ptr m, uint flags, - std::uint64_t ut, umutex_lock_mode mode) { - ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode); - return do_lock_normal(thread, m, flags, ut, mode); -} -static ErrorCode do_lock_pp(Thread *thread, ptr m, uint flags, - std::uint64_t ut, umutex_lock_mode mode) { - ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode); - return ErrorCode::NOSYS; -} -static ErrorCode do_unlock_normal(Thread *thread, ptr m, uint flags) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags); - - int owner = m->owner.load(std::memory_order_acquire); - if ((owner & ~kUmutexContested) != thread->tid) - return ErrorCode::PERM; - - if ((owner & kUmtxContested) == 0) { - if (m->owner.compare_exchange_strong(owner, kUmutexUnowned)) - return {}; - } - - auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); - std::size_t count = chain.sleep_queue.count(key); - bool ok = m->owner.compare_exchange_strong( - owner, count <= 1 ? kUmutexUnowned : kUmutexContested); - if (key.pid == 0) { - // IPC workaround (TODO) - chain.notify_all(key); - if (!ok) - return ErrorCode::INVAL; - return {}; - } - if (count) - chain.notify_one(key); - if (!ok) - return ErrorCode::INVAL; - return {}; -} -static ErrorCode do_unlock_pi(Thread *thread, ptr m, uint flags) { - return do_unlock_normal(thread, m, flags); -} -static ErrorCode do_unlock_pp(Thread *thread, ptr m, uint flags) { - ORBIS_LOG_TODO(__FUNCTION__, m, flags); - return ErrorCode::NOSYS; -} +orbis::ErrorCode orbis::umtx_lock_umtx(Thread* thread, ptr umtx, ulong id, + std::uint64_t ut) +{ + ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id, ut); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_unlock_umtx(Thread* thread, ptr umtx, + ulong id) +{ + ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_wait(Thread* thread, ptr addr, ulong id, + std::uint64_t ut, bool is32, bool ipc) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, id, ut, is32); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, ipc, addr); + auto node = chain.enqueue(key, thread); + ErrorCode result = {}; + ulong val = 0; + if (is32) + val = reinterpret_cast>>(addr)->load(); + else + val = reinterpret_cast>>(addr)->load(); + if (val == id) + { + if (ut + 1 == 0) + { + while (true) + { + node->second.cv.wait(chain.mtx); + if (node->second.thr != thread) + break; + } + } + else + { + auto start = std::chrono::steady_clock::now(); + std::uint64_t udiff = 0; + while (true) + { + node->second.cv.wait(chain.mtx, ut - udiff); + if (node->second.thr != thread) + break; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (udiff >= ut) + { + result = ErrorCode::TIMEDOUT; + break; + } + } + } + } + if (node->second.thr == thread) + chain.erase(node); + return result; +} + +orbis::ErrorCode orbis::umtx_wake(Thread* thread, ptr addr, sint n_wake) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, true, addr); + std::size_t count = chain.sleep_queue.count(key); + if (key.pid == 0) + { + // IPC workaround (TODO) + chain.notify_all(key); + return {}; + } + // TODO: check this + while (count--) + { + chain.notify_one(key); + if (n_wake-- <= 1) + break; + } + return {}; +} + +namespace orbis +{ + enum class umutex_lock_mode + { + lock, + try_, + wait, + }; + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + switch (get_object(arg)) + { + case umutex_lock_mode::lock: + out += "lock"; + break; + case umutex_lock_mode::try_: + out += "try"; + break; + case umutex_lock_mode::wait: + out += "wait"; + break; + } + } + static ErrorCode do_lock_normal(Thread* thread, ptr m, uint flags, + std::uint64_t ut, umutex_lock_mode mode) + { + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags, ut, mode); + + ErrorCode error = {}; + while (true) + { + int owner = m->owner.load(std::memory_order_acquire); + if (mode == umutex_lock_mode::wait) + { + if (owner == kUmutexUnowned || owner == kUmutexContested) + return {}; + } + else + { + owner = kUmutexUnowned; + if (m->owner.compare_exchange_strong(owner, thread->tid)) + return {}; + if (owner == kUmutexContested) + { + if (m->owner.compare_exchange_strong(owner, + thread->tid | kUmutexContested)) + return {}; + continue; + } + } + + if ((flags & kUmutexErrorCheck) != 0 && + (owner & ~kUmutexContested) == thread->tid) + return ErrorCode::DEADLK; + + if (mode == umutex_lock_mode::try_) + return ErrorCode::BUSY; + + if (error != ErrorCode{}) + return error; + + auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); + auto node = chain.enqueue(key, thread); + if (m->owner.compare_exchange_strong(owner, owner | kUmutexContested)) + { + node->second.cv.wait(chain.mtx, ut); + if (node->second.thr == thread) + { + error = ErrorCode::TIMEDOUT; + } + } + if (node->second.thr == thread) + chain.erase(node); + } + + return {}; + } + static ErrorCode do_lock_pi(Thread* thread, ptr m, uint flags, + std::uint64_t ut, umutex_lock_mode mode) + { + ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode); + return do_lock_normal(thread, m, flags, ut, mode); + } + static ErrorCode do_lock_pp(Thread* thread, ptr m, uint flags, + std::uint64_t ut, umutex_lock_mode mode) + { + ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode); + return ErrorCode::NOSYS; + } + static ErrorCode do_unlock_normal(Thread* thread, ptr m, uint flags) + { + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags); + + int owner = m->owner.load(std::memory_order_acquire); + if ((owner & ~kUmutexContested) != thread->tid) + return ErrorCode::PERM; + + if ((owner & kUmtxContested) == 0) + { + if (m->owner.compare_exchange_strong(owner, kUmutexUnowned)) + return {}; + } + + auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); + std::size_t count = chain.sleep_queue.count(key); + bool ok = m->owner.compare_exchange_strong( + owner, count <= 1 ? kUmutexUnowned : kUmutexContested); + if (key.pid == 0) + { + // IPC workaround (TODO) + chain.notify_all(key); + if (!ok) + return ErrorCode::INVAL; + return {}; + } + if (count) + chain.notify_one(key); + if (!ok) + return ErrorCode::INVAL; + return {}; + } + static ErrorCode do_unlock_pi(Thread* thread, ptr m, uint flags) + { + return do_unlock_normal(thread, m, flags); + } + static ErrorCode do_unlock_pp(Thread* thread, ptr m, uint flags) + { + ORBIS_LOG_TODO(__FUNCTION__, m, flags); + return ErrorCode::NOSYS; + } } // namespace orbis -orbis::ErrorCode orbis::umtx_trylock_umutex(Thread *thread, ptr m) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m); - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) { - case 0: - return do_lock_normal(thread, m, flags, 0, umutex_lock_mode::try_); - case kUmutexPrioInherit: - return do_lock_pi(thread, m, flags, 0, umutex_lock_mode::try_); - case kUmutexPrioProtect: - return do_lock_pp(thread, m, flags, 0, umutex_lock_mode::try_); - } - return ErrorCode::INVAL; -} - -orbis::ErrorCode orbis::umtx_lock_umutex(Thread *thread, ptr m, - std::uint64_t ut) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, ut); - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) { - case 0: - return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::lock); - case kUmutexPrioInherit: - return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::lock); - case kUmutexPrioProtect: - return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::lock); - } - return ErrorCode::INVAL; -} - -orbis::ErrorCode orbis::umtx_unlock_umutex(Thread *thread, ptr m) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m); - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) { - case 0: - return do_unlock_normal(thread, m, flags); - case kUmutexPrioInherit: - return do_unlock_pi(thread, m, flags); - case kUmutexPrioProtect: - return do_unlock_pp(thread, m, flags); - } - return ErrorCode::INVAL; -} - -orbis::ErrorCode orbis::umtx_set_ceiling(Thread *thread, ptr m, - std::uint32_t ceiling, - ptr oldCeiling) { - ORBIS_LOG_TODO(__FUNCTION__, m, ceiling, oldCeiling); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, - ptr m, std::uint64_t ut, - ulong wflags) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv, m, ut, wflags); - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - if ((wflags & ~(kCvWaitAbsTime | kCvWaitClockId))) { - ORBIS_LOG_FATAL("umtx_cv_wait: UNKNOWN wflags", wflags); - return ErrorCode::INVAL; - } - if ((wflags & kCvWaitClockId) != 0 && ut + 1) { - ORBIS_LOG_FATAL("umtx_cv_wait: CLOCK_ID unimplemented", wflags); - return ErrorCode::NOSYS; - } - if ((wflags & kCvWaitAbsTime) != 0 && ut + 1) { - ORBIS_LOG_FATAL("umtx_cv_wait: ABSTIME unimplemented", wflags); - return ErrorCode::NOSYS; - } - - auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); - auto node = chain.enqueue(key, thread); - - if (!cv->has_waiters.load(std::memory_order::relaxed)) - cv->has_waiters.store(1, std::memory_order::relaxed); - - ErrorCode result = umtx_unlock_umutex(thread, m); - if (result == ErrorCode{}) { - if (ut + 1 == 0) { - while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) - break; - } - } else { - auto start = std::chrono::steady_clock::now(); - std::uint64_t udiff = 0; - while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); - if (node->second.thr != thread) - break; - udiff = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count(); - if (udiff >= ut) { - result = ErrorCode::TIMEDOUT; - break; - } - } - } - } - - if (node->second.thr != thread) { - result = {}; - } else { - chain.erase(node); - if (chain.sleep_queue.count(key) == 0) - cv->has_waiters.store(0, std::memory_order::relaxed); - } - return result; -} - -orbis::ErrorCode orbis::umtx_cv_signal(Thread *thread, ptr cv) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); - if (key.pid == 0) { - // IPC workaround (TODO) - chain.notify_all(key); - cv->has_waiters = 0; - return {}; - } - std::size_t count = chain.sleep_queue.count(key); - if (chain.notify_one(key) >= count) - cv->has_waiters.store(0, std::memory_order::relaxed); - return {}; -} - -orbis::ErrorCode orbis::umtx_cv_broadcast(Thread *thread, ptr cv) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); - chain.notify_all(key); - cv->has_waiters.store(0, std::memory_order::relaxed); - return {}; -} - -orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr obj, - std::int64_t val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr obj, - std::int64_t val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_rw_unlock(Thread *thread, ptr obj, - std::int64_t val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); - return ErrorCode::NOSYS; -} - -orbis::ErrorCode orbis::umtx_wake_private(Thread *thread, ptr addr, - sint n_wake) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, false, addr); - std::size_t count = chain.sleep_queue.count(key); - // TODO: check this - while (count--) { - chain.notify_one(key); - if (n_wake-- <= 1) - break; - } - return {}; -} - -orbis::ErrorCode orbis::umtx_wait_umutex(Thread *thread, ptr m, - std::uint64_t ut) { - ORBIS_LOG_TRACE(__FUNCTION__, m, ut); - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) { - case 0: - return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::wait); - case kUmutexPrioInherit: - return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::wait); - case kUmutexPrioProtect: - return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::wait); - } - return ErrorCode::INVAL; -} - -orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr m) { - ORBIS_LOG_TRACE(__FUNCTION__, m); - int owner = m->owner.load(std::memory_order::acquire); - if ((owner & ~kUmutexContested) != 0) - return {}; - - uint flags; - if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) - return err; - - auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); - std::size_t count = chain.sleep_queue.count(key); - if (count <= 1) { - owner = kUmutexContested; - m->owner.compare_exchange_strong(owner, kUmutexUnowned); - } - if (count != 0 && (owner & ~kUmutexContested) == 0) - chain.notify_one(key); - return {}; -} - -orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr sem, - std::uint64_t ut) { - ORBIS_LOG_TRACE(__FUNCTION__, sem, ut); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem); - auto node = chain.enqueue(key, thread); - - std::uint32_t has_waiters = sem->has_waiters; - if (!has_waiters) - sem->has_waiters.compare_exchange_strong(has_waiters, 1); - - ErrorCode result = {}; - if (!sem->count) { - if (ut + 1 == 0) { - while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) - break; - } - } else { - auto start = std::chrono::steady_clock::now(); - std::uint64_t udiff = 0; - while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); - if (node->second.thr != thread) - break; - udiff = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count(); - if (udiff >= ut) { - result = ErrorCode::TIMEDOUT; - break; - } - } - } - } - - if (node->second.thr != thread) { - result = {}; - } else { - chain.erase(node); - } - return result; -} - -orbis::ErrorCode orbis::umtx_sem_wake(Thread *thread, ptr sem) { - ORBIS_LOG_TRACE(__FUNCTION__, sem); - auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem); - if (key.pid == 0) { - // IPC workaround (TODO) - chain.notify_all(key); - sem->has_waiters = 0; - return {}; - } - std::size_t count = chain.sleep_queue.count(key); - if (chain.notify_one(key) >= count) - sem->has_waiters.store(0, std::memory_order::relaxed); - return {}; -} - -orbis::ErrorCode orbis::umtx_nwake_private(Thread *thread, ptr uaddrs, - std::int64_t count) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, uaddrs, count); - while (count-- > 0) { - void *uaddr; - auto error = uread(uaddr, uaddrs++); - if (error != ErrorCode{}) - return error; - umtx_wake_private(thread, uaddr, 1); - } - return {}; -} - -orbis::ErrorCode orbis::umtx_wake2_umutex(Thread *thread, ptr obj, - std::int64_t val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); - return ErrorCode::NOSYS; +orbis::ErrorCode orbis::umtx_trylock_umutex(Thread* thread, ptr m) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m); + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) + { + case 0: + return do_lock_normal(thread, m, flags, 0, umutex_lock_mode::try_); + case kUmutexPrioInherit: + return do_lock_pi(thread, m, flags, 0, umutex_lock_mode::try_); + case kUmutexPrioProtect: + return do_lock_pp(thread, m, flags, 0, umutex_lock_mode::try_); + } + return ErrorCode::INVAL; +} + +orbis::ErrorCode orbis::umtx_lock_umutex(Thread* thread, ptr m, + std::uint64_t ut) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, ut); + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) + { + case 0: + return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::lock); + case kUmutexPrioInherit: + return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::lock); + case kUmutexPrioProtect: + return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::lock); + } + return ErrorCode::INVAL; +} + +orbis::ErrorCode orbis::umtx_unlock_umutex(Thread* thread, ptr m) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m); + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) + { + case 0: + return do_unlock_normal(thread, m, flags); + case kUmutexPrioInherit: + return do_unlock_pi(thread, m, flags); + case kUmutexPrioProtect: + return do_unlock_pp(thread, m, flags); + } + return ErrorCode::INVAL; +} + +orbis::ErrorCode orbis::umtx_set_ceiling(Thread* thread, ptr m, + std::uint32_t ceiling, + ptr oldCeiling) +{ + ORBIS_LOG_TODO(__FUNCTION__, m, ceiling, oldCeiling); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_cv_wait(Thread* thread, ptr cv, + ptr m, std::uint64_t ut, + ulong wflags) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv, m, ut, wflags); + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + if ((wflags & ~(kCvWaitAbsTime | kCvWaitClockId))) + { + ORBIS_LOG_FATAL("umtx_cv_wait: UNKNOWN wflags", wflags); + return ErrorCode::INVAL; + } + if ((wflags & kCvWaitClockId) != 0 && ut + 1) + { + ORBIS_LOG_FATAL("umtx_cv_wait: CLOCK_ID unimplemented", wflags); + return ErrorCode::NOSYS; + } + if ((wflags & kCvWaitAbsTime) != 0 && ut + 1) + { + ORBIS_LOG_FATAL("umtx_cv_wait: ABSTIME unimplemented", wflags); + return ErrorCode::NOSYS; + } + + auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); + auto node = chain.enqueue(key, thread); + + if (!cv->has_waiters.load(std::memory_order::relaxed)) + cv->has_waiters.store(1, std::memory_order::relaxed); + + ErrorCode result = umtx_unlock_umutex(thread, m); + if (result == ErrorCode{}) + { + if (ut + 1 == 0) + { + while (true) + { + node->second.cv.wait(chain.mtx, ut); + if (node->second.thr != thread) + break; + } + } + else + { + auto start = std::chrono::steady_clock::now(); + std::uint64_t udiff = 0; + while (true) + { + node->second.cv.wait(chain.mtx, ut - udiff); + if (node->second.thr != thread) + break; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (udiff >= ut) + { + result = ErrorCode::TIMEDOUT; + break; + } + } + } + } + + if (node->second.thr != thread) + { + result = {}; + } + else + { + chain.erase(node); + if (chain.sleep_queue.count(key) == 0) + cv->has_waiters.store(0, std::memory_order::relaxed); + } + return result; +} + +orbis::ErrorCode orbis::umtx_cv_signal(Thread* thread, ptr cv) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); + if (key.pid == 0) + { + // IPC workaround (TODO) + chain.notify_all(key); + cv->has_waiters = 0; + return {}; + } + std::size_t count = chain.sleep_queue.count(key); + if (chain.notify_one(key) >= count) + cv->has_waiters.store(0, std::memory_order::relaxed); + return {}; +} + +orbis::ErrorCode orbis::umtx_cv_broadcast(Thread* thread, ptr cv) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); + chain.notify_all(key); + cv->has_waiters.store(0, std::memory_order::relaxed); + return {}; +} + +orbis::ErrorCode orbis::umtx_rw_rdlock(Thread* thread, ptr obj, + std::int64_t val, ptr uaddr1, + ptr uaddr2) +{ + ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_rw_wrlock(Thread* thread, ptr obj, + std::int64_t val, ptr uaddr1, + ptr uaddr2) +{ + ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_rw_unlock(Thread* thread, ptr obj, + std::int64_t val, ptr uaddr1, + ptr uaddr2) +{ + ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); + return ErrorCode::NOSYS; +} + +orbis::ErrorCode orbis::umtx_wake_private(Thread* thread, ptr addr, + sint n_wake) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, false, addr); + std::size_t count = chain.sleep_queue.count(key); + // TODO: check this + while (count--) + { + chain.notify_one(key); + if (n_wake-- <= 1) + break; + } + return {}; +} + +orbis::ErrorCode orbis::umtx_wait_umutex(Thread* thread, ptr m, + std::uint64_t ut) +{ + ORBIS_LOG_TRACE(__FUNCTION__, m, ut); + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) + { + case 0: + return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::wait); + case kUmutexPrioInherit: + return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::wait); + case kUmutexPrioProtect: + return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::wait); + } + return ErrorCode::INVAL; +} + +orbis::ErrorCode orbis::umtx_wake_umutex(Thread* thread, ptr m) +{ + ORBIS_LOG_TRACE(__FUNCTION__, m); + int owner = m->owner.load(std::memory_order::acquire); + if ((owner & ~kUmutexContested) != 0) + return {}; + + uint flags; + if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{}) + return err; + + auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); + std::size_t count = chain.sleep_queue.count(key); + if (count <= 1) + { + owner = kUmutexContested; + m->owner.compare_exchange_strong(owner, kUmutexUnowned); + } + if (count != 0 && (owner & ~kUmutexContested) == 0) + chain.notify_one(key); + return {}; +} + +orbis::ErrorCode orbis::umtx_sem_wait(Thread* thread, ptr sem, + std::uint64_t ut) +{ + ORBIS_LOG_TRACE(__FUNCTION__, sem, ut); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem); + auto node = chain.enqueue(key, thread); + + std::uint32_t has_waiters = sem->has_waiters; + if (!has_waiters) + sem->has_waiters.compare_exchange_strong(has_waiters, 1); + + ErrorCode result = {}; + if (!sem->count) + { + if (ut + 1 == 0) + { + while (true) + { + node->second.cv.wait(chain.mtx, ut); + if (node->second.thr != thread) + break; + } + } + else + { + auto start = std::chrono::steady_clock::now(); + std::uint64_t udiff = 0; + while (true) + { + node->second.cv.wait(chain.mtx, ut - udiff); + if (node->second.thr != thread) + break; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (udiff >= ut) + { + result = ErrorCode::TIMEDOUT; + break; + } + } + } + } + + if (node->second.thr != thread) + { + result = {}; + } + else + { + chain.erase(node); + } + return result; +} + +orbis::ErrorCode orbis::umtx_sem_wake(Thread* thread, ptr sem) +{ + ORBIS_LOG_TRACE(__FUNCTION__, sem); + auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem); + if (key.pid == 0) + { + // IPC workaround (TODO) + chain.notify_all(key); + sem->has_waiters = 0; + return {}; + } + std::size_t count = chain.sleep_queue.count(key); + if (chain.notify_one(key) >= count) + sem->has_waiters.store(0, std::memory_order::relaxed); + return {}; +} + +orbis::ErrorCode orbis::umtx_nwake_private(Thread* thread, ptr uaddrs, + std::int64_t count) +{ + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, uaddrs, count); + while (count-- > 0) + { + void* uaddr; + auto error = uread(uaddr, uaddrs++); + if (error != ErrorCode{}) + return error; + umtx_wake_private(thread, uaddr, 1); + } + return {}; +} + +orbis::ErrorCode orbis::umtx_wake2_umutex(Thread* thread, ptr obj, + std::int64_t val, ptr uaddr1, + ptr uaddr2) +{ + ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); + return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/utils/Logs.cpp b/orbis-kernel/src/utils/Logs.cpp index b2abb09f..b8258736 100644 --- a/orbis-kernel/src/utils/Logs.cpp +++ b/orbis-kernel/src/utils/Logs.cpp @@ -8,530 +8,567 @@ #include #include -static void append_hex(std::string &out, std::unsigned_integral auto value) { - std::ostringstream buf; - if (value < 10) - buf << value; - else if (value >= decltype(value)(UINTMAX_MAX) - 1) - buf << "-" << std::uintmax_t(decltype(value)(-value)); - else - buf << "0x" << std::hex << std::uintmax_t(value); - out += buf.str(); +static void append_hex(std::string& out, std::unsigned_integral auto value) +{ + std::ostringstream buf; + if (value < 10) + buf << value; + else if (value >= decltype(value)(UINTMAX_MAX) - 1) + buf << "-" << std::uintmax_t(decltype(value)(-value)); + else + buf << "0x" << std::hex << std::uintmax_t(value); + out += buf.str(); } -namespace orbis::logs { -void log_class_string::format(std::string &out, const void *arg) { - const void *ptr = *reinterpret_cast(arg); - append_hex(out, reinterpret_cast(ptr)); -} - -void log_class_string::format_n(std::string &out, const void *arg, - std::size_t n) { - const char *ptr = reinterpret_cast(arg); - const auto addr = reinterpret_cast(ptr); - const auto _end = n ? addr + n - 1 : addr; - if (addr < 0x10000 || std::max(n, _end) > 0x7fff'ffff'ffff) { - out += "{{{{{BAD_ADDR:"; - append_hex(out, addr); - out += "}}}}}"; - return; - } - while (n--) { - const char c = *ptr++; - if (!c) - break; - out += c; - } -} - -void log_class_string::format(std::string &out, const void *arg) { - const char *ptr = *reinterpret_cast(arg); - const auto addr = reinterpret_cast(ptr); - if (addr < 0x10000 || addr > 0x7fff'ffff'ffff) { - out += "{{{{{BAD_ADDR:"; - append_hex(out, addr); - out += "}}}}}"; - return; - } - out += ptr; -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - out += get_object(arg); -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - out += get_object(arg); -} - -template <> -void log_class_string>::format(std::string &out, - const void *arg) { - const std::vector &obj = get_object(arg); - out.append(obj.cbegin(), obj.cend()); -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - const std::u8string &obj = get_object(arg); - out.append(obj.cbegin(), obj.cend()); -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - const std::u8string_view &obj = get_object(arg); - out.append(obj.cbegin(), obj.cend()); -} - -template <> -void log_class_string>::format(std::string &out, - const void *arg) { - const std::vector &obj = get_object(arg); - out.append(obj.cbegin(), obj.cend()); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - append_hex(out, get_object(arg)); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, get_object(arg)); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, get_object(arg)); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, get_object(arg)); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - append_hex(out, static_cast(get_object(arg))); -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - append_hex(out, get_object(arg)); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - std::ostringstream buf(out, std::ios_base::ate); - buf << get_object(arg); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - std::ostringstream buf(out, std::ios_base::ate); - buf << get_object(arg); -} - -template <> -void log_class_string::format(std::string &out, const void *arg) { - out += get_object(arg) ? "1" : "0"; -} - -template <> -void log_class_string::format(std::string &out, - const void *arg) { - auto errorCode = get_object(arg); - switch (errorCode) { - case ErrorCode::PERM: - out += "PERM"; - return; - case ErrorCode::NOENT: - out += "NOENT"; - return; - case ErrorCode::SRCH: - out += "SRCH"; - return; - case ErrorCode::INTR: - out += "INTR"; - return; - case ErrorCode::IO: - out += "IO"; - return; - case ErrorCode::NXIO: - out += "NXIO"; - return; - case ErrorCode::TOOBIG: - out += "TOOBIG"; - return; - case ErrorCode::NOEXEC: - out += "NOEXEC"; - return; - case ErrorCode::BADF: - out += "BADF"; - return; - case ErrorCode::CHILD: - out += "CHILD"; - return; - case ErrorCode::DEADLK: - out += "DEADLK"; - return; - case ErrorCode::NOMEM: - out += "NOMEM"; - return; - case ErrorCode::ACCES: - out += "ACCES"; - return; - case ErrorCode::FAULT: - out += "FAULT"; - return; - case ErrorCode::NOTBLK: - out += "NOTBLK"; - return; - case ErrorCode::BUSY: - out += "BUSY"; - return; - case ErrorCode::EXIST: - out += "EXIST"; - return; - case ErrorCode::XDEV: - out += "XDEV"; - return; - case ErrorCode::NODEV: - out += "NODEV"; - return; - case ErrorCode::NOTDIR: - out += "NOTDIR"; - return; - case ErrorCode::ISDIR: - out += "ISDIR"; - return; - case ErrorCode::INVAL: - out += "INVAL"; - return; - case ErrorCode::NFILE: - out += "NFILE"; - return; - case ErrorCode::MFILE: - out += "MFILE"; - return; - case ErrorCode::NOTTY: - out += "NOTTY"; - return; - case ErrorCode::TXTBSY: - out += "TXTBSY"; - return; - case ErrorCode::FBIG: - out += "FBIG"; - return; - case ErrorCode::NOSPC: - out += "NOSPC"; - return; - case ErrorCode::SPIPE: - out += "SPIPE"; - return; - case ErrorCode::ROFS: - out += "ROFS"; - return; - case ErrorCode::MLINK: - out += "MLINK"; - return; - case ErrorCode::PIPE: - out += "PIPE"; - return; - case ErrorCode::DOM: - out += "DOM"; - return; - case ErrorCode::RANGE: - out += "RANGE"; - return; - case ErrorCode::AGAIN: - out += "AGAIN"; - return; - case ErrorCode::INPROGRESS: - out += "INPROGRESS"; - return; - case ErrorCode::ALREADY: - out += "ALREADY"; - return; - case ErrorCode::NOTSOCK: - out += "NOTSOCK"; - return; - case ErrorCode::DESTADDRREQ: - out += "DESTADDRREQ"; - return; - case ErrorCode::MSGSIZE: - out += "MSGSIZE"; - return; - case ErrorCode::PROTOTYPE: - out += "PROTOTYPE"; - return; - case ErrorCode::NOPROTOOPT: - out += "NOPROTOOPT"; - return; - case ErrorCode::PROTONOSUPPORT: - out += "PROTONOSUPPORT"; - return; - case ErrorCode::SOCKTNOSUPPORT: - out += "SOCKTNOSUPPORT"; - return; - case ErrorCode::OPNOTSUPP: - out += "OPNOTSUPP"; - return; - case ErrorCode::PFNOSUPPORT: - out += "PFNOSUPPORT"; - return; - case ErrorCode::AFNOSUPPORT: - out += "AFNOSUPPORT"; - return; - case ErrorCode::ADDRINUSE: - out += "ADDRINUSE"; - return; - case ErrorCode::ADDRNOTAVAIL: - out += "ADDRNOTAVAIL"; - return; - case ErrorCode::NETDOWN: - out += "NETDOWN"; - return; - case ErrorCode::NETUNREACH: - out += "NETUNREACH"; - return; - case ErrorCode::NETRESET: - out += "NETRESET"; - return; - case ErrorCode::CONNABORTED: - out += "CONNABORTED"; - return; - case ErrorCode::CONNRESET: - out += "CONNRESET"; - return; - case ErrorCode::NOBUFS: - out += "NOBUFS"; - return; - case ErrorCode::ISCONN: - out += "ISCONN"; - return; - case ErrorCode::NOTCONN: - out += "NOTCONN"; - return; - case ErrorCode::SHUTDOWN: - out += "SHUTDOWN"; - return; - case ErrorCode::TOOMANYREFS: - out += "TOOMANYREFS"; - return; - case ErrorCode::TIMEDOUT: - out += "TIMEDOUT"; - return; - case ErrorCode::CONNREFUSED: - out += "CONNREFUSED"; - return; - case ErrorCode::LOOP: - out += "LOOP"; - return; - case ErrorCode::NAMETOOLONG: - out += "NAMETOOLONG"; - return; - case ErrorCode::HOSTDOWN: - out += "HOSTDOWN"; - return; - case ErrorCode::HOSTUNREACH: - out += "HOSTUNREACH"; - return; - case ErrorCode::NOTEMPTY: - out += "NOTEMPTY"; - return; - case ErrorCode::PROCLIM: - out += "PROCLIM"; - return; - case ErrorCode::USERS: - out += "USERS"; - return; - case ErrorCode::DQUOT: - out += "DQUOT"; - return; - case ErrorCode::STALE: - out += "STALE"; - return; - case ErrorCode::REMOTE: - out += "REMOTE"; - return; - case ErrorCode::BADRPC: - out += "BADRPC"; - return; - case ErrorCode::RPCMISMATCH: - out += "RPCMISMATCH"; - return; - case ErrorCode::PROGUNAVAIL: - out += "PROGUNAVAIL"; - return; - case ErrorCode::PROGMISMATCH: - out += "PROGMISMATCH"; - return; - case ErrorCode::PROCUNAVAIL: - out += "PROCUNAVAIL"; - return; - case ErrorCode::NOLCK: - out += "NOLCK"; - return; - case ErrorCode::NOSYS: - out += "NOSYS"; - return; - case ErrorCode::FTYPE: - out += "FTYPE"; - return; - case ErrorCode::AUTH: - out += "AUTH"; - return; - case ErrorCode::NEEDAUTH: - out += "NEEDAUTH"; - return; - case ErrorCode::IDRM: - out += "IDRM"; - return; - case ErrorCode::NOMSG: - out += "NOMSG"; - return; - case ErrorCode::OVERFLOW: - out += "OVERFLOW"; - return; - case ErrorCode::CANCELED: - out += "CANCELED"; - return; - case ErrorCode::ILSEQ: - out += "ILSEQ"; - return; - case ErrorCode::NOATTR: - out += "NOATTR"; - return; - case ErrorCode::DOOFUS: - out += "DOOFUS"; - return; - case ErrorCode::BADMSG: - out += "BADMSG"; - return; - case ErrorCode::MULTIHOP: - out += "MULTIHOP"; - return; - case ErrorCode::NOLINK: - out += "NOLINK"; - return; - case ErrorCode::PROTO: - out += "PROTO"; - return; - case ErrorCode::NOTCAPABLE: - out += "NOTCAPABLE"; - return; - case ErrorCode::CAPMODE: - out += "CAPMODE"; - return; - } - - out += ""; -} - -void _orbis_log_print(LogLevel lvl, std::string_view msg, - std::string_view names, const log_type_info *sup, ...) { - if (lvl > logs_level.load(std::memory_order::relaxed)) { - return; - } - - /*constinit thread_local*/ std::string text; - /*constinit thread_local*/ std::vector args; - - std::size_t args_count = 0; - for (auto v = sup; v && v->log_string; v++) - args_count++; - - text.reserve(50000); - args.resize(args_count); - - va_list c_args; - va_start(c_args, sup); - for (const void *&arg : args) - arg = va_arg(c_args, const void *); - va_end(c_args); - - text += msg; - if (args_count) - text += "("; - for (std::size_t i = 0; i < args_count; i++) { - if (i) - text += ", "; - names.remove_prefix(names.find_first_not_of(" \t\n\r")); - std::string_view name = names.substr(0, names.find_first_of(",")); - names.remove_prefix(name.size() + 1); - text += name; - text += "="; - sup[i].log_string(text, args[i]); - } - if (args_count) - text += ")"; - - const char *color = ""; - switch (lvl) { - case LogLevel::Always: - color = "\e[36;1m"; - break; - case LogLevel::Fatal: - color = "\e[35;1m"; - break; - case LogLevel::Error: - color = "\e[0;31m"; - break; - case LogLevel::Todo: - color = "\e[1;33m"; - break; - case LogLevel::Success: - color = "\e[1;32m"; - break; - case LogLevel::Warning: - color = "\e[0;33m"; - break; - case LogLevel::Notice: - color = "\e[0;36m"; - break; - case LogLevel::Trace: - color = ""; - break; - } - - static const bool istty = isatty(fileno(stderr)); - if (istty) { - std::fprintf(stderr, "%s%s\e[0m\n", color, text.c_str()); - } else { - std::fprintf(stderr, "%s\n", text.c_str()); - } -} +namespace orbis::logs +{ + void log_class_string::format(std::string& out, const void* arg) + { + const void* ptr = *reinterpret_cast(arg); + append_hex(out, reinterpret_cast(ptr)); + } + + void log_class_string::format_n(std::string& out, const void* arg, + std::size_t n) + { + const char* ptr = reinterpret_cast(arg); + const auto addr = reinterpret_cast(ptr); + const auto _end = n ? addr + n - 1 : addr; + if (addr < 0x10000 || std::max(n, _end) > 0x7fff'ffff'ffff) + { + out += "{{{{{BAD_ADDR:"; + append_hex(out, addr); + out += "}}}}}"; + return; + } + while (n--) + { + const char c = *ptr++; + if (!c) + break; + out += c; + } + } + + void log_class_string::format(std::string& out, const void* arg) + { + const char* ptr = *reinterpret_cast(arg); + const auto addr = reinterpret_cast(ptr); + if (addr < 0x10000 || addr > 0x7fff'ffff'ffff) + { + out += "{{{{{BAD_ADDR:"; + append_hex(out, addr); + out += "}}}}}"; + return; + } + out += ptr; + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + out += get_object(arg); + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + out += get_object(arg); + } + + template <> + void log_class_string>::format(std::string& out, + const void* arg) + { + const std::vector& obj = get_object(arg); + out.append(obj.cbegin(), obj.cend()); + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + const std::u8string& obj = get_object(arg); + out.append(obj.cbegin(), obj.cend()); + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + const std::u8string_view& obj = get_object(arg); + out.append(obj.cbegin(), obj.cend()); + } + + template <> + void log_class_string>::format(std::string& out, + const void* arg) + { + const std::vector& obj = get_object(arg); + out.append(obj.cbegin(), obj.cend()); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + append_hex(out, get_object(arg)); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, get_object(arg)); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, get_object(arg)); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, get_object(arg)); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + append_hex(out, static_cast(get_object(arg))); + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + append_hex(out, get_object(arg)); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + std::ostringstream buf(out, std::ios_base::ate); + buf << get_object(arg); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + std::ostringstream buf(out, std::ios_base::ate); + buf << get_object(arg); + } + + template <> + void log_class_string::format(std::string& out, const void* arg) + { + out += get_object(arg) ? "1" : "0"; + } + + template <> + void log_class_string::format(std::string& out, + const void* arg) + { + auto errorCode = get_object(arg); + switch (errorCode) + { + case ErrorCode::PERM: + out += "PERM"; + return; + case ErrorCode::NOENT: + out += "NOENT"; + return; + case ErrorCode::SRCH: + out += "SRCH"; + return; + case ErrorCode::INTR: + out += "INTR"; + return; + case ErrorCode::IO: + out += "IO"; + return; + case ErrorCode::NXIO: + out += "NXIO"; + return; + case ErrorCode::TOOBIG: + out += "TOOBIG"; + return; + case ErrorCode::NOEXEC: + out += "NOEXEC"; + return; + case ErrorCode::BADF: + out += "BADF"; + return; + case ErrorCode::CHILD: + out += "CHILD"; + return; + case ErrorCode::DEADLK: + out += "DEADLK"; + return; + case ErrorCode::NOMEM: + out += "NOMEM"; + return; + case ErrorCode::ACCES: + out += "ACCES"; + return; + case ErrorCode::FAULT: + out += "FAULT"; + return; + case ErrorCode::NOTBLK: + out += "NOTBLK"; + return; + case ErrorCode::BUSY: + out += "BUSY"; + return; + case ErrorCode::EXIST: + out += "EXIST"; + return; + case ErrorCode::XDEV: + out += "XDEV"; + return; + case ErrorCode::NODEV: + out += "NODEV"; + return; + case ErrorCode::NOTDIR: + out += "NOTDIR"; + return; + case ErrorCode::ISDIR: + out += "ISDIR"; + return; + case ErrorCode::INVAL: + out += "INVAL"; + return; + case ErrorCode::NFILE: + out += "NFILE"; + return; + case ErrorCode::MFILE: + out += "MFILE"; + return; + case ErrorCode::NOTTY: + out += "NOTTY"; + return; + case ErrorCode::TXTBSY: + out += "TXTBSY"; + return; + case ErrorCode::FBIG: + out += "FBIG"; + return; + case ErrorCode::NOSPC: + out += "NOSPC"; + return; + case ErrorCode::SPIPE: + out += "SPIPE"; + return; + case ErrorCode::ROFS: + out += "ROFS"; + return; + case ErrorCode::MLINK: + out += "MLINK"; + return; + case ErrorCode::PIPE: + out += "PIPE"; + return; + case ErrorCode::DOM: + out += "DOM"; + return; + case ErrorCode::RANGE: + out += "RANGE"; + return; + case ErrorCode::AGAIN: + out += "AGAIN"; + return; + case ErrorCode::INPROGRESS: + out += "INPROGRESS"; + return; + case ErrorCode::ALREADY: + out += "ALREADY"; + return; + case ErrorCode::NOTSOCK: + out += "NOTSOCK"; + return; + case ErrorCode::DESTADDRREQ: + out += "DESTADDRREQ"; + return; + case ErrorCode::MSGSIZE: + out += "MSGSIZE"; + return; + case ErrorCode::PROTOTYPE: + out += "PROTOTYPE"; + return; + case ErrorCode::NOPROTOOPT: + out += "NOPROTOOPT"; + return; + case ErrorCode::PROTONOSUPPORT: + out += "PROTONOSUPPORT"; + return; + case ErrorCode::SOCKTNOSUPPORT: + out += "SOCKTNOSUPPORT"; + return; + case ErrorCode::OPNOTSUPP: + out += "OPNOTSUPP"; + return; + case ErrorCode::PFNOSUPPORT: + out += "PFNOSUPPORT"; + return; + case ErrorCode::AFNOSUPPORT: + out += "AFNOSUPPORT"; + return; + case ErrorCode::ADDRINUSE: + out += "ADDRINUSE"; + return; + case ErrorCode::ADDRNOTAVAIL: + out += "ADDRNOTAVAIL"; + return; + case ErrorCode::NETDOWN: + out += "NETDOWN"; + return; + case ErrorCode::NETUNREACH: + out += "NETUNREACH"; + return; + case ErrorCode::NETRESET: + out += "NETRESET"; + return; + case ErrorCode::CONNABORTED: + out += "CONNABORTED"; + return; + case ErrorCode::CONNRESET: + out += "CONNRESET"; + return; + case ErrorCode::NOBUFS: + out += "NOBUFS"; + return; + case ErrorCode::ISCONN: + out += "ISCONN"; + return; + case ErrorCode::NOTCONN: + out += "NOTCONN"; + return; + case ErrorCode::SHUTDOWN: + out += "SHUTDOWN"; + return; + case ErrorCode::TOOMANYREFS: + out += "TOOMANYREFS"; + return; + case ErrorCode::TIMEDOUT: + out += "TIMEDOUT"; + return; + case ErrorCode::CONNREFUSED: + out += "CONNREFUSED"; + return; + case ErrorCode::LOOP: + out += "LOOP"; + return; + case ErrorCode::NAMETOOLONG: + out += "NAMETOOLONG"; + return; + case ErrorCode::HOSTDOWN: + out += "HOSTDOWN"; + return; + case ErrorCode::HOSTUNREACH: + out += "HOSTUNREACH"; + return; + case ErrorCode::NOTEMPTY: + out += "NOTEMPTY"; + return; + case ErrorCode::PROCLIM: + out += "PROCLIM"; + return; + case ErrorCode::USERS: + out += "USERS"; + return; + case ErrorCode::DQUOT: + out += "DQUOT"; + return; + case ErrorCode::STALE: + out += "STALE"; + return; + case ErrorCode::REMOTE: + out += "REMOTE"; + return; + case ErrorCode::BADRPC: + out += "BADRPC"; + return; + case ErrorCode::RPCMISMATCH: + out += "RPCMISMATCH"; + return; + case ErrorCode::PROGUNAVAIL: + out += "PROGUNAVAIL"; + return; + case ErrorCode::PROGMISMATCH: + out += "PROGMISMATCH"; + return; + case ErrorCode::PROCUNAVAIL: + out += "PROCUNAVAIL"; + return; + case ErrorCode::NOLCK: + out += "NOLCK"; + return; + case ErrorCode::NOSYS: + out += "NOSYS"; + return; + case ErrorCode::FTYPE: + out += "FTYPE"; + return; + case ErrorCode::AUTH: + out += "AUTH"; + return; + case ErrorCode::NEEDAUTH: + out += "NEEDAUTH"; + return; + case ErrorCode::IDRM: + out += "IDRM"; + return; + case ErrorCode::NOMSG: + out += "NOMSG"; + return; + case ErrorCode::OVERFLOW: + out += "OVERFLOW"; + return; + case ErrorCode::CANCELED: + out += "CANCELED"; + return; + case ErrorCode::ILSEQ: + out += "ILSEQ"; + return; + case ErrorCode::NOATTR: + out += "NOATTR"; + return; + case ErrorCode::DOOFUS: + out += "DOOFUS"; + return; + case ErrorCode::BADMSG: + out += "BADMSG"; + return; + case ErrorCode::MULTIHOP: + out += "MULTIHOP"; + return; + case ErrorCode::NOLINK: + out += "NOLINK"; + return; + case ErrorCode::PROTO: + out += "PROTO"; + return; + case ErrorCode::NOTCAPABLE: + out += "NOTCAPABLE"; + return; + case ErrorCode::CAPMODE: + out += "CAPMODE"; + return; + } + + out += ""; + } + + void _orbis_log_print(LogLevel lvl, std::string_view msg, + std::string_view names, const log_type_info* sup, ...) + { + if (lvl > logs_level.load(std::memory_order::relaxed)) + { + return; + } + + /*constinit thread_local*/ std::string text; + /*constinit thread_local*/ std::vector args; + + std::size_t args_count = 0; + for (auto v = sup; v && v->log_string; v++) + args_count++; + + text.reserve(50000); + args.resize(args_count); + + va_list c_args; + va_start(c_args, sup); + for (const void*& arg : args) + arg = va_arg(c_args, const void*); + va_end(c_args); + + text += msg; + if (args_count) + text += "("; + for (std::size_t i = 0; i < args_count; i++) + { + if (i) + text += ", "; + names.remove_prefix(names.find_first_not_of(" \t\n\r")); + std::string_view name = names.substr(0, names.find_first_of(",")); + names.remove_prefix(name.size() + 1); + text += name; + text += "="; + sup[i].log_string(text, args[i]); + } + if (args_count) + text += ")"; + + const char* color = ""; + switch (lvl) + { + case LogLevel::Always: + color = "\e[36;1m"; + break; + case LogLevel::Fatal: + color = "\e[35;1m"; + break; + case LogLevel::Error: + color = "\e[0;31m"; + break; + case LogLevel::Todo: + color = "\e[1;33m"; + break; + case LogLevel::Success: + color = "\e[1;32m"; + break; + case LogLevel::Warning: + color = "\e[0;33m"; + break; + case LogLevel::Notice: + color = "\e[0;36m"; + break; + case LogLevel::Trace: + color = ""; + break; + } + + static const bool istty = isatty(fileno(stderr)); + if (istty) + { + std::fprintf(stderr, "%s%s\e[0m\n", color, text.c_str()); + } + else + { + std::fprintf(stderr, "%s\n", text.c_str()); + } + } } // namespace orbis::logs diff --git a/orbis-kernel/src/utils/SharedCV.cpp b/orbis-kernel/src/utils/SharedCV.cpp index 37d9efac..704498ea 100644 --- a/orbis-kernel/src/utils/SharedCV.cpp +++ b/orbis-kernel/src/utils/SharedCV.cpp @@ -4,99 +4,109 @@ #include #include -namespace orbis::utils { -void shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, - std::uint64_t usec_timeout) noexcept { - // Not supposed to fail - if (!_val) - std::abort(); - - // Wait with timeout - struct timespec timeout {}; - timeout.tv_nsec = (usec_timeout % 1000'000) * 1000; - timeout.tv_sec = (usec_timeout / 1000'000); -again: - auto result = syscall(SYS_futex, &m_value, FUTEX_WAIT, _val, - usec_timeout + 1 ? &timeout : nullptr, 0, 0); - if (result < 0) - result = errno; - - // Cleanup - const auto old = atomic_fetch_op(m_value, [&](unsigned &value) { - // Remove waiter if no signals - if (!(value & ~c_waiter_mask) && result != EAGAIN) - value -= 1; - - // Try to remove signal - if (value & c_signal_mask) - value -= c_signal_one; - if (value & c_locked_mask) - value -= c_locked_mask; - }); - - // Lock is already acquired - if (old & c_locked_mask) { - return; - } - - // Wait directly (waiter has been added) - if (old & c_signal_mask) { - mutex.impl_wait(); - return; - } - - // Possibly spurious wakeup - if (result == EAGAIN) - goto again; - mutex.lock(); -} - -void shared_cv::impl_wake(shared_mutex &mutex, int _count) noexcept { - unsigned _old = m_value.load(); - const bool is_one = _count == 1; - - // Enqueue _count waiters - _count = std::min(_count, _old & c_waiter_mask); - if (_count <= 0) - return; - - // Try to lock the mutex - const bool locked = mutex.lock_forced(_count); - - const int max_sig = atomic_op(m_value, [&](unsigned &value) { - // Verify the number of waiters - int max_sig = std::min(_count, value & c_waiter_mask); - - // Add lock signal (mutex was immediately locked) - if (locked && max_sig) - value |= c_locked_mask; - else if (locked) - std::abort(); - - // Add normal signals - value += c_signal_one * max_sig; - - // Remove waiters - value -= max_sig; - _old = value; - return max_sig; - }); - - if (max_sig < _count) { - // Fixup mutex - mutex.lock_forced(max_sig - _count); - _count = max_sig; - } - - if (_count) { - // Wake up one thread + requeue remaining waiters - unsigned awake_count = locked ? 1 : 0; - if (auto r = syscall(SYS_futex, &m_value, FUTEX_REQUEUE, awake_count, - _count - awake_count, &mutex, 0); - r < _count) { - // Keep awaking waiters - return impl_wake(mutex, is_one ? 1 : INT_MAX); - } - } -} +namespace orbis::utils +{ + void shared_cv::impl_wait(shared_mutex& mutex, unsigned _val, + std::uint64_t usec_timeout) noexcept + { + // Not supposed to fail + if (!_val) + std::abort(); + + // Wait with timeout + struct timespec timeout + { + }; + timeout.tv_nsec = (usec_timeout % 1000'000) * 1000; + timeout.tv_sec = (usec_timeout / 1000'000); + again: + auto result = syscall(SYS_futex, &m_value, FUTEX_WAIT, _val, + usec_timeout + 1 ? &timeout : nullptr, 0, 0); + if (result < 0) + result = errno; + + // Cleanup + const auto old = atomic_fetch_op(m_value, [&](unsigned& value) { + // Remove waiter if no signals + if (!(value & ~c_waiter_mask) && result != EAGAIN) + value -= 1; + + // Try to remove signal + if (value & c_signal_mask) + value -= c_signal_one; + if (value & c_locked_mask) + value -= c_locked_mask; + }); + + // Lock is already acquired + if (old & c_locked_mask) + { + return; + } + + // Wait directly (waiter has been added) + if (old & c_signal_mask) + { + mutex.impl_wait(); + return; + } + + // Possibly spurious wakeup + if (result == EAGAIN) + goto again; + mutex.lock(); + } + + void shared_cv::impl_wake(shared_mutex& mutex, int _count) noexcept + { + unsigned _old = m_value.load(); + const bool is_one = _count == 1; + + // Enqueue _count waiters + _count = std::min(_count, _old & c_waiter_mask); + if (_count <= 0) + return; + + // Try to lock the mutex + const bool locked = mutex.lock_forced(_count); + + const int max_sig = atomic_op(m_value, [&](unsigned& value) { + // Verify the number of waiters + int max_sig = std::min(_count, value & c_waiter_mask); + + // Add lock signal (mutex was immediately locked) + if (locked && max_sig) + value |= c_locked_mask; + else if (locked) + std::abort(); + + // Add normal signals + value += c_signal_one * max_sig; + + // Remove waiters + value -= max_sig; + _old = value; + return max_sig; + }); + + if (max_sig < _count) + { + // Fixup mutex + mutex.lock_forced(max_sig - _count); + _count = max_sig; + } + + if (_count) + { + // Wake up one thread + requeue remaining waiters + unsigned awake_count = locked ? 1 : 0; + if (auto r = syscall(SYS_futex, &m_value, FUTEX_REQUEUE, awake_count, + _count - awake_count, &mutex, 0); + r < _count) + { + // Keep awaking waiters + return impl_wake(mutex, is_one ? 1 : INT_MAX); + } + } + } } // namespace orbis::utils diff --git a/orbis-kernel/src/utils/SharedMutex.cpp b/orbis-kernel/src/utils/SharedMutex.cpp index 1aa78f3a..3e457672 100644 --- a/orbis-kernel/src/utils/SharedMutex.cpp +++ b/orbis-kernel/src/utils/SharedMutex.cpp @@ -5,175 +5,206 @@ #include #include -static void busy_wait(unsigned long long cycles = 3000) { - const auto stop = __builtin_ia32_rdtsc() + cycles; - do - _mm_pause(); - while (__builtin_ia32_rdtsc() < stop); +static void busy_wait(unsigned long long cycles = 3000) +{ + const auto stop = __builtin_ia32_rdtsc() + cycles; + do + _mm_pause(); + while (__builtin_ia32_rdtsc() < stop); } -namespace orbis::utils { -void shared_mutex::impl_lock_shared(unsigned val) { - if (val >= c_err) - std::abort(); // "shared_mutex underflow" - - // Try to steal the notification bit - unsigned _old = val; - if (val & c_sig && m_value.compare_exchange_strong(_old, val - c_sig + 1)) { - return; - } - - for (int i = 0; i < 10; i++) { - if (try_lock_shared()) { - return; - } - - unsigned old = m_value; - - if (old & c_sig && m_value.compare_exchange_strong(old, old - c_sig + 1)) { - return; - } - - busy_wait(); - } - - // Acquire writer lock and downgrade - const unsigned old = m_value.fetch_add(c_one); - - if (old == 0) { - lock_downgrade(); - return; - } - - if ((old % c_sig) + c_one >= c_sig) - std::abort(); // "shared_mutex overflow" - - impl_wait(); - lock_downgrade(); -} -void shared_mutex::impl_unlock_shared(unsigned old) { - if (old - 1 >= c_err) - std::abort(); // "shared_mutex underflow" - - // Check reader count, notify the writer if necessary - if ((old - 1) % c_one == 0) { - impl_signal(); - } -} -void shared_mutex::impl_wait() { - while (true) { - const auto [old, ok] = atomic_fetch_op(m_value, [](unsigned &value) { - if (value >= c_sig) { - value -= c_sig; - return true; - } - - return false; - }); - - if (ok) { - break; - } - - syscall(SYS_futex, &m_value, FUTEX_WAIT, old, 0, 0, 0); - } -} -void shared_mutex::impl_signal() { - m_value += c_sig; - syscall(SYS_futex, &m_value, FUTEX_WAKE, 1, 0, 0, 0); -} -void shared_mutex::impl_lock(unsigned val) { - if (val >= c_err) - std::abort(); // "shared_mutex underflow" - - // Try to steal the notification bit - unsigned _old = val; - if (val & c_sig && - m_value.compare_exchange_strong(_old, val - c_sig + c_one)) { - return; - } - - for (int i = 0; i < 10; i++) { - busy_wait(); - - unsigned old = m_value; - - if (!old && try_lock()) { - return; - } - - if (old & c_sig && - m_value.compare_exchange_strong(old, old - c_sig + c_one)) { - return; - } - } - - const unsigned old = m_value.fetch_add(c_one); - - if (old == 0) { - return; - } - - if ((old % c_sig) + c_one >= c_sig) - std::abort(); // "shared_mutex overflow" - impl_wait(); -} -void shared_mutex::impl_unlock(unsigned old) { - if (old - c_one >= c_err) - std::abort(); // "shared_mutex underflow" - - // 1) Notify the next writer if necessary - // 2) Notify all readers otherwise if necessary (currently indistinguishable - // from writers) - if (old - c_one) { - impl_signal(); - } -} -void shared_mutex::impl_lock_upgrade() { - for (int i = 0; i < 10; i++) { - busy_wait(); - - if (try_lock_upgrade()) { - return; - } - } - - // Convert to writer lock - const unsigned old = m_value.fetch_add(c_one - 1); - - if ((old % c_sig) + c_one - 1 >= c_sig) - std::abort(); // "shared_mutex overflow" - - if (old % c_one == 1) { - return; - } - - impl_wait(); -} -bool shared_mutex::lock_forced(int count) { - if (count == 0) - return false; - if (count > 0) { - // Lock - return atomic_op(m_value, [&](unsigned &v) { - if (v & c_sig) { - v -= c_sig; - v += c_one * count; - return true; - } - - if (v == 0) { - v += c_one * count; - return true; - } - - v += c_one * count; - return false; - }); - } - - // Remove waiters - m_value.fetch_add(c_one * count); - return true; -} +namespace orbis::utils +{ + void shared_mutex::impl_lock_shared(unsigned val) + { + if (val >= c_err) + std::abort(); // "shared_mutex underflow" + + // Try to steal the notification bit + unsigned _old = val; + if (val & c_sig && m_value.compare_exchange_strong(_old, val - c_sig + 1)) + { + return; + } + + for (int i = 0; i < 10; i++) + { + if (try_lock_shared()) + { + return; + } + + unsigned old = m_value; + + if (old & c_sig && m_value.compare_exchange_strong(old, old - c_sig + 1)) + { + return; + } + + busy_wait(); + } + + // Acquire writer lock and downgrade + const unsigned old = m_value.fetch_add(c_one); + + if (old == 0) + { + lock_downgrade(); + return; + } + + if ((old % c_sig) + c_one >= c_sig) + std::abort(); // "shared_mutex overflow" + + impl_wait(); + lock_downgrade(); + } + void shared_mutex::impl_unlock_shared(unsigned old) + { + if (old - 1 >= c_err) + std::abort(); // "shared_mutex underflow" + + // Check reader count, notify the writer if necessary + if ((old - 1) % c_one == 0) + { + impl_signal(); + } + } + void shared_mutex::impl_wait() + { + while (true) + { + const auto [old, ok] = atomic_fetch_op(m_value, [](unsigned& value) { + if (value >= c_sig) + { + value -= c_sig; + return true; + } + + return false; + }); + + if (ok) + { + break; + } + + syscall(SYS_futex, &m_value, FUTEX_WAIT, old, 0, 0, 0); + } + } + void shared_mutex::impl_signal() + { + m_value += c_sig; + syscall(SYS_futex, &m_value, FUTEX_WAKE, 1, 0, 0, 0); + } + void shared_mutex::impl_lock(unsigned val) + { + if (val >= c_err) + std::abort(); // "shared_mutex underflow" + + // Try to steal the notification bit + unsigned _old = val; + if (val & c_sig && + m_value.compare_exchange_strong(_old, val - c_sig + c_one)) + { + return; + } + + for (int i = 0; i < 10; i++) + { + busy_wait(); + + unsigned old = m_value; + + if (!old && try_lock()) + { + return; + } + + if (old & c_sig && + m_value.compare_exchange_strong(old, old - c_sig + c_one)) + { + return; + } + } + + const unsigned old = m_value.fetch_add(c_one); + + if (old == 0) + { + return; + } + + if ((old % c_sig) + c_one >= c_sig) + std::abort(); // "shared_mutex overflow" + impl_wait(); + } + void shared_mutex::impl_unlock(unsigned old) + { + if (old - c_one >= c_err) + std::abort(); // "shared_mutex underflow" + + // 1) Notify the next writer if necessary + // 2) Notify all readers otherwise if necessary (currently indistinguishable + // from writers) + if (old - c_one) + { + impl_signal(); + } + } + void shared_mutex::impl_lock_upgrade() + { + for (int i = 0; i < 10; i++) + { + busy_wait(); + + if (try_lock_upgrade()) + { + return; + } + } + + // Convert to writer lock + const unsigned old = m_value.fetch_add(c_one - 1); + + if ((old % c_sig) + c_one - 1 >= c_sig) + std::abort(); // "shared_mutex overflow" + + if (old % c_one == 1) + { + return; + } + + impl_wait(); + } + bool shared_mutex::lock_forced(int count) + { + if (count == 0) + return false; + if (count > 0) + { + // Lock + return atomic_op(m_value, [&](unsigned& v) { + if (v & c_sig) + { + v -= c_sig; + v += c_one * count; + return true; + } + + if (v == 0) + { + v += c_one * count; + return true; + } + + v += c_one * count; + return false; + }); + } + + // Remove waiters + m_value.fetch_add(c_one * count); + return true; + } } // namespace orbis::utils diff --git a/rpcsx-gpu/main.cpp b/rpcsx-gpu/main.cpp index e7e82467..fd934afc 100644 --- a/rpcsx-gpu/main.cpp +++ b/rpcsx-gpu/main.cpp @@ -22,998 +22,1138 @@ #include // TODO: make in optional // TODO -extern void *g_rwMemory; +extern void* g_rwMemory; extern std::size_t g_memorySize; extern std::uint64_t g_memoryBase; extern amdgpu::RemoteMemory g_hostMemory; -static void usage(std::FILE *out, const char *argv0) { - std::fprintf(out, "usage: %s [options...]\n", argv0); - std::fprintf(out, " options:\n"); - std::fprintf(out, - " --cmd-bridge - setup command queue bridge name\n"); - std::fprintf(out, " --shm - setup shared memory name\n"); - std::fprintf( - out, - " --gpu - specify physical gpu index to use, default is 0\n"); - std::fprintf(out, - " --presenter - set flip engine target\n"); - std::fprintf(out, " --validate - enable validation layers\n"); - std::fprintf(out, " -h, --help - show this message\n"); - std::fprintf(out, "\n"); - std::fprintf(out, " presenter mode:\n"); - std::fprintf(out, " window - create and use native window (default)\n"); +static void usage(std::FILE* out, const char* argv0) +{ + std::fprintf(out, "usage: %s [options...]\n", argv0); + std::fprintf(out, " options:\n"); + std::fprintf(out, + " --cmd-bridge - setup command queue bridge name\n"); + std::fprintf(out, " --shm - setup shared memory name\n"); + std::fprintf( + out, + " --gpu - specify physical gpu index to use, default is 0\n"); + std::fprintf(out, + " --presenter - set flip engine target\n"); + std::fprintf(out, " --validate - enable validation layers\n"); + std::fprintf(out, " -h, --help - show this message\n"); + std::fprintf(out, "\n"); + std::fprintf(out, " presenter mode:\n"); + std::fprintf(out, " window - create and use native window (default)\n"); } -enum class PresenterMode { Window }; +enum class PresenterMode +{ + Window +}; static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void *pUserData) { - - std::fprintf(stderr, "validation layer: %s\n", pCallbackData->pMessage); - - if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - std::abort(); - } - return VK_FALSE; + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) +{ + + std::fprintf(stderr, "validation layer: %s\n", pCallbackData->pMessage); + + if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + { + std::abort(); + } + return VK_FALSE; } static VkResult _vkCreateDebugUtilsMessengerEXT( - VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugUtilsMessengerEXT *pDebugMessenger) { - static auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( - instance, "vkCreateDebugUtilsMessengerEXT"); - if (func != nullptr) { - return func(instance, pCreateInfo, pAllocator, pDebugMessenger); - } else { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } + VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pDebugMessenger) +{ + static auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + instance, "vkCreateDebugUtilsMessengerEXT"); + if (func != nullptr) + { + return func(instance, pCreateInfo, pAllocator, pDebugMessenger); + } + else + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } } -int main(int argc, const char *argv[]) { - if (argc == 2 && (argv[1] == std::string_view("-h") || - argv[1] == std::string_view("--help"))) { - usage(stdout, argv[0]); - return 0; - } - - const char *cmdBridgeName = "/rpcsx-gpu-cmds"; - const char *shmName = "/rpcsx-os-memory"; - unsigned long gpuIndex = 0; - auto presenter = PresenterMode::Window; - bool enableValidation = false; - - for (int i = 1; i < argc; ++i) { - if (argv[i] == std::string_view("--cmd-bridge")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - cmdBridgeName = argv[++i]; - continue; - } - - if (argv[i] == std::string_view("--shm")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - shmName = argv[++i]; - continue; - } - - if (argv[i] == std::string_view("--presenter")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - auto presenterText = std::string_view(argv[++i]); - - if (presenterText == "window") { - presenter = PresenterMode::Window; - } else { - usage(stderr, argv[0]); - return 1; - } - continue; - } - - if (argv[i] == std::string_view("--gpu")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - char *endPtr = nullptr; - gpuIndex = std::strtoul(argv[++i], &endPtr, 10); - if (endPtr == nullptr || *endPtr != '\0') { - usage(stderr, argv[0]); - return 1; - } - - continue; - } - - if (argv[i] == std::string_view("--validate")) { - enableValidation = true; - continue; - } - - usage(stderr, argv[0]); - return 1; - } - - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - auto window = glfwCreateWindow(1280, 720, "RPCSX", nullptr, nullptr); - - const char **glfwExtensions; - uint32_t glfwExtensionCount = 0; - - glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - - auto requiredInstanceExtensions = std::vector( - glfwExtensions, glfwExtensions + glfwExtensionCount); - - if (enableValidation) { - requiredInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - - uint32_t extCount = 0; - vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); - std::vector supportedInstanceExtensions; - - if (extCount > 0) { - std::vector extensions(extCount); - if (vkEnumerateInstanceExtensionProperties( - nullptr, &extCount, &extensions.front()) == VK_SUCCESS) { - supportedInstanceExtensions.reserve(extensions.size()); - for (VkExtensionProperties extension : extensions) { - supportedInstanceExtensions.push_back(extension.extensionName); - } - } - } - - for (const char *extension : requiredInstanceExtensions) { - if (std::find(supportedInstanceExtensions.begin(), - supportedInstanceExtensions.end(), - extension) == supportedInstanceExtensions.end()) { - util::unreachable("Requested instance extension '%s' is not present at " - "instance level", - extension); - } - } - - const char *validationLayerName = "VK_LAYER_KHRONOS_validation"; - - VkApplicationInfo appInfo = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "RPCSX", - .pEngineName = "none", - .apiVersion = VK_API_VERSION_1_3, - }; - - VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{}; - debugCreateInfo.sType = - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugCreateInfo.messageSeverity = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - 0 - // VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - ; - debugCreateInfo.pfnUserCallback = debugCallback; - - VkInstanceCreateInfo instanceCreateInfo = {}; - instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - if (enableValidation) { - instanceCreateInfo.pNext = &debugCreateInfo; - } - instanceCreateInfo.pApplicationInfo = &appInfo; - instanceCreateInfo.enabledExtensionCount = requiredInstanceExtensions.size(); - instanceCreateInfo.ppEnabledExtensionNames = - requiredInstanceExtensions.data(); - - std::vector enabledLayers; - // enabledLayers.push_back("VK_LAYER_KHRONOS_shader_object"); - - if (enableValidation) { - enabledLayers.push_back(validationLayerName); - } - - instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data(); - instanceCreateInfo.enabledLayerCount = enabledLayers.size(); - - VkInstance vkInstance; - Verify() << vkCreateInstance(&instanceCreateInfo, nullptr, &vkInstance); - auto getVkPhyDevice = [&](unsigned index) { - std::vector devices(index + 1); - uint32_t count = devices.size(); - Verify() << vkEnumeratePhysicalDevices(vkInstance, &count, devices.data()); - Verify() << (index < count); - return devices[index]; - }; - - if (enableValidation) { - VkDebugUtilsMessengerEXT debugMessenger; - _vkCreateDebugUtilsMessengerEXT(vkInstance, &debugCreateInfo, nullptr, - &debugMessenger); - } - - auto vkPhysicalDevice = getVkPhyDevice(gpuIndex); - - VkPhysicalDeviceProperties vkPhyDeviceProperties; - vkGetPhysicalDeviceProperties(vkPhysicalDevice, &vkPhyDeviceProperties); - std::printf("VK: Selected physical device is %s\n", - vkPhyDeviceProperties.deviceName); - VkPhysicalDeviceMemoryProperties vkPhyDeviceMemoryProperties; - vkGetPhysicalDeviceMemoryProperties(vkPhysicalDevice, - &vkPhyDeviceMemoryProperties); - - VkPhysicalDevice8BitStorageFeatures storage_8bit = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES}; - VkPhysicalDevice16BitStorageFeatures storage_16bit = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, - .pNext = &storage_8bit}; - VkPhysicalDeviceShaderFloat16Int8Features float16_int8 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, - .pNext = &storage_16bit}; - - VkPhysicalDeviceFeatures2 features2 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - .pNext = &float16_int8}; - vkGetPhysicalDeviceFeatures2(vkPhysicalDevice, &features2); - - Verify() << storage_8bit.uniformAndStorageBuffer8BitAccess; - Verify() << storage_16bit.uniformAndStorageBuffer16BitAccess; - Verify() << float16_int8.shaderFloat16; - Verify() << float16_int8.shaderInt8; - - std::vector vkSupportedDeviceExtensions; - { - uint32_t extCount = 0; - vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, nullptr, &extCount, - nullptr); - if (extCount > 0) { - std::vector extensions(extCount); - if (vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, nullptr, - &extCount, extensions.data()) == - VK_SUCCESS) { - - vkSupportedDeviceExtensions.reserve(extCount); - - for (auto ext : extensions) { - vkSupportedDeviceExtensions.push_back(ext.extensionName); - } - } - } - } - - auto isDeviceExtensionSupported = [&](std::string_view extension) { - return std::find(vkSupportedDeviceExtensions.begin(), - vkSupportedDeviceExtensions.end(), - extension) != vkSupportedDeviceExtensions.end(); - }; - - std::vector requestedDeviceExtensions = { - VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, - VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, - VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, - // VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, - // VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME, - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_EXT_SHADER_OBJECT_EXTENSION_NAME, - }; - - if (isDeviceExtensionSupported(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { - requestedDeviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); - } - - // for (auto extension : vkSupportedDeviceExtensions) { - // std::printf("supported device extension %s\n", extension.c_str()); - // } - - for (const char *requestedExtension : requestedDeviceExtensions) { - if (!isDeviceExtensionSupported(requestedExtension)) { - std::fprintf( - stderr, - "Requested device extension '%s' is not present at device level\n", - requestedExtension); - std::abort(); - } - } - - std::vector queueFamilyProperties; - - { - uint32_t queueFamilyCount; - vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, - &queueFamilyCount, nullptr); - Verify() << (queueFamilyCount > 0); - queueFamilyProperties.resize(queueFamilyCount); - for (auto &property : queueFamilyProperties) { - property.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; - } - - vkGetPhysicalDeviceQueueFamilyProperties2( - vkPhysicalDevice, &queueFamilyCount, queueFamilyProperties.data()); - } - - VkSurfaceKHR vkSurface; - Verify() << glfwCreateWindowSurface(vkInstance, window, nullptr, &vkSurface); - - std::set queueFamiliesWithPresentSupport; - std::set queueFamiliesWithTransferSupport; - std::set queueFamiliesWithComputeSupport; - std::set queueFamiliesWithGraphicsSupport; - - uint32_t queueFamiliesCount = 0; - for (auto &familyProperty : queueFamilyProperties) { - VkBool32 supportsPresent; - if (vkGetPhysicalDeviceSurfaceSupportKHR(vkPhysicalDevice, - queueFamiliesCount, vkSurface, - &supportsPresent) == VK_SUCCESS && - supportsPresent != 0) { - queueFamiliesWithPresentSupport.insert(queueFamiliesCount); - } - - if (familyProperty.queueFamilyProperties.queueFlags & - VK_QUEUE_SPARSE_BINDING_BIT) { - if (familyProperty.queueFamilyProperties.queueFlags & - VK_QUEUE_GRAPHICS_BIT) { - queueFamiliesWithGraphicsSupport.insert(queueFamiliesCount); - } - - if (familyProperty.queueFamilyProperties.queueFlags & - VK_QUEUE_COMPUTE_BIT) { - queueFamiliesWithComputeSupport.insert(queueFamiliesCount); - } - } - - if (familyProperty.queueFamilyProperties.queueFlags & - VK_QUEUE_TRANSFER_BIT) { - queueFamiliesWithTransferSupport.insert(queueFamiliesCount); - } - - queueFamiliesCount++; - } - - Verify() << !queueFamiliesWithPresentSupport.empty(); - Verify() << !queueFamiliesWithTransferSupport.empty(); - Verify() << !queueFamiliesWithComputeSupport.empty(); - Verify() << !queueFamiliesWithGraphicsSupport.empty(); - - std::vector requestedQueues; - - std::vector defaultQueuePriorities; - defaultQueuePriorities.resize(32); - - for (uint32_t queueFamily = 0; queueFamily < queueFamiliesCount; - ++queueFamily) { - if (queueFamiliesWithGraphicsSupport.contains(queueFamily)) { - requestedQueues.push_back( - {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = queueFamily, - .queueCount = - std::min(queueFamilyProperties[queueFamily] - .queueFamilyProperties.queueCount, - defaultQueuePriorities.size()), - .pQueuePriorities = defaultQueuePriorities.data()}); - } else if (queueFamiliesWithComputeSupport.contains(queueFamily) || - queueFamiliesWithTransferSupport.contains(queueFamily)) { - requestedQueues.push_back( - {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = queueFamily, - .queueCount = - std::min(queueFamilyProperties[queueFamily] - .queueFamilyProperties.queueCount, - defaultQueuePriorities.size()), - .pQueuePriorities = defaultQueuePriorities.data()}); - } - } - - VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, - .shaderObject = VK_TRUE}; - - VkPhysicalDeviceVulkan13Features phyDevFeatures13{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, - .pNext = &shaderObjectFeatures, - .synchronization2 = VK_TRUE, - .dynamicRendering = VK_TRUE, - .maintenance4 = VK_TRUE, - }; - - VkPhysicalDeviceVulkan12Features phyDevFeatures12{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, - .pNext = &phyDevFeatures13, - .storageBuffer8BitAccess = VK_TRUE, - .uniformAndStorageBuffer8BitAccess = VK_TRUE, - .shaderFloat16 = VK_TRUE, - .shaderInt8 = VK_TRUE, - .timelineSemaphore = VK_TRUE, - }; - - VkPhysicalDeviceVulkan11Features phyDevFeatures11{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, - .pNext = &phyDevFeatures12, - .storageBuffer16BitAccess = VK_TRUE, - .uniformAndStorageBuffer16BitAccess = VK_TRUE, - }; - - VkDeviceCreateInfo deviceCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = &phyDevFeatures11, - .queueCreateInfoCount = static_cast(requestedQueues.size()), - .pQueueCreateInfos = requestedQueues.data(), - .enabledExtensionCount = - static_cast(requestedDeviceExtensions.size()), - .ppEnabledExtensionNames = requestedDeviceExtensions.data(), - .pEnabledFeatures = &features2.features}; - - VkDevice vkDevice; - Verify() << vkCreateDevice(vkPhysicalDevice, &deviceCreateInfo, nullptr, - &vkDevice); - VkSwapchainKHR swapchain = VK_NULL_HANDLE; - VkExtent2D swapchainExtent{}; - - std::vector swapchainImages; - - VkFormat swapchainColorFormat = VK_FORMAT_B8G8R8A8_UNORM; - VkColorSpaceKHR swapchainColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - - uint32_t formatCount; - Verify() << vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, vkSurface, - &formatCount, nullptr); - Verify() << (formatCount > 0); - - std::vector surfaceFormats(formatCount); - Verify() << vkGetPhysicalDeviceSurfaceFormatsKHR( - vkPhysicalDevice, vkSurface, &formatCount, surfaceFormats.data()); - - if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { - swapchainColorFormat = VK_FORMAT_B8G8R8A8_UNORM; - swapchainColorSpace = surfaceFormats[0].colorSpace; - } else { - bool found_B8G8R8A8_UNORM = false; - for (auto &&surfaceFormat : surfaceFormats) { - if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM) { - swapchainColorFormat = surfaceFormat.format; - swapchainColorSpace = surfaceFormat.colorSpace; - found_B8G8R8A8_UNORM = true; - break; - } - } - - if (!found_B8G8R8A8_UNORM) { - swapchainColorFormat = surfaceFormats[0].format; - swapchainColorSpace = surfaceFormats[0].colorSpace; - } - } - - auto createSwapchain = [&] { - VkSwapchainKHR oldSwapchain = swapchain; - - VkSurfaceCapabilitiesKHR surfCaps; - Verify() << vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, - vkSurface, &surfCaps); - uint32_t presentModeCount; - Verify() << vkGetPhysicalDeviceSurfacePresentModesKHR( - vkPhysicalDevice, vkSurface, &presentModeCount, NULL); - Verify() << (presentModeCount > 0); - - std::vector presentModes(presentModeCount); - Verify() << vkGetPhysicalDeviceSurfacePresentModesKHR( - vkPhysicalDevice, vkSurface, &presentModeCount, presentModes.data()); - - if (surfCaps.currentExtent.width != (uint32_t)-1) { - swapchainExtent = surfCaps.currentExtent; - } - - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - for (std::size_t i = 0; i < presentModeCount; i++) { - if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - continue; - } - - if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; - break; - } - } - - uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount; - if ((surfCaps.maxImageCount > 0) && - (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { - desiredNumberOfSwapchainImages = surfCaps.maxImageCount; - } - - VkSurfaceTransformFlagsKHR preTransform; - if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { - preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - } else { - preTransform = surfCaps.currentTransform; - } - - VkCompositeAlphaFlagBitsKHR compositeAlpha = - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - std::vector compositeAlphaFlags = { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - }; - - for (auto &compositeAlphaFlag : compositeAlphaFlags) { - if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) { - compositeAlpha = compositeAlphaFlag; - break; - } - } - - VkSwapchainCreateInfoKHR swapchainCI = {}; - swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchainCI.surface = vkSurface; - swapchainCI.minImageCount = desiredNumberOfSwapchainImages; - swapchainCI.imageFormat = swapchainColorFormat; - swapchainCI.imageColorSpace = swapchainColorSpace; - swapchainCI.imageExtent = {swapchainExtent.width, swapchainExtent.height}; - swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform; - swapchainCI.imageArrayLayers = 1; - swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchainCI.queueFamilyIndexCount = 0; - swapchainCI.presentMode = swapchainPresentMode; - swapchainCI.oldSwapchain = oldSwapchain; - swapchainCI.clipped = VK_TRUE; - swapchainCI.compositeAlpha = compositeAlpha; - - if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { - swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - } - - if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { - swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - - Verify() << vkCreateSwapchainKHR(vkDevice, &swapchainCI, nullptr, - &swapchain); - - if (oldSwapchain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(vkDevice, oldSwapchain, nullptr); - } - - uint32_t swapchainImageCount = 0; - Verify() << vkGetSwapchainImagesKHR(vkDevice, swapchain, - &swapchainImageCount, nullptr); - - swapchainImages.resize(swapchainImageCount); - Verify() << vkGetSwapchainImagesKHR( - vkDevice, swapchain, &swapchainImageCount, swapchainImages.data()); - }; - - createSwapchain(); - - std::vector> computeQueues; - std::vector> graphicsQueues; - VkQueue presentQueue = VK_NULL_HANDLE; - unsigned presentQueueFamily; - - for (auto &queueInfo : requestedQueues) { - if (queueFamiliesWithGraphicsSupport.contains(queueInfo.queueFamilyIndex)) { - for (uint32_t queueIndex = 0; queueIndex < queueInfo.queueCount; - ++queueIndex) { - - if (presentQueue == VK_NULL_HANDLE && - queueFamiliesWithPresentSupport.contains( - queueInfo.queueFamilyIndex)) { - presentQueueFamily = queueInfo.queueFamilyIndex; - vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, 0, - &presentQueue); - - continue; - } - - auto &[queue, index] = graphicsQueues.emplace_back(); - index = queueInfo.queueFamilyIndex; - vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, - &queue); - } - - continue; - } - - if (queueFamiliesWithComputeSupport.contains(queueInfo.queueFamilyIndex)) { - if (!queueFamiliesWithTransferSupport.contains( - queueInfo.queueFamilyIndex)) { - util::unreachable(); - } - - uint32_t queueIndex = 0; - for (; queueIndex < queueInfo.queueCount; ++queueIndex) { - auto &[queue, index] = computeQueues.emplace_back(); - index = queueInfo.queueFamilyIndex; - vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, - &queue); - } - - continue; - } - } - - if (graphicsQueues.empty() && presentQueue != VK_NULL_HANDLE) { - graphicsQueues.push_back({presentQueue, presentQueueFamily}); - } - - Verify() << (computeQueues.size() > 1); - Verify() << (graphicsQueues.size() > 0); - Verify() << (presentQueue != VK_NULL_HANDLE); - - amdgpu::device::vk::g_computeQueues = computeQueues; - amdgpu::device::vk::g_graphicsQueues = graphicsQueues; - - VkCommandPoolCreateInfo commandPoolCreateInfo = { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = presentQueueFamily, - }; - - VkCommandPool commandPool; - Verify() << vkCreateCommandPool(vkDevice, &commandPoolCreateInfo, nullptr, - &commandPool); - std::vector inFlightFences(swapchainImages.size()); - - for (auto &fence : inFlightFences) { - VkFenceCreateInfo fenceInfo{}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - Verify() << vkCreateFence(vkDevice, &fenceInfo, nullptr, &fence); - } - - VkSemaphore presentCompleteSemaphore; - VkSemaphore renderCompleteSemaphore; - { - VkSemaphoreCreateInfo semaphoreCreateInfo{}; - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - Verify() << vkCreateSemaphore(vkDevice, &semaphoreCreateInfo, nullptr, - &presentCompleteSemaphore); - Verify() << vkCreateSemaphore(vkDevice, &semaphoreCreateInfo, nullptr, - &renderCompleteSemaphore); - } - - amdgpu::device::setVkDevice(vkDevice, vkPhyDeviceMemoryProperties, - vkPhyDeviceProperties); - - auto bridge = amdgpu::bridge::openShmCommandBuffer(cmdBridgeName); - if (bridge == nullptr) { - bridge = amdgpu::bridge::createShmCommandBuffer(cmdBridgeName); - } - - if (bridge->pullerPid > 0 && ::kill(bridge->pullerPid, 0) == 0) { - // another instance of rpcsx-gpu on the same bridge, kill self after that - - std::fprintf(stderr, "Another instance already exists\n"); - return 1; - } - - bridge->pullerPid = ::getpid(); - - amdgpu::bridge::BridgePuller bridgePuller{bridge}; - amdgpu::bridge::Command commandsBuffer[1]; - - if (!std::filesystem::exists(std::string("/dev/shm") + shmName)) { - std::printf("Waiting for OS\n"); - while (!std::filesystem::exists(std::string("/dev/shm") + shmName)) { - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - } - } - - int memoryFd = ::shm_open(shmName, O_RDWR, S_IRUSR | S_IWUSR); - - if (memoryFd < 0) { - std::printf("failed to open shared memory\n"); - return 1; - } - - struct stat memoryStat; - ::fstat(memoryFd, &memoryStat); - amdgpu::RemoteMemory memory{(char *)::mmap( - nullptr, memoryStat.st_size, PROT_NONE, MAP_SHARED, memoryFd, 0)}; - - extern void *g_rwMemory; - g_memorySize = memoryStat.st_size; - g_memoryBase = 0x40000; - g_rwMemory = ::mmap(nullptr, g_memorySize, PROT_READ | PROT_WRITE, MAP_SHARED, - memoryFd, 0); - - g_hostMemory = memory; - - { - amdgpu::device::AmdgpuDevice device(bridgePuller.header); - - for (std::uint32_t end = bridge->memoryAreaCount, i = 0; i < end; ++i) { - auto area = bridge->memoryAreas[i]; - device.handleProtectMemory(area.address, area.size, area.prot); - } - - std::vector presentCmdBuffers(swapchainImages.size()); - - { - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = commandPool; - allocInfo.commandBufferCount = presentCmdBuffers.size(); - vkAllocateCommandBuffers(vkDevice, &allocInfo, presentCmdBuffers.data()); - } - - std::vector> flipTaskChain( - swapchainImages.size()); - - for (auto &chain : flipTaskChain) { - chain = amdgpu::device::TaskChain::Create(); - } - std::printf("Initialization complete\n"); - - uint32_t imageIndex = 0; - bool isImageAcquired = false; - uint32_t gpIndex = -1; - GLFWgamepadstate gpState; - - while (!glfwWindowShouldClose(window)) { - glfwPollEvents(); - - std::size_t pulledCount = - bridgePuller.pullCommands(commandsBuffer, std::size(commandsBuffer)); - - if (gpIndex > GLFW_JOYSTICK_LAST) { - for (int i = 0; i <= GLFW_JOYSTICK_LAST; ++i) { - if (glfwJoystickIsGamepad(i) == GLFW_TRUE) { - std::printf("Gamepad \"%s\" activated", glfwGetGamepadName(i)); - gpIndex = i; - break; - } - } - } else if (gpIndex <= GLFW_JOYSTICK_LAST) { - if (!glfwJoystickIsGamepad(gpIndex)) { - gpIndex = -1; - } - } - - if (gpIndex <= GLFW_JOYSTICK_LAST) { - if (glfwGetGamepadState(gpIndex, &gpState) == GLFW_TRUE) { - bridge->kbPadState.leftStickX = - gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 127.5f + 127.5f; - bridge->kbPadState.leftStickY = - gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 127.5f + 127.5f; - bridge->kbPadState.rightStickX = - gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 127.5f + 127.5f; - bridge->kbPadState.rightStickY = - gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 127.5f + 127.5f; - bridge->kbPadState.l2 = - (gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 127.5f; - bridge->kbPadState.r2 = - (gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 127.5f; - bridge->kbPadState.buttons = 0; - - if (bridge->kbPadState.l2 == 0xFF) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; - } - - if (bridge->kbPadState.r2 == 0xFF) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; - } - - static const uint32_t gpmap[GLFW_GAMEPAD_BUTTON_LAST + 1] = { - [GLFW_GAMEPAD_BUTTON_A] = amdgpu::bridge::kPadBtnCross, - [GLFW_GAMEPAD_BUTTON_B] = amdgpu::bridge::kPadBtnCircle, - [GLFW_GAMEPAD_BUTTON_X] = amdgpu::bridge::kPadBtnSquare, - [GLFW_GAMEPAD_BUTTON_Y] = amdgpu::bridge::kPadBtnTriangle, - [GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = amdgpu::bridge::kPadBtnL1, - [GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = amdgpu::bridge::kPadBtnR1, - [GLFW_GAMEPAD_BUTTON_BACK] = 0, - [GLFW_GAMEPAD_BUTTON_START] = amdgpu::bridge::kPadBtnOptions, - [GLFW_GAMEPAD_BUTTON_GUIDE] = 0, - [GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = amdgpu::bridge::kPadBtnL3, - [GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = amdgpu::bridge::kPadBtnR3, - [GLFW_GAMEPAD_BUTTON_DPAD_UP] = amdgpu::bridge::kPadBtnUp, - [GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = amdgpu::bridge::kPadBtnRight, - [GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = amdgpu::bridge::kPadBtnDown, - [GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = amdgpu::bridge::kPadBtnLeft}; - - for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; ++i) { - if (gpState.buttons[i] == GLFW_PRESS) { - bridge->kbPadState.buttons |= gpmap[i]; - } - } - } - } else { - bridge->kbPadState.leftStickX = 0x80; - bridge->kbPadState.leftStickY = 0x80; - bridge->kbPadState.rightStickX = 0x80; - bridge->kbPadState.rightStickY = 0x80; - bridge->kbPadState.buttons = 0; - - if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { - bridge->kbPadState.leftStickX = 0; - } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { - bridge->kbPadState.leftStickX = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { - bridge->kbPadState.leftStickY = 0; - } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { - bridge->kbPadState.leftStickY = 0xff; - } - - if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) { - bridge->kbPadState.rightStickX = 0; - } else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) { - bridge->kbPadState.rightStickX = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) { - bridge->kbPadState.rightStickY = 0; - } else if (glfwGetKey(window, GLFW_KEY_SEMICOLON) == GLFW_PRESS) { - bridge->kbPadState.rightStickY = 0xff; - } - - if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnUp; - } - if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnDown; - } - if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnLeft; - } - if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnRight; - } - if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnSquare; - } - if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCross; - } - if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCircle; - } - if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnTriangle; - } - - if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL1; - } - if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; - bridge->kbPadState.l2 = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL3; - } - - if (glfwGetKey(window, GLFW_KEY_I) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR1; - } - if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; - bridge->kbPadState.r2 = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_APOSTROPHE) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR3; - } - - if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnOptions; - } - } - - bridge->kbPadState.timestamp = - std::chrono::high_resolution_clock::now().time_since_epoch().count(); - - if (pulledCount == 0) { - // std::this_thread::sleep_for( - // std::chrono::milliseconds(1)); // Just for testing, should be - // removed - continue; - } - - for (auto cmd : std::span(commandsBuffer, pulledCount)) { - switch (cmd.id) { - case amdgpu::bridge::CommandId::ProtectMemory: - device.handleProtectMemory(cmd.memoryProt.address, - cmd.memoryProt.size, cmd.memoryProt.prot); - break; - case amdgpu::bridge::CommandId::CommandBuffer: - device.handleCommandBuffer(cmd.commandBuffer.queue, - cmd.commandBuffer.address, - cmd.commandBuffer.size); - break; - case amdgpu::bridge::CommandId::Flip: { - if (!isImageAcquired) { - Verify() << vkAcquireNextImageKHR(vkDevice, swapchain, UINT64_MAX, - presentCompleteSemaphore, nullptr, - &imageIndex); - - vkWaitForFences(vkDevice, 1, &inFlightFences[imageIndex], VK_TRUE, - UINT64_MAX); - vkResetFences(vkDevice, 1, &inFlightFences[imageIndex]); - } - - isImageAcquired = false; - - vkResetCommandBuffer(presentCmdBuffers[imageIndex], 0); - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - vkBeginCommandBuffer(presentCmdBuffers[imageIndex], &beginInfo); - - if (device.handleFlip( - presentQueue, presentCmdBuffers[imageIndex], - *flipTaskChain[imageIndex].get(), cmd.flip.bufferIndex, - cmd.flip.arg, swapchainImages[imageIndex], swapchainExtent, - presentCompleteSemaphore, renderCompleteSemaphore, - inFlightFences[imageIndex])) { - VkPresentInfoKHR presentInfo{ - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &renderCompleteSemaphore, - .swapchainCount = 1, - .pSwapchains = &swapchain, - .pImageIndices = &imageIndex, - }; - if (vkQueuePresentKHR(presentQueue, &presentInfo) != VK_SUCCESS) { - std::printf("swapchain was invalidated\n"); - createSwapchain(); - } - } else { - isImageAcquired = true; - } - break; - } - - default: - util::unreachable("Unexpected command id %u\n", (unsigned)cmd.id); - } - } - } - - if (bridge->pusherPid > 0) { - kill(bridge->pusherPid, SIGINT); - } - - for (auto fence : inFlightFences) { - vkDestroyFence(vkDevice, fence, nullptr); - } - - vkDestroySemaphore(vkDevice, presentCompleteSemaphore, nullptr); - vkDestroySemaphore(vkDevice, renderCompleteSemaphore, nullptr); - vkDestroyCommandPool(vkDevice, commandPool, nullptr); - } - - vkDestroySwapchainKHR(vkDevice, swapchain, nullptr); - vkDestroyDevice(vkDevice, nullptr); - vkDestroySurfaceKHR(vkInstance, vkSurface, nullptr); - vkDestroyInstance(vkInstance, nullptr); - - glfwDestroyWindow(window); - - amdgpu::bridge::destroyShmCommandBuffer(bridge); - amdgpu::bridge::unlinkShm(cmdBridgeName); - return 0; +int main(int argc, const char* argv[]) +{ + if (argc == 2 && (argv[1] == std::string_view("-h") || + argv[1] == std::string_view("--help"))) + { + usage(stdout, argv[0]); + return 0; + } + + const char* cmdBridgeName = "/rpcsx-gpu-cmds"; + const char* shmName = "/rpcsx-os-memory"; + unsigned long gpuIndex = 0; + auto presenter = PresenterMode::Window; + bool enableValidation = false; + + for (int i = 1; i < argc; ++i) + { + if (argv[i] == std::string_view("--cmd-bridge")) + { + if (argc <= i + 1) + { + usage(stderr, argv[0]); + return 1; + } + + cmdBridgeName = argv[++i]; + continue; + } + + if (argv[i] == std::string_view("--shm")) + { + if (argc <= i + 1) + { + usage(stderr, argv[0]); + return 1; + } + shmName = argv[++i]; + continue; + } + + if (argv[i] == std::string_view("--presenter")) + { + if (argc <= i + 1) + { + usage(stderr, argv[0]); + return 1; + } + + auto presenterText = std::string_view(argv[++i]); + + if (presenterText == "window") + { + presenter = PresenterMode::Window; + } + else + { + usage(stderr, argv[0]); + return 1; + } + continue; + } + + if (argv[i] == std::string_view("--gpu")) + { + if (argc <= i + 1) + { + usage(stderr, argv[0]); + return 1; + } + + char* endPtr = nullptr; + gpuIndex = std::strtoul(argv[++i], &endPtr, 10); + if (endPtr == nullptr || *endPtr != '\0') + { + usage(stderr, argv[0]); + return 1; + } + + continue; + } + + if (argv[i] == std::string_view("--validate")) + { + enableValidation = true; + continue; + } + + usage(stderr, argv[0]); + return 1; + } + + glfwInit(); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + auto window = glfwCreateWindow(1280, 720, "RPCSX", nullptr, nullptr); + + const char** glfwExtensions; + uint32_t glfwExtensionCount = 0; + + glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + + auto requiredInstanceExtensions = std::vector( + glfwExtensions, glfwExtensions + glfwExtensionCount); + + if (enableValidation) + { + requiredInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + + uint32_t extCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); + std::vector supportedInstanceExtensions; + + if (extCount > 0) + { + std::vector extensions(extCount); + if (vkEnumerateInstanceExtensionProperties( + nullptr, &extCount, &extensions.front()) == VK_SUCCESS) + { + supportedInstanceExtensions.reserve(extensions.size()); + for (VkExtensionProperties extension : extensions) + { + supportedInstanceExtensions.push_back(extension.extensionName); + } + } + } + + for (const char* extension : requiredInstanceExtensions) + { + if (std::find(supportedInstanceExtensions.begin(), + supportedInstanceExtensions.end(), + extension) == supportedInstanceExtensions.end()) + { + util::unreachable("Requested instance extension '%s' is not present at " + "instance level", + extension); + } + } + + const char* validationLayerName = "VK_LAYER_KHRONOS_validation"; + + VkApplicationInfo appInfo = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "RPCSX", + .pEngineName = "none", + .apiVersion = VK_API_VERSION_1_3, + }; + + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{}; + debugCreateInfo.sType = + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + 0 + // VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT + ; + debugCreateInfo.pfnUserCallback = debugCallback; + + VkInstanceCreateInfo instanceCreateInfo = {}; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + if (enableValidation) + { + instanceCreateInfo.pNext = &debugCreateInfo; + } + instanceCreateInfo.pApplicationInfo = &appInfo; + instanceCreateInfo.enabledExtensionCount = requiredInstanceExtensions.size(); + instanceCreateInfo.ppEnabledExtensionNames = + requiredInstanceExtensions.data(); + + std::vector enabledLayers; + // enabledLayers.push_back("VK_LAYER_KHRONOS_shader_object"); + + if (enableValidation) + { + enabledLayers.push_back(validationLayerName); + } + + instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data(); + instanceCreateInfo.enabledLayerCount = enabledLayers.size(); + + VkInstance vkInstance; + Verify() << vkCreateInstance(&instanceCreateInfo, nullptr, &vkInstance); + auto getVkPhyDevice = [&](unsigned index) { + std::vector devices(index + 1); + uint32_t count = devices.size(); + Verify() << vkEnumeratePhysicalDevices(vkInstance, &count, devices.data()); + Verify() << (index < count); + return devices[index]; + }; + + if (enableValidation) + { + VkDebugUtilsMessengerEXT debugMessenger; + _vkCreateDebugUtilsMessengerEXT(vkInstance, &debugCreateInfo, nullptr, + &debugMessenger); + } + + auto vkPhysicalDevice = getVkPhyDevice(gpuIndex); + + VkPhysicalDeviceProperties vkPhyDeviceProperties; + vkGetPhysicalDeviceProperties(vkPhysicalDevice, &vkPhyDeviceProperties); + std::printf("VK: Selected physical device is %s\n", + vkPhyDeviceProperties.deviceName); + VkPhysicalDeviceMemoryProperties vkPhyDeviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(vkPhysicalDevice, + &vkPhyDeviceMemoryProperties); + + VkPhysicalDevice8BitStorageFeatures storage_8bit = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES}; + VkPhysicalDevice16BitStorageFeatures storage_16bit = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + .pNext = &storage_8bit}; + VkPhysicalDeviceShaderFloat16Int8Features float16_int8 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + .pNext = &storage_16bit}; + + VkPhysicalDeviceFeatures2 features2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &float16_int8}; + vkGetPhysicalDeviceFeatures2(vkPhysicalDevice, &features2); + + Verify() << storage_8bit.uniformAndStorageBuffer8BitAccess; + Verify() << storage_16bit.uniformAndStorageBuffer16BitAccess; + Verify() << float16_int8.shaderFloat16; + Verify() << float16_int8.shaderInt8; + + std::vector vkSupportedDeviceExtensions; + { + uint32_t extCount = 0; + vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, nullptr, &extCount, + nullptr); + if (extCount > 0) + { + std::vector extensions(extCount); + if (vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, nullptr, + &extCount, extensions.data()) == + VK_SUCCESS) + { + + vkSupportedDeviceExtensions.reserve(extCount); + + for (auto ext : extensions) + { + vkSupportedDeviceExtensions.push_back(ext.extensionName); + } + } + } + } + + auto isDeviceExtensionSupported = [&](std::string_view extension) { + return std::find(vkSupportedDeviceExtensions.begin(), + vkSupportedDeviceExtensions.end(), + extension) != vkSupportedDeviceExtensions.end(); + }; + + std::vector requestedDeviceExtensions = { + VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, + VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, + VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, + // VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, + // VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME, + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_SHADER_OBJECT_EXTENSION_NAME, + }; + + if (isDeviceExtensionSupported(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) + { + requestedDeviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + } + + // for (auto extension : vkSupportedDeviceExtensions) { + // std::printf("supported device extension %s\n", extension.c_str()); + // } + + for (const char* requestedExtension : requestedDeviceExtensions) + { + if (!isDeviceExtensionSupported(requestedExtension)) + { + std::fprintf( + stderr, + "Requested device extension '%s' is not present at device level\n", + requestedExtension); + std::abort(); + } + } + + std::vector queueFamilyProperties; + + { + uint32_t queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, + &queueFamilyCount, nullptr); + Verify() << (queueFamilyCount > 0); + queueFamilyProperties.resize(queueFamilyCount); + for (auto& property : queueFamilyProperties) + { + property.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; + } + + vkGetPhysicalDeviceQueueFamilyProperties2( + vkPhysicalDevice, &queueFamilyCount, queueFamilyProperties.data()); + } + + VkSurfaceKHR vkSurface; + Verify() << glfwCreateWindowSurface(vkInstance, window, nullptr, &vkSurface); + + std::set queueFamiliesWithPresentSupport; + std::set queueFamiliesWithTransferSupport; + std::set queueFamiliesWithComputeSupport; + std::set queueFamiliesWithGraphicsSupport; + + uint32_t queueFamiliesCount = 0; + for (auto& familyProperty : queueFamilyProperties) + { + VkBool32 supportsPresent; + if (vkGetPhysicalDeviceSurfaceSupportKHR(vkPhysicalDevice, + queueFamiliesCount, vkSurface, + &supportsPresent) == VK_SUCCESS && + supportsPresent != 0) + { + queueFamiliesWithPresentSupport.insert(queueFamiliesCount); + } + + if (familyProperty.queueFamilyProperties.queueFlags & + VK_QUEUE_SPARSE_BINDING_BIT) + { + if (familyProperty.queueFamilyProperties.queueFlags & + VK_QUEUE_GRAPHICS_BIT) + { + queueFamiliesWithGraphicsSupport.insert(queueFamiliesCount); + } + + if (familyProperty.queueFamilyProperties.queueFlags & + VK_QUEUE_COMPUTE_BIT) + { + queueFamiliesWithComputeSupport.insert(queueFamiliesCount); + } + } + + if (familyProperty.queueFamilyProperties.queueFlags & + VK_QUEUE_TRANSFER_BIT) + { + queueFamiliesWithTransferSupport.insert(queueFamiliesCount); + } + + queueFamiliesCount++; + } + + Verify() << !queueFamiliesWithPresentSupport.empty(); + Verify() << !queueFamiliesWithTransferSupport.empty(); + Verify() << !queueFamiliesWithComputeSupport.empty(); + Verify() << !queueFamiliesWithGraphicsSupport.empty(); + + std::vector requestedQueues; + + std::vector defaultQueuePriorities; + defaultQueuePriorities.resize(32); + + for (uint32_t queueFamily = 0; queueFamily < queueFamiliesCount; + ++queueFamily) + { + if (queueFamiliesWithGraphicsSupport.contains(queueFamily)) + { + requestedQueues.push_back( + {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = queueFamily, + .queueCount = + std::min(queueFamilyProperties[queueFamily] + .queueFamilyProperties.queueCount, + defaultQueuePriorities.size()), + .pQueuePriorities = defaultQueuePriorities.data()}); + } + else if (queueFamiliesWithComputeSupport.contains(queueFamily) || + queueFamiliesWithTransferSupport.contains(queueFamily)) + { + requestedQueues.push_back( + {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = queueFamily, + .queueCount = + std::min(queueFamilyProperties[queueFamily] + .queueFamilyProperties.queueCount, + defaultQueuePriorities.size()), + .pQueuePriorities = defaultQueuePriorities.data()}); + } + } + + VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, + .shaderObject = VK_TRUE}; + + VkPhysicalDeviceVulkan13Features phyDevFeatures13{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &shaderObjectFeatures, + .synchronization2 = VK_TRUE, + .dynamicRendering = VK_TRUE, + .maintenance4 = VK_TRUE, + }; + + VkPhysicalDeviceVulkan12Features phyDevFeatures12{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = &phyDevFeatures13, + .storageBuffer8BitAccess = VK_TRUE, + .uniformAndStorageBuffer8BitAccess = VK_TRUE, + .shaderFloat16 = VK_TRUE, + .shaderInt8 = VK_TRUE, + .timelineSemaphore = VK_TRUE, + }; + + VkPhysicalDeviceVulkan11Features phyDevFeatures11{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, + .pNext = &phyDevFeatures12, + .storageBuffer16BitAccess = VK_TRUE, + .uniformAndStorageBuffer16BitAccess = VK_TRUE, + }; + + VkDeviceCreateInfo deviceCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &phyDevFeatures11, + .queueCreateInfoCount = static_cast(requestedQueues.size()), + .pQueueCreateInfos = requestedQueues.data(), + .enabledExtensionCount = + static_cast(requestedDeviceExtensions.size()), + .ppEnabledExtensionNames = requestedDeviceExtensions.data(), + .pEnabledFeatures = &features2.features}; + + VkDevice vkDevice; + Verify() << vkCreateDevice(vkPhysicalDevice, &deviceCreateInfo, nullptr, + &vkDevice); + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkExtent2D swapchainExtent{}; + + std::vector swapchainImages; + + VkFormat swapchainColorFormat = VK_FORMAT_B8G8R8A8_UNORM; + VkColorSpaceKHR swapchainColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + + uint32_t formatCount; + Verify() << vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, vkSurface, + &formatCount, nullptr); + Verify() << (formatCount > 0); + + std::vector surfaceFormats(formatCount); + Verify() << vkGetPhysicalDeviceSurfaceFormatsKHR( + vkPhysicalDevice, vkSurface, &formatCount, surfaceFormats.data()); + + if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) + { + swapchainColorFormat = VK_FORMAT_B8G8R8A8_UNORM; + swapchainColorSpace = surfaceFormats[0].colorSpace; + } + else + { + bool found_B8G8R8A8_UNORM = false; + for (auto&& surfaceFormat : surfaceFormats) + { + if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM) + { + swapchainColorFormat = surfaceFormat.format; + swapchainColorSpace = surfaceFormat.colorSpace; + found_B8G8R8A8_UNORM = true; + break; + } + } + + if (!found_B8G8R8A8_UNORM) + { + swapchainColorFormat = surfaceFormats[0].format; + swapchainColorSpace = surfaceFormats[0].colorSpace; + } + } + + auto createSwapchain = [&] { + VkSwapchainKHR oldSwapchain = swapchain; + + VkSurfaceCapabilitiesKHR surfCaps; + Verify() << vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, + vkSurface, &surfCaps); + uint32_t presentModeCount; + Verify() << vkGetPhysicalDeviceSurfacePresentModesKHR( + vkPhysicalDevice, vkSurface, &presentModeCount, NULL); + Verify() << (presentModeCount > 0); + + std::vector presentModes(presentModeCount); + Verify() << vkGetPhysicalDeviceSurfacePresentModesKHR( + vkPhysicalDevice, vkSurface, &presentModeCount, presentModes.data()); + + if (surfCaps.currentExtent.width != (uint32_t)-1) + { + swapchainExtent = surfCaps.currentExtent; + } + + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (std::size_t i = 0; i < presentModeCount; i++) + { + if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + continue; + } + + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) + { + swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; + break; + } + } + + uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount; + if ((surfCaps.maxImageCount > 0) && + (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) + { + desiredNumberOfSwapchainImages = surfCaps.maxImageCount; + } + + VkSurfaceTransformFlagsKHR preTransform; + if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + { + preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + } + else + { + preTransform = surfCaps.currentTransform; + } + + VkCompositeAlphaFlagBitsKHR compositeAlpha = + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + std::vector compositeAlphaFlags = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + }; + + for (auto& compositeAlphaFlag : compositeAlphaFlags) + { + if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) + { + compositeAlpha = compositeAlphaFlag; + break; + } + } + + VkSwapchainCreateInfoKHR swapchainCI = {}; + swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainCI.surface = vkSurface; + swapchainCI.minImageCount = desiredNumberOfSwapchainImages; + swapchainCI.imageFormat = swapchainColorFormat; + swapchainCI.imageColorSpace = swapchainColorSpace; + swapchainCI.imageExtent = {swapchainExtent.width, swapchainExtent.height}; + swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform; + swapchainCI.imageArrayLayers = 1; + swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainCI.queueFamilyIndexCount = 0; + swapchainCI.presentMode = swapchainPresentMode; + swapchainCI.oldSwapchain = oldSwapchain; + swapchainCI.clipped = VK_TRUE; + swapchainCI.compositeAlpha = compositeAlpha; + + if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + { + swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) + { + swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + Verify() << vkCreateSwapchainKHR(vkDevice, &swapchainCI, nullptr, + &swapchain); + + if (oldSwapchain != VK_NULL_HANDLE) + { + vkDestroySwapchainKHR(vkDevice, oldSwapchain, nullptr); + } + + uint32_t swapchainImageCount = 0; + Verify() << vkGetSwapchainImagesKHR(vkDevice, swapchain, + &swapchainImageCount, nullptr); + + swapchainImages.resize(swapchainImageCount); + Verify() << vkGetSwapchainImagesKHR( + vkDevice, swapchain, &swapchainImageCount, swapchainImages.data()); + }; + + createSwapchain(); + + std::vector> computeQueues; + std::vector> graphicsQueues; + VkQueue presentQueue = VK_NULL_HANDLE; + unsigned presentQueueFamily; + + for (auto& queueInfo : requestedQueues) + { + if (queueFamiliesWithGraphicsSupport.contains(queueInfo.queueFamilyIndex)) + { + for (uint32_t queueIndex = 0; queueIndex < queueInfo.queueCount; + ++queueIndex) + { + + if (presentQueue == VK_NULL_HANDLE && + queueFamiliesWithPresentSupport.contains( + queueInfo.queueFamilyIndex)) + { + presentQueueFamily = queueInfo.queueFamilyIndex; + vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, 0, + &presentQueue); + + continue; + } + + auto& [queue, index] = graphicsQueues.emplace_back(); + index = queueInfo.queueFamilyIndex; + vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, + &queue); + } + + continue; + } + + if (queueFamiliesWithComputeSupport.contains(queueInfo.queueFamilyIndex)) + { + if (!queueFamiliesWithTransferSupport.contains( + queueInfo.queueFamilyIndex)) + { + util::unreachable(); + } + + uint32_t queueIndex = 0; + for (; queueIndex < queueInfo.queueCount; ++queueIndex) + { + auto& [queue, index] = computeQueues.emplace_back(); + index = queueInfo.queueFamilyIndex; + vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, + &queue); + } + + continue; + } + } + + if (graphicsQueues.empty() && presentQueue != VK_NULL_HANDLE) + { + graphicsQueues.push_back({presentQueue, presentQueueFamily}); + } + + Verify() << (computeQueues.size() > 1); + Verify() << (graphicsQueues.size() > 0); + Verify() << (presentQueue != VK_NULL_HANDLE); + + amdgpu::device::vk::g_computeQueues = computeQueues; + amdgpu::device::vk::g_graphicsQueues = graphicsQueues; + + VkCommandPoolCreateInfo commandPoolCreateInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = presentQueueFamily, + }; + + VkCommandPool commandPool; + Verify() << vkCreateCommandPool(vkDevice, &commandPoolCreateInfo, nullptr, + &commandPool); + std::vector inFlightFences(swapchainImages.size()); + + for (auto& fence : inFlightFences) + { + VkFenceCreateInfo fenceInfo{}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + Verify() << vkCreateFence(vkDevice, &fenceInfo, nullptr, &fence); + } + + VkSemaphore presentCompleteSemaphore; + VkSemaphore renderCompleteSemaphore; + { + VkSemaphoreCreateInfo semaphoreCreateInfo{}; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + Verify() << vkCreateSemaphore(vkDevice, &semaphoreCreateInfo, nullptr, + &presentCompleteSemaphore); + Verify() << vkCreateSemaphore(vkDevice, &semaphoreCreateInfo, nullptr, + &renderCompleteSemaphore); + } + + amdgpu::device::setVkDevice(vkDevice, vkPhyDeviceMemoryProperties, + vkPhyDeviceProperties); + + auto bridge = amdgpu::bridge::openShmCommandBuffer(cmdBridgeName); + if (bridge == nullptr) + { + bridge = amdgpu::bridge::createShmCommandBuffer(cmdBridgeName); + } + + if (bridge->pullerPid > 0 && ::kill(bridge->pullerPid, 0) == 0) + { + // another instance of rpcsx-gpu on the same bridge, kill self after that + + std::fprintf(stderr, "Another instance already exists\n"); + return 1; + } + + bridge->pullerPid = ::getpid(); + + amdgpu::bridge::BridgePuller bridgePuller{bridge}; + amdgpu::bridge::Command commandsBuffer[1]; + + if (!std::filesystem::exists(std::string("/dev/shm") + shmName)) + { + std::printf("Waiting for OS\n"); + while (!std::filesystem::exists(std::string("/dev/shm") + shmName)) + { + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + } + } + + int memoryFd = ::shm_open(shmName, O_RDWR, S_IRUSR | S_IWUSR); + + if (memoryFd < 0) + { + std::printf("failed to open shared memory\n"); + return 1; + } + + struct stat memoryStat; + ::fstat(memoryFd, &memoryStat); + amdgpu::RemoteMemory memory{(char*)::mmap( + nullptr, memoryStat.st_size, PROT_NONE, MAP_SHARED, memoryFd, 0)}; + + extern void* g_rwMemory; + g_memorySize = memoryStat.st_size; + g_memoryBase = 0x40000; + g_rwMemory = ::mmap(nullptr, g_memorySize, PROT_READ | PROT_WRITE, MAP_SHARED, + memoryFd, 0); + + g_hostMemory = memory; + + { + amdgpu::device::AmdgpuDevice device(bridgePuller.header); + + for (std::uint32_t end = bridge->memoryAreaCount, i = 0; i < end; ++i) + { + auto area = bridge->memoryAreas[i]; + device.handleProtectMemory(area.address, area.size, area.prot); + } + + std::vector presentCmdBuffers(swapchainImages.size()); + + { + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = presentCmdBuffers.size(); + vkAllocateCommandBuffers(vkDevice, &allocInfo, presentCmdBuffers.data()); + } + + std::vector> flipTaskChain( + swapchainImages.size()); + + for (auto& chain : flipTaskChain) + { + chain = amdgpu::device::TaskChain::Create(); + } + std::printf("Initialization complete\n"); + + uint32_t imageIndex = 0; + bool isImageAcquired = false; + uint32_t gpIndex = -1; + GLFWgamepadstate gpState; + + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + + std::size_t pulledCount = + bridgePuller.pullCommands(commandsBuffer, std::size(commandsBuffer)); + + if (gpIndex > GLFW_JOYSTICK_LAST) + { + for (int i = 0; i <= GLFW_JOYSTICK_LAST; ++i) + { + if (glfwJoystickIsGamepad(i) == GLFW_TRUE) + { + std::printf("Gamepad \"%s\" activated", glfwGetGamepadName(i)); + gpIndex = i; + break; + } + } + } + else if (gpIndex <= GLFW_JOYSTICK_LAST) + { + if (!glfwJoystickIsGamepad(gpIndex)) + { + gpIndex = -1; + } + } + + if (gpIndex <= GLFW_JOYSTICK_LAST) + { + if (glfwGetGamepadState(gpIndex, &gpState) == GLFW_TRUE) + { + bridge->kbPadState.leftStickX = + gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 127.5f + 127.5f; + bridge->kbPadState.leftStickY = + gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 127.5f + 127.5f; + bridge->kbPadState.rightStickX = + gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 127.5f + 127.5f; + bridge->kbPadState.rightStickY = + gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 127.5f + 127.5f; + bridge->kbPadState.l2 = + (gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 127.5f; + bridge->kbPadState.r2 = + (gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 127.5f; + bridge->kbPadState.buttons = 0; + + if (bridge->kbPadState.l2 == 0xFF) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; + } + + if (bridge->kbPadState.r2 == 0xFF) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; + } + + static const uint32_t gpmap[GLFW_GAMEPAD_BUTTON_LAST + 1] = { + [GLFW_GAMEPAD_BUTTON_A] = amdgpu::bridge::kPadBtnCross, + [GLFW_GAMEPAD_BUTTON_B] = amdgpu::bridge::kPadBtnCircle, + [GLFW_GAMEPAD_BUTTON_X] = amdgpu::bridge::kPadBtnSquare, + [GLFW_GAMEPAD_BUTTON_Y] = amdgpu::bridge::kPadBtnTriangle, + [GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = amdgpu::bridge::kPadBtnL1, + [GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = amdgpu::bridge::kPadBtnR1, + [GLFW_GAMEPAD_BUTTON_BACK] = 0, + [GLFW_GAMEPAD_BUTTON_START] = amdgpu::bridge::kPadBtnOptions, + [GLFW_GAMEPAD_BUTTON_GUIDE] = 0, + [GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = amdgpu::bridge::kPadBtnL3, + [GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = amdgpu::bridge::kPadBtnR3, + [GLFW_GAMEPAD_BUTTON_DPAD_UP] = amdgpu::bridge::kPadBtnUp, + [GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = amdgpu::bridge::kPadBtnRight, + [GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = amdgpu::bridge::kPadBtnDown, + [GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = amdgpu::bridge::kPadBtnLeft}; + + for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; ++i) + { + if (gpState.buttons[i] == GLFW_PRESS) + { + bridge->kbPadState.buttons |= gpmap[i]; + } + } + } + } + else + { + bridge->kbPadState.leftStickX = 0x80; + bridge->kbPadState.leftStickY = 0x80; + bridge->kbPadState.rightStickX = 0x80; + bridge->kbPadState.rightStickY = 0x80; + bridge->kbPadState.buttons = 0; + + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + { + bridge->kbPadState.leftStickX = 0; + } + else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + { + bridge->kbPadState.leftStickX = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + { + bridge->kbPadState.leftStickY = 0; + } + else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + { + bridge->kbPadState.leftStickY = 0xff; + } + + if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) + { + bridge->kbPadState.rightStickX = 0; + } + else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) + { + bridge->kbPadState.rightStickX = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) + { + bridge->kbPadState.rightStickY = 0; + } + else if (glfwGetKey(window, GLFW_KEY_SEMICOLON) == GLFW_PRESS) + { + bridge->kbPadState.rightStickY = 0xff; + } + + if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnUp; + } + if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnDown; + } + if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnLeft; + } + if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnRight; + } + if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnSquare; + } + if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCross; + } + if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCircle; + } + if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnTriangle; + } + + if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL1; + } + if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; + bridge->kbPadState.l2 = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL3; + } + + if (glfwGetKey(window, GLFW_KEY_I) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR1; + } + if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; + bridge->kbPadState.r2 = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_APOSTROPHE) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR3; + } + + if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS) + { + bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnOptions; + } + } + + bridge->kbPadState.timestamp = + std::chrono::high_resolution_clock::now().time_since_epoch().count(); + + if (pulledCount == 0) + { + // std::this_thread::sleep_for( + // std::chrono::milliseconds(1)); // Just for testing, should be + // removed + continue; + } + + for (auto cmd : std::span(commandsBuffer, pulledCount)) + { + switch (cmd.id) + { + case amdgpu::bridge::CommandId::ProtectMemory: + device.handleProtectMemory(cmd.memoryProt.address, + cmd.memoryProt.size, cmd.memoryProt.prot); + break; + case amdgpu::bridge::CommandId::CommandBuffer: + device.handleCommandBuffer(cmd.commandBuffer.queue, + cmd.commandBuffer.address, + cmd.commandBuffer.size); + break; + case amdgpu::bridge::CommandId::Flip: + { + if (!isImageAcquired) + { + Verify() << vkAcquireNextImageKHR(vkDevice, swapchain, UINT64_MAX, + presentCompleteSemaphore, nullptr, + &imageIndex); + + vkWaitForFences(vkDevice, 1, &inFlightFences[imageIndex], VK_TRUE, + UINT64_MAX); + vkResetFences(vkDevice, 1, &inFlightFences[imageIndex]); + } + + isImageAcquired = false; + + vkResetCommandBuffer(presentCmdBuffers[imageIndex], 0); + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(presentCmdBuffers[imageIndex], &beginInfo); + + if (device.handleFlip( + presentQueue, presentCmdBuffers[imageIndex], + *flipTaskChain[imageIndex].get(), cmd.flip.bufferIndex, + cmd.flip.arg, swapchainImages[imageIndex], swapchainExtent, + presentCompleteSemaphore, renderCompleteSemaphore, + inFlightFences[imageIndex])) + { + VkPresentInfoKHR presentInfo{ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &renderCompleteSemaphore, + .swapchainCount = 1, + .pSwapchains = &swapchain, + .pImageIndices = &imageIndex, + }; + if (vkQueuePresentKHR(presentQueue, &presentInfo) != VK_SUCCESS) + { + std::printf("swapchain was invalidated\n"); + createSwapchain(); + } + } + else + { + isImageAcquired = true; + } + break; + } + + default: + util::unreachable("Unexpected command id %u\n", (unsigned)cmd.id); + } + } + } + + if (bridge->pusherPid > 0) + { + kill(bridge->pusherPid, SIGINT); + } + + for (auto fence : inFlightFences) + { + vkDestroyFence(vkDevice, fence, nullptr); + } + + vkDestroySemaphore(vkDevice, presentCompleteSemaphore, nullptr); + vkDestroySemaphore(vkDevice, renderCompleteSemaphore, nullptr); + vkDestroyCommandPool(vkDevice, commandPool, nullptr); + } + + vkDestroySwapchainKHR(vkDevice, swapchain, nullptr); + vkDestroyDevice(vkDevice, nullptr); + vkDestroySurfaceKHR(vkInstance, vkSurface, nullptr); + vkDestroyInstance(vkInstance, nullptr); + + glfwDestroyWindow(window); + + amdgpu::bridge::destroyShmCommandBuffer(bridge); + amdgpu::bridge::unlinkShm(cmdBridgeName); + return 0; } diff --git a/rpcsx-os/align.hpp b/rpcsx-os/align.hpp index 9ec863aa..541d30de 100644 --- a/rpcsx-os/align.hpp +++ b/rpcsx-os/align.hpp @@ -2,13 +2,16 @@ #include -namespace utils { -inline constexpr std::uint64_t alignUp(std::uint64_t value, - std::uint64_t alignment) { - return (value + (alignment - 1)) & ~(alignment - 1); -} -inline constexpr std::uint64_t alignDown(std::uint64_t value, - std::uint64_t alignment) { - return value & ~(alignment - 1); -} +namespace utils +{ + inline constexpr std::uint64_t alignUp(std::uint64_t value, + std::uint64_t alignment) + { + return (value + (alignment - 1)) & ~(alignment - 1); + } + inline constexpr std::uint64_t alignDown(std::uint64_t value, + std::uint64_t alignment) + { + return value & ~(alignment - 1); + } } // namespace utils diff --git a/rpcsx-os/backtrace.cpp b/rpcsx-os/backtrace.cpp index a6e8ad5c..dfe5b6cb 100644 --- a/rpcsx-os/backtrace.cpp +++ b/rpcsx-os/backtrace.cpp @@ -6,123 +6,134 @@ #include #include -std::size_t rx::printAddressLocation(char *dest, std::size_t destLen, - orbis::Thread *thread, - std::uint64_t address) { - if (thread == nullptr || address == 0) { - return 0; - } - - for (auto [id, module] : thread->tproc->modulesMap) { - auto moduleBase = reinterpret_cast(module->base); - if (moduleBase > address || moduleBase + module->size <= address) { - continue; - } - - return std::snprintf(dest, destLen, "%s+%#" PRIx64 " (%#" PRIx64 ")", - module->soName[0] != '\0' ? module->soName - : module->moduleName, - address - moduleBase, address); - } - - return 0; +std::size_t rx::printAddressLocation(char* dest, std::size_t destLen, + orbis::Thread* thread, + std::uint64_t address) +{ + if (thread == nullptr || address == 0) + { + return 0; + } + + for (auto [id, module] : thread->tproc->modulesMap) + { + auto moduleBase = reinterpret_cast(module->base); + if (moduleBase > address || moduleBase + module->size <= address) + { + continue; + } + + return std::snprintf(dest, destLen, "%s+%#" PRIx64 " (%#" PRIx64 ")", + module->soName[0] != '\0' ? module->soName : module->moduleName, + address - moduleBase, address); + } + + return 0; } -void rx::printStackTrace(ucontext_t *context, int fileno) { - unw_cursor_t cursor; - - char buffer[1024]; - - flockfile(stderr); - if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) { - int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", - unw_strerror(r)); - write(fileno, buffer, len); - funlockfile(stderr); - return; - } - - char functionName[256]; - - int count = 0; - do { - unw_word_t ip; - unw_get_reg(&cursor, UNW_REG_IP, &ip); - - unw_word_t off; - int proc_res = - unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); - - Dl_info dlinfo; - int dladdr_res = ::dladdr((void *)ip, &dlinfo); - - unsigned long baseAddress = - dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) : 0; - - int len = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", - count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), - reinterpret_cast(ip - baseAddress), - (proc_res == 0 ? functionName : "??"), - reinterpret_cast( - proc_res == 0 ? ip - baseAddress - off : 0), - static_cast(proc_res == 0 ? off : 0)); - write(fileno, buffer, len); - count++; - } while (unw_step(&cursor) > 0 && count < 32); - funlockfile(stderr); +void rx::printStackTrace(ucontext_t* context, int fileno) +{ + unw_cursor_t cursor; + + char buffer[1024]; + + flockfile(stderr); + if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) + { + int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", + unw_strerror(r)); + write(fileno, buffer, len); + funlockfile(stderr); + return; + } + + char functionName[256]; + + int count = 0; + do + { + unw_word_t ip; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + + unw_word_t off; + int proc_res = + unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); + + Dl_info dlinfo; + int dladdr_res = ::dladdr((void*)ip, &dlinfo); + + unsigned long baseAddress = + dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) : 0; + + int len = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", + count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), + reinterpret_cast(ip - baseAddress), + (proc_res == 0 ? functionName : "??"), + reinterpret_cast( + proc_res == 0 ? ip - baseAddress - off : 0), + static_cast(proc_res == 0 ? off : 0)); + write(fileno, buffer, len); + count++; + } while (unw_step(&cursor) > 0 && count < 32); + funlockfile(stderr); } -void rx::printStackTrace(ucontext_t *context, orbis::Thread *thread, - int fileno) { - unw_cursor_t cursor; - - char buffer[1024]; - flockfile(stderr); - if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) { - int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", - unw_strerror(r)); - write(fileno, buffer, len); - funlockfile(stderr); - return; - } - - int count = 0; - char functionName[256]; - do { - unw_word_t ip; - unw_get_reg(&cursor, UNW_REG_IP, &ip); - std::size_t offset = 0; - - offset += - std::snprintf(buffer + offset, sizeof(buffer) - offset, "%3d: ", count); - - if (auto loc = printAddressLocation(buffer + offset, - sizeof(buffer) - offset, thread, ip)) { - offset += loc; - offset += std::snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); - } else { - unw_word_t off; - int proc_res = - unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); - - Dl_info dlinfo; - int dladdr_res = ::dladdr((void *)ip, &dlinfo); - - unsigned long baseAddress = - dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) - : 0; - - offset = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", - count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), - reinterpret_cast(ip - baseAddress), - (proc_res == 0 ? functionName : "??"), - reinterpret_cast( - proc_res == 0 ? ip - baseAddress - off : 0), - static_cast(proc_res == 0 ? off : 0)); - } - - write(fileno, buffer, offset); - count++; - } while (unw_step(&cursor) > 0 && count < 32); - funlockfile(stderr); +void rx::printStackTrace(ucontext_t* context, orbis::Thread* thread, + int fileno) +{ + unw_cursor_t cursor; + + char buffer[1024]; + flockfile(stderr); + if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) + { + int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", + unw_strerror(r)); + write(fileno, buffer, len); + funlockfile(stderr); + return; + } + + int count = 0; + char functionName[256]; + do + { + unw_word_t ip; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + std::size_t offset = 0; + + offset += + std::snprintf(buffer + offset, sizeof(buffer) - offset, "%3d: ", count); + + if (auto loc = printAddressLocation(buffer + offset, + sizeof(buffer) - offset, thread, ip)) + { + offset += loc; + offset += std::snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); + } + else + { + unw_word_t off; + int proc_res = + unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); + + Dl_info dlinfo; + int dladdr_res = ::dladdr((void*)ip, &dlinfo); + + unsigned long baseAddress = + dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) : 0; + + offset = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", + count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), + reinterpret_cast(ip - baseAddress), + (proc_res == 0 ? functionName : "??"), + reinterpret_cast( + proc_res == 0 ? ip - baseAddress - off : 0), + static_cast(proc_res == 0 ? off : 0)); + } + + write(fileno, buffer, offset); + count++; + } while (unw_step(&cursor) > 0 && count < 32); + funlockfile(stderr); } diff --git a/rpcsx-os/backtrace.hpp b/rpcsx-os/backtrace.hpp index bd350e3d..fdb8219d 100644 --- a/rpcsx-os/backtrace.hpp +++ b/rpcsx-os/backtrace.hpp @@ -4,9 +4,10 @@ #include #include -namespace rx { -std::size_t printAddressLocation(char *dest, std::size_t destLen, - orbis::Thread *thread, std::uint64_t address); -void printStackTrace(ucontext_t *context, int fileno); -void printStackTrace(ucontext_t *context, orbis::Thread *thread, int fileno); +namespace rx +{ + std::size_t printAddressLocation(char* dest, std::size_t destLen, + orbis::Thread* thread, std::uint64_t address); + void printStackTrace(ucontext_t* context, int fileno); + void printStackTrace(ucontext_t* context, orbis::Thread* thread, int fileno); } // namespace rx diff --git a/rpcsx-os/bridge.hpp b/rpcsx-os/bridge.hpp index 21c9f904..12a0f6ed 100644 --- a/rpcsx-os/bridge.hpp +++ b/rpcsx-os/bridge.hpp @@ -2,6 +2,7 @@ #include -namespace rx { -extern amdgpu::bridge::BridgePusher bridge; +namespace rx +{ + extern amdgpu::bridge::BridgePusher bridge; } diff --git a/rpcsx-os/io-device.cpp b/rpcsx-os/io-device.cpp index 568f4eaf..eea51211 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx-os/io-device.cpp @@ -18,486 +18,620 @@ #include #include -struct HostFile : orbis::File { - int hostFd = -1; - - ~HostFile() { - if (hostFd > 0) { - ::close(hostFd); - } - } +struct HostFile : orbis::File +{ + int hostFd = -1; + + ~HostFile() + { + if (hostFd > 0) + { + ::close(hostFd); + } + } }; -struct SocketFile : orbis::File { - orbis::utils::kstring name; - int hostFd = -1; - - ~SocketFile() { - if (hostFd > 0) { - ::close(hostFd); - } - } +struct SocketFile : orbis::File +{ + orbis::utils::kstring name; + int hostFd = -1; + + ~SocketFile() + { + if (hostFd > 0) + { + ::close(hostFd); + } + } }; -struct HostFsDevice : IoDevice { - orbis::kstring hostPath; - - explicit HostFsDevice(orbis::kstring path) : hostPath(std::move(path)) {} - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; - orbis::ErrorCode mkdir(const char *path, int mode, orbis::Thread *thread) override; - orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) override; - orbis::ErrorCode rename(const char *from, const char *to, orbis::Thread *thread) override; +struct HostFsDevice : IoDevice +{ + orbis::kstring hostPath; + + explicit HostFsDevice(orbis::kstring path) + : hostPath(std::move(path)) + { + } + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; + orbis::ErrorCode mkdir(const char* path, int mode, orbis::Thread* thread) override; + orbis::ErrorCode rmdir(const char* path, orbis::Thread* thread) override; + orbis::ErrorCode rename(const char* from, const char* to, orbis::Thread* thread) override; }; -static orbis::ErrorCode convertErrc(std::errc errc) { - if (errc == std::errc{}) { - return{}; - } - - switch (errc) { - case std::errc::address_family_not_supported: return orbis::ErrorCode::AFNOSUPPORT; - case std::errc::address_in_use: return orbis::ErrorCode::ADDRINUSE; - case std::errc::address_not_available: return orbis::ErrorCode::ADDRNOTAVAIL; - case std::errc::already_connected: return orbis::ErrorCode::ISCONN; - case std::errc::argument_out_of_domain: return orbis::ErrorCode::DOM; - case std::errc::bad_address: return orbis::ErrorCode::FAULT; - case std::errc::bad_file_descriptor: return orbis::ErrorCode::BADF; - case std::errc::bad_message: return orbis::ErrorCode::BADMSG; - case std::errc::broken_pipe: return orbis::ErrorCode::PIPE; - case std::errc::connection_aborted: return orbis::ErrorCode::CONNABORTED; - case std::errc::connection_already_in_progress: return orbis::ErrorCode::ALREADY; - case std::errc::connection_refused: return orbis::ErrorCode::CONNREFUSED; - case std::errc::connection_reset: return orbis::ErrorCode::CONNRESET; - case std::errc::cross_device_link: return orbis::ErrorCode::XDEV; - case std::errc::destination_address_required: return orbis::ErrorCode::DESTADDRREQ; - case std::errc::device_or_resource_busy: return orbis::ErrorCode::BUSY; - case std::errc::directory_not_empty: return orbis::ErrorCode::NOTEMPTY; - case std::errc::executable_format_error: return orbis::ErrorCode::NOEXEC; - case std::errc::file_exists: return orbis::ErrorCode::EXIST; - case std::errc::file_too_large: return orbis::ErrorCode::FBIG; - case std::errc::filename_too_long: return orbis::ErrorCode::NAMETOOLONG; - case std::errc::function_not_supported: return orbis::ErrorCode::NOSYS; - case std::errc::host_unreachable: return orbis::ErrorCode::HOSTUNREACH; - case std::errc::identifier_removed: return orbis::ErrorCode::IDRM; - case std::errc::illegal_byte_sequence: return orbis::ErrorCode::ILSEQ; - case std::errc::inappropriate_io_control_operation: return orbis::ErrorCode::NOTTY; - case std::errc::interrupted: return orbis::ErrorCode::INTR; - case std::errc::invalid_argument: return orbis::ErrorCode::INVAL; - case std::errc::invalid_seek: return orbis::ErrorCode::SPIPE; - case std::errc::io_error: return orbis::ErrorCode::IO; - case std::errc::is_a_directory: return orbis::ErrorCode::ISDIR; - case std::errc::message_size: return orbis::ErrorCode::MSGSIZE; - case std::errc::network_down: return orbis::ErrorCode::NETDOWN; - case std::errc::network_reset: return orbis::ErrorCode::NETRESET; - case std::errc::network_unreachable: return orbis::ErrorCode::NETUNREACH; - case std::errc::no_buffer_space: return orbis::ErrorCode::NOBUFS; - case std::errc::no_child_process: return orbis::ErrorCode::CHILD; - case std::errc::no_link: return orbis::ErrorCode::NOLINK; - case std::errc::no_lock_available: return orbis::ErrorCode::NOLCK; - case std::errc::no_message: return orbis::ErrorCode::NOMSG; - case std::errc::no_protocol_option: return orbis::ErrorCode::NOPROTOOPT; - case std::errc::no_space_on_device: return orbis::ErrorCode::NOSPC; - case std::errc::no_such_device_or_address: return orbis::ErrorCode::NXIO; - case std::errc::no_such_device: return orbis::ErrorCode::NODEV; - case std::errc::no_such_file_or_directory: return orbis::ErrorCode::NOENT; - case std::errc::no_such_process: return orbis::ErrorCode::SRCH; - case std::errc::not_a_directory: return orbis::ErrorCode::NOTDIR; - case std::errc::not_a_socket: return orbis::ErrorCode::NOTSOCK; - case std::errc::not_connected: return orbis::ErrorCode::NOTCONN; - case std::errc::not_enough_memory: return orbis::ErrorCode::NOMEM; - case std::errc::not_supported: return orbis::ErrorCode::NOTSUP; - case std::errc::operation_canceled: return orbis::ErrorCode::CANCELED; - case std::errc::operation_in_progress: return orbis::ErrorCode::INPROGRESS; - case std::errc::operation_not_permitted: return orbis::ErrorCode::PERM; - case std::errc::operation_would_block: return orbis::ErrorCode::WOULDBLOCK; - case std::errc::permission_denied: return orbis::ErrorCode::ACCES; - case std::errc::protocol_error: return orbis::ErrorCode::PROTO; - case std::errc::protocol_not_supported: return orbis::ErrorCode::PROTONOSUPPORT; - case std::errc::read_only_file_system: return orbis::ErrorCode::ROFS; - case std::errc::resource_deadlock_would_occur: return orbis::ErrorCode::DEADLK; - case std::errc::result_out_of_range: return orbis::ErrorCode::RANGE; - case std::errc::text_file_busy: return orbis::ErrorCode::TXTBSY; - case std::errc::timed_out: return orbis::ErrorCode::TIMEDOUT; - case std::errc::too_many_files_open_in_system: return orbis::ErrorCode::NFILE; - case std::errc::too_many_files_open: return orbis::ErrorCode::MFILE; - case std::errc::too_many_links: return orbis::ErrorCode::MLINK; - case std::errc::too_many_symbolic_link_levels: return orbis::ErrorCode::LOOP; - case std::errc::value_too_large: return orbis::ErrorCode::OVERFLOW; - case std::errc::wrong_protocol_type: return orbis::ErrorCode::PROTOTYPE; - default: - return orbis::ErrorCode::FAULT; - } +static orbis::ErrorCode convertErrc(std::errc errc) +{ + if (errc == std::errc{}) + { + return {}; + } + + switch (errc) + { + case std::errc::address_family_not_supported: + return orbis::ErrorCode::AFNOSUPPORT; + case std::errc::address_in_use: + return orbis::ErrorCode::ADDRINUSE; + case std::errc::address_not_available: + return orbis::ErrorCode::ADDRNOTAVAIL; + case std::errc::already_connected: + return orbis::ErrorCode::ISCONN; + case std::errc::argument_out_of_domain: + return orbis::ErrorCode::DOM; + case std::errc::bad_address: + return orbis::ErrorCode::FAULT; + case std::errc::bad_file_descriptor: + return orbis::ErrorCode::BADF; + case std::errc::bad_message: + return orbis::ErrorCode::BADMSG; + case std::errc::broken_pipe: + return orbis::ErrorCode::PIPE; + case std::errc::connection_aborted: + return orbis::ErrorCode::CONNABORTED; + case std::errc::connection_already_in_progress: + return orbis::ErrorCode::ALREADY; + case std::errc::connection_refused: + return orbis::ErrorCode::CONNREFUSED; + case std::errc::connection_reset: + return orbis::ErrorCode::CONNRESET; + case std::errc::cross_device_link: + return orbis::ErrorCode::XDEV; + case std::errc::destination_address_required: + return orbis::ErrorCode::DESTADDRREQ; + case std::errc::device_or_resource_busy: + return orbis::ErrorCode::BUSY; + case std::errc::directory_not_empty: + return orbis::ErrorCode::NOTEMPTY; + case std::errc::executable_format_error: + return orbis::ErrorCode::NOEXEC; + case std::errc::file_exists: + return orbis::ErrorCode::EXIST; + case std::errc::file_too_large: + return orbis::ErrorCode::FBIG; + case std::errc::filename_too_long: + return orbis::ErrorCode::NAMETOOLONG; + case std::errc::function_not_supported: + return orbis::ErrorCode::NOSYS; + case std::errc::host_unreachable: + return orbis::ErrorCode::HOSTUNREACH; + case std::errc::identifier_removed: + return orbis::ErrorCode::IDRM; + case std::errc::illegal_byte_sequence: + return orbis::ErrorCode::ILSEQ; + case std::errc::inappropriate_io_control_operation: + return orbis::ErrorCode::NOTTY; + case std::errc::interrupted: + return orbis::ErrorCode::INTR; + case std::errc::invalid_argument: + return orbis::ErrorCode::INVAL; + case std::errc::invalid_seek: + return orbis::ErrorCode::SPIPE; + case std::errc::io_error: + return orbis::ErrorCode::IO; + case std::errc::is_a_directory: + return orbis::ErrorCode::ISDIR; + case std::errc::message_size: + return orbis::ErrorCode::MSGSIZE; + case std::errc::network_down: + return orbis::ErrorCode::NETDOWN; + case std::errc::network_reset: + return orbis::ErrorCode::NETRESET; + case std::errc::network_unreachable: + return orbis::ErrorCode::NETUNREACH; + case std::errc::no_buffer_space: + return orbis::ErrorCode::NOBUFS; + case std::errc::no_child_process: + return orbis::ErrorCode::CHILD; + case std::errc::no_link: + return orbis::ErrorCode::NOLINK; + case std::errc::no_lock_available: + return orbis::ErrorCode::NOLCK; + case std::errc::no_message: + return orbis::ErrorCode::NOMSG; + case std::errc::no_protocol_option: + return orbis::ErrorCode::NOPROTOOPT; + case std::errc::no_space_on_device: + return orbis::ErrorCode::NOSPC; + case std::errc::no_such_device_or_address: + return orbis::ErrorCode::NXIO; + case std::errc::no_such_device: + return orbis::ErrorCode::NODEV; + case std::errc::no_such_file_or_directory: + return orbis::ErrorCode::NOENT; + case std::errc::no_such_process: + return orbis::ErrorCode::SRCH; + case std::errc::not_a_directory: + return orbis::ErrorCode::NOTDIR; + case std::errc::not_a_socket: + return orbis::ErrorCode::NOTSOCK; + case std::errc::not_connected: + return orbis::ErrorCode::NOTCONN; + case std::errc::not_enough_memory: + return orbis::ErrorCode::NOMEM; + case std::errc::not_supported: + return orbis::ErrorCode::NOTSUP; + case std::errc::operation_canceled: + return orbis::ErrorCode::CANCELED; + case std::errc::operation_in_progress: + return orbis::ErrorCode::INPROGRESS; + case std::errc::operation_not_permitted: + return orbis::ErrorCode::PERM; + case std::errc::operation_would_block: + return orbis::ErrorCode::WOULDBLOCK; + case std::errc::permission_denied: + return orbis::ErrorCode::ACCES; + case std::errc::protocol_error: + return orbis::ErrorCode::PROTO; + case std::errc::protocol_not_supported: + return orbis::ErrorCode::PROTONOSUPPORT; + case std::errc::read_only_file_system: + return orbis::ErrorCode::ROFS; + case std::errc::resource_deadlock_would_occur: + return orbis::ErrorCode::DEADLK; + case std::errc::result_out_of_range: + return orbis::ErrorCode::RANGE; + case std::errc::text_file_busy: + return orbis::ErrorCode::TXTBSY; + case std::errc::timed_out: + return orbis::ErrorCode::TIMEDOUT; + case std::errc::too_many_files_open_in_system: + return orbis::ErrorCode::NFILE; + case std::errc::too_many_files_open: + return orbis::ErrorCode::MFILE; + case std::errc::too_many_links: + return orbis::ErrorCode::MLINK; + case std::errc::too_many_symbolic_link_levels: + return orbis::ErrorCode::LOOP; + case std::errc::value_too_large: + return orbis::ErrorCode::OVERFLOW; + case std::errc::wrong_protocol_type: + return orbis::ErrorCode::PROTOTYPE; + default: + return orbis::ErrorCode::FAULT; + } } -static orbis::ErrorCode convertErrorCode(const std::error_code &code) { - if (!code) { - return{}; - } - return convertErrc(static_cast(code.value())); +static orbis::ErrorCode convertErrorCode(const std::error_code& code) +{ + if (!code) + { + return {}; + } + return convertErrc(static_cast(code.value())); } -static orbis::ErrorCode convertErrno() { - switch (auto error = errno) { - case EPERM: - return orbis::ErrorCode::PERM; - case ENOENT: - return orbis::ErrorCode::NOENT; - case EBADF: - return orbis::ErrorCode::BADF; - case EIO: - return orbis::ErrorCode::IO; - case EACCES: - return orbis::ErrorCode::ACCES; - case EEXIST: - return orbis::ErrorCode::EXIST; - case EBUSY: - return orbis::ErrorCode::BUSY; - case ENOTDIR: - return orbis::ErrorCode::NOTDIR; - case EISDIR: - return orbis::ErrorCode::ISDIR; - case EFBIG: - return orbis::ErrorCode::FBIG; - case ENOSPC: - return orbis::ErrorCode::NOSPC; - case ESPIPE: - return orbis::ErrorCode::SPIPE; - case EPIPE: - return orbis::ErrorCode::PIPE; - case EINVAL: - return orbis::ErrorCode::INVAL; - - default: - ORBIS_LOG_ERROR("Unconverted errno", error); - } - - return orbis::ErrorCode::IO; +static orbis::ErrorCode convertErrno() +{ + switch (auto error = errno) + { + case EPERM: + return orbis::ErrorCode::PERM; + case ENOENT: + return orbis::ErrorCode::NOENT; + case EBADF: + return orbis::ErrorCode::BADF; + case EIO: + return orbis::ErrorCode::IO; + case EACCES: + return orbis::ErrorCode::ACCES; + case EEXIST: + return orbis::ErrorCode::EXIST; + case EBUSY: + return orbis::ErrorCode::BUSY; + case ENOTDIR: + return orbis::ErrorCode::NOTDIR; + case EISDIR: + return orbis::ErrorCode::ISDIR; + case EFBIG: + return orbis::ErrorCode::FBIG; + case ENOSPC: + return orbis::ErrorCode::NOSPC; + case ESPIPE: + return orbis::ErrorCode::SPIPE; + case EPIPE: + return orbis::ErrorCode::PIPE; + case EINVAL: + return orbis::ErrorCode::INVAL; + + default: + ORBIS_LOG_ERROR("Unconverted errno", error); + } + + return orbis::ErrorCode::IO; } -static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - - std::vector vec; - for (auto entry : std::span(uio->iov, uio->iovcnt)) { - vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); - } - - ssize_t cnt = 0; - if (hostFile->hostFd == 0) { - for (auto io : vec) { - cnt += ::read(hostFile->hostFd, io.iov_base, io.iov_len); - - if (cnt != io.iov_len) { - break; - } - } - } else { - cnt = ::preadv(hostFile->hostFd, vec.data(), vec.size(), uio->offset); - } - if (cnt < 0) { - return convertErrno(); - } - - uio->resid -= cnt; - uio->offset += cnt; - return {}; +static orbis::ErrorCode host_read(orbis::File* file, orbis::Uio* uio, + orbis::Thread*) +{ + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + std::vector vec; + for (auto entry : std::span(uio->iov, uio->iovcnt)) + { + vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); + } + + ssize_t cnt = 0; + if (hostFile->hostFd == 0) + { + for (auto io : vec) + { + cnt += ::read(hostFile->hostFd, io.iov_base, io.iov_len); + + if (cnt != io.iov_len) + { + break; + } + } + } + else + { + cnt = ::preadv(hostFile->hostFd, vec.data(), vec.size(), uio->offset); + } + if (cnt < 0) + { + return convertErrno(); + } + + uio->resid -= cnt; + uio->offset += cnt; + return {}; } -static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - - std::vector vec; - for (auto entry : std::span(uio->iov, uio->iovcnt)) { - vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); - } - - ssize_t cnt = 0; - if (hostFile->hostFd == 1 || hostFile->hostFd == 2) { - for (auto io : vec) { - cnt += ::write(hostFile->hostFd, io.iov_base, io.iov_len); - - if (cnt != io.iov_len) { - break; - } - } - } else { - cnt = ::pwritev(hostFile->hostFd, vec.data(), vec.size(), uio->offset); - } - if (cnt < 0) { - return convertErrno(); - } - - uio->resid -= cnt; - uio->offset += cnt; - return {}; +static orbis::ErrorCode host_write(orbis::File* file, orbis::Uio* uio, + orbis::Thread*) +{ + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + std::vector vec; + for (auto entry : std::span(uio->iov, uio->iovcnt)) + { + vec.push_back({.iov_base = entry.base, .iov_len = entry.len}); + } + + ssize_t cnt = 0; + if (hostFile->hostFd == 1 || hostFile->hostFd == 2) + { + for (auto io : vec) + { + cnt += ::write(hostFile->hostFd, io.iov_base, io.iov_len); + + if (cnt != io.iov_len) + { + break; + } + } + } + else + { + cnt = ::pwritev(hostFile->hostFd, vec.data(), vec.size(), uio->offset); + } + if (cnt < 0) + { + return convertErrno(); + } + + uio->resid -= cnt; + uio->offset += cnt; + return {}; } -static orbis::ErrorCode host_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - - auto result = - rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly); - - if (result == (void *)-1) { - return orbis::ErrorCode::NOMEM; - } - - result = ::mmap(result, size, prot & rx::vm::kMapProtCpuAll, - MAP_SHARED | MAP_FIXED, hostFile->hostFd, offset); - if (result == (void *)-1) { - auto result = convertErrno(); - return result; - } - - std::printf("shm mapped at %p-%p\n", result, (char *)result + size); - - *address = result; - return {}; +static orbis::ErrorCode host_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + auto result = + rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly); + + if (result == (void*)-1) + { + return orbis::ErrorCode::NOMEM; + } + + result = ::mmap(result, size, prot & rx::vm::kMapProtCpuAll, + MAP_SHARED | MAP_FIXED, hostFile->hostFd, offset); + if (result == (void*)-1) + { + auto result = convertErrno(); + return result; + } + + std::printf("shm mapped at %p-%p\n", result, (char*)result + size); + + *address = result; + return {}; } -static orbis::ErrorCode host_stat(orbis::File *file, orbis::Stat *sb, - orbis::Thread *thread) { - auto hostFile = static_cast(file); - struct stat hostStat; - ::fstat(hostFile->hostFd, &hostStat); - sb->dev = hostStat.st_dev; // TODO - sb->ino = hostStat.st_ino; - sb->mode = hostStat.st_mode; - sb->nlink = hostStat.st_nlink; - sb->uid = hostStat.st_uid; - sb->gid = hostStat.st_gid; - sb->rdev = hostStat.st_rdev; - sb->atim = { - .sec = static_cast(hostStat.st_atim.tv_sec), - .nsec = static_cast(hostStat.st_atim.tv_nsec), - }; - sb->mtim = { - .sec = static_cast(hostStat.st_mtim.tv_sec), - .nsec = static_cast(hostStat.st_mtim.tv_nsec), - }; - sb->ctim = { - .sec = static_cast(hostStat.st_mtim.tv_sec), - .nsec = static_cast(hostStat.st_mtim.tv_nsec), - }; - sb->size = hostStat.st_size; - sb->blocks = hostStat.st_blocks; - sb->blksize = hostStat.st_blksize; - // TODO - sb->flags = 0; - sb->gen = 0; - sb->lspare = 0; - sb->birthtim = { - .sec = static_cast(hostStat.st_mtim.tv_sec), - .nsec = static_cast(hostStat.st_mtim.tv_nsec), - }; - - return {}; +static orbis::ErrorCode host_stat(orbis::File* file, orbis::Stat* sb, + orbis::Thread* thread) +{ + auto hostFile = static_cast(file); + struct stat hostStat; + ::fstat(hostFile->hostFd, &hostStat); + sb->dev = hostStat.st_dev; // TODO + sb->ino = hostStat.st_ino; + sb->mode = hostStat.st_mode; + sb->nlink = hostStat.st_nlink; + sb->uid = hostStat.st_uid; + sb->gid = hostStat.st_gid; + sb->rdev = hostStat.st_rdev; + sb->atim = { + .sec = static_cast(hostStat.st_atim.tv_sec), + .nsec = static_cast(hostStat.st_atim.tv_nsec), + }; + sb->mtim = { + .sec = static_cast(hostStat.st_mtim.tv_sec), + .nsec = static_cast(hostStat.st_mtim.tv_nsec), + }; + sb->ctim = { + .sec = static_cast(hostStat.st_mtim.tv_sec), + .nsec = static_cast(hostStat.st_mtim.tv_nsec), + }; + sb->size = hostStat.st_size; + sb->blocks = hostStat.st_blocks; + sb->blksize = hostStat.st_blksize; + // TODO + sb->flags = 0; + sb->gen = 0; + sb->lspare = 0; + sb->birthtim = { + .sec = static_cast(hostStat.st_mtim.tv_sec), + .nsec = static_cast(hostStat.st_mtim.tv_nsec), + }; + + return {}; } -static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len, - orbis::Thread *thread) { - auto hostFile = static_cast(file); - if (!hostFile->dirEntries.empty()) - return orbis::ErrorCode::ISDIR; - - // hack for audio control shared memory - std::uint64_t realLen = len; - if (len == 3880) { - realLen = 0x10000; - } - if (::ftruncate(hostFile->hostFd, realLen)) { - return convertErrno(); - } - - return {}; +static orbis::ErrorCode host_truncate(orbis::File* file, std::uint64_t len, + orbis::Thread* thread) +{ + auto hostFile = static_cast(file); + if (!hostFile->dirEntries.empty()) + return orbis::ErrorCode::ISDIR; + + // hack for audio control shared memory + std::uint64_t realLen = len; + if (len == 3880) + { + realLen = 0x10000; + } + if (::ftruncate(hostFile->hostFd, realLen)) + { + return convertErrno(); + } + + return {}; } -static orbis::ErrorCode socket_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - auto soc = static_cast(file); - ORBIS_LOG_FATAL("Unhandled socket ioctl", request, soc->name); - return {}; +static orbis::ErrorCode socket_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + auto soc = static_cast(file); + ORBIS_LOG_FATAL("Unhandled socket ioctl", request, soc->name); + return {}; } static const orbis::FileOps hostOps = { - .read = host_read, - .write = host_write, - .truncate = host_truncate, - .stat = host_stat, - .mmap = host_mmap, + .read = host_read, + .write = host_write, + .truncate = host_truncate, + .stat = host_stat, + .mmap = host_mmap, }; static const orbis::FileOps socketOps = { - .ioctl = socket_ioctl, + .ioctl = socket_ioctl, }; -IoDevice *createHostIoDevice(orbis::kstring hostPath) { - while (hostPath.size() > 1 && hostPath.ends_with("/")) { - hostPath.resize(hostPath.size() - 1); - } +IoDevice* createHostIoDevice(orbis::kstring hostPath) +{ + while (hostPath.size() > 1 && hostPath.ends_with("/")) + { + hostPath.resize(hostPath.size() - 1); + } - return orbis::knew(std::move(hostPath)); + return orbis::knew(std::move(hostPath)); } -orbis::ErrorCode createSocket(orbis::Ref *file, - orbis::kstring name, int dom, int type, - int prot) { - auto fd = ::socket(dom, type, prot); - if (fd < 0) { - return convertErrno(); - } - - auto s = orbis::knew(); - s->name = std::move(name); - s->hostFd = fd; - s->ops = &socketOps; - *file = s; - return {}; +orbis::ErrorCode createSocket(orbis::Ref* file, + orbis::kstring name, int dom, int type, + int prot) +{ + auto fd = ::socket(dom, type, prot); + if (fd < 0) + { + return convertErrno(); + } + + auto s = orbis::knew(); + s->name = std::move(name); + s->hostFd = fd; + s->ops = &socketOps; + *file = s; + return {}; } -orbis::ErrorCode HostFsDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto realPath = hostPath + "/" + path; - - int realFlags = flags & O_ACCMODE; - flags &= ~O_ACCMODE; - - if ((flags & kOpenFlagAppend) != 0) { - realFlags |= O_APPEND; - flags &= ~kOpenFlagAppend; - } - - if ((flags & kOpenFlagNonBlock) != 0) { - realFlags |= O_NONBLOCK; - flags &= ~kOpenFlagNonBlock; - } - - if ((flags & kOpenFlagFsync) != 0) { - realFlags |= O_FSYNC; - flags &= ~kOpenFlagFsync; - } - - if ((flags & kOpenFlagAsync) != 0) { - realFlags |= O_ASYNC; - flags &= ~kOpenFlagAsync; - } - - if ((flags & kOpenFlagTrunc) != 0) { - realFlags |= O_TRUNC; - flags &= ~kOpenFlagTrunc; - } - - if ((flags & kOpenFlagCreat) != 0) { - realFlags |= O_CREAT; - flags &= ~kOpenFlagCreat; - } - - if ((flags & kOpenFlagExcl) != 0) { - realFlags |= O_EXCL; - flags &= ~kOpenFlagExcl; - } - - if ((flags & kOpenFlagDirectory) != 0) { - realFlags |= O_DIRECTORY; - flags &= ~kOpenFlagDirectory; - } - - if (flags != 0) { - ORBIS_LOG_ERROR("host_open: ***ERROR*** Unhandled open flags", flags); - } - - int hostFd = ::open(realPath.c_str(), realFlags, 0777); - - if (hostFd < 0) { - auto error = convertErrno(); - ORBIS_LOG_ERROR("host_open failed", path, realPath, error); - return error; - } - - // Assume the file is a directory and try to read direntries - orbis::utils::kvector dirEntries; - while (true) { - ::dirent64 hostEntry{}; - auto r = getdents64(hostFd, &hostEntry, sizeof(hostEntry)); - if (r <= 0) - break; - - auto &entry = dirEntries.emplace_back(); - entry.fileno = dirEntries.size(); // TODO - entry.reclen = sizeof(entry); - entry.namlen = std::strlen(hostEntry.d_name); - std::strncpy(entry.name, hostEntry.d_name, sizeof(entry.name)); - if (hostEntry.d_type == DT_REG) - entry.type = orbis::kDtReg; - else if (hostEntry.d_type == DT_DIR || hostEntry.d_type == DT_LNK) - entry.type = orbis::kDtDir; // Assume symlinks to be dirs - else { - ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", realPath, - hostEntry.d_name, hostEntry.d_type); - dirEntries.pop_back(); - } - } - - auto newFile = orbis::knew(); - newFile->hostFd = hostFd; - newFile->dirEntries = std::move(dirEntries); - newFile->ops = &hostOps; - newFile->device = this; - *file = newFile; - return {}; +orbis::ErrorCode HostFsDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto realPath = hostPath + "/" + path; + + int realFlags = flags & O_ACCMODE; + flags &= ~O_ACCMODE; + + if ((flags & kOpenFlagAppend) != 0) + { + realFlags |= O_APPEND; + flags &= ~kOpenFlagAppend; + } + + if ((flags & kOpenFlagNonBlock) != 0) + { + realFlags |= O_NONBLOCK; + flags &= ~kOpenFlagNonBlock; + } + + if ((flags & kOpenFlagFsync) != 0) + { + realFlags |= O_FSYNC; + flags &= ~kOpenFlagFsync; + } + + if ((flags & kOpenFlagAsync) != 0) + { + realFlags |= O_ASYNC; + flags &= ~kOpenFlagAsync; + } + + if ((flags & kOpenFlagTrunc) != 0) + { + realFlags |= O_TRUNC; + flags &= ~kOpenFlagTrunc; + } + + if ((flags & kOpenFlagCreat) != 0) + { + realFlags |= O_CREAT; + flags &= ~kOpenFlagCreat; + } + + if ((flags & kOpenFlagExcl) != 0) + { + realFlags |= O_EXCL; + flags &= ~kOpenFlagExcl; + } + + if ((flags & kOpenFlagDirectory) != 0) + { + realFlags |= O_DIRECTORY; + flags &= ~kOpenFlagDirectory; + } + + if (flags != 0) + { + ORBIS_LOG_ERROR("host_open: ***ERROR*** Unhandled open flags", flags); + } + + int hostFd = ::open(realPath.c_str(), realFlags, 0777); + + if (hostFd < 0) + { + auto error = convertErrno(); + ORBIS_LOG_ERROR("host_open failed", path, realPath, error); + return error; + } + + // Assume the file is a directory and try to read direntries + orbis::utils::kvector dirEntries; + while (true) + { + ::dirent64 hostEntry{}; + auto r = getdents64(hostFd, &hostEntry, sizeof(hostEntry)); + if (r <= 0) + break; + + auto& entry = dirEntries.emplace_back(); + entry.fileno = dirEntries.size(); // TODO + entry.reclen = sizeof(entry); + entry.namlen = std::strlen(hostEntry.d_name); + std::strncpy(entry.name, hostEntry.d_name, sizeof(entry.name)); + if (hostEntry.d_type == DT_REG) + entry.type = orbis::kDtReg; + else if (hostEntry.d_type == DT_DIR || hostEntry.d_type == DT_LNK) + entry.type = orbis::kDtDir; // Assume symlinks to be dirs + else + { + ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", realPath, + hostEntry.d_name, hostEntry.d_type); + dirEntries.pop_back(); + } + } + + auto newFile = orbis::knew(); + newFile->hostFd = hostFd; + newFile->dirEntries = std::move(dirEntries); + newFile->ops = &hostOps; + newFile->device = this; + *file = newFile; + return {}; } -orbis::ErrorCode HostFsDevice::mkdir(const char *path, int mode, orbis::Thread *thread) { - std::error_code ec; - std::filesystem::create_directories(hostPath + "/" + path, ec); - return convertErrorCode(ec); +orbis::ErrorCode HostFsDevice::mkdir(const char* path, int mode, orbis::Thread* thread) +{ + std::error_code ec; + std::filesystem::create_directories(hostPath + "/" + path, ec); + return convertErrorCode(ec); } -orbis::ErrorCode HostFsDevice::rmdir(const char *path, orbis::Thread *thread) { - std::error_code ec; - std::filesystem::remove(hostPath + "/" + path, ec); - return convertErrorCode(ec); +orbis::ErrorCode HostFsDevice::rmdir(const char* path, orbis::Thread* thread) +{ + std::error_code ec; + std::filesystem::remove(hostPath + "/" + path, ec); + return convertErrorCode(ec); } -orbis::ErrorCode HostFsDevice::rename(const char *from, const char *to, orbis::Thread *thread) { - std::error_code ec; - std::filesystem::rename(hostPath + "/" + from, hostPath + "/" + to, ec); - return convertErrorCode(ec); +orbis::ErrorCode HostFsDevice::rename(const char* from, const char* to, orbis::Thread* thread) +{ + std::error_code ec; + std::filesystem::rename(hostPath + "/" + from, hostPath + "/" + to, ec); + return convertErrorCode(ec); } -orbis::File *createHostFile(int hostFd, orbis::Ref device) { - auto newFile = orbis::knew(); - newFile->hostFd = hostFd; - newFile->ops = &hostOps; - newFile->device = device; - return newFile; +orbis::File* createHostFile(int hostFd, orbis::Ref device) +{ + auto newFile = orbis::knew(); + newFile->hostFd = hostFd; + newFile->ops = &hostOps; + newFile->device = device; + return newFile; } -struct FdWrapDevice : public IoDevice { - int fd; - - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - *file = createHostFile(fd, this); - return {}; - } +struct FdWrapDevice : public IoDevice +{ + int fd; + + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + *file = createHostFile(fd, this); + return {}; + } }; -IoDevice *createFdWrapDevice(int fd) { - auto result = orbis::knew(); - result->fd = fd; - return result; +IoDevice* createFdWrapDevice(int fd) +{ + auto result = orbis::knew(); + result->fd = fd; + return result; } diff --git a/rpcsx-os/io-device.hpp b/rpcsx-os/io-device.hpp index 4f877c21..f110603e 100644 --- a/rpcsx-os/io-device.hpp +++ b/rpcsx-os/io-device.hpp @@ -5,44 +5,50 @@ #include "orbis/utils/Rc.hpp" #include -enum OpenFlags { - kOpenFlagReadOnly = 0x0, - kOpenFlagWriteOnly = 0x1, - kOpenFlagReadWrite = 0x2, - kOpenFlagNonBlock = 0x4, - kOpenFlagAppend = 0x8, - kOpenFlagShLock = 0x10, - kOpenFlagExLock = 0x20, - kOpenFlagAsync = 0x40, - kOpenFlagFsync = 0x80, - kOpenFlagCreat = 0x200, - kOpenFlagTrunc = 0x400, - kOpenFlagExcl = 0x800, - kOpenFlagDSync = 0x1000, - kOpenFlagDirect = 0x10000, - kOpenFlagDirectory = 0x20000, +enum OpenFlags +{ + kOpenFlagReadOnly = 0x0, + kOpenFlagWriteOnly = 0x1, + kOpenFlagReadWrite = 0x2, + kOpenFlagNonBlock = 0x4, + kOpenFlagAppend = 0x8, + kOpenFlagShLock = 0x10, + kOpenFlagExLock = 0x20, + kOpenFlagAsync = 0x40, + kOpenFlagFsync = 0x80, + kOpenFlagCreat = 0x200, + kOpenFlagTrunc = 0x400, + kOpenFlagExcl = 0x800, + kOpenFlagDSync = 0x1000, + kOpenFlagDirect = 0x10000, + kOpenFlagDirectory = 0x20000, }; -struct IoDevice : orbis::RcBase { - virtual orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) = 0; - virtual orbis::ErrorCode unlink(const char *path, orbis::Thread *thread) { - return orbis::ErrorCode::NOTSUP; - } - virtual orbis::ErrorCode mkdir(const char *path, int mode, orbis::Thread *thread) { - return orbis::ErrorCode::NOTSUP; - } - virtual orbis::ErrorCode rmdir(const char *path, orbis::Thread *thread) { - return orbis::ErrorCode::NOTSUP; - } - virtual orbis::ErrorCode rename(const char *from, const char *to, orbis::Thread *thread) { - return orbis::ErrorCode::NOTSUP; - } +struct IoDevice : orbis::RcBase +{ + virtual orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) = 0; + virtual orbis::ErrorCode unlink(const char* path, orbis::Thread* thread) + { + return orbis::ErrorCode::NOTSUP; + } + virtual orbis::ErrorCode mkdir(const char* path, int mode, orbis::Thread* thread) + { + return orbis::ErrorCode::NOTSUP; + } + virtual orbis::ErrorCode rmdir(const char* path, orbis::Thread* thread) + { + return orbis::ErrorCode::NOTSUP; + } + virtual orbis::ErrorCode rename(const char* from, const char* to, orbis::Thread* thread) + { + return orbis::ErrorCode::NOTSUP; + } }; -IoDevice *createHostIoDevice(orbis::kstring hostPath); -orbis::ErrorCode createSocket(orbis::Ref *file, - orbis::kstring name, int dom, int type, int prot); -orbis::File *createHostFile(int hostFd, orbis::Ref device); -IoDevice *createFdWrapDevice(int fd); +IoDevice* createHostIoDevice(orbis::kstring hostPath); +orbis::ErrorCode createSocket(orbis::Ref* file, + orbis::kstring name, int dom, int type, int prot); +orbis::File* createHostFile(int hostFd, orbis::Ref device); +IoDevice* createFdWrapDevice(int fd); diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index 9e6abb37..4e438d7c 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -2,24 +2,24 @@ struct IoDevice; -IoDevice *createDceCharacterDevice(); -IoDevice *createDipswCharacterDevice(); -IoDevice *createDmemCharacterDevice(int index); -IoDevice *createGcCharacterDevice(); -IoDevice *createHidCharacterDevice(); -IoDevice *createHmd3daCharacterDevice(); -IoDevice *createHmdCmdCharacterDevice(); -IoDevice *createHmdMmapCharacterDevice(); -IoDevice *createHmdSnsrCharacterDevice(); -IoDevice *createNullCharacterDevice(); -IoDevice *createZeroCharacterDevice(); -IoDevice *createRngCharacterDevice(); -IoDevice *createAjmCharacterDevice(); -IoDevice *createIccConfigurationCharacterDevice(); -IoDevice *createNpdrmCharacterDevice(); -IoDevice *createConsoleCharacterDevice(); -IoDevice *createSblSrvCharacterDevice(); -IoDevice *createShmDevice(); -IoDevice *createBlockPoolDevice(); -IoDevice *createUrandomCharacterDevice(); -IoDevice *createCameraCharacterDevice(); +IoDevice* createDceCharacterDevice(); +IoDevice* createDipswCharacterDevice(); +IoDevice* createDmemCharacterDevice(int index); +IoDevice* createGcCharacterDevice(); +IoDevice* createHidCharacterDevice(); +IoDevice* createHmd3daCharacterDevice(); +IoDevice* createHmdCmdCharacterDevice(); +IoDevice* createHmdMmapCharacterDevice(); +IoDevice* createHmdSnsrCharacterDevice(); +IoDevice* createNullCharacterDevice(); +IoDevice* createZeroCharacterDevice(); +IoDevice* createRngCharacterDevice(); +IoDevice* createAjmCharacterDevice(); +IoDevice* createIccConfigurationCharacterDevice(); +IoDevice* createNpdrmCharacterDevice(); +IoDevice* createConsoleCharacterDevice(); +IoDevice* createSblSrvCharacterDevice(); +IoDevice* createShmDevice(); +IoDevice* createBlockPoolDevice(); +IoDevice* createUrandomCharacterDevice(); +IoDevice* createCameraCharacterDevice(); diff --git a/rpcsx-os/iodev/ajm.cpp b/rpcsx-os/iodev/ajm.cpp index fb6f4b92..7ae55f63 100644 --- a/rpcsx-os/iodev/ajm.cpp +++ b/rpcsx-os/iodev/ajm.cpp @@ -3,30 +3,35 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct AjmFile : orbis::File {}; +struct AjmFile : orbis::File +{ +}; -static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode ajm_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ - ORBIS_LOG_FATAL("Unhandled AJM ioctl", request); - return {}; + ORBIS_LOG_FATAL("Unhandled AJM ioctl", request); + return {}; } static const orbis::FileOps fileOps = { - .ioctl = ajm_ioctl, + .ioctl = ajm_ioctl, }; -struct AjmDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fileOps; - newFile->device = this; +struct AjmDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; - *file = newFile; - return {}; - } + *file = newFile; + return {}; + } }; -IoDevice *createAjmCharacterDevice() { return orbis::knew(); } +IoDevice* createAjmCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/blockpool.cpp b/rpcsx-os/iodev/blockpool.cpp index a620204c..cb2f6881 100644 --- a/rpcsx-os/iodev/blockpool.cpp +++ b/rpcsx-os/iodev/blockpool.cpp @@ -10,107 +10,120 @@ #include #include -struct BlockPoolFile : public orbis::File {}; +struct BlockPoolFile : public orbis::File +{ +}; -static orbis::ErrorCode blockpool_ioctl(orbis::File *file, - std::uint64_t request, void *argp, - orbis::Thread *thread) { - auto blockPool = static_cast(file->device.get()); - std::lock_guard lock(blockPool->mtx); +static orbis::ErrorCode blockpool_ioctl(orbis::File* file, + std::uint64_t request, void* argp, + orbis::Thread* thread) +{ + auto blockPool = static_cast(file->device.get()); + std::lock_guard lock(blockPool->mtx); - switch (request) { - case 0xc020a801: { - struct Args { - std::uint64_t len; - std::uint64_t searchStart; - std::uint64_t searchEnd; - std::uint32_t flags; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_TODO("blockpool expand", args->len, args->searchStart, - args->searchEnd, args->flags); + switch (request) + { + case 0xc020a801: + { + struct Args + { + std::uint64_t len; + std::uint64_t searchStart; + std::uint64_t searchEnd; + std::uint32_t flags; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_TODO("blockpool expand", args->len, args->searchStart, + args->searchEnd, args->flags); - // auto dmem = static_cast(orbis::g_context.dmemDevice.get()); - // std::lock_guard lock(dmem->mtx); - // std::uint64_t start = args->searchStart; - // std::uint64_t len = std::min(args->searchEnd - start, args->len); - // if (dmem->nextOffset > args->searchEnd) { - // ORBIS_LOG_TODO("blockpool out of allocation", args->len, - // args->searchStart, args->searchEnd, args->flags); - // return orbis::ErrorCode::INVAL; - // } + // auto dmem = static_cast(orbis::g_context.dmemDevice.get()); + // std::lock_guard lock(dmem->mtx); + // std::uint64_t start = args->searchStart; + // std::uint64_t len = std::min(args->searchEnd - start, args->len); + // if (dmem->nextOffset > args->searchEnd) { + // ORBIS_LOG_TODO("blockpool out of allocation", args->len, + // args->searchStart, args->searchEnd, args->flags); + // return orbis::ErrorCode::INVAL; + // } - // start = std::max(dmem->nextOffset, start); - // auto end = std::min(start + len, args->searchEnd); - // dmem->nextOffset = end; - // args->searchStart = start; + // start = std::max(dmem->nextOffset, start); + // auto end = std::min(start + len, args->searchEnd); + // dmem->nextOffset = end; + // args->searchStart = start; - // blockPool->len += end - start; - return {}; - } - } + // blockPool->len += end - start; + return {}; + } + } - ORBIS_LOG_FATAL("Unhandled blockpool ioctl", request); - thread->where(); - return {}; + ORBIS_LOG_FATAL("Unhandled blockpool ioctl", request); + thread->where(); + return {}; } -static orbis::ErrorCode blockpool_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - auto blockPool = static_cast(file->device.get()); - std::lock_guard lock(blockPool->mtx); - ORBIS_LOG_FATAL("blockpool mmap", *address, size, offset, blockPool->len); - size = std::min( - 0x1000000, size); // FIXME: hack, investigate why we report so many memory - size = std::min(blockPool->len, size); - auto result = rx::vm::map(*address, size, prot, flags); +static orbis::ErrorCode blockpool_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + auto blockPool = static_cast(file->device.get()); + std::lock_guard lock(blockPool->mtx); + ORBIS_LOG_FATAL("blockpool mmap", *address, size, offset, blockPool->len); + size = std::min( + 0x1000000, size); // FIXME: hack, investigate why we report so many memory + size = std::min(blockPool->len, size); + auto result = rx::vm::map(*address, size, prot, flags); - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } - blockPool->len -= size; - *address = result; - return {}; + blockPool->len -= size; + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = blockpool_ioctl, - .mmap = blockpool_mmap, + .ioctl = blockpool_ioctl, + .mmap = blockpool_mmap, }; -orbis::ErrorCode BlockPoolDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, - orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode BlockPoolDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -orbis::ErrorCode BlockPoolDevice::map(void **address, std::uint64_t len, - std::int32_t prot, std::int32_t flags, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("blockpool device map", *address, len); - auto result = rx::vm::map(*address, len, prot, flags); +orbis::ErrorCode BlockPoolDevice::map(void** address, std::uint64_t len, + std::int32_t prot, std::int32_t flags, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("blockpool device map", *address, len); + auto result = rx::vm::map(*address, len, prot, flags); - if (result == (void *)-1) { - return orbis::ErrorCode::NOMEM; - } + if (result == (void*)-1) + { + return orbis::ErrorCode::NOMEM; + } - *address = result; - return {}; + *address = result; + return {}; } -orbis::ErrorCode BlockPoolDevice::unmap(void *address, std::uint64_t len, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("blockpool device unmap", address, len); - if (rx::vm::unmap(address, len)) { - return {}; - } - return orbis::ErrorCode::INVAL; +orbis::ErrorCode BlockPoolDevice::unmap(void* address, std::uint64_t len, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("blockpool device unmap", address, len); + if (rx::vm::unmap(address, len)) + { + return {}; + } + return orbis::ErrorCode::INVAL; } -IoDevice *createBlockPoolDevice() { return orbis::knew(); } +IoDevice* createBlockPoolDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/blockpool.hpp b/rpcsx-os/iodev/blockpool.hpp index 4b428ea7..83e287e4 100644 --- a/rpcsx-os/iodev/blockpool.hpp +++ b/rpcsx-os/iodev/blockpool.hpp @@ -7,15 +7,16 @@ #include "orbis/utils/SharedMutex.hpp" #include -struct BlockPoolDevice : public IoDevice { - orbis::shared_mutex mtx; - std::uint64_t len = 0; +struct BlockPoolDevice : public IoDevice +{ + orbis::shared_mutex mtx; + std::uint64_t len = 0; - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; - orbis::ErrorCode map(void **address, std::uint64_t len, std::int32_t prot, - std::int32_t flags, orbis::Thread *thread); - orbis::ErrorCode unmap(void *address, std::uint64_t len, - orbis::Thread *thread); + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; + orbis::ErrorCode map(void** address, std::uint64_t len, std::int32_t prot, + std::int32_t flags, orbis::Thread* thread); + orbis::ErrorCode unmap(void* address, std::uint64_t len, + orbis::Thread* thread); }; diff --git a/rpcsx-os/iodev/camera.cpp b/rpcsx-os/iodev/camera.cpp index b7253f9c..99816e79 100644 --- a/rpcsx-os/iodev/camera.cpp +++ b/rpcsx-os/iodev/camera.cpp @@ -3,30 +3,35 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct CameraFile : orbis::File {}; +struct CameraFile : orbis::File +{ +}; -static orbis::ErrorCode camera_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode camera_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ - ORBIS_LOG_FATAL("Unhandled camera ioctl", request); - return {}; + ORBIS_LOG_FATAL("Unhandled camera ioctl", request); + return {}; } static const orbis::FileOps fileOps = { - .ioctl = camera_ioctl, + .ioctl = camera_ioctl, }; -struct CameraDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fileOps; - newFile->device = this; +struct CameraDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; - *file = newFile; - return {}; - } + *file = newFile; + return {}; + } }; -IoDevice *createCameraCharacterDevice() { return orbis::knew(); } +IoDevice* createCameraCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/console.cpp b/rpcsx-os/iodev/console.cpp index ca1f2804..2c4c85b6 100644 --- a/rpcsx-os/iodev/console.cpp +++ b/rpcsx-os/iodev/console.cpp @@ -3,30 +3,35 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct ConsoleFile : orbis::File {}; +struct ConsoleFile : orbis::File +{ +}; -static orbis::ErrorCode console_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode console_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ - ORBIS_LOG_FATAL("Unhandled console ioctl", request); - return {}; + ORBIS_LOG_FATAL("Unhandled console ioctl", request); + return {}; } static const orbis::FileOps fileOps = { - .ioctl = console_ioctl, + .ioctl = console_ioctl, }; -struct ConsoleDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fileOps; - newFile->device = this; +struct ConsoleDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; - *file = newFile; - return {}; - } + *file = newFile; + return {}; + } }; -IoDevice *createConsoleCharacterDevice() { return orbis::knew(); } +IoDevice* createConsoleCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/dce.cpp b/rpcsx-os/iodev/dce.cpp index 17343a01..9c51d587 100644 --- a/rpcsx-os/iodev/dce.cpp +++ b/rpcsx-os/iodev/dce.cpp @@ -10,298 +10,334 @@ #include #include -struct VideoOutBuffer { - std::uint32_t pixelFormat; - std::uint32_t tilingMode; - std::uint32_t pitch; - std::uint32_t width; - std::uint32_t height; +struct VideoOutBuffer +{ + std::uint32_t pixelFormat; + std::uint32_t tilingMode; + std::uint32_t pitch; + std::uint32_t width; + std::uint32_t height; }; -struct RegisterBuffer { - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 - std::uint32_t index; //buffer index - std::uint32_t vid; //video output port id ? - std::uint64_t address; //left buffer ptr - std::uint64_t address2; //right buffer ptr (Stereo) +struct RegisterBuffer +{ + std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 + std::uint32_t index; //buffer index + std::uint32_t vid; //video output port id ? + std::uint64_t address; //left buffer ptr + std::uint64_t address2; //right buffer ptr (Stereo) }; -struct RegisterBufferAttributeArgs { - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 - std::uint8_t vid; //video output port id ? - std::uint8_t submit; //0 = RegisterBuffers ; 1 = SubmitChangeBufferAttribute - std::uint16_t unk3; //0 - std::uint32_t pixelFormat; - std::uint32_t tilingMode; // 1 // tilingMode? - std::uint32_t pitch; - std::uint32_t width; - std::uint32_t height; - std::uint8_t unk4_zero; // 0 - std::uint8_t unk5_zero; // 0 - std::uint16_t options; - std::uint64_t reserved1; // -1 - std::uint32_t reserved2; +struct RegisterBufferAttributeArgs +{ + std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 + std::uint8_t vid; //video output port id ? + std::uint8_t submit; //0 = RegisterBuffers ; 1 = SubmitChangeBufferAttribute + std::uint16_t unk3; //0 + std::uint32_t pixelFormat; + std::uint32_t tilingMode; // 1 // tilingMode? + std::uint32_t pitch; + std::uint32_t width; + std::uint32_t height; + std::uint8_t unk4_zero; // 0 + std::uint8_t unk5_zero; // 0 + std::uint16_t options; + std::uint64_t reserved1; // -1 + std::uint32_t reserved2; }; -struct FlipRequestArgs { //submit_flip - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 - std::uint64_t displayBufferIndex; - std::uint32_t flipMode; // flip mode? - std::uint32_t unk1; - std::uint64_t flipArg; - std::uint64_t flipArg2; //not used - std::uint32_t eop_nz; - std::uint32_t unk2; - std::uint32_t eop_val; - std::uint32_t unk3; - std::uint64_t unk4; - std::uint64_t* rout; //extraout of result error +struct FlipRequestArgs +{ //submit_flip + std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 + std::uint64_t displayBufferIndex; + std::uint32_t flipMode; // flip mode? + std::uint32_t unk1; + std::uint64_t flipArg; + std::uint64_t flipArg2; //not used + std::uint32_t eop_nz; + std::uint32_t unk2; + std::uint32_t eop_val; + std::uint32_t unk3; + std::uint64_t unk4; + std::uint64_t* rout; //extraout of result error }; -struct FlipControlStatus { - std::uint64_t flipArg; - std::uint64_t flipArg2; //not used - std::uint64_t count; - std::uint64_t processTime; - std::uint64_t tsc; - std::uint32_t currentBuffer; - std::uint32_t flipPendingNum0; //flipPendingNum = flipPendingNum0 + gcQueueNum + flipPendingNum1 - std::uint32_t gcQueueNum; - std::uint32_t flipPendingNum1; - std::uint32_t submitTsc; - std::uint64_t unk1; +struct FlipControlStatus +{ + std::uint64_t flipArg; + std::uint64_t flipArg2; //not used + std::uint64_t count; + std::uint64_t processTime; + std::uint64_t tsc; + std::uint32_t currentBuffer; + std::uint32_t flipPendingNum0; //flipPendingNum = flipPendingNum0 + gcQueueNum + flipPendingNum1 + std::uint32_t gcQueueNum; + std::uint32_t flipPendingNum1; + std::uint32_t submitTsc; + std::uint64_t unk1; }; -struct FlipControlArgs { - std::uint32_t id; - // std::uint32_t padding; - std::uint64_t arg2; - void *ptr; - std::uint64_t size; // 0x48 // size? - std::uint64_t arg5; - std::uint64_t arg6; +struct FlipControlArgs +{ + std::uint32_t id; + // std::uint32_t padding; + std::uint64_t arg2; + void* ptr; + std::uint64_t size; // 0x48 // size? + std::uint64_t arg5; + std::uint64_t arg6; }; -struct ResolutionStatus { - std::uint32_t width; - std::uint32_t heigth; - std::uint32_t paneWidth; - std::uint32_t paneHeight; - std::uint32_t refreshHz; - std::uint32_t screenSizeInInch; - std::byte padding[20]; +struct ResolutionStatus +{ + std::uint32_t width; + std::uint32_t heigth; + std::uint32_t paneWidth; + std::uint32_t paneHeight; + std::uint32_t refreshHz; + std::uint32_t screenSizeInInch; + std::byte padding[20]; }; - //refreshRate = 0 REFRESH_RATE_UNKNOWN - //refreshRate = 3; result.refreshHz = 0x426fc28f REFRESH_RATE_59_94HZ - //refreshRate = 2, result.refreshHz = 0x42480000 REFRESH_RATE_50HZ - //refreshRate = 1, result.refreshHz = 0x41bfd70a REFRESH_RATE_23_98HZ - //refreshRate = 4, result.refreshHz = 0x41c00000 - //refreshRate = 5, result.refreshHz = 0x41f00000 - //refreshRate = 6, result.refreshHz = 0x41efc28f REFRESH_RATE_29_97HZ - //refreshRate = 7, result.refreshHz = 0x41c80000 - //refreshRate = 9, result.refreshHz = 0x42700000 - //refreshRate = 10, result.refreshHz = 0x42400000 - //refreshRate = 0xb, result.refreshHz = 0x423fcccd - //refreshRate = 0xc, result.refreshHz = 0x42c80000 - //refreshRate = 0xd, result.refreshHz = 0x42efc28f REFRESH_RATE_119_88HZ - //refreshRate = 0xe, result.refreshHz = 0x42f00000 - //refreshRate = 0xf, result.refreshHz = 0x43480000 - //refreshRate = 0x10, result.refreshHz = 0x436fc28f - //refreshRate = 0x11, result.refreshHz = 0x43700000 - //refreshRate = 0x14, result.refreshHz = 0x413fd70a - //refreshRate = 0x15, result.refreshHz = 0x41400000 - //refreshRate = 0x16, result.refreshHz = 0x416fd70a - //refreshRate = 0x17, result.refreshHz = 0x41700000 - //refreshRate = 0x23, result.refreshHz = 0x42b3d1ec REFRESH_RATE_89_91HZ - -struct DceFile : public orbis::File {}; - -struct DceDevice : IoDevice { - orbis::shared_mutex mtx; - VideoOutBuffer bufferAttributes{}; // TODO - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +//refreshRate = 0 REFRESH_RATE_UNKNOWN +//refreshRate = 3; result.refreshHz = 0x426fc28f REFRESH_RATE_59_94HZ +//refreshRate = 2, result.refreshHz = 0x42480000 REFRESH_RATE_50HZ +//refreshRate = 1, result.refreshHz = 0x41bfd70a REFRESH_RATE_23_98HZ +//refreshRate = 4, result.refreshHz = 0x41c00000 +//refreshRate = 5, result.refreshHz = 0x41f00000 +//refreshRate = 6, result.refreshHz = 0x41efc28f REFRESH_RATE_29_97HZ +//refreshRate = 7, result.refreshHz = 0x41c80000 +//refreshRate = 9, result.refreshHz = 0x42700000 +//refreshRate = 10, result.refreshHz = 0x42400000 +//refreshRate = 0xb, result.refreshHz = 0x423fcccd +//refreshRate = 0xc, result.refreshHz = 0x42c80000 +//refreshRate = 0xd, result.refreshHz = 0x42efc28f REFRESH_RATE_119_88HZ +//refreshRate = 0xe, result.refreshHz = 0x42f00000 +//refreshRate = 0xf, result.refreshHz = 0x43480000 +//refreshRate = 0x10, result.refreshHz = 0x436fc28f +//refreshRate = 0x11, result.refreshHz = 0x43700000 +//refreshRate = 0x14, result.refreshHz = 0x413fd70a +//refreshRate = 0x15, result.refreshHz = 0x41400000 +//refreshRate = 0x16, result.refreshHz = 0x416fd70a +//refreshRate = 0x17, result.refreshHz = 0x41700000 +//refreshRate = 0x23, result.refreshHz = 0x42b3d1ec REFRESH_RATE_89_91HZ + +struct DceFile : public orbis::File +{ }; -static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - auto device = static_cast(file->device.get()); - - std::lock_guard lock(device->mtx); - - if (request == 0xc0308203) { - // returns: - // PERM - // NOMEM - // FAULT - // BUSY - // INVAL - // OPNOTSUPP - // flip control - - // 0xc - scaler ctl - // 0x11 - output ctl - // 0x12 - vblank ctl - // 0x14 - display ctl - // 0x15 - subwindow ctl - // 0x18 - cursor ctl - // 0x19 - port ctl - // 0x1d - color ctl - // 0x1f - config ctl - // 0x20 - zoom buffer ctl - // 0x21 - adjust color - auto args = reinterpret_cast(argp); - - // ORBIS_LOG_NOTICE("dce: FlipControl", args->id, args->arg2, args->ptr, - // args->size); - - if (args->id == 6) { // set flip rate? - ORBIS_LOG_NOTICE("dce: FlipControl: set flip rate", args->arg2, args->ptr, - args->size); - } else if (args->id == 10) { - if (args->size != sizeof(FlipControlStatus)) { - return {}; - } - - FlipControlStatus flipStatus{}; - // TODO: lock bridge header - flipStatus.flipArg = rx::bridge.header->flipArg; - flipStatus.count = rx::bridge.header->flipCount; - flipStatus.processTime = 0; // TODO - flipStatus.tsc = 0; // TODO - flipStatus.currentBuffer = rx::bridge.header->flipBuffer; - flipStatus.flipPendingNum0 = 0; // TODO - flipStatus.gcQueueNum = 0; // TODO - flipStatus.flipPendingNum1 = 0; // TODO - flipStatus.submitTsc = 0; // TODO - - std::memcpy(args->ptr, &flipStatus, sizeof(FlipControlStatus)); - } else if (args->id == 12) { - *(std::uint64_t *)args->ptr = 0; - } else if (args->id == 19) { - // get resolution status - auto status = (ResolutionStatus *)args->ptr; - status->width = 1920; - status->heigth = 1080; - status->paneWidth = 1920; - status->paneHeight = 1080; - } else if (args->id == 9) { - ORBIS_LOG_NOTICE("dce: FlipControl allocate", args->id, args->arg2, - args->ptr, args->size); - *(std::uint64_t *)args->ptr = 0; // dev offset - *(std::uint64_t *)args->size = 0x100000; // size - } else if (args->id == 31) { - rx::bridge.header->bufferInUseAddress = args->size; - return {}; - } else if (args->id == 33) { // adjust color - std::printf("adjust color\n"); - return {}; - } else if (args->id != 0 && args->id != 1) { // used during open/close - ORBIS_LOG_NOTICE("dce: UNIMPLEMENTED FlipControl", args->id, args->arg2, - args->ptr, args->size); - - std::fflush(stdout); - //__builtin_trap(); - } - return {}; - } - - if (request == 0xc0308206) { - auto args = reinterpret_cast(argp); - ORBIS_LOG_ERROR("dce: RegisterBuffer", args->canary, args->index, - args->address, args->address2); - - if (args->index >= std::size(rx::bridge.header->buffers)) { - // TODO - ORBIS_LOG_FATAL("dce: out of buffers!"); - return orbis::ErrorCode::NOMEM; - } - - // TODO: lock bridge header - rx::bridge.header->buffers[args->index] = { - .width = device->bufferAttributes.width, - .height = device->bufferAttributes.height, - .pitch = device->bufferAttributes.pitch, - .address = args->address, - .pixelFormat = device->bufferAttributes.pixelFormat, - .tilingMode = device->bufferAttributes.tilingMode}; - return {}; - } - - if (request == 0xc0308207) { // SCE_SYS_DCE_IOCTL_REGISTER_BUFFER_ATTRIBUTE - auto args = reinterpret_cast(argp); - - ORBIS_LOG_ERROR("dce: RegisterBufferAttributes", args->canary, args->vid, - args->submit, args->unk3, args->pixelFormat, - args->tilingMode, args->pitch, args->width, args->height, - args->unk4_zero, args->unk5_zero, args->options, args->reserved1, - args->reserved2); - - device->bufferAttributes.pixelFormat = args->pixelFormat; - device->bufferAttributes.tilingMode = args->tilingMode; - device->bufferAttributes.pitch = args->pitch; - device->bufferAttributes.width = args->width; - device->bufferAttributes.height = args->height; - return {}; - } - - if (request == 0xc0488204) { - // flip request - auto args = reinterpret_cast(argp); - - // ORBIS_LOG_ERROR("dce: FlipRequestArgs", args->arg1, - // args->displayBufferIndex, args->flipMode, args->flipArg, - // args->arg5, args->arg6, args->arg7, args->arg8); - - rx::bridge.sendFlip(args->displayBufferIndex, - /*args->flipMode,*/ args->flipArg); - return {}; - } - - if (request == 0x80088209) { // deallocate? - auto arg = *reinterpret_cast(argp); - ORBIS_LOG_ERROR("dce: 0x80088209", arg); - return {}; - } - - ORBIS_LOG_FATAL("Unhandled dce ioctl", request); - // 0xc0188213 - color conversion - - std::fflush(stdout); - __builtin_trap(); - return {}; -} - -static orbis::ErrorCode dce_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("dce mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); +struct DceDevice : IoDevice +{ + orbis::shared_mutex mtx; + VideoOutBuffer bufferAttributes{}; // TODO + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } +static orbis::ErrorCode dce_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + auto device = static_cast(file->device.get()); + + std::lock_guard lock(device->mtx); + + if (request == 0xc0308203) + { + // returns: + // PERM + // NOMEM + // FAULT + // BUSY + // INVAL + // OPNOTSUPP + // flip control + + // 0xc - scaler ctl + // 0x11 - output ctl + // 0x12 - vblank ctl + // 0x14 - display ctl + // 0x15 - subwindow ctl + // 0x18 - cursor ctl + // 0x19 - port ctl + // 0x1d - color ctl + // 0x1f - config ctl + // 0x20 - zoom buffer ctl + // 0x21 - adjust color + auto args = reinterpret_cast(argp); + + // ORBIS_LOG_NOTICE("dce: FlipControl", args->id, args->arg2, args->ptr, + // args->size); + + if (args->id == 6) + { // set flip rate? + ORBIS_LOG_NOTICE("dce: FlipControl: set flip rate", args->arg2, args->ptr, + args->size); + } + else if (args->id == 10) + { + if (args->size != sizeof(FlipControlStatus)) + { + return {}; + } + + FlipControlStatus flipStatus{}; + // TODO: lock bridge header + flipStatus.flipArg = rx::bridge.header->flipArg; + flipStatus.count = rx::bridge.header->flipCount; + flipStatus.processTime = 0; // TODO + flipStatus.tsc = 0; // TODO + flipStatus.currentBuffer = rx::bridge.header->flipBuffer; + flipStatus.flipPendingNum0 = 0; // TODO + flipStatus.gcQueueNum = 0; // TODO + flipStatus.flipPendingNum1 = 0; // TODO + flipStatus.submitTsc = 0; // TODO + + std::memcpy(args->ptr, &flipStatus, sizeof(FlipControlStatus)); + } + else if (args->id == 12) + { + *(std::uint64_t*)args->ptr = 0; + } + else if (args->id == 19) + { + // get resolution status + auto status = (ResolutionStatus*)args->ptr; + status->width = 1920; + status->heigth = 1080; + status->paneWidth = 1920; + status->paneHeight = 1080; + } + else if (args->id == 9) + { + ORBIS_LOG_NOTICE("dce: FlipControl allocate", args->id, args->arg2, + args->ptr, args->size); + *(std::uint64_t*)args->ptr = 0; // dev offset + *(std::uint64_t*)args->size = 0x100000; // size + } + else if (args->id == 31) + { + rx::bridge.header->bufferInUseAddress = args->size; + return {}; + } + else if (args->id == 33) + { // adjust color + std::printf("adjust color\n"); + return {}; + } + else if (args->id != 0 && args->id != 1) + { // used during open/close + ORBIS_LOG_NOTICE("dce: UNIMPLEMENTED FlipControl", args->id, args->arg2, + args->ptr, args->size); + + std::fflush(stdout); + //__builtin_trap(); + } + return {}; + } + + if (request == 0xc0308206) + { + auto args = reinterpret_cast(argp); + ORBIS_LOG_ERROR("dce: RegisterBuffer", args->canary, args->index, + args->address, args->address2); + + if (args->index >= std::size(rx::bridge.header->buffers)) + { + // TODO + ORBIS_LOG_FATAL("dce: out of buffers!"); + return orbis::ErrorCode::NOMEM; + } + + // TODO: lock bridge header + rx::bridge.header->buffers[args->index] = { + .width = device->bufferAttributes.width, + .height = device->bufferAttributes.height, + .pitch = device->bufferAttributes.pitch, + .address = args->address, + .pixelFormat = device->bufferAttributes.pixelFormat, + .tilingMode = device->bufferAttributes.tilingMode}; + return {}; + } + + if (request == 0xc0308207) + { // SCE_SYS_DCE_IOCTL_REGISTER_BUFFER_ATTRIBUTE + auto args = reinterpret_cast(argp); + + ORBIS_LOG_ERROR("dce: RegisterBufferAttributes", args->canary, args->vid, + args->submit, args->unk3, args->pixelFormat, + args->tilingMode, args->pitch, args->width, args->height, + args->unk4_zero, args->unk5_zero, args->options, args->reserved1, + args->reserved2); + + device->bufferAttributes.pixelFormat = args->pixelFormat; + device->bufferAttributes.tilingMode = args->tilingMode; + device->bufferAttributes.pitch = args->pitch; + device->bufferAttributes.width = args->width; + device->bufferAttributes.height = args->height; + return {}; + } + + if (request == 0xc0488204) + { + // flip request + auto args = reinterpret_cast(argp); + + // ORBIS_LOG_ERROR("dce: FlipRequestArgs", args->arg1, + // args->displayBufferIndex, args->flipMode, args->flipArg, + // args->arg5, args->arg6, args->arg7, args->arg8); + + rx::bridge.sendFlip(args->displayBufferIndex, + /*args->flipMode,*/ args->flipArg); + return {}; + } + + if (request == 0x80088209) + { // deallocate? + auto arg = *reinterpret_cast(argp); + ORBIS_LOG_ERROR("dce: 0x80088209", arg); + return {}; + } + + ORBIS_LOG_FATAL("Unhandled dce ioctl", request); + // 0xc0188213 - color conversion + + std::fflush(stdout); + __builtin_trap(); + return {}; +} - *address = result; - return {}; +static orbis::ErrorCode dce_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("dce mmap", address, size, offset); + auto result = rx::vm::map(*address, size, prot, flags); + + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } + + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = dce_ioctl, - .mmap = dce_mmap, + .ioctl = dce_ioctl, + .mmap = dce_mmap, }; -orbis::ErrorCode DceDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode DceDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createDceCharacterDevice() { return orbis::knew(); } +IoDevice* createDceCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/dipsw.cpp b/rpcsx-os/iodev/dipsw.cpp index 36ef156d..c1125fab 100644 --- a/rpcsx-os/iodev/dipsw.cpp +++ b/rpcsx-os/iodev/dipsw.cpp @@ -4,66 +4,76 @@ #include "orbis/utils/Logs.hpp" #include "orbis/thread/Thread.hpp" -struct DipswFile : public orbis::File {}; +struct DipswFile : public orbis::File +{ +}; -static orbis::ErrorCode dipsw_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - if (request == 0x40048806) { // isDevelopmentMode - ORBIS_LOG_ERROR("dipsw ioctl isDevelopmentMode", argp); +static orbis::ErrorCode dipsw_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + if (request == 0x40048806) + { // isDevelopmentMode + ORBIS_LOG_ERROR("dipsw ioctl isDevelopmentMode", argp); - *reinterpret_cast(argp) = 0; - return {}; - } + *reinterpret_cast(argp) = 0; + return {}; + } - if (request == 0x40048807) { - ORBIS_LOG_ERROR("dipsw ioctl 0x40048807", argp); - *reinterpret_cast(argp) = 1; - return {}; - } + if (request == 0x40048807) + { + ORBIS_LOG_ERROR("dipsw ioctl 0x40048807", argp); + *reinterpret_cast(argp) = 1; + return {}; + } - // 0x40088808 - // 0x40088809 + // 0x40088808 + // 0x40088809 - if (request == 0x40088808) { - ORBIS_LOG_ERROR("dipsw ioctl 0x40088808", argp); - *reinterpret_cast(argp) = 1; - return {}; - } + if (request == 0x40088808) + { + ORBIS_LOG_ERROR("dipsw ioctl 0x40088808", argp); + *reinterpret_cast(argp) = 1; + return {}; + } - // 0x8010880a - if (request == 0x8010880a) { // write data? used on initilization - struct Args { - std::uint64_t address; - std::uint64_t size; - }; + // 0x8010880a + if (request == 0x8010880a) + { // write data? used on initilization + struct Args + { + std::uint64_t address; + std::uint64_t size; + }; - auto args = reinterpret_cast(argp); + auto args = reinterpret_cast(argp); - ORBIS_LOG_ERROR("dipsw ioctl 0x8010880a", args->address, args->size); + ORBIS_LOG_ERROR("dipsw ioctl 0x8010880a", args->address, args->size); - return {}; - } + return {}; + } - ORBIS_LOG_FATAL("Unhandled dipsw ioctl", request); - thread->where(); - //__builtin_trap(); - return {}; + ORBIS_LOG_FATAL("Unhandled dipsw ioctl", request); + thread->where(); + //__builtin_trap(); + return {}; } static const orbis::FileOps ops = { - .ioctl = dipsw_ioctl, + .ioctl = dipsw_ioctl, }; -struct DipswDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; - } +struct DipswDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; + } }; -IoDevice *createDipswCharacterDevice() { return orbis::knew(); } +IoDevice* createDipswCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/dmem.cpp b/rpcsx-os/iodev/dmem.cpp index 37b348ef..19f61089 100644 --- a/rpcsx-os/iodev/dmem.cpp +++ b/rpcsx-os/iodev/dmem.cpp @@ -7,300 +7,349 @@ #include "vm.hpp" #include -struct DmemFile : public orbis::File {}; - -struct AllocateDirectMemoryArgs { - std::uint64_t searchStart; - std::uint64_t searchEnd; - std::uint64_t len; - std::uint64_t alignment; - std::uint32_t memoryType; +struct DmemFile : public orbis::File +{ +}; + +struct AllocateDirectMemoryArgs +{ + std::uint64_t searchStart; + std::uint64_t searchEnd; + std::uint64_t len; + std::uint64_t alignment; + std::uint32_t memoryType; }; static constexpr auto dmemSize = 8ull * 1024 * 1024 * 1024; // static const std::uint64_t nextOffset = 0; // static const std::uint64_t memBeginAddress = 0xfe0000000; -orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, - std::int32_t prot, std::int32_t flags, - std::int64_t directMemoryStart) { - auto result = - rx::vm::map(*address, len, prot, flags, 0, this, directMemoryStart); - - ORBIS_LOG_WARNING("dmem mmap", index, directMemoryStart, prot, flags, result); - if (result == (void *)-1) { - return orbis::ErrorCode::NOMEM; // TODO - } - - *address = result; - return {}; +orbis::ErrorCode DmemDevice::mmap(void** address, std::uint64_t len, + std::int32_t prot, std::int32_t flags, + std::int64_t directMemoryStart) +{ + auto result = + rx::vm::map(*address, len, prot, flags, 0, this, directMemoryStart); + + ORBIS_LOG_WARNING("dmem mmap", index, directMemoryStart, prot, flags, result); + if (result == (void*)-1) + { + return orbis::ErrorCode::NOMEM; // TODO + } + + *address = result; + return {}; } -static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - auto device = static_cast(file->device.get()); - - std::lock_guard lock(device->mtx); - switch (request) { - case 0x4008800a: // get size - ORBIS_LOG_WARNING("dmem getTotalSize", device->index, argp); - *(std::uint64_t *)argp = device->dmemTotalSize; - return {}; - - case 0xc0208016: { // get available size - struct Args { - std::uint64_t searchStart; - std::uint64_t searchEnd; - std::uint64_t alignment; - std::uint64_t size; - }; - - auto args = reinterpret_cast(argp); - - return device->queryMaxFreeChunkSize(&args->searchStart, args->searchEnd, - args->alignment, &args->size); - } - - case 0xc0288011: - case 0xc0288001: { // sceKernelAllocateDirectMemory - auto args = reinterpret_cast(argp); - - return device->allocate(&args->searchStart, args->searchEnd, args->len, - args->alignment, args->memoryType); - } - - case 0x80108002: { // sceKernelReleaseDirectMemory - struct Args { - std::uint64_t address; - std::uint64_t size; - }; - - auto args = reinterpret_cast(argp); - - ORBIS_LOG_WARNING("dmem releaseDirectMemory", device->index, args->address, - args->size); - - device->allocations.map(args->address, args->address + args->size, - {.memoryType = 0}); - return {}; - } - - case 0x80288012: { // direct memory query - struct DirectMemoryQueryInfo { - std::uint64_t start; - std::uint64_t end; - std::uint32_t memoryType; - }; - - struct Args { - std::uint32_t devIndex; - std::uint32_t flags; - std::uint32_t unk; - std::uint64_t offset; - orbis::ptr info; - std::uint64_t infoSize; - }; - - auto args = reinterpret_cast(argp); - - ORBIS_LOG_WARNING("dmem directMemoryQuery", device->index, args->devIndex, - args->unk, args->flags, args->offset, args->info, - args->infoSize); - - if (args->devIndex != device->index) { - // TODO - ORBIS_LOG_ERROR("dmem directMemoryQuery: device mismatch", device->index, - args->devIndex, args->unk, args->flags, args->offset, - args->info, args->infoSize); - - return orbis::ErrorCode::INVAL; - } - - if (args->infoSize != sizeof(DirectMemoryQueryInfo)) { - return orbis::ErrorCode::INVAL; - } - - auto it = device->allocations.lowerBound(args->offset); - - if (it == device->allocations.end()) { - return orbis::ErrorCode::ACCES; - } - - auto queryInfo = *it; - - if (queryInfo.payload.memoryType == 0) { - return orbis::ErrorCode::ACCES; - } - - if ((args->flags & 1) == 0) { - if (queryInfo.endAddress <= args->offset) { - return orbis::ErrorCode::ACCES; - } - } else { - if (queryInfo.beginAddress > args->offset || - queryInfo.endAddress <= args->offset) { - return orbis::ErrorCode::ACCES; - } - } - - DirectMemoryQueryInfo info{ - .start = queryInfo.beginAddress, - .end = queryInfo.endAddress, - .memoryType = queryInfo.payload.memoryType, - }; - - ORBIS_LOG_WARNING("dmem directMemoryQuery", device->index, args->devIndex, - args->unk, args->flags, args->offset, args->info, - args->infoSize, info.start, info.end, info.memoryType); - return orbis::uwrite(args->info, info); - } - } - - thread->where(); - ORBIS_LOG_FATAL("Unhandled dmem ioctl", device->index, request); - return {}; +static orbis::ErrorCode dmem_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + auto device = static_cast(file->device.get()); + + std::lock_guard lock(device->mtx); + switch (request) + { + case 0x4008800a: // get size + ORBIS_LOG_WARNING("dmem getTotalSize", device->index, argp); + *(std::uint64_t*)argp = device->dmemTotalSize; + return {}; + + case 0xc0208016: + { // get available size + struct Args + { + std::uint64_t searchStart; + std::uint64_t searchEnd; + std::uint64_t alignment; + std::uint64_t size; + }; + + auto args = reinterpret_cast(argp); + + return device->queryMaxFreeChunkSize(&args->searchStart, args->searchEnd, + args->alignment, &args->size); + } + + case 0xc0288011: + case 0xc0288001: + { // sceKernelAllocateDirectMemory + auto args = reinterpret_cast(argp); + + return device->allocate(&args->searchStart, args->searchEnd, args->len, + args->alignment, args->memoryType); + } + + case 0x80108002: + { // sceKernelReleaseDirectMemory + struct Args + { + std::uint64_t address; + std::uint64_t size; + }; + + auto args = reinterpret_cast(argp); + + ORBIS_LOG_WARNING("dmem releaseDirectMemory", device->index, args->address, + args->size); + + device->allocations.map(args->address, args->address + args->size, + {.memoryType = 0}); + return {}; + } + + case 0x80288012: + { // direct memory query + struct DirectMemoryQueryInfo + { + std::uint64_t start; + std::uint64_t end; + std::uint32_t memoryType; + }; + + struct Args + { + std::uint32_t devIndex; + std::uint32_t flags; + std::uint32_t unk; + std::uint64_t offset; + orbis::ptr info; + std::uint64_t infoSize; + }; + + auto args = reinterpret_cast(argp); + + ORBIS_LOG_WARNING("dmem directMemoryQuery", device->index, args->devIndex, + args->unk, args->flags, args->offset, args->info, + args->infoSize); + + if (args->devIndex != device->index) + { + // TODO + ORBIS_LOG_ERROR("dmem directMemoryQuery: device mismatch", device->index, + args->devIndex, args->unk, args->flags, args->offset, + args->info, args->infoSize); + + return orbis::ErrorCode::INVAL; + } + + if (args->infoSize != sizeof(DirectMemoryQueryInfo)) + { + return orbis::ErrorCode::INVAL; + } + + auto it = device->allocations.lowerBound(args->offset); + + if (it == device->allocations.end()) + { + return orbis::ErrorCode::ACCES; + } + + auto queryInfo = *it; + + if (queryInfo.payload.memoryType == 0) + { + return orbis::ErrorCode::ACCES; + } + + if ((args->flags & 1) == 0) + { + if (queryInfo.endAddress <= args->offset) + { + return orbis::ErrorCode::ACCES; + } + } + else + { + if (queryInfo.beginAddress > args->offset || + queryInfo.endAddress <= args->offset) + { + return orbis::ErrorCode::ACCES; + } + } + + DirectMemoryQueryInfo info{ + .start = queryInfo.beginAddress, + .end = queryInfo.endAddress, + .memoryType = queryInfo.payload.memoryType, + }; + + ORBIS_LOG_WARNING("dmem directMemoryQuery", device->index, args->devIndex, + args->unk, args->flags, args->offset, args->info, + args->infoSize, info.start, info.end, info.memoryType); + return orbis::uwrite(args->info, info); + } + } + + thread->where(); + ORBIS_LOG_FATAL("Unhandled dmem ioctl", device->index, request); + return {}; } -static orbis::ErrorCode dmem_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - auto device = static_cast(file->device.get()); - return device->mmap(address, size, prot, flags, offset); +static orbis::ErrorCode dmem_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + auto device = static_cast(file->device.get()); + return device->mmap(address, size, prot, flags, offset); } static const orbis::FileOps ops = { - .ioctl = dmem_ioctl, - .mmap = dmem_mmap, + .ioctl = dmem_ioctl, + .mmap = dmem_mmap, }; -orbis::ErrorCode DmemDevice::allocate(std::uint64_t *start, - std::uint64_t searchEnd, - std::uint64_t len, - std::uint64_t alignment, - std::uint32_t memoryType) { - std::size_t offset = *start; - if (alignment == 0) { - alignment = 1; - } - if (searchEnd == 0) { - searchEnd = dmemTotalSize; - } - - while (offset < searchEnd) { - offset += alignment - 1; - offset &= ~(alignment - 1); - - if (offset + len > dmemTotalSize) { - ORBIS_LOG_ERROR("dmem: failed to allocate direct memory: out of memory", - *start, searchEnd, len, alignment, memoryType, offset); - return orbis::ErrorCode::AGAIN; - } - - auto it = allocations.lowerBound(offset); - - if (it != allocations.end()) { - auto allocation = *it; - if (allocation.payload.memoryType == 0) { - if (offset < allocation.beginAddress) { - offset = allocation.beginAddress + alignment - 1; - offset &= ~(alignment - 1); - } - - if (offset + len >= allocation.endAddress) { - offset = allocation.endAddress; - continue; - } - } else { - if (offset + len > allocation.beginAddress) { - offset = allocation.endAddress; - continue; - } - } - } - - allocations.map(offset, offset + len, - { - .memoryType = memoryType, - }); - ORBIS_LOG_WARNING("dmem: allocated direct memory", *start, searchEnd, len, - alignment, memoryType, offset); - *start = offset; - return {}; - } - - ORBIS_LOG_ERROR("dmem: failed to allocate direct memory", *start, searchEnd, - len, alignment, memoryType, offset); - return orbis::ErrorCode::AGAIN; +orbis::ErrorCode DmemDevice::allocate(std::uint64_t* start, + std::uint64_t searchEnd, + std::uint64_t len, + std::uint64_t alignment, + std::uint32_t memoryType) +{ + std::size_t offset = *start; + if (alignment == 0) + { + alignment = 1; + } + if (searchEnd == 0) + { + searchEnd = dmemTotalSize; + } + + while (offset < searchEnd) + { + offset += alignment - 1; + offset &= ~(alignment - 1); + + if (offset + len > dmemTotalSize) + { + ORBIS_LOG_ERROR("dmem: failed to allocate direct memory: out of memory", + *start, searchEnd, len, alignment, memoryType, offset); + return orbis::ErrorCode::AGAIN; + } + + auto it = allocations.lowerBound(offset); + + if (it != allocations.end()) + { + auto allocation = *it; + if (allocation.payload.memoryType == 0) + { + if (offset < allocation.beginAddress) + { + offset = allocation.beginAddress + alignment - 1; + offset &= ~(alignment - 1); + } + + if (offset + len >= allocation.endAddress) + { + offset = allocation.endAddress; + continue; + } + } + else + { + if (offset + len > allocation.beginAddress) + { + offset = allocation.endAddress; + continue; + } + } + } + + allocations.map(offset, offset + len, + { + .memoryType = memoryType, + }); + ORBIS_LOG_WARNING("dmem: allocated direct memory", *start, searchEnd, len, + alignment, memoryType, offset); + *start = offset; + return {}; + } + + ORBIS_LOG_ERROR("dmem: failed to allocate direct memory", *start, searchEnd, + len, alignment, memoryType, offset); + return orbis::ErrorCode::AGAIN; } -orbis::ErrorCode DmemDevice::queryMaxFreeChunkSize(std::uint64_t *start, - std::uint64_t searchEnd, - std::uint64_t alignment, - std::uint64_t *size) { - std::size_t offset = *start; - std::size_t resultSize = 0; - std::size_t resultOffset = 0; - while (offset < searchEnd) { - offset += alignment - 1; - offset &= ~(alignment - 1); - - if (offset >= dmemTotalSize) { - break; - } - - auto it = allocations.lowerBound(offset); - - if (it == allocations.end()) { - if (resultSize < dmemTotalSize - offset) { - resultSize = dmemTotalSize - offset; - resultOffset = offset; - } - - break; - } - - auto allocation = *it; - if (allocation.payload.memoryType == 0) { - if (offset < allocation.beginAddress) { - offset = allocation.beginAddress + alignment - 1; - offset &= ~(alignment - 1); - } - - if (allocation.endAddress > offset && - resultSize < allocation.endAddress - offset) { - resultSize = allocation.endAddress - offset; - resultOffset = offset; - } - } else if (offset > allocation.beginAddress && - resultSize < offset - allocation.beginAddress) { - resultSize = offset - allocation.beginAddress; - resultOffset = offset; - } - - offset = allocation.endAddress; - } - - *start = resultOffset; - *size = resultSize; - - ORBIS_LOG_WARNING("dmem queryMaxFreeChunkSize", resultOffset, resultSize); - return {}; +orbis::ErrorCode DmemDevice::queryMaxFreeChunkSize(std::uint64_t* start, + std::uint64_t searchEnd, + std::uint64_t alignment, + std::uint64_t* size) +{ + std::size_t offset = *start; + std::size_t resultSize = 0; + std::size_t resultOffset = 0; + while (offset < searchEnd) + { + offset += alignment - 1; + offset &= ~(alignment - 1); + + if (offset >= dmemTotalSize) + { + break; + } + + auto it = allocations.lowerBound(offset); + + if (it == allocations.end()) + { + if (resultSize < dmemTotalSize - offset) + { + resultSize = dmemTotalSize - offset; + resultOffset = offset; + } + + break; + } + + auto allocation = *it; + if (allocation.payload.memoryType == 0) + { + if (offset < allocation.beginAddress) + { + offset = allocation.beginAddress + alignment - 1; + offset &= ~(alignment - 1); + } + + if (allocation.endAddress > offset && + resultSize < allocation.endAddress - offset) + { + resultSize = allocation.endAddress - offset; + resultOffset = offset; + } + } + else if (offset > allocation.beginAddress && + resultSize < offset - allocation.beginAddress) + { + resultSize = offset - allocation.beginAddress; + resultOffset = offset; + } + + offset = allocation.endAddress; + } + + *start = resultOffset; + *size = resultSize; + + ORBIS_LOG_WARNING("dmem queryMaxFreeChunkSize", resultOffset, resultSize); + return {}; } -orbis::ErrorCode DmemDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode DmemDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createDmemCharacterDevice(int index) { - auto *newDevice = orbis::knew(); - newDevice->index = index; - newDevice->dmemTotalSize = dmemSize; - return newDevice; +IoDevice* createDmemCharacterDevice(int index) +{ + auto* newDevice = orbis::knew(); + newDevice->index = index; + newDevice->dmemTotalSize = dmemSize; + return newDevice; } diff --git a/rpcsx-os/iodev/dmem.hpp b/rpcsx-os/iodev/dmem.hpp index bff4efd0..303f5951 100644 --- a/rpcsx-os/iodev/dmem.hpp +++ b/rpcsx-os/iodev/dmem.hpp @@ -9,35 +9,37 @@ #include #include -struct DmemDevice : public IoDevice { - orbis::shared_mutex mtx; - int index; - std::size_t dmemTotalSize; +struct DmemDevice : public IoDevice +{ + orbis::shared_mutex mtx; + int index; + std::size_t dmemTotalSize; - struct AllocationInfo { - std::uint32_t memoryType; + struct AllocationInfo + { + std::uint32_t memoryType; - bool operator==(const AllocationInfo &) const = default; - auto operator<=>(const AllocationInfo &) const = default; - }; + bool operator==(const AllocationInfo&) const = default; + auto operator<=>(const AllocationInfo&) const = default; + }; - rx::MemoryTableWithPayload allocations; + rx::MemoryTableWithPayload allocations; - orbis::ErrorCode allocate(std::uint64_t *start, std::uint64_t searchEnd, - std::uint64_t len, std::uint64_t alignment, - std::uint32_t memoryType); + orbis::ErrorCode allocate(std::uint64_t* start, std::uint64_t searchEnd, + std::uint64_t len, std::uint64_t alignment, + std::uint32_t memoryType); - orbis::ErrorCode queryMaxFreeChunkSize(std::uint64_t *start, - std::uint64_t searchEnd, - std::uint64_t alignment, - std::uint64_t *size); + orbis::ErrorCode queryMaxFreeChunkSize(std::uint64_t* start, + std::uint64_t searchEnd, + std::uint64_t alignment, + std::uint64_t* size); - orbis::ErrorCode release(std::uint64_t start, std::uint64_t size); + orbis::ErrorCode release(std::uint64_t start, std::uint64_t size); - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; - orbis::ErrorCode mmap(void **address, std::uint64_t len, std::int32_t prot, - std::int32_t flags, std::int64_t directMemoryStart); + orbis::ErrorCode mmap(void** address, std::uint64_t len, std::int32_t prot, + std::int32_t flags, std::int64_t directMemoryStart); }; diff --git a/rpcsx-os/iodev/gc.cpp b/rpcsx-os/iodev/gc.cpp index c3b57867..c7e993a5 100644 --- a/rpcsx-os/iodev/gc.cpp +++ b/rpcsx-os/iodev/gc.cpp @@ -10,289 +10,320 @@ #include #include -struct ComputeQueue { - std::uint64_t ringBaseAddress{}; - std::uint64_t readPtrAddress{}; - std::uint64_t dingDongPtr{}; - std::uint64_t offset{}; - std::uint64_t len{}; +struct ComputeQueue +{ + std::uint64_t ringBaseAddress{}; + std::uint64_t readPtrAddress{}; + std::uint64_t dingDongPtr{}; + std::uint64_t offset{}; + std::uint64_t len{}; }; -struct GcDevice : public IoDevice { - orbis::shared_mutex mtx; - orbis::kmap computeQueues; - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct GcDevice : public IoDevice +{ + orbis::shared_mutex mtx; + orbis::kmap computeQueues; + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct GcFile : public orbis::File +{ }; -struct GcFile : public orbis::File {}; static std::uint64_t g_submitDoneFlag; -static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - // 0xc00c8110 - // 0xc0848119 - - auto device = static_cast(file->device.get()); - std::lock_guard lock(device->mtx); - - switch (request) { - case 0xc008811b: // get submit done flag ptr? - // TODO - ORBIS_LOG_ERROR("gc ioctl 0xc008811b", *(std::uint64_t *)argp); - *reinterpret_cast(argp) = &g_submitDoneFlag; - break; - - case 0xc0108102: { // submit? - struct Args { - std::uint32_t arg0; - std::uint32_t count; - std::uint64_t *cmds; - }; - - auto args = reinterpret_cast(argp); - - flockfile(stderr); - ORBIS_LOG_ERROR("gc ioctl 0xc0108102", args->arg0, args->count, args->cmds); - - for (unsigned i = 0; i < args->count; ++i) { - auto cmd = args->cmds + (i * 2); - auto cmdId = cmd[0] & 0xffff'ffff; - auto addressLoPart = cmd[0] >> 32; - auto addressHiPart = cmd[1] & 0xff; - auto address = addressLoPart | (addressHiPart << 32); - auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; - auto size = ((cmd[1] >> 32) & 0xfffff) << 2; - - // std::fprintf(stderr, " %lx\n", cmd[0]); - // std::fprintf(stderr, " %lx\n", cmd[1]); - // std::fprintf(stderr, " %u:\n", i); - // std::fprintf(stderr, " cmdId = %lx\n", cmdId); - // std::fprintf(stderr, " address = %lx\n", address); - // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); - // std::fprintf(stderr, " size = %lu\n", size); - - rx::bridge.sendCommandBuffer(cmdId, address, size); - } - funlockfile(stderr); - - break; - } - - case 0xc0088101: { // switch buffer? - struct Args { - std::uint32_t arg0; - std::uint32_t arg1; - }; - - auto args = reinterpret_cast(argp); - - ORBIS_LOG_ERROR("gc ioctl 0xc0088101\n", args->arg0, args->arg1); - break; - } - - case 0xc020810c: { // submit and flip? - struct Args { - std::uint32_t arg0; - std::uint32_t count; - std::uint64_t *cmds; - std::uint64_t arg3; // flipArg? - std::uint32_t arg4; // bufferIndex? - }; - - auto args = reinterpret_cast(argp); - - flockfile(stderr); - ORBIS_LOG_ERROR("gc ioctl 0xc020810c", args->arg0, args->count, args->cmds, - args->arg3, args->arg4); - - for (unsigned i = 0; i < args->count; ++i) { - auto cmd = args->cmds + (i * 2); - auto cmdId = cmd[0] & 0xffff'ffff; - auto addressLoPart = cmd[0] >> 32; - auto addressHiPart = cmd[1] & 0xff; - auto address = addressLoPart | (addressHiPart << 32); - auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; - auto size = ((cmd[1] >> 32) & 0xfffff) << 2; - - // std::fprintf(stderr, " %lx\n", cmd[0]); - // std::fprintf(stderr, " %lx\n", cmd[1]); - // std::fprintf(stderr, " %u:\n", i); - // std::fprintf(stderr, " cmdId = %lx\n", cmdId); - // std::fprintf(stderr, " address = %lx\n", address); - // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); - // std::fprintf(stderr, " size = %lu\n", size); - - rx::bridge.sendCommandBuffer(cmdId, address, size); - } - funlockfile(stderr); - - // orbis::bridge.sendDoFlip(); - break; - } - - case 0xc0048116: { - ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t *)argp); - thread->where(); - break; - } - - case 0xc00c8110: { - // set gs ring sizes - struct Args { - std::uint32_t arg1; - std::uint32_t arg2; - std::uint32_t unk; // 0 - }; - auto args = reinterpret_cast(argp); - - ORBIS_LOG_ERROR("gc ioctl set gs ring sizes", args->arg1, args->arg2, - args->unk); - break; - } - - case 0xc0848119: { // stats report control? - struct Args { - std::uint32_t unk; // 0x10001 - std::uint32_t arg1; - std::uint32_t arg2; - std::uint32_t arg3; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_ERROR("gc ioctl stats report control", args->unk, args->arg1, - args->arg2, args->arg3); - break; - } - - case 0xc010810b: { // something like stats masks? - struct Args { - std::uint64_t arg1; - std::uint64_t arg2; - }; - - auto args = reinterpret_cast(argp); - ORBIS_LOG_ERROR("gc ioctl stats mask", args->arg1, args->arg2); - break; - } - - case 0xc030810d: { // map compute queue - struct Args { - std::uint32_t pipeHi; - std::uint32_t pipeLo; - std::uint32_t queueId; - std::uint32_t offset; - std::uint64_t ringBaseAddress; - std::uint64_t readPtrAddress; - std::uint64_t dingDongPtr; - std::uint32_t lenLog2; - }; - - auto args = reinterpret_cast(argp); - - ORBIS_LOG_ERROR("gc ioctl map compute queue", args->pipeHi, args->pipeLo, - args->queueId, args->offset, args->ringBaseAddress, - args->readPtrAddress, args->dingDongPtr, args->lenLog2); - - auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; - device->computeQueues[id] = { - .ringBaseAddress = args->ringBaseAddress, - .readPtrAddress = args->readPtrAddress, - .dingDongPtr = args->dingDongPtr, - .len = static_cast(1) << args->lenLog2, - }; - args->pipeHi = 0x769c766; - args->pipeLo = 0x72e8e3c1; - args->queueId = -0x248d50d8; - args->offset = 0xd245ed58; - - ((std::uint64_t *)args->dingDongPtr)[0xf0 / sizeof(std::uint64_t)] = 1; - break; - } - - case 0xc010811c: { - // ding dong for workload - struct Args { - std::uint32_t pipeHi; - std::uint32_t pipeLo; - std::uint32_t queueId; - std::uint32_t nextStartOffsetInDw; - }; - - auto args = reinterpret_cast(argp); - ORBIS_LOG_ERROR("gc ioctl ding dong for workload", args->pipeHi, - args->pipeLo, args->queueId, args->nextStartOffsetInDw); - - auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; - - auto queue = device->computeQueues.at(id); - auto address = (queue.ringBaseAddress + queue.offset); - auto endOffset = static_cast(args->nextStartOffsetInDw) << 2; - auto size = endOffset - queue.offset; - - rx::bridge.sendCommandBuffer(id, address, size); - - queue.offset = endOffset; - break; - } - - case 0xc0048114: { - // SetWaveLimitMultipliers - ORBIS_LOG_WARNING("Unknown gc ioctl", request, - (unsigned long)*(std::uint32_t *)argp); - thread->where(); - break; - } - - case 0xc004811f: { - ORBIS_LOG_WARNING("Unknown gc ioctl", request, - (unsigned long)*(std::uint32_t *)argp); - break; - } - - case 0x802450c9: { - // used during Net initialization - std::fprintf(stderr, "***WARNING*** Unknown gc ioctl_%lx(0x%lx)\n", request, - (unsigned long)*(std::uint32_t *)argp); - break; - } - - default: - ORBIS_LOG_FATAL("Unhandled gc ioctl", request); - std::fflush(stdout); - __builtin_trap(); - break; - } - return {}; +static orbis::ErrorCode gc_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + // 0xc00c8110 + // 0xc0848119 + + auto device = static_cast(file->device.get()); + std::lock_guard lock(device->mtx); + + switch (request) + { + case 0xc008811b: // get submit done flag ptr? + // TODO + ORBIS_LOG_ERROR("gc ioctl 0xc008811b", *(std::uint64_t*)argp); + *reinterpret_cast(argp) = &g_submitDoneFlag; + break; + + case 0xc0108102: + { // submit? + struct Args + { + std::uint32_t arg0; + std::uint32_t count; + std::uint64_t* cmds; + }; + + auto args = reinterpret_cast(argp); + + flockfile(stderr); + ORBIS_LOG_ERROR("gc ioctl 0xc0108102", args->arg0, args->count, args->cmds); + + for (unsigned i = 0; i < args->count; ++i) + { + auto cmd = args->cmds + (i * 2); + auto cmdId = cmd[0] & 0xffff'ffff; + auto addressLoPart = cmd[0] >> 32; + auto addressHiPart = cmd[1] & 0xff; + auto address = addressLoPart | (addressHiPart << 32); + auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; + auto size = ((cmd[1] >> 32) & 0xfffff) << 2; + + // std::fprintf(stderr, " %lx\n", cmd[0]); + // std::fprintf(stderr, " %lx\n", cmd[1]); + // std::fprintf(stderr, " %u:\n", i); + // std::fprintf(stderr, " cmdId = %lx\n", cmdId); + // std::fprintf(stderr, " address = %lx\n", address); + // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); + // std::fprintf(stderr, " size = %lu\n", size); + + rx::bridge.sendCommandBuffer(cmdId, address, size); + } + funlockfile(stderr); + + break; + } + + case 0xc0088101: + { // switch buffer? + struct Args + { + std::uint32_t arg0; + std::uint32_t arg1; + }; + + auto args = reinterpret_cast(argp); + + ORBIS_LOG_ERROR("gc ioctl 0xc0088101\n", args->arg0, args->arg1); + break; + } + + case 0xc020810c: + { // submit and flip? + struct Args + { + std::uint32_t arg0; + std::uint32_t count; + std::uint64_t* cmds; + std::uint64_t arg3; // flipArg? + std::uint32_t arg4; // bufferIndex? + }; + + auto args = reinterpret_cast(argp); + + flockfile(stderr); + ORBIS_LOG_ERROR("gc ioctl 0xc020810c", args->arg0, args->count, args->cmds, + args->arg3, args->arg4); + + for (unsigned i = 0; i < args->count; ++i) + { + auto cmd = args->cmds + (i * 2); + auto cmdId = cmd[0] & 0xffff'ffff; + auto addressLoPart = cmd[0] >> 32; + auto addressHiPart = cmd[1] & 0xff; + auto address = addressLoPart | (addressHiPart << 32); + auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; + auto size = ((cmd[1] >> 32) & 0xfffff) << 2; + + // std::fprintf(stderr, " %lx\n", cmd[0]); + // std::fprintf(stderr, " %lx\n", cmd[1]); + // std::fprintf(stderr, " %u:\n", i); + // std::fprintf(stderr, " cmdId = %lx\n", cmdId); + // std::fprintf(stderr, " address = %lx\n", address); + // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); + // std::fprintf(stderr, " size = %lu\n", size); + + rx::bridge.sendCommandBuffer(cmdId, address, size); + } + funlockfile(stderr); + + // orbis::bridge.sendDoFlip(); + break; + } + + case 0xc0048116: + { + ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t*)argp); + thread->where(); + break; + } + + case 0xc00c8110: + { + // set gs ring sizes + struct Args + { + std::uint32_t arg1; + std::uint32_t arg2; + std::uint32_t unk; // 0 + }; + auto args = reinterpret_cast(argp); + + ORBIS_LOG_ERROR("gc ioctl set gs ring sizes", args->arg1, args->arg2, + args->unk); + break; + } + + case 0xc0848119: + { // stats report control? + struct Args + { + std::uint32_t unk; // 0x10001 + std::uint32_t arg1; + std::uint32_t arg2; + std::uint32_t arg3; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_ERROR("gc ioctl stats report control", args->unk, args->arg1, + args->arg2, args->arg3); + break; + } + + case 0xc010810b: + { // something like stats masks? + struct Args + { + std::uint64_t arg1; + std::uint64_t arg2; + }; + + auto args = reinterpret_cast(argp); + ORBIS_LOG_ERROR("gc ioctl stats mask", args->arg1, args->arg2); + break; + } + + case 0xc030810d: + { // map compute queue + struct Args + { + std::uint32_t pipeHi; + std::uint32_t pipeLo; + std::uint32_t queueId; + std::uint32_t offset; + std::uint64_t ringBaseAddress; + std::uint64_t readPtrAddress; + std::uint64_t dingDongPtr; + std::uint32_t lenLog2; + }; + + auto args = reinterpret_cast(argp); + + ORBIS_LOG_ERROR("gc ioctl map compute queue", args->pipeHi, args->pipeLo, + args->queueId, args->offset, args->ringBaseAddress, + args->readPtrAddress, args->dingDongPtr, args->lenLog2); + + auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; + device->computeQueues[id] = { + .ringBaseAddress = args->ringBaseAddress, + .readPtrAddress = args->readPtrAddress, + .dingDongPtr = args->dingDongPtr, + .len = static_cast(1) << args->lenLog2, + }; + args->pipeHi = 0x769c766; + args->pipeLo = 0x72e8e3c1; + args->queueId = -0x248d50d8; + args->offset = 0xd245ed58; + + ((std::uint64_t*)args->dingDongPtr)[0xf0 / sizeof(std::uint64_t)] = 1; + break; + } + + case 0xc010811c: + { + // ding dong for workload + struct Args + { + std::uint32_t pipeHi; + std::uint32_t pipeLo; + std::uint32_t queueId; + std::uint32_t nextStartOffsetInDw; + }; + + auto args = reinterpret_cast(argp); + ORBIS_LOG_ERROR("gc ioctl ding dong for workload", args->pipeHi, + args->pipeLo, args->queueId, args->nextStartOffsetInDw); + + auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; + + auto queue = device->computeQueues.at(id); + auto address = (queue.ringBaseAddress + queue.offset); + auto endOffset = static_cast(args->nextStartOffsetInDw) << 2; + auto size = endOffset - queue.offset; + + rx::bridge.sendCommandBuffer(id, address, size); + + queue.offset = endOffset; + break; + } + + case 0xc0048114: + { + // SetWaveLimitMultipliers + ORBIS_LOG_WARNING("Unknown gc ioctl", request, + (unsigned long)*(std::uint32_t*)argp); + thread->where(); + break; + } + + case 0xc004811f: + { + ORBIS_LOG_WARNING("Unknown gc ioctl", request, + (unsigned long)*(std::uint32_t*)argp); + break; + } + + case 0x802450c9: + { + // used during Net initialization + std::fprintf(stderr, "***WARNING*** Unknown gc ioctl_%lx(0x%lx)\n", request, + (unsigned long)*(std::uint32_t*)argp); + break; + } + + default: + ORBIS_LOG_FATAL("Unhandled gc ioctl", request); + std::fflush(stdout); + __builtin_trap(); + break; + } + return {}; } -static orbis::ErrorCode gc_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("gc mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); - - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } - - *address = result; - return {}; +static orbis::ErrorCode gc_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("gc mmap", address, size, offset); + auto result = rx::vm::map(*address, size, prot, flags); + + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } + + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = gc_ioctl, - .mmap = gc_mmap, + .ioctl = gc_ioctl, + .mmap = gc_mmap, }; -orbis::ErrorCode GcDevice::open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode GcDevice::open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createGcCharacterDevice() { return orbis::knew(); } +IoDevice* createGcCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/hid.cpp b/rpcsx-os/iodev/hid.cpp index 6c2ad0c3..195c46cb 100644 --- a/rpcsx-os/iodev/hid.cpp +++ b/rpcsx-os/iodev/hid.cpp @@ -7,102 +7,111 @@ #include "orbis/utils/Logs.hpp" #include -struct HidDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct HidDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct HidFile : public orbis::File +{ }; -struct HidFile : public orbis::File {}; -static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("hid ioctl", request); - switch (request) { - case 0x800c4802: - thread->retval[0] = 1; // hid id - return {}; +static orbis::ErrorCode hid_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("hid ioctl", request); + switch (request) + { + case 0x800c4802: + thread->retval[0] = 1; // hid id + return {}; - case 0x8030482e: { - // read state - struct ReadStateArgs { - std::uint32_t hidId; - std::uint32_t unk0; - void *state; - std::uint32_t unk2; - std::uint32_t *connected; - std::uint32_t *unk4; - std::uint64_t unk5; - }; + case 0x8030482e: + { + // read state + struct ReadStateArgs + { + std::uint32_t hidId; + std::uint32_t unk0; + void* state; + std::uint32_t unk2; + std::uint32_t* connected; + std::uint32_t* unk4; + std::uint64_t unk5; + }; - // struct PadState { - // std::uint64_t timestamp; - // std::uint32_t unk; - // std::uint32_t buttons; - // std::uint8_t leftStickX; - // std::uint8_t leftStickY; - // std::uint8_t rightStickX; - // std::uint8_t rightStickY; - // std::uint8_t l2; - // std::uint8_t r2; - // }; + // struct PadState { + // std::uint64_t timestamp; + // std::uint32_t unk; + // std::uint32_t buttons; + // std::uint8_t leftStickX; + // std::uint8_t leftStickY; + // std::uint8_t rightStickX; + // std::uint8_t rightStickY; + // std::uint8_t l2; + // std::uint8_t r2; + // }; - // enum { - // kPadBtnL3 = 1 << 1, - // kPadBtnR3 = 1 << 2, - // kPadBtnOptions = 1 << 3, - // kPadBtnUp = 1 << 4, - // kPadBtnRight = 1 << 5, - // kPadBtnDown = 1 << 6, - // kPadBtnLeft = 1 << 7, - // kPadBtnL2 = 1 << 8, - // kPadBtnR2 = 1 << 9, - // kPadBtnL1 = 1 << 10, - // kPadBtnR1 = 1 << 11, - // kPadBtnTriangle = 1 << 12, - // kPadBtnCircle = 1 << 13, - // kPadBtnCross = 1 << 14, - // kPadBtnSquare = 1 << 15, - // kPadBtnTouchPad = 1 << 20, - // kPadBtnIntercepted = 1 << 31, - // }; + // enum { + // kPadBtnL3 = 1 << 1, + // kPadBtnR3 = 1 << 2, + // kPadBtnOptions = 1 << 3, + // kPadBtnUp = 1 << 4, + // kPadBtnRight = 1 << 5, + // kPadBtnDown = 1 << 6, + // kPadBtnLeft = 1 << 7, + // kPadBtnL2 = 1 << 8, + // kPadBtnR2 = 1 << 9, + // kPadBtnL1 = 1 << 10, + // kPadBtnR1 = 1 << 11, + // kPadBtnTriangle = 1 << 12, + // kPadBtnCircle = 1 << 13, + // kPadBtnCross = 1 << 14, + // kPadBtnSquare = 1 << 15, + // kPadBtnTouchPad = 1 << 20, + // kPadBtnIntercepted = 1 << 31, + // }; - auto args = *reinterpret_cast(argp); - // ORBIS_LOG_ERROR("hid read state", args.hidId, args.unk0, args.state, - // args.unk2, args.connected, args.unk4, args.unk5); + auto args = *reinterpret_cast(argp); + // ORBIS_LOG_ERROR("hid read state", args.hidId, args.unk0, args.state, + // args.unk2, args.connected, args.unk4, args.unk5); - auto state = (amdgpu::bridge::PadState *)args.state; - *state = rx::bridge.header->kbPadState; - *args.connected = 1; - *args.unk4 = 1; // is wireless? - thread->retval[0] = 1; - return {}; - } + auto state = (amdgpu::bridge::PadState*)args.state; + *state = rx::bridge.header->kbPadState; + *args.connected = 1; + *args.unk4 = 1; // is wireless? + thread->retval[0] = 1; + return {}; + } - case 0x8010480e: { - // read information - ORBIS_LOG_ERROR("hid read information"); - return {}; - } + case 0x8010480e: + { + // read information + ORBIS_LOG_ERROR("hid read information"); + return {}; + } - default: - ORBIS_LOG_FATAL("Unhandled hid ioctl", request); - } + default: + ORBIS_LOG_FATAL("Unhandled hid ioctl", request); + } - return {}; + return {}; } static const orbis::FileOps ops = { - .ioctl = hid_ioctl, + .ioctl = hid_ioctl, }; -orbis::ErrorCode HidDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode HidDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createHidCharacterDevice() { return orbis::knew(); } +IoDevice* createHidCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/hmd_3da.cpp b/rpcsx-os/iodev/hmd_3da.cpp index 5136b463..5c253dfa 100644 --- a/rpcsx-os/iodev/hmd_3da.cpp +++ b/rpcsx-os/iodev/hmd_3da.cpp @@ -3,33 +3,38 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct Hmd3daDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct Hmd3daDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct Hmd3daFile : public orbis::File +{ }; -struct Hmd3daFile : public orbis::File {}; -static orbis::ErrorCode hmd_3da_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled hmd_3da ioctl", request); +static orbis::ErrorCode hmd_3da_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled hmd_3da ioctl", request); - // 0x800c4802 - return {}; + // 0x800c4802 + return {}; } static const orbis::FileOps ops = { - .ioctl = hmd_3da_ioctl, + .ioctl = hmd_3da_ioctl, }; -orbis::ErrorCode Hmd3daDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode Hmd3daDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createHmd3daCharacterDevice() { return orbis::knew(); } +IoDevice* createHmd3daCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/hmd_cmd.cpp b/rpcsx-os/iodev/hmd_cmd.cpp index fffc6179..60374f31 100644 --- a/rpcsx-os/iodev/hmd_cmd.cpp +++ b/rpcsx-os/iodev/hmd_cmd.cpp @@ -2,33 +2,38 @@ #include "orbis/KernelAllocator.hpp" #include "orbis/utils/Logs.hpp" -struct HmdCmdDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct HmdCmdDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct HmdCmdFile : public orbis::File +{ }; -struct HmdCmdFile : public orbis::File {}; -static orbis::ErrorCode hmd_cmd_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled hmd_cmd ioctl", request); +static orbis::ErrorCode hmd_cmd_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled hmd_cmd ioctl", request); - // 0x800c4802 - return {}; + // 0x800c4802 + return {}; } static const orbis::FileOps ops = { - .ioctl = hmd_cmd_ioctl, + .ioctl = hmd_cmd_ioctl, }; -orbis::ErrorCode HmdCmdDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode HmdCmdDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createHmdCmdCharacterDevice() { return orbis::knew(); } +IoDevice* createHmdCmdCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/hmd_mmap.cpp b/rpcsx-os/iodev/hmd_mmap.cpp index 32cff3a2..1f98ddd2 100644 --- a/rpcsx-os/iodev/hmd_mmap.cpp +++ b/rpcsx-os/iodev/hmd_mmap.cpp @@ -3,52 +3,60 @@ #include "orbis/utils/Logs.hpp" #include "vm.hpp" -struct HmdMmapDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct HmdMmapDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct HmdMmapFile : public orbis::File +{ }; -struct HmdMmapFile : public orbis::File {}; -static orbis::ErrorCode hmd_mmap_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled hmd_mmap ioctl", request); +static orbis::ErrorCode hmd_mmap_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled hmd_mmap ioctl", request); - // 0x800c4802 - return {}; + // 0x800c4802 + return {}; } -static orbis::ErrorCode hmd_mmap_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("hmd_mmap mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); - - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } - - *address = result; - return {}; +static orbis::ErrorCode hmd_mmap_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("hmd_mmap mmap", address, size, offset); + auto result = rx::vm::map(*address, size, prot, flags); + + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } + + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = hmd_mmap_ioctl, - .mmap = hmd_mmap_mmap, + .ioctl = hmd_mmap_ioctl, + .mmap = hmd_mmap_mmap, }; -orbis::ErrorCode HmdMmapDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, - orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode HmdMmapDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createHmdMmapCharacterDevice() { - return orbis::knew(); +IoDevice* createHmdMmapCharacterDevice() +{ + return orbis::knew(); } diff --git a/rpcsx-os/iodev/hmd_snsr.cpp b/rpcsx-os/iodev/hmd_snsr.cpp index effaa2b9..9e0baf40 100644 --- a/rpcsx-os/iodev/hmd_snsr.cpp +++ b/rpcsx-os/iodev/hmd_snsr.cpp @@ -3,36 +3,42 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct HmdSnsrDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct HmdSnsrDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct HmdSnsrFile : public orbis::File +{ }; -struct HmdSnsrFile : public orbis::File {}; -static orbis::ErrorCode hmd_snsr_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled hmd_snsr ioctl", request); +static orbis::ErrorCode hmd_snsr_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled hmd_snsr ioctl", request); - // 0x800c4802 - return {}; + // 0x800c4802 + return {}; } static const orbis::FileOps ops = { - .ioctl = hmd_snsr_ioctl, + .ioctl = hmd_snsr_ioctl, }; -orbis::ErrorCode HmdSnsrDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, - orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode HmdSnsrDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createHmdSnsrCharacterDevice() { - return orbis::knew(); +IoDevice* createHmdSnsrCharacterDevice() +{ + return orbis::knew(); } diff --git a/rpcsx-os/iodev/icc_configuration.cpp b/rpcsx-os/iodev/icc_configuration.cpp index fcdab850..f73706ea 100644 --- a/rpcsx-os/iodev/icc_configuration.cpp +++ b/rpcsx-os/iodev/icc_configuration.cpp @@ -3,30 +3,35 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct IccConfigurationFile : orbis::File {}; +struct IccConfigurationFile : orbis::File +{ +}; -static orbis::ErrorCode icc_configuration_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode icc_configuration_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ - ORBIS_LOG_FATAL("Unhandled icc_configuration ioctl", request); - return {}; + ORBIS_LOG_FATAL("Unhandled icc_configuration ioctl", request); + return {}; } static const orbis::FileOps fileOps = { - .ioctl = icc_configuration_ioctl, + .ioctl = icc_configuration_ioctl, }; -struct IccConfigurationDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fileOps; - newFile->device = this; +struct IccConfigurationDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; - *file = newFile; - return {}; - } + *file = newFile; + return {}; + } }; -IoDevice *createIccConfigurationCharacterDevice() { return orbis::knew(); } +IoDevice* createIccConfigurationCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/npdrm.cpp b/rpcsx-os/iodev/npdrm.cpp index 0da9e288..653ee6b5 100644 --- a/rpcsx-os/iodev/npdrm.cpp +++ b/rpcsx-os/iodev/npdrm.cpp @@ -3,30 +3,35 @@ #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" -struct NpdrmFile : orbis::File {}; +struct NpdrmFile : orbis::File +{ +}; -static orbis::ErrorCode npdrm_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode npdrm_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ - ORBIS_LOG_FATAL("Unhandled NPDRM ioctl", request); - return {}; + ORBIS_LOG_FATAL("Unhandled NPDRM ioctl", request); + return {}; } static const orbis::FileOps fileOps = { - .ioctl = npdrm_ioctl, + .ioctl = npdrm_ioctl, }; -struct NpdrmDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fileOps; - newFile->device = this; +struct NpdrmDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; - *file = newFile; - return {}; - } + *file = newFile; + return {}; + } }; -IoDevice *createNpdrmCharacterDevice() { return orbis::knew(); } +IoDevice* createNpdrmCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/null.cpp b/rpcsx-os/iodev/null.cpp index 201d72a9..1fd0f294 100644 --- a/rpcsx-os/iodev/null.cpp +++ b/rpcsx-os/iodev/null.cpp @@ -2,31 +2,36 @@ #include "orbis/KernelAllocator.hpp" #include "orbis/uio.hpp" -struct NullDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct NullDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct NullFile : public orbis::File +{ }; -struct NullFile : public orbis::File {}; -static orbis::ErrorCode null_write(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - uio->resid = 0; - return {}; +static orbis::ErrorCode null_write(orbis::File* file, orbis::Uio* uio, + orbis::Thread*) +{ + uio->resid = 0; + return {}; } static const orbis::FileOps ops = { - .write = null_write, + .write = null_write, }; -orbis::ErrorCode NullDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode NullDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createNullCharacterDevice() { return orbis::knew(); } +IoDevice* createNullCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/rng.cpp b/rpcsx-os/iodev/rng.cpp index 52b2d357..11dea8ee 100644 --- a/rpcsx-os/iodev/rng.cpp +++ b/rpcsx-os/iodev/rng.cpp @@ -3,49 +3,56 @@ #include "orbis/utils/Logs.hpp" #include "vm.hpp" -struct RngDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct RngDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct RngFile : public orbis::File +{ }; -struct RngFile : public orbis::File {}; -static orbis::ErrorCode rng_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled rng ioctl", request); +static orbis::ErrorCode rng_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled rng ioctl", request); - // 0x800c4802 - return {}; + // 0x800c4802 + return {}; } -static orbis::ErrorCode rng_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("rng mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); - - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } - - *address = result; - return {}; +static orbis::ErrorCode rng_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("rng mmap", address, size, offset); + auto result = rx::vm::map(*address, size, prot, flags); + + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } + + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = rng_ioctl, - .mmap = rng_mmap, + .ioctl = rng_ioctl, + .mmap = rng_mmap, }; -orbis::ErrorCode RngDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode RngDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createRngCharacterDevice() { return orbis::knew(); } +IoDevice* createRngCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/sbl_srv.cpp b/rpcsx-os/iodev/sbl_srv.cpp index 8bdda8d3..38ff363d 100644 --- a/rpcsx-os/iodev/sbl_srv.cpp +++ b/rpcsx-os/iodev/sbl_srv.cpp @@ -8,50 +8,57 @@ #include "vm.hpp" #include -struct SblSrvFile : public orbis::File {}; +struct SblSrvFile : public orbis::File +{ +}; -struct SblSrvDevice : IoDevice { - orbis::shared_mutex mtx; - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct SblSrvDevice : IoDevice +{ + orbis::shared_mutex mtx; + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; }; -static orbis::ErrorCode sbl_srv_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled sbl_srv ioctl", request); - thread->where(); - return {}; +static orbis::ErrorCode sbl_srv_ioctl(orbis::File* file, std::uint64_t request, + void* argp, orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("Unhandled sbl_srv ioctl", request); + thread->where(); + return {}; } -static orbis::ErrorCode sbl_srv_mmap(orbis::File *file, void **address, - std::uint64_t size, std::int32_t prot, - std::int32_t flags, std::int64_t offset, - orbis::Thread *thread) { - ORBIS_LOG_FATAL("sbl_srv mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); +static orbis::ErrorCode sbl_srv_mmap(orbis::File* file, void** address, + std::uint64_t size, std::int32_t prot, + std::int32_t flags, std::int64_t offset, + orbis::Thread* thread) +{ + ORBIS_LOG_FATAL("sbl_srv mmap", address, size, offset); + auto result = rx::vm::map(*address, size, prot, flags); - if (result == (void *)-1) { - return orbis::ErrorCode::INVAL; // TODO - } + if (result == (void*)-1) + { + return orbis::ErrorCode::INVAL; // TODO + } - *address = result; - return {}; + *address = result; + return {}; } static const orbis::FileOps ops = { - .ioctl = sbl_srv_ioctl, - .mmap = sbl_srv_mmap, + .ioctl = sbl_srv_ioctl, + .mmap = sbl_srv_mmap, }; -orbis::ErrorCode SblSrvDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode SblSrvDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createSblSrvCharacterDevice() { return orbis::knew(); } +IoDevice* createSblSrvCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/shm.cpp b/rpcsx-os/iodev/shm.cpp index e5578da7..a7c202cc 100644 --- a/rpcsx-os/iodev/shm.cpp +++ b/rpcsx-os/iodev/shm.cpp @@ -7,67 +7,88 @@ #include #include -struct ShmDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct ShmDevice : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; }; -orbis::ErrorCode ShmDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - ORBIS_LOG_WARNING("shm_open", path, flags, mode); +orbis::ErrorCode ShmDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + ORBIS_LOG_WARNING("shm_open", path, flags, mode); - std::string name = "/rpcsx-"; - if (std::string_view{path}.starts_with("/")) { - name += path + 1; - } else { - name += path; - } + std::string name = "/rpcsx-"; + if (std::string_view{path}.starts_with("/")) + { + name += path + 1; + } + else + { + name += path; + } - auto realFlags = O_RDWR; // TODO + auto realFlags = O_RDWR; // TODO - std::size_t size = 0; - if (~flags & 0x200) { - if (name == "/rpcsx-SceShellCoreUtil") { - // TODO - realFlags |= O_CREAT; - size = 0x4000; - } else if (name == "/rpcsx-vmicDdShmAin") { - // TODO - realFlags |= O_CREAT; - size = 0x4000; - } else if (name == "/rpcsx-SceNpTpip") { - // TODO - realFlags |= O_CREAT; - size = 0x4000; - } else if (name == "/rpcsx-SceNpPlusLogger") { - realFlags |= O_CREAT; - size = 0x4400; - } else if (name == "/rpcsx-SceAvSetting") { - realFlags |= O_CREAT; - size = 0x4400; - } else { - ORBIS_LOG_ERROR("SHM: unknown shared memory", path); - thread->where(); - std::abort(); - } - } else { - realFlags |= O_CREAT; - } + std::size_t size = 0; + if (~flags & 0x200) + { + if (name == "/rpcsx-SceShellCoreUtil") + { + // TODO + realFlags |= O_CREAT; + size = 0x4000; + } + else if (name == "/rpcsx-vmicDdShmAin") + { + // TODO + realFlags |= O_CREAT; + size = 0x4000; + } + else if (name == "/rpcsx-SceNpTpip") + { + // TODO + realFlags |= O_CREAT; + size = 0x4000; + } + else if (name == "/rpcsx-SceNpPlusLogger") + { + realFlags |= O_CREAT; + size = 0x4400; + } + else if (name == "/rpcsx-SceAvSetting") + { + realFlags |= O_CREAT; + size = 0x4400; + } + else + { + ORBIS_LOG_ERROR("SHM: unknown shared memory", path); + thread->where(); + std::abort(); + } + } + else + { + realFlags |= O_CREAT; + } - int fd = shm_open(name.c_str(), realFlags, S_IRUSR | S_IWUSR); - if (fd < 0) { - std::printf("shm_open: error %u\n", errno); - return orbis::ErrorCode::ACCES; - } - auto hostFile = createHostFile(fd, this); - if (size != 0) { - hostFile->ops->truncate(hostFile, size, thread); - } + int fd = shm_open(name.c_str(), realFlags, S_IRUSR | S_IWUSR); + if (fd < 0) + { + std::printf("shm_open: error %u\n", errno); + return orbis::ErrorCode::ACCES; + } + auto hostFile = createHostFile(fd, this); + if (size != 0) + { + hostFile->ops->truncate(hostFile, size, thread); + } - *file = hostFile; - return {}; + *file = hostFile; + return {}; } -IoDevice *createShmDevice() { return orbis::knew(); } +IoDevice* createShmDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/urandom.cpp b/rpcsx-os/iodev/urandom.cpp index 01239e34..c1489539 100644 --- a/rpcsx-os/iodev/urandom.cpp +++ b/rpcsx-os/iodev/urandom.cpp @@ -4,35 +4,41 @@ #include #include -struct UrandomDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct UrandomDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct UrandomFile : public orbis::File +{ }; -struct UrandomFile : public orbis::File {}; -static orbis::ErrorCode zero_read(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - for (auto entry : std::span(uio->iov, uio->iovcnt)) { - std::memset(entry.base, 0, entry.len); - uio->offset += entry.len; - } - uio->resid = 0; - return {}; +static orbis::ErrorCode zero_read(orbis::File* file, orbis::Uio* uio, + orbis::Thread*) +{ + for (auto entry : std::span(uio->iov, uio->iovcnt)) + { + std::memset(entry.base, 0, entry.len); + uio->offset += entry.len; + } + uio->resid = 0; + return {}; } static const orbis::FileOps ops = { - .read = zero_read, + .read = zero_read, }; -orbis::ErrorCode UrandomDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode UrandomDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createUrandomCharacterDevice() { return orbis::knew(); } +IoDevice* createUrandomCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/zero.cpp b/rpcsx-os/iodev/zero.cpp index c25076c7..a3833318 100644 --- a/rpcsx-os/iodev/zero.cpp +++ b/rpcsx-os/iodev/zero.cpp @@ -4,35 +4,41 @@ #include #include -struct ZeroDevice : public IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; +struct ZeroDevice : public IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override; +}; +struct ZeroFile : public orbis::File +{ }; -struct ZeroFile : public orbis::File {}; -static orbis::ErrorCode zero_read(orbis::File *file, orbis::Uio *uio, - orbis::Thread *) { - for (auto entry : std::span(uio->iov, uio->iovcnt)) { - std::memset(entry.base, 0, entry.len); - uio->offset += entry.len; - } - uio->resid = 0; - return {}; +static orbis::ErrorCode zero_read(orbis::File* file, orbis::Uio* uio, + orbis::Thread*) +{ + for (auto entry : std::span(uio->iov, uio->iovcnt)) + { + std::memset(entry.base, 0, entry.len); + uio->offset += entry.len; + } + uio->resid = 0; + return {}; } static const orbis::FileOps ops = { - .read = zero_read, + .read = zero_read, }; -orbis::ErrorCode ZeroDevice::open(orbis::Ref *file, - const char *path, std::uint32_t flags, - std::uint32_t mode, orbis::Thread *thread) { - auto newFile = orbis::knew(); - newFile->device = this; - newFile->ops = &ops; - *file = newFile; - return {}; +orbis::ErrorCode ZeroDevice::open(orbis::Ref* file, + const char* path, std::uint32_t flags, + std::uint32_t mode, orbis::Thread* thread) +{ + auto newFile = orbis::knew(); + newFile->device = this; + newFile->ops = &ops; + *file = newFile; + return {}; } -IoDevice *createZeroCharacterDevice() { return orbis::knew(); } +IoDevice* createZeroCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index 90df7a09..e2ecbc7b 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -18,1041 +18,1138 @@ using orbis::utils::Ref; -static std::vector unself(const std::byte *image, std::size_t size) { - struct [[gnu::packed]] Header { - std::uint32_t magic; - std::uint32_t unk; - std::uint8_t category; - std::uint8_t programType; - std::uint16_t padding; - std::uint16_t headerSize; - std::uint16_t signSize; - std::uint32_t fileSize; - std::uint32_t padding2; - std::uint16_t segmentCount; - std::uint16_t unk1; - std::uint32_t padding3; - }; - static_assert(sizeof(Header) == 0x20); - - struct [[gnu::packed]] Segment { - std::uint64_t flags; - std::uint64_t offset; - std::uint64_t encryptedSize; - std::uint64_t decryptedSize; - }; - static_assert(sizeof(Segment) == 0x20); - - auto header = std::bit_cast
(image); - auto segments = std::bit_cast(image + sizeof(Header)); - - auto elfOffset = sizeof(Header) + sizeof(Segment) * header->segmentCount; - std::vector result; - result.reserve(header->fileSize); - result.resize(sizeof(Elf64_Ehdr)); - - auto ehdr = std::bit_cast(image + elfOffset); - auto phdrs = std::bit_cast(image + elfOffset + ehdr->e_phoff); - std::memcpy(result.data(), ehdr, sizeof(Elf64_Ehdr)); - - auto phdrEndOffset = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; - if (result.size() < phdrEndOffset) { - result.resize(phdrEndOffset); - } - - for (std::size_t i = 0; i < ehdr->e_phnum; ++i) { - std::memcpy(result.data() + ehdr->e_phoff + ehdr->e_phentsize * i, - image + elfOffset + ehdr->e_phoff + ehdr->e_phentsize * i, - sizeof(Elf64_Phdr)); - } - - for (std::size_t i = 0; i < header->segmentCount; ++i) { - auto &segment = segments[i]; - if ((segment.flags & 0x7fb) != 0 || - segment.decryptedSize != segment.encryptedSize) { - std::fprintf(stderr, "Unsupported self segment (%lx)\n", segment.flags); - std::abort(); - } - - if (~segment.flags & 0x800) { - continue; - } - - auto &phdr = phdrs[segment.flags >> 20]; - - auto endOffset = phdr.p_offset + segment.decryptedSize; - if (result.size() < endOffset) { - result.resize(endOffset); - } - - std::memcpy(result.data() + phdr.p_offset, image + segment.offset, - segment.decryptedSize); - } - - return result; +static std::vector unself(const std::byte* image, std::size_t size) +{ + struct [[gnu::packed]] Header + { + std::uint32_t magic; + std::uint32_t unk; + std::uint8_t category; + std::uint8_t programType; + std::uint16_t padding; + std::uint16_t headerSize; + std::uint16_t signSize; + std::uint32_t fileSize; + std::uint32_t padding2; + std::uint16_t segmentCount; + std::uint16_t unk1; + std::uint32_t padding3; + }; + static_assert(sizeof(Header) == 0x20); + + struct [[gnu::packed]] Segment + { + std::uint64_t flags; + std::uint64_t offset; + std::uint64_t encryptedSize; + std::uint64_t decryptedSize; + }; + static_assert(sizeof(Segment) == 0x20); + + auto header = std::bit_cast(image); + auto segments = std::bit_cast(image + sizeof(Header)); + + auto elfOffset = sizeof(Header) + sizeof(Segment) * header->segmentCount; + std::vector result; + result.reserve(header->fileSize); + result.resize(sizeof(Elf64_Ehdr)); + + auto ehdr = std::bit_cast(image + elfOffset); + auto phdrs = std::bit_cast(image + elfOffset + ehdr->e_phoff); + std::memcpy(result.data(), ehdr, sizeof(Elf64_Ehdr)); + + auto phdrEndOffset = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; + if (result.size() < phdrEndOffset) + { + result.resize(phdrEndOffset); + } + + for (std::size_t i = 0; i < ehdr->e_phnum; ++i) + { + std::memcpy(result.data() + ehdr->e_phoff + ehdr->e_phentsize * i, + image + elfOffset + ehdr->e_phoff + ehdr->e_phentsize * i, + sizeof(Elf64_Phdr)); + } + + for (std::size_t i = 0; i < header->segmentCount; ++i) + { + auto& segment = segments[i]; + if ((segment.flags & 0x7fb) != 0 || + segment.decryptedSize != segment.encryptedSize) + { + std::fprintf(stderr, "Unsupported self segment (%lx)\n", segment.flags); + std::abort(); + } + + if (~segment.flags & 0x800) + { + continue; + } + + auto& phdr = phdrs[segment.flags >> 20]; + + auto endOffset = phdr.p_offset + segment.decryptedSize; + if (result.size() < endOffset) + { + result.resize(endOffset); + } + + std::memcpy(result.data() + phdr.p_offset, image + segment.offset, + segment.decryptedSize); + } + + return result; } -std::uint64_t rx::linker::encodeFid(std::string_view fid) { - static const char suffix[] = - "\x51\x8D\x64\xA6\x35\xDE\xD8\xC1\xE6\xB0\x39\xB1\xC3\xE5\x52\x30"; +std::uint64_t rx::linker::encodeFid(std::string_view fid) +{ + static const char suffix[] = + "\x51\x8D\x64\xA6\x35\xDE\xD8\xC1\xE6\xB0\x39\xB1\xC3\xE5\x52\x30"; - sha1_context ctx; - unsigned char output[20]; + sha1_context ctx; + unsigned char output[20]; - sha1_starts(&ctx); - sha1_update(&ctx, reinterpret_cast(fid.data()), - fid.length()); - sha1_update(&ctx, reinterpret_cast(suffix), - sizeof(suffix) - 1); - sha1_finish(&ctx, output); + sha1_starts(&ctx); + sha1_update(&ctx, reinterpret_cast(fid.data()), + fid.length()); + sha1_update(&ctx, reinterpret_cast(suffix), + sizeof(suffix) - 1); + sha1_finish(&ctx, output); - std::uint64_t hash; - std::memcpy(&hash, output, sizeof(hash)); - return hash; + std::uint64_t hash; + std::memcpy(&hash, output, sizeof(hash)); + return hash; } -enum OrbisElfProgramType { - kElfProgramTypeNull = 0, - kElfProgramTypeLoad = 1, - kElfProgramTypeDynamic = 2, - kElfProgramTypeInterp = 3, - kElfProgramTypeNote = 4, - kElfProgramTypeShlib = 5, - kElfProgramTypePhdr = 6, - kElfProgramTypeTls = 7, - kElfProgramTypeSceDynlibData = 0x61000000, - kElfProgramTypeSceProcParam = 0x61000001, - kElfProgramTypeSceModuleParam = 0x61000002, - kElfProgramTypeSceRelRo = 0x61000010, - kElfProgramTypeGnuEhFrame = 0x6474e550, - kElfProgramTypeGnuRelRo = 0x6474e552, - kElfProgramTypeSceComment = 0x6fffff00, - kElfProgramTypeSceVersion = 0x6fffff01, +enum OrbisElfProgramType +{ + kElfProgramTypeNull = 0, + kElfProgramTypeLoad = 1, + kElfProgramTypeDynamic = 2, + kElfProgramTypeInterp = 3, + kElfProgramTypeNote = 4, + kElfProgramTypeShlib = 5, + kElfProgramTypePhdr = 6, + kElfProgramTypeTls = 7, + kElfProgramTypeSceDynlibData = 0x61000000, + kElfProgramTypeSceProcParam = 0x61000001, + kElfProgramTypeSceModuleParam = 0x61000002, + kElfProgramTypeSceRelRo = 0x61000010, + kElfProgramTypeGnuEhFrame = 0x6474e550, + kElfProgramTypeGnuRelRo = 0x6474e552, + kElfProgramTypeSceComment = 0x6fffff00, + kElfProgramTypeSceVersion = 0x6fffff01, }; -enum OrbisElfDynamicType { - kElfDynamicTypeNull = 0, - kElfDynamicTypeNeeded = 1, - kElfDynamicTypePltRelSize = 2, - kElfDynamicTypePltGot = 3, - kElfDynamicTypeHash = 4, - kElfDynamicTypeStrTab = 5, - kElfDynamicTypeSymTab = 6, - kElfDynamicTypeRela = 7, - kElfDynamicTypeRelaSize = 8, - kElfDynamicTypeRelaEnt = 9, - kElfDynamicTypeStrSize = 10, - kElfDynamicTypeSymEnt = 11, - kElfDynamicTypeInit = 12, - kElfDynamicTypeFini = 13, - kElfDynamicTypeSoName = 14, - kElfDynamicTypeRpath = 15, - kElfDynamicTypeSymbolic = 16, - kElfDynamicTypeRel = 17, - kElfDynamicTypeRelSize = 18, - kElfDynamicTypeRelEent = 19, - kElfDynamicTypePltRel = 20, - kElfDynamicTypeDebug = 21, - kElfDynamicTypeTextRel = 22, - kElfDynamicTypeJmpRel = 23, - kElfDynamicTypeBindNow = 24, - kElfDynamicTypeInitArray = 25, - kElfDynamicTypeFiniArray = 26, - kElfDynamicTypeInitArraySize = 27, - kElfDynamicTypeFiniArraySize = 28, - kElfDynamicTypeRunPath = 29, - kElfDynamicTypeFlags = 30, - kElfDynamicTypePreinitArray = 32, - kElfDynamicTypePreinitArraySize = 33, - kElfDynamicTypeSceFingerprint = 0x61000007, - kElfDynamicTypeSceOriginalFilename = 0x61000009, - kElfDynamicTypeSceModuleInfo = 0x6100000d, - kElfDynamicTypeSceNeededModule = 0x6100000f, - kElfDynamicTypeSceModuleAttr = 0x61000011, - kElfDynamicTypeSceExportLib = 0x61000013, - kElfDynamicTypeSceImportLib = 0x61000015, - kElfDynamicTypeSceExportLibAttr = 0x61000017, - kElfDynamicTypeSceImportLibAttr = 0x61000019, - kElfDynamicTypeSceHash = 0x61000025, - kElfDynamicTypeScePltGot = 0x61000027, - kElfDynamicTypeSceJmpRel = 0x61000029, - kElfDynamicTypeScePltRel = 0x6100002b, - kElfDynamicTypeScePltRelSize = 0x6100002d, - kElfDynamicTypeSceRela = 0x6100002f, - kElfDynamicTypeSceRelaSize = 0x61000031, - kElfDynamicTypeSceRelaEnt = 0x61000033, - kElfDynamicTypeSceStrTab = 0x61000035, - kElfDynamicTypeSceStrSize = 0x61000037, - kElfDynamicTypeSceSymTab = 0x61000039, - kElfDynamicTypeSceSymEnt = 0x6100003b, - kElfDynamicTypeSceHashSize = 0x6100003d, - kElfDynamicTypeSceOriginalFilename1 = 0x61000041, - kElfDynamicTypeSceModuleInfo1 = 0x61000043, - kElfDynamicTypeSceNeededModule1 = 0x61000045, - kElfDynamicTypeSceImportLib1 = 0x61000049, - kElfDynamicTypeSceSymTabSize = 0x6100003f, - kElfDynamicTypeRelaCount = 0x6ffffff9 +enum OrbisElfDynamicType +{ + kElfDynamicTypeNull = 0, + kElfDynamicTypeNeeded = 1, + kElfDynamicTypePltRelSize = 2, + kElfDynamicTypePltGot = 3, + kElfDynamicTypeHash = 4, + kElfDynamicTypeStrTab = 5, + kElfDynamicTypeSymTab = 6, + kElfDynamicTypeRela = 7, + kElfDynamicTypeRelaSize = 8, + kElfDynamicTypeRelaEnt = 9, + kElfDynamicTypeStrSize = 10, + kElfDynamicTypeSymEnt = 11, + kElfDynamicTypeInit = 12, + kElfDynamicTypeFini = 13, + kElfDynamicTypeSoName = 14, + kElfDynamicTypeRpath = 15, + kElfDynamicTypeSymbolic = 16, + kElfDynamicTypeRel = 17, + kElfDynamicTypeRelSize = 18, + kElfDynamicTypeRelEent = 19, + kElfDynamicTypePltRel = 20, + kElfDynamicTypeDebug = 21, + kElfDynamicTypeTextRel = 22, + kElfDynamicTypeJmpRel = 23, + kElfDynamicTypeBindNow = 24, + kElfDynamicTypeInitArray = 25, + kElfDynamicTypeFiniArray = 26, + kElfDynamicTypeInitArraySize = 27, + kElfDynamicTypeFiniArraySize = 28, + kElfDynamicTypeRunPath = 29, + kElfDynamicTypeFlags = 30, + kElfDynamicTypePreinitArray = 32, + kElfDynamicTypePreinitArraySize = 33, + kElfDynamicTypeSceFingerprint = 0x61000007, + kElfDynamicTypeSceOriginalFilename = 0x61000009, + kElfDynamicTypeSceModuleInfo = 0x6100000d, + kElfDynamicTypeSceNeededModule = 0x6100000f, + kElfDynamicTypeSceModuleAttr = 0x61000011, + kElfDynamicTypeSceExportLib = 0x61000013, + kElfDynamicTypeSceImportLib = 0x61000015, + kElfDynamicTypeSceExportLibAttr = 0x61000017, + kElfDynamicTypeSceImportLibAttr = 0x61000019, + kElfDynamicTypeSceHash = 0x61000025, + kElfDynamicTypeScePltGot = 0x61000027, + kElfDynamicTypeSceJmpRel = 0x61000029, + kElfDynamicTypeScePltRel = 0x6100002b, + kElfDynamicTypeScePltRelSize = 0x6100002d, + kElfDynamicTypeSceRela = 0x6100002f, + kElfDynamicTypeSceRelaSize = 0x61000031, + kElfDynamicTypeSceRelaEnt = 0x61000033, + kElfDynamicTypeSceStrTab = 0x61000035, + kElfDynamicTypeSceStrSize = 0x61000037, + kElfDynamicTypeSceSymTab = 0x61000039, + kElfDynamicTypeSceSymEnt = 0x6100003b, + kElfDynamicTypeSceHashSize = 0x6100003d, + kElfDynamicTypeSceOriginalFilename1 = 0x61000041, + kElfDynamicTypeSceModuleInfo1 = 0x61000043, + kElfDynamicTypeSceNeededModule1 = 0x61000045, + kElfDynamicTypeSceImportLib1 = 0x61000049, + kElfDynamicTypeSceSymTabSize = 0x6100003f, + kElfDynamicTypeRelaCount = 0x6ffffff9 }; -inline const char *toString(OrbisElfDynamicType dynType) { - switch (dynType) { - case kElfDynamicTypeNull: - return "Null"; - case kElfDynamicTypeNeeded: - return "Needed"; - case kElfDynamicTypePltRelSize: - return "PltRelSize"; - case kElfDynamicTypePltGot: - return "PltGot"; - case kElfDynamicTypeHash: - return "Hash"; - case kElfDynamicTypeStrTab: - return "StrTab"; - case kElfDynamicTypeSymTab: - return "SymTab"; - case kElfDynamicTypeRela: - return "Rela"; - case kElfDynamicTypeRelaSize: - return "RelaSize"; - case kElfDynamicTypeRelaEnt: - return "RelaEnt"; - case kElfDynamicTypeStrSize: - return "StrSize"; - case kElfDynamicTypeSymEnt: - return "SymEnt"; - case kElfDynamicTypeInit: - return "Init"; - case kElfDynamicTypeFini: - return "Fini"; - case kElfDynamicTypeSoName: - return "SoName"; - case kElfDynamicTypeRpath: - return "Rpath"; - case kElfDynamicTypeSymbolic: - return "Symbolic"; - case kElfDynamicTypeRel: - return "Rel"; - case kElfDynamicTypeRelSize: - return "RelSize"; - case kElfDynamicTypeRelEent: - return "RelEent"; - case kElfDynamicTypePltRel: - return "PltRel"; - case kElfDynamicTypeDebug: - return "Debug"; - case kElfDynamicTypeTextRel: - return "TextRel"; - case kElfDynamicTypeJmpRel: - return "JmpRel"; - case kElfDynamicTypeBindNow: - return "BindNow"; - case kElfDynamicTypeInitArray: - return "InitArray"; - case kElfDynamicTypeFiniArray: - return "FiniArray"; - case kElfDynamicTypeInitArraySize: - return "InitArraySize"; - case kElfDynamicTypeFiniArraySize: - return "FiniArraySize"; - case kElfDynamicTypeRunPath: - return "RunPath"; - case kElfDynamicTypeFlags: - return "Flags"; - case kElfDynamicTypePreinitArray: - return "PreinitArray"; - case kElfDynamicTypePreinitArraySize: - return "PreinitArraySize"; - case kElfDynamicTypeSceFingerprint: - return "SceFingerprint"; - case kElfDynamicTypeSceOriginalFilename: - return "SceOriginalFilename"; - case kElfDynamicTypeSceModuleInfo: - return "SceModuleInfo"; - case kElfDynamicTypeSceNeededModule: - return "SceNeededModule"; - case kElfDynamicTypeSceModuleAttr: - return "SceModuleAttr"; - case kElfDynamicTypeSceExportLib: - return "SceExportLib"; - case kElfDynamicTypeSceImportLib: - return "SceImportLib"; - case kElfDynamicTypeSceExportLibAttr: - return "SceExportLibAttr"; - case kElfDynamicTypeSceImportLibAttr: - return "SceImportLibAttr"; - case kElfDynamicTypeSceHash: - return "SceHash"; - case kElfDynamicTypeScePltGot: - return "ScePltGot"; - case kElfDynamicTypeSceJmpRel: - return "SceJmpRel"; - case kElfDynamicTypeScePltRel: - return "ScePltRel"; - case kElfDynamicTypeScePltRelSize: - return "ScePltRelSize"; - case kElfDynamicTypeSceRela: - return "SceRela"; - case kElfDynamicTypeSceRelaSize: - return "SceRelaSize"; - case kElfDynamicTypeSceRelaEnt: - return "SceRelaEnt"; - case kElfDynamicTypeSceStrTab: - return "SceStrTab"; - case kElfDynamicTypeSceStrSize: - return "SceStrSize"; - case kElfDynamicTypeSceSymTab: - return "SceSymTab"; - case kElfDynamicTypeSceSymEnt: - return "SceSymEnt"; - case kElfDynamicTypeSceHashSize: - return "SceHashSize"; - case kElfDynamicTypeSceOriginalFilename1: - return "SceOriginalFilename1"; - case kElfDynamicTypeSceModuleInfo1: - return "SceModuleInfo1"; - case kElfDynamicTypeSceNeededModule1: - return "SceNeededModule1"; - case kElfDynamicTypeSceImportLib1: - return "SceImportLib1"; - case kElfDynamicTypeSceSymTabSize: - return "SceSymTabSize"; - case kElfDynamicTypeRelaCount: - return "RelaCount"; - } - - return ""; +inline const char* toString(OrbisElfDynamicType dynType) +{ + switch (dynType) + { + case kElfDynamicTypeNull: + return "Null"; + case kElfDynamicTypeNeeded: + return "Needed"; + case kElfDynamicTypePltRelSize: + return "PltRelSize"; + case kElfDynamicTypePltGot: + return "PltGot"; + case kElfDynamicTypeHash: + return "Hash"; + case kElfDynamicTypeStrTab: + return "StrTab"; + case kElfDynamicTypeSymTab: + return "SymTab"; + case kElfDynamicTypeRela: + return "Rela"; + case kElfDynamicTypeRelaSize: + return "RelaSize"; + case kElfDynamicTypeRelaEnt: + return "RelaEnt"; + case kElfDynamicTypeStrSize: + return "StrSize"; + case kElfDynamicTypeSymEnt: + return "SymEnt"; + case kElfDynamicTypeInit: + return "Init"; + case kElfDynamicTypeFini: + return "Fini"; + case kElfDynamicTypeSoName: + return "SoName"; + case kElfDynamicTypeRpath: + return "Rpath"; + case kElfDynamicTypeSymbolic: + return "Symbolic"; + case kElfDynamicTypeRel: + return "Rel"; + case kElfDynamicTypeRelSize: + return "RelSize"; + case kElfDynamicTypeRelEent: + return "RelEent"; + case kElfDynamicTypePltRel: + return "PltRel"; + case kElfDynamicTypeDebug: + return "Debug"; + case kElfDynamicTypeTextRel: + return "TextRel"; + case kElfDynamicTypeJmpRel: + return "JmpRel"; + case kElfDynamicTypeBindNow: + return "BindNow"; + case kElfDynamicTypeInitArray: + return "InitArray"; + case kElfDynamicTypeFiniArray: + return "FiniArray"; + case kElfDynamicTypeInitArraySize: + return "InitArraySize"; + case kElfDynamicTypeFiniArraySize: + return "FiniArraySize"; + case kElfDynamicTypeRunPath: + return "RunPath"; + case kElfDynamicTypeFlags: + return "Flags"; + case kElfDynamicTypePreinitArray: + return "PreinitArray"; + case kElfDynamicTypePreinitArraySize: + return "PreinitArraySize"; + case kElfDynamicTypeSceFingerprint: + return "SceFingerprint"; + case kElfDynamicTypeSceOriginalFilename: + return "SceOriginalFilename"; + case kElfDynamicTypeSceModuleInfo: + return "SceModuleInfo"; + case kElfDynamicTypeSceNeededModule: + return "SceNeededModule"; + case kElfDynamicTypeSceModuleAttr: + return "SceModuleAttr"; + case kElfDynamicTypeSceExportLib: + return "SceExportLib"; + case kElfDynamicTypeSceImportLib: + return "SceImportLib"; + case kElfDynamicTypeSceExportLibAttr: + return "SceExportLibAttr"; + case kElfDynamicTypeSceImportLibAttr: + return "SceImportLibAttr"; + case kElfDynamicTypeSceHash: + return "SceHash"; + case kElfDynamicTypeScePltGot: + return "ScePltGot"; + case kElfDynamicTypeSceJmpRel: + return "SceJmpRel"; + case kElfDynamicTypeScePltRel: + return "ScePltRel"; + case kElfDynamicTypeScePltRelSize: + return "ScePltRelSize"; + case kElfDynamicTypeSceRela: + return "SceRela"; + case kElfDynamicTypeSceRelaSize: + return "SceRelaSize"; + case kElfDynamicTypeSceRelaEnt: + return "SceRelaEnt"; + case kElfDynamicTypeSceStrTab: + return "SceStrTab"; + case kElfDynamicTypeSceStrSize: + return "SceStrSize"; + case kElfDynamicTypeSceSymTab: + return "SceSymTab"; + case kElfDynamicTypeSceSymEnt: + return "SceSymEnt"; + case kElfDynamicTypeSceHashSize: + return "SceHashSize"; + case kElfDynamicTypeSceOriginalFilename1: + return "SceOriginalFilename1"; + case kElfDynamicTypeSceModuleInfo1: + return "SceModuleInfo1"; + case kElfDynamicTypeSceNeededModule1: + return "SceNeededModule1"; + case kElfDynamicTypeSceImportLib1: + return "SceImportLib1"; + case kElfDynamicTypeSceSymTabSize: + return "SceSymTabSize"; + case kElfDynamicTypeRelaCount: + return "RelaCount"; + } + + return ""; } -struct SceProcessParam { - std::uint64_t size = 0x40; - std::uint32_t magic = 0x4942524F; - std::uint32_t entryCount = 3; - std::uint64_t sdkVersion = 0x4508101; +struct SceProcessParam +{ + std::uint64_t size = 0x40; + std::uint32_t magic = 0x4942524F; + std::uint32_t entryCount = 3; + std::uint64_t sdkVersion = 0x4508101; - std::uint64_t unk0 = 0; - std::uint64_t unk1 = 0; - std::uint64_t unk2 = 0; - std::uint64_t unk3 = 0; + std::uint64_t unk0 = 0; + std::uint64_t unk1 = 0; + std::uint64_t unk2 = 0; + std::uint64_t unk3 = 0; - std::uint64_t sceLibcParam_ptr = 0; + std::uint64_t sceLibcParam_ptr = 0; - // ext, size == 0x50 - std::uint64_t sceLibcKernelMemParam_ptr = 0; - std::uint64_t sceLibcKernelFsParam_ptr = 0; + // ext, size == 0x50 + std::uint64_t sceLibcKernelMemParam_ptr = 0; + std::uint64_t sceLibcKernelFsParam_ptr = 0; }; -struct Symbol { - orbis::Module *module; - std::uint64_t address; - std::uint64_t bindMode; +struct Symbol +{ + orbis::Module* module; + std::uint64_t address; + std::uint64_t bindMode; }; static std::map> - g_moduleOverrideTable; + g_moduleOverrideTable; void rx::linker::override(std::string originalModuleName, - std::filesystem::path replacedModulePath) { - g_moduleOverrideTable[std::move(originalModuleName)] = - std::move(replacedModulePath); + std::filesystem::path replacedModulePath) +{ + g_moduleOverrideTable[std::move(originalModuleName)] = + std::move(replacedModulePath); } Ref rx::linker::loadModule(std::span image, - orbis::Process *process) { - Ref result{orbis::knew()}; - - Elf64_Ehdr header; - std::memcpy(&header, image.data(), sizeof(Elf64_Ehdr)); - result->type = header.e_type; - - Elf64_Phdr phdrsStorage[16]; - if (header.e_phnum > std::size(phdrsStorage)) { - std::abort(); - } - - std::memcpy(phdrsStorage, image.data() + header.e_phoff, - header.e_phnum * sizeof(Elf64_Phdr)); - auto phdrs = std::span(phdrsStorage, header.e_phnum); - - std::uint64_t imageSize = 0; - std::uint64_t baseAddress = ~static_cast(0); - int dynamicPhdrIndex = -1; - int interpPhdrIndex = -1; - int notePhdrIndex = -1; - int shlibPhdrIndex = -1; - int phdrPhdrIndex = -1; - int tlsPhdrIndex = -1; - int sceDynlibDataPhdrIndex = -1; - int sceProcParamIndex = -1; - int sceModuleParamIndex = -1; - int sceRelRoPhdrIndex = -1; - int gnuEhFramePhdrIndex = -1; - int gnuRelRoPhdrIndex = -1; - int sceCommentPhdrIndex = -1; - int sceVersionPhdrIndex = -1; - - for (auto &phdr : phdrs) { - std::size_t index = &phdr - phdrs.data(); - - switch (phdr.p_type) { - case kElfProgramTypeNull: - break; - case kElfProgramTypeLoad: - baseAddress = - std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align)); - imageSize = std::max( - imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align)); - break; - case kElfProgramTypeDynamic: - dynamicPhdrIndex = index; - break; - case kElfProgramTypeInterp: - interpPhdrIndex = index; - break; - case kElfProgramTypeNote: - notePhdrIndex = index; - break; - case kElfProgramTypeShlib: - shlibPhdrIndex = index; - break; - case kElfProgramTypePhdr: - phdrPhdrIndex = index; - break; - case kElfProgramTypeTls: - tlsPhdrIndex = index; - break; - case kElfProgramTypeSceDynlibData: - sceDynlibDataPhdrIndex = index; - break; - case kElfProgramTypeSceProcParam: - sceProcParamIndex = index; - break; - case kElfProgramTypeSceModuleParam: - sceModuleParamIndex = index; - break; - case kElfProgramTypeSceRelRo: - sceRelRoPhdrIndex = index; - baseAddress = - std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align)); - imageSize = std::max( - imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align)); - break; - case kElfProgramTypeGnuEhFrame: - gnuEhFramePhdrIndex = index; - break; - case kElfProgramTypeGnuRelRo: - gnuRelRoPhdrIndex = index; - break; - case kElfProgramTypeSceComment: - sceCommentPhdrIndex = index; - break; - case kElfProgramTypeSceVersion: - sceVersionPhdrIndex = index; - break; - } - } - - auto imageBase = reinterpret_cast( - rx::vm::map(reinterpret_cast(baseAddress), - utils::alignUp(imageSize, rx::vm::kPageSize), 0, - rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous)); - - if (imageBase == MAP_FAILED) { - std::abort(); - } - - result->entryPoint = - header.e_entry - ? reinterpret_cast(imageBase + header.e_entry) - : 0; - - if (sceProcParamIndex >= 0) { - result->processParam = - phdrs[sceProcParamIndex].p_vaddr - ? reinterpret_cast(imageBase + - phdrs[sceProcParamIndex].p_vaddr) - : nullptr; - result->processParamSize = phdrs[sceProcParamIndex].p_memsz; - } - - if (sceModuleParamIndex >= 0) { - result->moduleParam = - phdrs[sceModuleParamIndex].p_vaddr - ? reinterpret_cast(imageBase + - phdrs[sceModuleParamIndex].p_vaddr) - : nullptr; - result->moduleParamSize = phdrs[sceModuleParamIndex].p_memsz; - - // std::printf("sce_module_param: "); - // for (auto elem : image.subspan(phdrs[sceModuleParamIndex].p_offset, - // phdrs[sceModuleParamIndex].p_filesz)) { - // std::printf(" %02x", (unsigned)elem); - // } - // std::printf("\n"); - } - - if (tlsPhdrIndex >= 0) { - result->tlsAlign = phdrs[tlsPhdrIndex].p_align; - result->tlsSize = phdrs[tlsPhdrIndex].p_memsz; - result->tlsInitSize = phdrs[tlsPhdrIndex].p_filesz; - result->tlsInit = phdrs[tlsPhdrIndex].p_vaddr - ? imageBase + phdrs[tlsPhdrIndex].p_vaddr - : nullptr; - } - - if (gnuEhFramePhdrIndex >= 0 && phdrs[gnuEhFramePhdrIndex].p_vaddr > 0) { - result->ehFrameHdr = imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr; - result->ehFrameHdrSize = phdrs[gnuEhFramePhdrIndex].p_memsz; - - struct GnuExceptionInfo { - uint8_t version; - uint8_t encoding; - uint8_t fdeCount; - uint8_t encodingTable; - std::byte first; - }; - - auto *exinfo = reinterpret_cast( - image.data() + phdrs[gnuEhFramePhdrIndex].p_offset); - - if (exinfo->version != 1) { - std::abort(); - } - - if (exinfo->fdeCount != 0x03) { - std::abort(); - } - - if (exinfo->encodingTable != 0x3b) { - std::abort(); - } - - std::byte *dataBuffer = nullptr; - - if (exinfo->encoding == 0x03) { - auto offset = *reinterpret_cast(&exinfo->first); - dataBuffer = imageBase + offset; - } else if (exinfo->encoding == 0x1B) { - auto offset = *reinterpret_cast(&exinfo->first); - dataBuffer = &exinfo->first + sizeof(std::int32_t) + offset; - } else { - std::abort(); - } - - auto *dataBufferIt = dataBuffer; - while (true) { - auto size = *reinterpret_cast(dataBufferIt); - dataBufferIt += sizeof(std::uint32_t); - - if (size == 0) { - break; - } - - if (size == -1) { - size = *reinterpret_cast(dataBufferIt) + - sizeof(std::uint64_t); - } - - dataBufferIt += size; - } - - result->ehFrame = - imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr + - (dataBuffer - image.data() - phdrs[gnuEhFramePhdrIndex].p_offset); - result->ehFrameSize = dataBufferIt - dataBuffer; - } - - if (dynamicPhdrIndex >= 0 && phdrs[dynamicPhdrIndex].p_filesz > 0) { - auto &dynPhdr = phdrs[dynamicPhdrIndex]; - std::vector dyns(dynPhdr.p_filesz / sizeof(Elf64_Dyn)); - std::memcpy(dyns.data(), image.data() + dynPhdr.p_offset, - dyns.size() * sizeof(Elf64_Dyn)); - - int sceStrtabIndex = -1; - int sceSymtabIndex = -1; - std::size_t sceSymtabSize = 0; - for (auto &dyn : dyns) { - if (dyn.d_tag == kElfDynamicTypeSceStrTab) { - sceStrtabIndex = &dyn - dyns.data(); - } else if (dyn.d_tag == kElfDynamicTypeSceSymTab) { - sceSymtabIndex = &dyn - dyns.data(); - } else if (dyn.d_tag == kElfDynamicTypeSceSymTabSize) { - sceSymtabSize = dyn.d_un.d_val; - } - } - - auto sceStrtab = sceStrtabIndex >= 0 && sceDynlibDataPhdrIndex >= 0 - ? reinterpret_cast( - image.data() + dyns[sceStrtabIndex].d_un.d_val + - phdrs[sceDynlibDataPhdrIndex].p_offset) - : nullptr; - - auto sceDynlibData = - sceDynlibDataPhdrIndex >= 0 - ? image.data() + phdrs[sceDynlibDataPhdrIndex].p_offset - : nullptr; - - auto sceSymtabData = - sceSymtabIndex >= 0 && sceDynlibData != nullptr - ? reinterpret_cast( - sceDynlibData + dyns[sceSymtabIndex].d_un.d_val) - : nullptr; - - std::unordered_map idToModuleIndex; - std::unordered_map idToLibraryIndex; - - orbis::Relocation *pltRelocations = nullptr; - std::size_t pltRelocationCount = 0; - orbis::Relocation *nonPltRelocations = nullptr; - std::size_t nonPltRelocationCount = 0; - - auto patchSoName = [](std::string_view name) { - if (name.ends_with(".prx")) { - name.remove_suffix(4); - } - if (name.ends_with("-PRX")) { - name.remove_suffix(4); // TODO: implement lib scan - } - if (name.ends_with("-module")) { - name.remove_suffix(7); // TODO: implement lib scan - } - if (name.ends_with("_padebug")) { - name.remove_suffix(8); - } - if (name.ends_with("_sys")) { - name.remove_suffix(4); - } - - return name; - }; - - for (auto dyn : dyns) { - // std::printf("%s: %lx", toString((OrbisElfDynamicType)dyn.d_tag), - // dyn.d_un.d_val); - - // if (dyn.d_tag == kElfDynamicTypeSceNeededModule || - // dyn.d_tag == kElfDynamicTypeNeeded || - // dyn.d_tag == kElfDynamicTypeSceOriginalFilename || - // dyn.d_tag == kElfDynamicTypeSceImportLib || - // dyn.d_tag == kElfDynamicTypeSceExportLib || - // dyn.d_tag == kElfDynamicTypeSceModuleInfo) { - // std::printf(" ('%s')", - // sceStrtab - // ? sceStrtab + - // static_cast(dyn.d_un.d_val) : ""); - // } - - // std::printf("\n"); - - if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) { - std::strncpy(result->moduleName, - sceStrtab + static_cast(dyn.d_un.d_val), - sizeof(result->moduleName)); - } else if (dyn.d_tag == kElfDynamicTypeSceModuleAttr) { - result->attributes = dyn.d_un.d_val; - } - - if (dyn.d_tag == kElfDynamicTypeSoName) { - auto name = - patchSoName(sceStrtab + static_cast(dyn.d_un.d_val)); - std::memcpy(result->soName, name.data(), name.size()); - std::memcpy(result->soName + name.size(), ".prx", sizeof(".prx")); - } - - // if (dyn.d_tag == kElfDynamicTypeNeeded) { - // auto name = std::string_view( - // sceStrtab + static_cast(dyn.d_un.d_val)); - // if (name == "STREQUAL") { - // // HACK for broken FWs - // result->needed.push_back("libSceDolbyVision.prx"); - // } else { - // name = patchSoName(name); - // if (name != "libSceFreeTypeOptBm") { // TODO - // result->needed.emplace_back(name); - // result->needed.back() += ".prx"; - // } - // } - // } - - if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) { - idToModuleIndex[dyn.d_un.d_val >> 48] = -1; - } - - if (dyn.d_tag == kElfDynamicTypeSceNeededModule) { - auto [it, inserted] = idToModuleIndex.try_emplace( - dyn.d_un.d_val >> 48, result->neededModules.size()); - - if (inserted) { - result->neededModules.emplace_back(); - } - - auto &mod = result->neededModules[it->second]; - mod.name = sceStrtab + static_cast(dyn.d_un.d_val); - mod.attr = static_cast(dyn.d_un.d_val >> 32); - mod.isExport = false; - } else if (dyn.d_tag == kElfDynamicTypeSceImportLib || - dyn.d_tag == kElfDynamicTypeSceExportLib) { - auto [it, inserted] = idToLibraryIndex.try_emplace( - dyn.d_un.d_val >> 48, result->neededLibraries.size()); - - if (inserted) { - result->neededLibraries.emplace_back(); - } - - auto &lib = result->neededLibraries[it->second]; - - lib.name = sceStrtab + static_cast(dyn.d_un.d_val); - lib.isExport = dyn.d_tag == kElfDynamicTypeSceExportLib; - } else if (dyn.d_tag == kElfDynamicTypeSceExportLibAttr || - dyn.d_tag == kElfDynamicTypeSceImportLibAttr) { - auto [it, inserted] = idToLibraryIndex.try_emplace( - dyn.d_un.d_val >> 48, result->neededLibraries.size()); - - if (inserted) { - result->neededLibraries.emplace_back(); - } - - auto &lib = result->neededLibraries[it->second]; - - lib.attr = dyn.d_un.d_val & ((static_cast(1) << 48) - 1); - } - - switch (dyn.d_tag) { - case kElfDynamicTypeScePltGot: - result->pltGot = - dyn.d_un.d_ptr - ? reinterpret_cast(imageBase + dyn.d_un.d_ptr) - : nullptr; - break; - - case kElfDynamicTypeSceJmpRel: - if (sceDynlibData != nullptr) { - pltRelocations = reinterpret_cast( - sceDynlibData + dyn.d_un.d_ptr); - } - break; - case kElfDynamicTypeScePltRel: - break; - case kElfDynamicTypeScePltRelSize: - pltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); - break; - case kElfDynamicTypeSceRela: - if (sceDynlibData != nullptr) { - nonPltRelocations = reinterpret_cast( - sceDynlibData + dyn.d_un.d_ptr); - } - break; - case kElfDynamicTypeSceRelaSize: - nonPltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); - break; - case kElfDynamicTypeSceRelaEnt: - break; - - case kElfDynamicTypeInit: - result->initProc = imageBase + dyn.d_un.d_ptr; - break; - case kElfDynamicTypeFini: - result->finiProc = imageBase + dyn.d_un.d_ptr; - break; - } - } - - if (sceSymtabData != nullptr && sceSymtabSize / sizeof(Elf64_Sym) > 0) { - auto sceSymtab = - std::span(sceSymtabData, sceSymtabSize / sizeof(Elf64_Sym)); - - result->symbols.reserve(sceSymtab.size()); - - for (auto &sym : sceSymtab) { - auto visibility = ELF64_ST_VISIBILITY(sym.st_other); - auto type = ELF64_ST_TYPE(sym.st_info); - auto bind = ELF64_ST_BIND(sym.st_info); - orbis::Symbol symbol{ - .address = sym.st_value, - .size = sym.st_size, - .visibility = static_cast(visibility), - .bind = static_cast(bind), - .type = static_cast(type), - }; - - if (sceStrtab != nullptr && sym.st_name != 0) { - auto fullName = std::string_view(sceStrtab + sym.st_name); - if (auto hashPos = fullName.find('#'); - hashPos != std::string_view::npos) { - std::string_view module; - std::string_view library; - std::string_view name; - - name = fullName.substr(0, hashPos); - auto moduleLibary = fullName.substr(hashPos + 1); - - hashPos = moduleLibary.find('#'); - - if (hashPos == std::string_view::npos) { - std::abort(); - } - - library = moduleLibary.substr(0, hashPos); - module = moduleLibary.substr(hashPos + 1); - - auto libaryNid = *decodeNid(library); - auto moduleNid = *decodeNid(module); - - symbol.libraryIndex = idToLibraryIndex.at(libaryNid); - symbol.moduleIndex = idToModuleIndex.at(moduleNid); - symbol.id = *decodeNid(name); - } else if (auto nid = decodeNid(fullName)) { - symbol.id = *nid; - symbol.libraryIndex = -1; - symbol.moduleIndex = -1; - } else { - symbol.id = - encodeFid(sceStrtab + static_cast(sym.st_name)); - symbol.libraryIndex = -1; - symbol.moduleIndex = -1; - } - } - - result->symbols.push_back(symbol); - } - } - - if (pltRelocations != nullptr && pltRelocationCount > 0) { - result->pltRelocations.reserve(pltRelocationCount); - for (auto rel : std::span(pltRelocations, pltRelocationCount)) { - result->pltRelocations.push_back(rel); - } - } - - if (nonPltRelocations != nullptr && nonPltRelocationCount > 0) { - result->nonPltRelocations.reserve(nonPltRelocationCount); - for (auto rel : std::span(nonPltRelocations, nonPltRelocationCount)) { - result->nonPltRelocations.push_back(rel); - } - } - } - - for (auto phdr : phdrs) { - if (phdr.p_type == kElfProgramTypeLoad || - phdr.p_type == kElfProgramTypeSceRelRo) { - auto segmentSize = utils::alignUp(phdr.p_memsz, phdr.p_align); - ::mprotect(imageBase + phdr.p_vaddr, segmentSize, PROT_WRITE); - std::memcpy(imageBase + phdr.p_vaddr, image.data() + phdr.p_offset, - phdr.p_filesz); - std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz, 0, - phdr.p_memsz - phdr.p_filesz); - - if (phdr.p_type == kElfProgramTypeSceRelRo) { - phdr.p_flags |= vm::kMapProtCpuWrite; // TODO: reprotect on relocations - } - - vm::protect(imageBase + phdr.p_vaddr, segmentSize, phdr.p_flags); - - if (phdr.p_type == kElfProgramTypeLoad) { - if (result->segmentCount >= std::size(result->segments)) { - std::abort(); - } - - auto &segment = result->segments[result->segmentCount++]; - segment.addr = imageBase + phdr.p_vaddr; - segment.size = phdr.p_memsz; - segment.prot = phdr.p_flags; - } - } - } - - result->base = imageBase; - result->size = imageSize; - // std::printf("Needed modules: ["); - // for (bool isFirst = true; auto &module : result->neededModules) { - // if (isFirst) { - // isFirst = false; - // } else { - // std::printf(", "); - // } - - // std::printf("'%s'", module.name.c_str()); - // } - // std::printf("]\n"); - // std::printf("Needed libraries: ["); - // for (bool isFirst = true; auto &library : result->neededLibraries) { - // if (isFirst) { - // isFirst = false; - // } else { - // std::printf(", "); - // } - - // std::printf("'%s'", library.name.c_str()); - // } - // std::printf("]\n"); - - result->proc = process; - - std::printf("Loaded module '%s' (%lx) from object '%s', address: %p - %p\n", - result->moduleName, (unsigned long)result->attributes, - result->soName, result->base, - (char *)result->base + result->size); - - for (auto mod : result->neededModules) { - std::printf(" needed module '%s' (%lx)\n", mod.name.c_str(), - (unsigned long)mod.attr); - } - - for (auto lib : result->neededLibraries) { - std::printf(" needed library '%s' (%lx), kind %s\n", lib.name.c_str(), - (unsigned long)lib.attr, lib.isExport ? "export" : "import"); - } - - if (tlsPhdrIndex >= 0 /* result->tlsSize != 0 */) { - result->tlsIndex = process->nextTlsSlot++; - } - - return result; + orbis::Process* process) +{ + Ref result{orbis::knew()}; + + Elf64_Ehdr header; + std::memcpy(&header, image.data(), sizeof(Elf64_Ehdr)); + result->type = header.e_type; + + Elf64_Phdr phdrsStorage[16]; + if (header.e_phnum > std::size(phdrsStorage)) + { + std::abort(); + } + + std::memcpy(phdrsStorage, image.data() + header.e_phoff, + header.e_phnum * sizeof(Elf64_Phdr)); + auto phdrs = std::span(phdrsStorage, header.e_phnum); + + std::uint64_t imageSize = 0; + std::uint64_t baseAddress = ~static_cast(0); + int dynamicPhdrIndex = -1; + int interpPhdrIndex = -1; + int notePhdrIndex = -1; + int shlibPhdrIndex = -1; + int phdrPhdrIndex = -1; + int tlsPhdrIndex = -1; + int sceDynlibDataPhdrIndex = -1; + int sceProcParamIndex = -1; + int sceModuleParamIndex = -1; + int sceRelRoPhdrIndex = -1; + int gnuEhFramePhdrIndex = -1; + int gnuRelRoPhdrIndex = -1; + int sceCommentPhdrIndex = -1; + int sceVersionPhdrIndex = -1; + + for (auto& phdr : phdrs) + { + std::size_t index = &phdr - phdrs.data(); + + switch (phdr.p_type) + { + case kElfProgramTypeNull: + break; + case kElfProgramTypeLoad: + baseAddress = + std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align)); + imageSize = std::max( + imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align)); + break; + case kElfProgramTypeDynamic: + dynamicPhdrIndex = index; + break; + case kElfProgramTypeInterp: + interpPhdrIndex = index; + break; + case kElfProgramTypeNote: + notePhdrIndex = index; + break; + case kElfProgramTypeShlib: + shlibPhdrIndex = index; + break; + case kElfProgramTypePhdr: + phdrPhdrIndex = index; + break; + case kElfProgramTypeTls: + tlsPhdrIndex = index; + break; + case kElfProgramTypeSceDynlibData: + sceDynlibDataPhdrIndex = index; + break; + case kElfProgramTypeSceProcParam: + sceProcParamIndex = index; + break; + case kElfProgramTypeSceModuleParam: + sceModuleParamIndex = index; + break; + case kElfProgramTypeSceRelRo: + sceRelRoPhdrIndex = index; + baseAddress = + std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align)); + imageSize = std::max( + imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align)); + break; + case kElfProgramTypeGnuEhFrame: + gnuEhFramePhdrIndex = index; + break; + case kElfProgramTypeGnuRelRo: + gnuRelRoPhdrIndex = index; + break; + case kElfProgramTypeSceComment: + sceCommentPhdrIndex = index; + break; + case kElfProgramTypeSceVersion: + sceVersionPhdrIndex = index; + break; + } + } + + auto imageBase = reinterpret_cast( + rx::vm::map(reinterpret_cast(baseAddress), + utils::alignUp(imageSize, rx::vm::kPageSize), 0, + rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous)); + + if (imageBase == MAP_FAILED) + { + std::abort(); + } + + result->entryPoint = + header.e_entry ? reinterpret_cast(imageBase + header.e_entry) : 0; + + if (sceProcParamIndex >= 0) + { + result->processParam = + phdrs[sceProcParamIndex].p_vaddr ? reinterpret_cast(imageBase + + phdrs[sceProcParamIndex].p_vaddr) : + nullptr; + result->processParamSize = phdrs[sceProcParamIndex].p_memsz; + } + + if (sceModuleParamIndex >= 0) + { + result->moduleParam = + phdrs[sceModuleParamIndex].p_vaddr ? reinterpret_cast(imageBase + + phdrs[sceModuleParamIndex].p_vaddr) : + nullptr; + result->moduleParamSize = phdrs[sceModuleParamIndex].p_memsz; + + // std::printf("sce_module_param: "); + // for (auto elem : image.subspan(phdrs[sceModuleParamIndex].p_offset, + // phdrs[sceModuleParamIndex].p_filesz)) { + // std::printf(" %02x", (unsigned)elem); + // } + // std::printf("\n"); + } + + if (tlsPhdrIndex >= 0) + { + result->tlsAlign = phdrs[tlsPhdrIndex].p_align; + result->tlsSize = phdrs[tlsPhdrIndex].p_memsz; + result->tlsInitSize = phdrs[tlsPhdrIndex].p_filesz; + result->tlsInit = phdrs[tlsPhdrIndex].p_vaddr ? imageBase + phdrs[tlsPhdrIndex].p_vaddr : nullptr; + } + + if (gnuEhFramePhdrIndex >= 0 && phdrs[gnuEhFramePhdrIndex].p_vaddr > 0) + { + result->ehFrameHdr = imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr; + result->ehFrameHdrSize = phdrs[gnuEhFramePhdrIndex].p_memsz; + + struct GnuExceptionInfo + { + uint8_t version; + uint8_t encoding; + uint8_t fdeCount; + uint8_t encodingTable; + std::byte first; + }; + + auto* exinfo = reinterpret_cast( + image.data() + phdrs[gnuEhFramePhdrIndex].p_offset); + + if (exinfo->version != 1) + { + std::abort(); + } + + if (exinfo->fdeCount != 0x03) + { + std::abort(); + } + + if (exinfo->encodingTable != 0x3b) + { + std::abort(); + } + + std::byte* dataBuffer = nullptr; + + if (exinfo->encoding == 0x03) + { + auto offset = *reinterpret_cast(&exinfo->first); + dataBuffer = imageBase + offset; + } + else if (exinfo->encoding == 0x1B) + { + auto offset = *reinterpret_cast(&exinfo->first); + dataBuffer = &exinfo->first + sizeof(std::int32_t) + offset; + } + else + { + std::abort(); + } + + auto* dataBufferIt = dataBuffer; + while (true) + { + auto size = *reinterpret_cast(dataBufferIt); + dataBufferIt += sizeof(std::uint32_t); + + if (size == 0) + { + break; + } + + if (size == -1) + { + size = *reinterpret_cast(dataBufferIt) + + sizeof(std::uint64_t); + } + + dataBufferIt += size; + } + + result->ehFrame = + imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr + + (dataBuffer - image.data() - phdrs[gnuEhFramePhdrIndex].p_offset); + result->ehFrameSize = dataBufferIt - dataBuffer; + } + + if (dynamicPhdrIndex >= 0 && phdrs[dynamicPhdrIndex].p_filesz > 0) + { + auto& dynPhdr = phdrs[dynamicPhdrIndex]; + std::vector dyns(dynPhdr.p_filesz / sizeof(Elf64_Dyn)); + std::memcpy(dyns.data(), image.data() + dynPhdr.p_offset, + dyns.size() * sizeof(Elf64_Dyn)); + + int sceStrtabIndex = -1; + int sceSymtabIndex = -1; + std::size_t sceSymtabSize = 0; + for (auto& dyn : dyns) + { + if (dyn.d_tag == kElfDynamicTypeSceStrTab) + { + sceStrtabIndex = &dyn - dyns.data(); + } + else if (dyn.d_tag == kElfDynamicTypeSceSymTab) + { + sceSymtabIndex = &dyn - dyns.data(); + } + else if (dyn.d_tag == kElfDynamicTypeSceSymTabSize) + { + sceSymtabSize = dyn.d_un.d_val; + } + } + + auto sceStrtab = sceStrtabIndex >= 0 && sceDynlibDataPhdrIndex >= 0 ? reinterpret_cast( + image.data() + dyns[sceStrtabIndex].d_un.d_val + + phdrs[sceDynlibDataPhdrIndex].p_offset) : + nullptr; + + auto sceDynlibData = + sceDynlibDataPhdrIndex >= 0 ? image.data() + phdrs[sceDynlibDataPhdrIndex].p_offset : nullptr; + + auto sceSymtabData = + sceSymtabIndex >= 0 && sceDynlibData != nullptr ? reinterpret_cast( + sceDynlibData + dyns[sceSymtabIndex].d_un.d_val) : + nullptr; + + std::unordered_map idToModuleIndex; + std::unordered_map idToLibraryIndex; + + orbis::Relocation* pltRelocations = nullptr; + std::size_t pltRelocationCount = 0; + orbis::Relocation* nonPltRelocations = nullptr; + std::size_t nonPltRelocationCount = 0; + + auto patchSoName = [](std::string_view name) { + if (name.ends_with(".prx")) + { + name.remove_suffix(4); + } + if (name.ends_with("-PRX")) + { + name.remove_suffix(4); // TODO: implement lib scan + } + if (name.ends_with("-module")) + { + name.remove_suffix(7); // TODO: implement lib scan + } + if (name.ends_with("_padebug")) + { + name.remove_suffix(8); + } + if (name.ends_with("_sys")) + { + name.remove_suffix(4); + } + + return name; + }; + + for (auto dyn : dyns) + { + // std::printf("%s: %lx", toString((OrbisElfDynamicType)dyn.d_tag), + // dyn.d_un.d_val); + + // if (dyn.d_tag == kElfDynamicTypeSceNeededModule || + // dyn.d_tag == kElfDynamicTypeNeeded || + // dyn.d_tag == kElfDynamicTypeSceOriginalFilename || + // dyn.d_tag == kElfDynamicTypeSceImportLib || + // dyn.d_tag == kElfDynamicTypeSceExportLib || + // dyn.d_tag == kElfDynamicTypeSceModuleInfo) { + // std::printf(" ('%s')", + // sceStrtab + // ? sceStrtab + + // static_cast(dyn.d_un.d_val) : ""); + // } + + // std::printf("\n"); + + if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) + { + std::strncpy(result->moduleName, + sceStrtab + static_cast(dyn.d_un.d_val), + sizeof(result->moduleName)); + } + else if (dyn.d_tag == kElfDynamicTypeSceModuleAttr) + { + result->attributes = dyn.d_un.d_val; + } + + if (dyn.d_tag == kElfDynamicTypeSoName) + { + auto name = + patchSoName(sceStrtab + static_cast(dyn.d_un.d_val)); + std::memcpy(result->soName, name.data(), name.size()); + std::memcpy(result->soName + name.size(), ".prx", sizeof(".prx")); + } + + // if (dyn.d_tag == kElfDynamicTypeNeeded) { + // auto name = std::string_view( + // sceStrtab + static_cast(dyn.d_un.d_val)); + // if (name == "STREQUAL") { + // // HACK for broken FWs + // result->needed.push_back("libSceDolbyVision.prx"); + // } else { + // name = patchSoName(name); + // if (name != "libSceFreeTypeOptBm") { // TODO + // result->needed.emplace_back(name); + // result->needed.back() += ".prx"; + // } + // } + // } + + if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) + { + idToModuleIndex[dyn.d_un.d_val >> 48] = -1; + } + + if (dyn.d_tag == kElfDynamicTypeSceNeededModule) + { + auto [it, inserted] = idToModuleIndex.try_emplace( + dyn.d_un.d_val >> 48, result->neededModules.size()); + + if (inserted) + { + result->neededModules.emplace_back(); + } + + auto& mod = result->neededModules[it->second]; + mod.name = sceStrtab + static_cast(dyn.d_un.d_val); + mod.attr = static_cast(dyn.d_un.d_val >> 32); + mod.isExport = false; + } + else if (dyn.d_tag == kElfDynamicTypeSceImportLib || + dyn.d_tag == kElfDynamicTypeSceExportLib) + { + auto [it, inserted] = idToLibraryIndex.try_emplace( + dyn.d_un.d_val >> 48, result->neededLibraries.size()); + + if (inserted) + { + result->neededLibraries.emplace_back(); + } + + auto& lib = result->neededLibraries[it->second]; + + lib.name = sceStrtab + static_cast(dyn.d_un.d_val); + lib.isExport = dyn.d_tag == kElfDynamicTypeSceExportLib; + } + else if (dyn.d_tag == kElfDynamicTypeSceExportLibAttr || + dyn.d_tag == kElfDynamicTypeSceImportLibAttr) + { + auto [it, inserted] = idToLibraryIndex.try_emplace( + dyn.d_un.d_val >> 48, result->neededLibraries.size()); + + if (inserted) + { + result->neededLibraries.emplace_back(); + } + + auto& lib = result->neededLibraries[it->second]; + + lib.attr = dyn.d_un.d_val & ((static_cast(1) << 48) - 1); + } + + switch (dyn.d_tag) + { + case kElfDynamicTypeScePltGot: + result->pltGot = + dyn.d_un.d_ptr ? reinterpret_cast(imageBase + dyn.d_un.d_ptr) : nullptr; + break; + + case kElfDynamicTypeSceJmpRel: + if (sceDynlibData != nullptr) + { + pltRelocations = reinterpret_cast( + sceDynlibData + dyn.d_un.d_ptr); + } + break; + case kElfDynamicTypeScePltRel: + break; + case kElfDynamicTypeScePltRelSize: + pltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); + break; + case kElfDynamicTypeSceRela: + if (sceDynlibData != nullptr) + { + nonPltRelocations = reinterpret_cast( + sceDynlibData + dyn.d_un.d_ptr); + } + break; + case kElfDynamicTypeSceRelaSize: + nonPltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); + break; + case kElfDynamicTypeSceRelaEnt: + break; + + case kElfDynamicTypeInit: + result->initProc = imageBase + dyn.d_un.d_ptr; + break; + case kElfDynamicTypeFini: + result->finiProc = imageBase + dyn.d_un.d_ptr; + break; + } + } + + if (sceSymtabData != nullptr && sceSymtabSize / sizeof(Elf64_Sym) > 0) + { + auto sceSymtab = + std::span(sceSymtabData, sceSymtabSize / sizeof(Elf64_Sym)); + + result->symbols.reserve(sceSymtab.size()); + + for (auto& sym : sceSymtab) + { + auto visibility = ELF64_ST_VISIBILITY(sym.st_other); + auto type = ELF64_ST_TYPE(sym.st_info); + auto bind = ELF64_ST_BIND(sym.st_info); + orbis::Symbol symbol{ + .address = sym.st_value, + .size = sym.st_size, + .visibility = static_cast(visibility), + .bind = static_cast(bind), + .type = static_cast(type), + }; + + if (sceStrtab != nullptr && sym.st_name != 0) + { + auto fullName = std::string_view(sceStrtab + sym.st_name); + if (auto hashPos = fullName.find('#'); + hashPos != std::string_view::npos) + { + std::string_view module; + std::string_view library; + std::string_view name; + + name = fullName.substr(0, hashPos); + auto moduleLibary = fullName.substr(hashPos + 1); + + hashPos = moduleLibary.find('#'); + + if (hashPos == std::string_view::npos) + { + std::abort(); + } + + library = moduleLibary.substr(0, hashPos); + module = moduleLibary.substr(hashPos + 1); + + auto libaryNid = *decodeNid(library); + auto moduleNid = *decodeNid(module); + + symbol.libraryIndex = idToLibraryIndex.at(libaryNid); + symbol.moduleIndex = idToModuleIndex.at(moduleNid); + symbol.id = *decodeNid(name); + } + else if (auto nid = decodeNid(fullName)) + { + symbol.id = *nid; + symbol.libraryIndex = -1; + symbol.moduleIndex = -1; + } + else + { + symbol.id = + encodeFid(sceStrtab + static_cast(sym.st_name)); + symbol.libraryIndex = -1; + symbol.moduleIndex = -1; + } + } + + result->symbols.push_back(symbol); + } + } + + if (pltRelocations != nullptr && pltRelocationCount > 0) + { + result->pltRelocations.reserve(pltRelocationCount); + for (auto rel : std::span(pltRelocations, pltRelocationCount)) + { + result->pltRelocations.push_back(rel); + } + } + + if (nonPltRelocations != nullptr && nonPltRelocationCount > 0) + { + result->nonPltRelocations.reserve(nonPltRelocationCount); + for (auto rel : std::span(nonPltRelocations, nonPltRelocationCount)) + { + result->nonPltRelocations.push_back(rel); + } + } + } + + for (auto phdr : phdrs) + { + if (phdr.p_type == kElfProgramTypeLoad || + phdr.p_type == kElfProgramTypeSceRelRo) + { + auto segmentSize = utils::alignUp(phdr.p_memsz, phdr.p_align); + ::mprotect(imageBase + phdr.p_vaddr, segmentSize, PROT_WRITE); + std::memcpy(imageBase + phdr.p_vaddr, image.data() + phdr.p_offset, + phdr.p_filesz); + std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz, 0, + phdr.p_memsz - phdr.p_filesz); + + if (phdr.p_type == kElfProgramTypeSceRelRo) + { + phdr.p_flags |= vm::kMapProtCpuWrite; // TODO: reprotect on relocations + } + + vm::protect(imageBase + phdr.p_vaddr, segmentSize, phdr.p_flags); + + if (phdr.p_type == kElfProgramTypeLoad) + { + if (result->segmentCount >= std::size(result->segments)) + { + std::abort(); + } + + auto& segment = result->segments[result->segmentCount++]; + segment.addr = imageBase + phdr.p_vaddr; + segment.size = phdr.p_memsz; + segment.prot = phdr.p_flags; + } + } + } + + result->base = imageBase; + result->size = imageSize; + // std::printf("Needed modules: ["); + // for (bool isFirst = true; auto &module : result->neededModules) { + // if (isFirst) { + // isFirst = false; + // } else { + // std::printf(", "); + // } + + // std::printf("'%s'", module.name.c_str()); + // } + // std::printf("]\n"); + // std::printf("Needed libraries: ["); + // for (bool isFirst = true; auto &library : result->neededLibraries) { + // if (isFirst) { + // isFirst = false; + // } else { + // std::printf(", "); + // } + + // std::printf("'%s'", library.name.c_str()); + // } + // std::printf("]\n"); + + result->proc = process; + + std::printf("Loaded module '%s' (%lx) from object '%s', address: %p - %p\n", + result->moduleName, (unsigned long)result->attributes, + result->soName, result->base, + (char*)result->base + result->size); + + for (auto mod : result->neededModules) + { + std::printf(" needed module '%s' (%lx)\n", mod.name.c_str(), + (unsigned long)mod.attr); + } + + for (auto lib : result->neededLibraries) + { + std::printf(" needed library '%s' (%lx), kind %s\n", lib.name.c_str(), + (unsigned long)lib.attr, lib.isExport ? "export" : "import"); + } + + if (tlsPhdrIndex >= 0 /* result->tlsSize != 0 */) + { + result->tlsIndex = process->nextTlsSlot++; + } + + return result; } Ref rx::linker::loadModuleFile(std::string_view path, - orbis::Thread *thread) { - if (!path.contains('/')) { - return loadModuleByName(path, thread); - } - - orbis::Ref instance; - if (vfs::open(path, kOpenFlagReadOnly, 0, &instance, thread).isError()) { - return {}; - } - - orbis::Stat fileStat; - if (instance->ops->stat(instance.get(), &fileStat, nullptr) != - orbis::ErrorCode{}) { - return {}; - } - - auto len = fileStat.size; - - std::vector image(len); - auto ptr = image.data(); - orbis::IoVec ioVec{ - .base = ptr, - .len = static_cast(len), - }; - orbis::Uio io{ - .offset = 0, - .iov = &ioVec, - .iovcnt = 1, - .resid = 0, - .segflg = orbis::UioSeg::SysSpace, - .rw = orbis::UioRw::Read, - .td = thread, - }; - - while (io.offset < image.size()) { - ioVec = { - .base = ptr + io.offset, - .len = image.size() - io.offset, - }; - auto result = instance->ops->read(instance.get(), &io, thread); - if (result != orbis::ErrorCode{}) { - std::fprintf(stderr, "Module file reading error\n"); - std::abort(); - } - } - - if (image[0] != std::byte{'\x7f'} || image[1] != std::byte{'E'} || - image[2] != std::byte{'L'} || image[3] != std::byte{'F'}) { - image = unself(image.data(), image.size()); - - std::ofstream("a.out", std::ios::binary).write((const char *)image.data(), image.size()); - } - - return loadModule(image, thread->tproc); + orbis::Thread* thread) +{ + if (!path.contains('/')) + { + return loadModuleByName(path, thread); + } + + orbis::Ref instance; + if (vfs::open(path, kOpenFlagReadOnly, 0, &instance, thread).isError()) + { + return {}; + } + + orbis::Stat fileStat; + if (instance->ops->stat(instance.get(), &fileStat, nullptr) != + orbis::ErrorCode{}) + { + return {}; + } + + auto len = fileStat.size; + + std::vector image(len); + auto ptr = image.data(); + orbis::IoVec ioVec{ + .base = ptr, + .len = static_cast(len), + }; + orbis::Uio io{ + .offset = 0, + .iov = &ioVec, + .iovcnt = 1, + .resid = 0, + .segflg = orbis::UioSeg::SysSpace, + .rw = orbis::UioRw::Read, + .td = thread, + }; + + while (io.offset < image.size()) + { + ioVec = { + .base = ptr + io.offset, + .len = image.size() - io.offset, + }; + auto result = instance->ops->read(instance.get(), &io, thread); + if (result != orbis::ErrorCode{}) + { + std::fprintf(stderr, "Module file reading error\n"); + std::abort(); + } + } + + if (image[0] != std::byte{'\x7f'} || image[1] != std::byte{'E'} || + image[2] != std::byte{'L'} || image[3] != std::byte{'F'}) + { + image = unself(image.data(), image.size()); + + std::ofstream("a.out", std::ios::binary).write((const char*)image.data(), image.size()); + } + + return loadModule(image, thread->tproc); } -static Ref createSceFreeTypeFull(orbis::Thread *thread) { - auto result = orbis::knew(); +static Ref createSceFreeTypeFull(orbis::Thread* thread) +{ + auto result = orbis::knew(); - std::strncpy(result->soName, "libSceFreeTypeFull.prx", - sizeof(result->soName) - 1); - std::strncpy(result->moduleName, "libSceFreeType", - sizeof(result->moduleName) - 1); + std::strncpy(result->soName, "libSceFreeTypeFull.prx", + sizeof(result->soName) - 1); + std::strncpy(result->moduleName, "libSceFreeType", + sizeof(result->moduleName) - 1); - result->neededLibraries.push_back( - {.name = "libSceFreeType", .isExport = true}); + result->neededLibraries.push_back( + {.name = "libSceFreeType", .isExport = true}); - for (auto dep : - {"libSceFreeTypeSubFunc", "libSceFreeTypeOl", "libSceFreeTypeOt", - "libSceFreeTypeOptOl", "libSceFreeTypeHinter"}) { - result->needed.push_back(dep); - result->needed.back() += ".prx"; - } + for (auto dep : + {"libSceFreeTypeSubFunc", "libSceFreeTypeOl", "libSceFreeTypeOt", + "libSceFreeTypeOptOl", "libSceFreeTypeHinter"}) + { + result->needed.push_back(dep); + result->needed.back() += ".prx"; + } - for (auto needed : result->needed) { - auto neededMod = rx::linker::loadModuleByName(needed, thread); + for (auto needed : result->needed) + { + auto neededMod = rx::linker::loadModuleByName(needed, thread); - if (neededMod == nullptr) { - std::fprintf(stderr, "Failed to load needed '%s' for FreeType\n", - needed.c_str()); - std::abort(); - } + if (neededMod == nullptr) + { + std::fprintf(stderr, "Failed to load needed '%s' for FreeType\n", + needed.c_str()); + std::abort(); + } - result->namespaceModules.push_back(neededMod); - } + result->namespaceModules.push_back(neededMod); + } - // TODO: load native library with module_start and module_stop - result->initProc = reinterpret_cast(+[] {}); - result->finiProc = reinterpret_cast(+[] {}); + // TODO: load native library with module_start and module_stop + result->initProc = reinterpret_cast(+[] {}); + result->finiProc = reinterpret_cast(+[] {}); - result->proc = thread->tproc; + result->proc = thread->tproc; - return result; + return result; } Ref rx::linker::loadModuleByName(std::string_view name, - orbis::Thread *thread) { - if (name.ends_with(".prx")) { - name.remove_suffix(4); - } - - if (auto it = g_moduleOverrideTable.find(name); - it != g_moduleOverrideTable.end()) { - return loadModuleFile(it->second.c_str(), thread); - } - - if (name == "libSceAbstractTwitch") { - return nullptr; - } - - if (name == "libSceFreeTypeFull") { - return createSceFreeTypeFull(thread); - } - - { - std::string filePath = "/app0/sce_module/"; - filePath += name; - filePath += ".elf"; - if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) { - return result; - } - filePath.resize(filePath.size() - 4); - filePath += ".sprx"; - if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) { - return result; - } - filePath.resize(filePath.size() - 5); - filePath += ".prx"; - if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) { - return result; - } - } - - for (auto path : {"/system/common/lib/", "/system/priv/lib/"}) { - auto filePath = std::string(path); - filePath += name; - filePath += ".sprx"; - - if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) { - return result; - } - } - - return {}; + orbis::Thread* thread) +{ + if (name.ends_with(".prx")) + { + name.remove_suffix(4); + } + + if (auto it = g_moduleOverrideTable.find(name); + it != g_moduleOverrideTable.end()) + { + return loadModuleFile(it->second.c_str(), thread); + } + + if (name == "libSceAbstractTwitch") + { + return nullptr; + } + + if (name == "libSceFreeTypeFull") + { + return createSceFreeTypeFull(thread); + } + + { + std::string filePath = "/app0/sce_module/"; + filePath += name; + filePath += ".elf"; + if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) + { + return result; + } + filePath.resize(filePath.size() - 4); + filePath += ".sprx"; + if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) + { + return result; + } + filePath.resize(filePath.size() - 5); + filePath += ".prx"; + if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) + { + return result; + } + } + + for (auto path : {"/system/common/lib/", "/system/priv/lib/"}) + { + auto filePath = std::string(path); + filePath += name; + filePath += ".sprx"; + + if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) + { + return result; + } + } + + return {}; } diff --git a/rpcsx-os/linker.hpp b/rpcsx-os/linker.hpp index 9a0f798a..3ed6b1b4 100644 --- a/rpcsx-os/linker.hpp +++ b/rpcsx-os/linker.hpp @@ -7,78 +7,88 @@ #include #include -namespace rx::linker { -inline constexpr char nidLookup[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; - -constexpr std::optional decodeNid(std::string_view nid) { - std::uint64_t result = 0; - - if (nid.size() > 11) { - return {}; - } - - for (std::size_t i = 0; i < nid.size(); ++i) { - auto it = std::strchr(nidLookup, nid[i]); - - if (it == nullptr) { - return {}; - } - - auto value = static_cast(it - nidLookup); - - if (i == 10) { - result <<= 4; - result |= (value >> 2); - break; - } - - result <<= 6; - result |= value; - } - - return result; -} - -struct nid { - char string[12]; -}; - -constexpr nid encodeNid(std::uint64_t hash) { - return {{nidLookup[(hash >> 58) & 0x3f], nidLookup[(hash >> 52) & 0x3f], - nidLookup[(hash >> 46) & 0x3f], nidLookup[(hash >> 40) & 0x3f], - nidLookup[(hash >> 34) & 0x3f], nidLookup[(hash >> 28) & 0x3f], - nidLookup[(hash >> 22) & 0x3f], nidLookup[(hash >> 16) & 0x3f], - nidLookup[(hash >> 10) & 0x3f], nidLookup[(hash >> 4) & 0x3f], - nidLookup[(hash & 0xf) * 4], 0}}; -} - -std::uint64_t encodeFid(std::string_view fid); - -struct Symbol { - orbis::Module *module; - std::uint64_t address; - std::uint64_t bindMode; -}; - -enum OrbisElfType_t { - kElfTypeNone = 0, - kElfTypeRel = 1, - kElfTypeExec = 2, - kElfTypeDyn = 3, - kElfTypeCore = 4, - kElfTypeNum = 5, - kElfTypeSceExec = 0xfe00, - kElfTypeSceDynExec = 0xfe10, - kElfTypeSceDynamic = 0xfe18 -}; - -void override(std::string originalModuleName, - std::filesystem::path replacedModulePath); -orbis::Ref loadModule(std::span image, - orbis::Process *process); -orbis::Ref loadModuleFile(std::string_view path, - orbis::Thread *thread); -orbis::Ref loadModuleByName(std::string_view name, - orbis::Thread *thread); +namespace rx::linker +{ + inline constexpr char nidLookup[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; + + constexpr std::optional decodeNid(std::string_view nid) + { + std::uint64_t result = 0; + + if (nid.size() > 11) + { + return {}; + } + + for (std::size_t i = 0; i < nid.size(); ++i) + { + auto it = std::strchr(nidLookup, nid[i]); + + if (it == nullptr) + { + return {}; + } + + auto value = static_cast(it - nidLookup); + + if (i == 10) + { + result <<= 4; + result |= (value >> 2); + break; + } + + result <<= 6; + result |= value; + } + + return result; + } + + struct nid + { + char string[12]; + }; + + constexpr nid encodeNid(std::uint64_t hash) + { + return {{nidLookup[(hash >> 58) & 0x3f], nidLookup[(hash >> 52) & 0x3f], + nidLookup[(hash >> 46) & 0x3f], nidLookup[(hash >> 40) & 0x3f], + nidLookup[(hash >> 34) & 0x3f], nidLookup[(hash >> 28) & 0x3f], + nidLookup[(hash >> 22) & 0x3f], nidLookup[(hash >> 16) & 0x3f], + nidLookup[(hash >> 10) & 0x3f], nidLookup[(hash >> 4) & 0x3f], + nidLookup[(hash & 0xf) * 4], 0}}; + } + + std::uint64_t encodeFid(std::string_view fid); + + struct Symbol + { + orbis::Module* module; + std::uint64_t address; + std::uint64_t bindMode; + }; + + enum OrbisElfType_t + { + kElfTypeNone = 0, + kElfTypeRel = 1, + kElfTypeExec = 2, + kElfTypeDyn = 3, + kElfTypeCore = 4, + kElfTypeNum = 5, + kElfTypeSceExec = 0xfe00, + kElfTypeSceDynExec = 0xfe10, + kElfTypeSceDynamic = 0xfe18 + }; + + void override(std::string originalModuleName, + std::filesystem::path replacedModulePath); + orbis::Ref loadModule(std::span image, + orbis::Process* process); + orbis::Ref loadModuleFile(std::string_view path, + orbis::Thread* thread); + orbis::Ref loadModuleByName(std::string_view name, + orbis::Thread* thread); } // namespace rx::linker diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index 1d5b4054..a0347eaf 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -34,690 +34,796 @@ static int g_gpuPid; __attribute__((no_stack_protector)) static void -handle_signal(int sig, siginfo_t *info, void *ucontext) { - if (auto hostFs = _readgsbase_u64()) { - _writefsbase_u64(hostFs); - } - - auto signalAddress = reinterpret_cast(info->si_addr); - - if (rx::thread::g_current != nullptr && sig == SIGSEGV && - signalAddress >= 0x40000 && signalAddress < 0x100'0000'0000) { - auto ctx = reinterpret_cast(ucontext); - bool isWrite = (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) != 0; - auto origVmProt = rx::vm::getPageProtection(signalAddress); - int prot = 0; - auto page = signalAddress / amdgpu::bridge::kHostPageSize; - - if (origVmProt & rx::vm::kMapProtCpuRead) { - prot |= PROT_READ; - } - if (origVmProt & rx::vm::kMapProtCpuWrite) { - prot |= PROT_WRITE; - } - if (origVmProt & rx::vm::kMapProtCpuExec) { - prot |= PROT_EXEC; - } - - if (prot & (isWrite ? PROT_WRITE : PROT_READ)) { - auto bridge = rx::bridge.header; - - while (true) { - auto flags = bridge->cachePages[page].load(std::memory_order::relaxed); - - if ((flags & amdgpu::bridge::kPageReadWriteLock) != 0) { - if ((flags & amdgpu::bridge::kPageLazyLock) != 0) { - if (std::uint32_t gpuCommand = 0; - !bridge->gpuCacheCommand.compare_exchange_weak(gpuCommand, - page)) { - continue; - } - - while (!bridge->cachePages[page].compare_exchange_weak( - flags, flags & ~amdgpu::bridge::kPageLazyLock, - std::memory_order::relaxed)) { - } - } - continue; - } - - if ((flags & amdgpu::bridge::kPageWriteWatch) == 0) { - break; - } - - if (!isWrite) { - prot &= ~PROT_WRITE; - break; - } - - if (bridge->cachePages[page].compare_exchange_weak( - flags, amdgpu::bridge::kPageInvalidated, - std::memory_order::relaxed)) { - break; - } - } - - if (::mprotect((void *)(page * amdgpu::bridge::kHostPageSize), - amdgpu::bridge::kHostPageSize, prot)) { - std::perror("cache reprotection error"); - std::abort(); - } - - _writefsbase_u64(rx::thread::g_current->fsBase); - return; - } - - std::fprintf(stderr, "SIGSEGV, address %lx, access %s, prot %s\n", - signalAddress, isWrite ? "write" : "read", - rx::vm::mapProtToString(origVmProt).c_str()); - } - - if (g_gpuPid > 0) { - // stop gpu thread - ::kill(g_gpuPid, SIGINT); - } - - if (sig != SIGINT) { - char buf[128] = ""; - int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n", - rx::thread::g_current ? "guest" : "host", - rx::thread::g_current ? rx::thread::g_current->tid - : ::gettid(), - info->si_addr); - write(2, buf, len); - - if (std::size_t printed = - rx::printAddressLocation(buf, sizeof(buf), rx::thread::g_current, - (std::uint64_t)info->si_addr)) { - printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n"); - write(2, buf, printed); - } - - if (rx::thread::g_current) { - rx::printStackTrace(reinterpret_cast(ucontext), - rx::thread::g_current, 2); - } else { - rx::printStackTrace(reinterpret_cast(ucontext), 2); - } - } - - struct sigaction act {}; - sigset_t mask; - sigemptyset(&mask); - - act.sa_handler = SIG_DFL; - act.sa_flags = SA_SIGINFO | SA_ONSTACK; - act.sa_mask = mask; - - if (sigaction(sig, &act, NULL)) { - perror("Error sigaction:"); - std::exit(-1); - } - - if (sig == SIGINT) { - std::raise(SIGINT); - } +handle_signal(int sig, siginfo_t* info, void* ucontext) +{ + if (auto hostFs = _readgsbase_u64()) + { + _writefsbase_u64(hostFs); + } + + auto signalAddress = reinterpret_cast(info->si_addr); + + if (rx::thread::g_current != nullptr && sig == SIGSEGV && + signalAddress >= 0x40000 && signalAddress < 0x100'0000'0000) + { + auto ctx = reinterpret_cast(ucontext); + bool isWrite = (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) != 0; + auto origVmProt = rx::vm::getPageProtection(signalAddress); + int prot = 0; + auto page = signalAddress / amdgpu::bridge::kHostPageSize; + + if (origVmProt & rx::vm::kMapProtCpuRead) + { + prot |= PROT_READ; + } + if (origVmProt & rx::vm::kMapProtCpuWrite) + { + prot |= PROT_WRITE; + } + if (origVmProt & rx::vm::kMapProtCpuExec) + { + prot |= PROT_EXEC; + } + + if (prot & (isWrite ? PROT_WRITE : PROT_READ)) + { + auto bridge = rx::bridge.header; + + while (true) + { + auto flags = bridge->cachePages[page].load(std::memory_order::relaxed); + + if ((flags & amdgpu::bridge::kPageReadWriteLock) != 0) + { + if ((flags & amdgpu::bridge::kPageLazyLock) != 0) + { + if (std::uint32_t gpuCommand = 0; + !bridge->gpuCacheCommand.compare_exchange_weak(gpuCommand, + page)) + { + continue; + } + + while (!bridge->cachePages[page].compare_exchange_weak( + flags, flags & ~amdgpu::bridge::kPageLazyLock, + std::memory_order::relaxed)) + { + } + } + continue; + } + + if ((flags & amdgpu::bridge::kPageWriteWatch) == 0) + { + break; + } + + if (!isWrite) + { + prot &= ~PROT_WRITE; + break; + } + + if (bridge->cachePages[page].compare_exchange_weak( + flags, amdgpu::bridge::kPageInvalidated, + std::memory_order::relaxed)) + { + break; + } + } + + if (::mprotect((void*)(page * amdgpu::bridge::kHostPageSize), + amdgpu::bridge::kHostPageSize, prot)) + { + std::perror("cache reprotection error"); + std::abort(); + } + + _writefsbase_u64(rx::thread::g_current->fsBase); + return; + } + + std::fprintf(stderr, "SIGSEGV, address %lx, access %s, prot %s\n", + signalAddress, isWrite ? "write" : "read", + rx::vm::mapProtToString(origVmProt).c_str()); + } + + if (g_gpuPid > 0) + { + // stop gpu thread + ::kill(g_gpuPid, SIGINT); + } + + if (sig != SIGINT) + { + char buf[128] = ""; + int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n", + rx::thread::g_current ? "guest" : "host", + rx::thread::g_current ? rx::thread::g_current->tid : ::gettid(), + info->si_addr); + write(2, buf, len); + + if (std::size_t printed = + rx::printAddressLocation(buf, sizeof(buf), rx::thread::g_current, + (std::uint64_t)info->si_addr)) + { + printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n"); + write(2, buf, printed); + } + + if (rx::thread::g_current) + { + rx::printStackTrace(reinterpret_cast(ucontext), + rx::thread::g_current, 2); + } + else + { + rx::printStackTrace(reinterpret_cast(ucontext), 2); + } + } + + struct sigaction act + { + }; + sigset_t mask; + sigemptyset(&mask); + + act.sa_handler = SIG_DFL; + act.sa_flags = SA_SIGINFO | SA_ONSTACK; + act.sa_mask = mask; + + if (sigaction(sig, &act, NULL)) + { + perror("Error sigaction:"); + std::exit(-1); + } + + if (sig == SIGINT) + { + std::raise(SIGINT); + } } -static void setupSigHandlers() { - stack_t ss; - auto sigStackSize = std::max( - SIGSTKSZ, utils::alignUp(8 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); - ss.ss_sp = malloc(sigStackSize); - if (ss.ss_sp == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - - ss.ss_size = sigStackSize; - ss.ss_flags = 0; - - if (sigaltstack(&ss, NULL) == -1) { - perror("sigaltstack"); - exit(EXIT_FAILURE); - } - - struct sigaction act {}; - act.sa_sigaction = handle_signal; - act.sa_flags = SA_SIGINFO | SA_ONSTACK; - - if (sigaction(SIGSYS, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGILL, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGSEGV, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGBUS, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGABRT, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGINT, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } +static void setupSigHandlers() +{ + stack_t ss; + auto sigStackSize = std::max( + SIGSTKSZ, utils::alignUp(8 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); + ss.ss_sp = malloc(sigStackSize); + if (ss.ss_sp == NULL) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + + ss.ss_size = sigStackSize; + ss.ss_flags = 0; + + if (sigaltstack(&ss, NULL) == -1) + { + perror("sigaltstack"); + exit(EXIT_FAILURE); + } + + struct sigaction act + { + }; + act.sa_sigaction = handle_signal; + act.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction(SIGSYS, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGILL, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGSEGV, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGBUS, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGABRT, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGINT, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } } -struct StackWriter { - std::uint64_t address; - - template std::uint64_t push(T value) { - address -= sizeof(value); - address &= ~(alignof(T) - 1); - *reinterpret_cast(address) = value; - return address; - } - - void align(std::uint64_t alignment) { address &= ~(alignment - 1); } - - std::uint64_t pushString(const char *value) { - auto len = std::strlen(value); - address -= len + 1; - std::memcpy(reinterpret_cast(address), value, len + 1); - return address; - } - - std::uint64_t alloc(std::uint64_t size, std::uint64_t alignment) { - address -= size; - address &= ~(alignment - 1); - return address; - } +struct StackWriter +{ + std::uint64_t address; + + template + std::uint64_t push(T value) + { + address -= sizeof(value); + address &= ~(alignof(T) - 1); + *reinterpret_cast(address) = value; + return address; + } + + void align(std::uint64_t alignment) { address &= ~(alignment - 1); } + + std::uint64_t pushString(const char* value) + { + auto len = std::strlen(value); + address -= len + 1; + std::memcpy(reinterpret_cast(address), value, len + 1); + return address; + } + + std::uint64_t alloc(std::uint64_t size, std::uint64_t alignment) + { + address -= size; + address &= ~(alignment - 1); + return address; + } }; static bool g_traceSyscalls = false; -static const char *getSyscallName(orbis::Thread *thread, int sysno) { - auto sysvec = thread->tproc->sysent; +static const char* getSyscallName(orbis::Thread* thread, int sysno) +{ + auto sysvec = thread->tproc->sysent; - if (sysno >= sysvec->size) { - return nullptr; - } + if (sysno >= sysvec->size) + { + return nullptr; + } - return orbis::getSysentName(sysvec->table[sysno].call); + return orbis::getSysentName(sysvec->table[sysno].call); } -static void onSysEnter(orbis::Thread *thread, int id, uint64_t *args, - int argsCount) { - if (true || !g_traceSyscalls) { - return; - } - flockfile(stderr); - std::fprintf(stderr, " [%u] ", thread->tid); - - if (auto name = getSyscallName(thread, id)) { - std::fprintf(stderr, "%s(", name); - } else { - std::fprintf(stderr, "sys_%u(", id); - } - - for (int i = 0; i < argsCount; ++i) { - if (i != 0) { - std::fprintf(stderr, ", "); - } - - std::fprintf(stderr, "%#lx", args[i]); - } - - std::fprintf(stderr, ")\n"); - funlockfile(stderr); +static void onSysEnter(orbis::Thread* thread, int id, uint64_t* args, + int argsCount) +{ + if (true || !g_traceSyscalls) + { + return; + } + flockfile(stderr); + std::fprintf(stderr, " [%u] ", thread->tid); + + if (auto name = getSyscallName(thread, id)) + { + std::fprintf(stderr, "%s(", name); + } + else + { + std::fprintf(stderr, "sys_%u(", id); + } + + for (int i = 0; i < argsCount; ++i) + { + if (i != 0) + { + std::fprintf(stderr, ", "); + } + + std::fprintf(stderr, "%#lx", args[i]); + } + + std::fprintf(stderr, ")\n"); + funlockfile(stderr); } -static void onSysExit(orbis::Thread *thread, int id, uint64_t *args, - int argsCount, orbis::SysResult result) { - if (!result.isError() && !g_traceSyscalls) { - return; - } - - flockfile(stderr); - std::fprintf(stderr, "%c: [%u] ", result.isError() ? 'E' : 'S', thread->tid); - - if (auto name = getSyscallName(thread, id)) { - std::fprintf(stderr, "%s(", name); - } else { - std::fprintf(stderr, "sys_%u(", id); - } - - for (int i = 0; i < argsCount; ++i) { - if (i != 0) { - std::fprintf(stderr, ", "); - } - - std::fprintf(stderr, "%#lx", args[i]); - } - - std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(), - thread->retval[0], thread->retval[1]); - - thread->where(); - funlockfile(stderr); +static void onSysExit(orbis::Thread* thread, int id, uint64_t* args, + int argsCount, orbis::SysResult result) +{ + if (!result.isError() && !g_traceSyscalls) + { + return; + } + + flockfile(stderr); + std::fprintf(stderr, "%c: [%u] ", result.isError() ? 'E' : 'S', thread->tid); + + if (auto name = getSyscallName(thread, id)) + { + std::fprintf(stderr, "%s(", name); + } + else + { + std::fprintf(stderr, "sys_%u(", id); + } + + for (int i = 0; i < argsCount; ++i) + { + if (i != 0) + { + std::fprintf(stderr, ", "); + } + + std::fprintf(stderr, "%#lx", args[i]); + } + + std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(), + thread->retval[0], thread->retval[1]); + + thread->where(); + funlockfile(stderr); } -static int ps4Exec(orbis::Thread *mainThread, - orbis::utils::Ref executableModule, - std::span argv, std::span envp) { - const auto stackEndAddress = 0x7'ffff'c000ull; - const auto stackSize = 0x40000 * 16; - auto stackStartAddress = stackEndAddress - stackSize; - mainThread->stackStart = - rx::vm::map(reinterpret_cast(stackStartAddress), stackSize, - rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead, - rx::vm::kMapFlagAnonymous | rx::vm::kMapFlagFixed | - rx::vm::kMapFlagPrivate | rx::vm::kMapFlagStack); - - mainThread->stackEnd = - reinterpret_cast(mainThread->stackStart) + stackSize; - - auto dmem1 = createDmemCharacterDevice(1); - orbis::g_context.dmemDevice = dmem1; - - rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); - rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); - rx::vfs::addDevice("icc_configuration", createIccConfigurationCharacterDevice()); - rx::vfs::addDevice("console", createConsoleCharacterDevice()); - rx::vfs::addDevice("camera", createCameraCharacterDevice()); - rx::vfs::addDevice("dmem1", dmem1); - rx::vfs::addDevice("dmem2", createDmemCharacterDevice(2)); - rx::vfs::addDevice("stdout", createFdWrapDevice(STDOUT_FILENO)); - rx::vfs::addDevice("stderr", createFdWrapDevice(STDERR_FILENO)); - rx::vfs::addDevice("stdin", createFdWrapDevice(STDIN_FILENO)); - rx::vfs::addDevice("zero", createZeroCharacterDevice()); - rx::vfs::addDevice("null", createNullCharacterDevice()); - rx::vfs::addDevice("dipsw", createDipswCharacterDevice()); - rx::vfs::addDevice("dce", createDceCharacterDevice()); - rx::vfs::addDevice("hmd_cmd", createHmdCmdCharacterDevice()); - rx::vfs::addDevice("hmd_snsr", createHmdSnsrCharacterDevice()); - rx::vfs::addDevice("hmd_3da", createHmd3daCharacterDevice()); - rx::vfs::addDevice("hmd_dist", createHmdMmapCharacterDevice()); - rx::vfs::addDevice("hid", createHidCharacterDevice()); - rx::vfs::addDevice("gc", createGcCharacterDevice()); - rx::vfs::addDevice("rng", createRngCharacterDevice()); - rx::vfs::addDevice("sbl_srv", createSblSrvCharacterDevice()); - rx::vfs::addDevice("ajm", createAjmCharacterDevice()); - rx::vfs::addDevice("urandom", createUrandomCharacterDevice()); - - orbis::Ref stdinFile; - orbis::Ref stdoutFile; - orbis::Ref stderrFile; - rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile); - rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile); - rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile); - - mainThread->tproc->fileDescriptors.insert(stdinFile); - mainThread->tproc->fileDescriptors.insert(stdoutFile); - mainThread->tproc->fileDescriptors.insert(stderrFile); - - orbis::g_context.shmDevice = createShmDevice(); - orbis::g_context.blockpoolDevice = createBlockPoolDevice(); - - std::vector argvOffsets; - std::vector envpOffsets; - - auto libSceLibcInternal = rx::linker::loadModuleFile( - "/system/common/lib/libSceLibcInternal.sprx", mainThread); - - if (libSceLibcInternal == nullptr) { - std::fprintf(stderr, "libSceLibcInternal not found\n"); - return 1; - } - - libSceLibcInternal->id = mainThread->tproc->modulesMap.insert(libSceLibcInternal); - - auto libkernel = rx::linker::loadModuleFile( - "/system/common/lib/libkernel_sys.sprx", mainThread); - - if (libkernel == nullptr) { - std::fprintf(stderr, "libkernel not found\n"); - return 1; - } - - libkernel->id = mainThread->tproc->modulesMap.insert(libkernel); - - // *reinterpret_cast( - // reinterpret_cast(libkernel->base) + 0x6c2e4) = ~0; - - StackWriter stack{reinterpret_cast(mainThread->stackEnd)}; - - for (auto elem : argv) { - argvOffsets.push_back(stack.pushString(elem)); - } - - argvOffsets.push_back(0); - - for (auto elem : envp) { - envpOffsets.push_back(stack.pushString(elem)); - } - - envpOffsets.push_back(0); - - // clang-format off +static int ps4Exec(orbis::Thread* mainThread, + orbis::utils::Ref executableModule, + std::span argv, std::span envp) +{ + const auto stackEndAddress = 0x7'ffff'c000ull; + const auto stackSize = 0x40000 * 16; + auto stackStartAddress = stackEndAddress - stackSize; + mainThread->stackStart = + rx::vm::map(reinterpret_cast(stackStartAddress), stackSize, + rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead, + rx::vm::kMapFlagAnonymous | rx::vm::kMapFlagFixed | + rx::vm::kMapFlagPrivate | rx::vm::kMapFlagStack); + + mainThread->stackEnd = + reinterpret_cast(mainThread->stackStart) + stackSize; + + auto dmem1 = createDmemCharacterDevice(1); + orbis::g_context.dmemDevice = dmem1; + + rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); + rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); + rx::vfs::addDevice("icc_configuration", createIccConfigurationCharacterDevice()); + rx::vfs::addDevice("console", createConsoleCharacterDevice()); + rx::vfs::addDevice("camera", createCameraCharacterDevice()); + rx::vfs::addDevice("dmem1", dmem1); + rx::vfs::addDevice("dmem2", createDmemCharacterDevice(2)); + rx::vfs::addDevice("stdout", createFdWrapDevice(STDOUT_FILENO)); + rx::vfs::addDevice("stderr", createFdWrapDevice(STDERR_FILENO)); + rx::vfs::addDevice("stdin", createFdWrapDevice(STDIN_FILENO)); + rx::vfs::addDevice("zero", createZeroCharacterDevice()); + rx::vfs::addDevice("null", createNullCharacterDevice()); + rx::vfs::addDevice("dipsw", createDipswCharacterDevice()); + rx::vfs::addDevice("dce", createDceCharacterDevice()); + rx::vfs::addDevice("hmd_cmd", createHmdCmdCharacterDevice()); + rx::vfs::addDevice("hmd_snsr", createHmdSnsrCharacterDevice()); + rx::vfs::addDevice("hmd_3da", createHmd3daCharacterDevice()); + rx::vfs::addDevice("hmd_dist", createHmdMmapCharacterDevice()); + rx::vfs::addDevice("hid", createHidCharacterDevice()); + rx::vfs::addDevice("gc", createGcCharacterDevice()); + rx::vfs::addDevice("rng", createRngCharacterDevice()); + rx::vfs::addDevice("sbl_srv", createSblSrvCharacterDevice()); + rx::vfs::addDevice("ajm", createAjmCharacterDevice()); + rx::vfs::addDevice("urandom", createUrandomCharacterDevice()); + + orbis::Ref stdinFile; + orbis::Ref stdoutFile; + orbis::Ref stderrFile; + rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile); + rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile); + rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile); + + mainThread->tproc->fileDescriptors.insert(stdinFile); + mainThread->tproc->fileDescriptors.insert(stdoutFile); + mainThread->tproc->fileDescriptors.insert(stderrFile); + + orbis::g_context.shmDevice = createShmDevice(); + orbis::g_context.blockpoolDevice = createBlockPoolDevice(); + + std::vector argvOffsets; + std::vector envpOffsets; + + auto libSceLibcInternal = rx::linker::loadModuleFile( + "/system/common/lib/libSceLibcInternal.sprx", mainThread); + + if (libSceLibcInternal == nullptr) + { + std::fprintf(stderr, "libSceLibcInternal not found\n"); + return 1; + } + + libSceLibcInternal->id = mainThread->tproc->modulesMap.insert(libSceLibcInternal); + + auto libkernel = rx::linker::loadModuleFile( + "/system/common/lib/libkernel_sys.sprx", mainThread); + + if (libkernel == nullptr) + { + std::fprintf(stderr, "libkernel not found\n"); + return 1; + } + + libkernel->id = mainThread->tproc->modulesMap.insert(libkernel); + + // *reinterpret_cast( + // reinterpret_cast(libkernel->base) + 0x6c2e4) = ~0; + + StackWriter stack{reinterpret_cast(mainThread->stackEnd)}; + + for (auto elem : argv) + { + argvOffsets.push_back(stack.pushString(elem)); + } + + argvOffsets.push_back(0); + + for (auto elem : envp) + { + envpOffsets.push_back(stack.pushString(elem)); + } + + envpOffsets.push_back(0); + + // clang-format off std::uint64_t auxv[] = { AT_ENTRY, executableModule->entryPoint, AT_BASE, reinterpret_cast(libkernel->base), AT_NULL, 0 }; - // clang-format on + // clang-format on - std::size_t argSize = - sizeof(std::uint64_t) + sizeof(std::uint64_t) * argvOffsets.size() + - sizeof(std::uint64_t) * envpOffsets.size() + sizeof(auxv); + std::size_t argSize = + sizeof(std::uint64_t) + sizeof(std::uint64_t) * argvOffsets.size() + + sizeof(std::uint64_t) * envpOffsets.size() + sizeof(auxv); - auto sp = stack.alloc(argSize, 32); + auto sp = stack.alloc(argSize, 32); - auto arg = reinterpret_cast(sp); - *arg++ = argvOffsets.size() - 1; + auto arg = reinterpret_cast(sp); + *arg++ = argvOffsets.size() - 1; - for (auto argvOffsets : argvOffsets) { - *arg++ = argvOffsets; - } + for (auto argvOffsets : argvOffsets) + { + *arg++ = argvOffsets; + } - for (auto envpOffset : envpOffsets) { - *arg++ = envpOffset; - } + for (auto envpOffset : envpOffsets) + { + *arg++ = envpOffset; + } - executableModule = {}; + executableModule = {}; - memcpy(arg, auxv, sizeof(auxv)); + memcpy(arg, auxv, sizeof(auxv)); - auto context = new ucontext_t{}; + auto context = new ucontext_t{}; - context->uc_mcontext.gregs[REG_RDI] = sp; - context->uc_mcontext.gregs[REG_RSP] = sp; + context->uc_mcontext.gregs[REG_RDI] = sp; + context->uc_mcontext.gregs[REG_RSP] = sp; - // FIXME: should be at guest user space - context->uc_mcontext.gregs[REG_RDX] = - reinterpret_cast(+[] { std::printf("At exit\n"); }); - ; - context->uc_mcontext.gregs[REG_RIP] = libkernel->entryPoint; + // FIXME: should be at guest user space + context->uc_mcontext.gregs[REG_RDX] = + reinterpret_cast(+[] { std::printf("At exit\n"); }); + ; + context->uc_mcontext.gregs[REG_RIP] = libkernel->entryPoint; - mainThread->context = context; - rx::thread::invoke(mainThread); - std::abort(); + mainThread->context = context; + rx::thread::invoke(mainThread); + std::abort(); } -static void usage(const char *argv0) { - std::printf("%s [...] [args...]\n", argv0); - std::printf(" options:\n"); - std::printf(" -m, --mount \n"); - std::printf(" -a, --enable-audio\n"); - std::printf(" -o, --override \n"); - std::printf(" --trace\n"); +static void usage(const char* argv0) +{ + std::printf("%s [...] [args...]\n", argv0); + std::printf(" options:\n"); + std::printf(" -m, --mount \n"); + std::printf(" -a, --enable-audio\n"); + std::printf(" -o, --override \n"); + std::printf(" --trace\n"); } -static std::filesystem::path getSelfDir() { - char path[PATH_MAX]; - int len = ::readlink("/proc/self/exe", path, sizeof(path)); - if (len < 0 || len >= sizeof(path)) { - // TODO - return std::filesystem::current_path(); - } - - return std::filesystem::path(path).parent_path(); +static std::filesystem::path getSelfDir() +{ + char path[PATH_MAX]; + int len = ::readlink("/proc/self/exe", path, sizeof(path)); + if (len < 0 || len >= sizeof(path)) + { + // TODO + return std::filesystem::current_path(); + } + + return std::filesystem::path(path).parent_path(); } -static bool isRpsxGpuPid(int pid) { - if (pid <= 0 || ::kill(pid, 0) != 0) { - return false; - } +static bool isRpsxGpuPid(int pid) +{ + if (pid <= 0 || ::kill(pid, 0) != 0) + { + return false; + } - char path[PATH_MAX]; - std::string procPath = "/proc/" + std::to_string(pid) + "/exe"; - auto len = ::readlink(procPath.c_str(), path, sizeof(path)); + char path[PATH_MAX]; + std::string procPath = "/proc/" + std::to_string(pid) + "/exe"; + auto len = ::readlink(procPath.c_str(), path, sizeof(path)); - if (len < 0 || len >= std::size(path)) { - return false; - } + if (len < 0 || len >= std::size(path)) + { + return false; + } - path[len] = 0; + path[len] = 0; - std::printf("filename is '%s'\n", - std::filesystem::path(path).filename().c_str()); + std::printf("filename is '%s'\n", + std::filesystem::path(path).filename().c_str()); - return std::filesystem::path(path).filename() == "rpcsx-gpu"; + return std::filesystem::path(path).filename() == "rpcsx-gpu"; } -static void runRpsxGpu() { - const char *cmdBufferName = "/rpcsx-gpu-cmds"; - amdgpu::bridge::BridgeHeader *bridgeHeader = - amdgpu::bridge::openShmCommandBuffer(cmdBufferName); - - if (bridgeHeader != nullptr && bridgeHeader->pullerPid > 0 && - isRpsxGpuPid(bridgeHeader->pullerPid)) { - bridgeHeader->pusherPid = ::getpid(); - g_gpuPid = bridgeHeader->pullerPid; - rx::bridge = bridgeHeader; - return; - } - - std::printf("Starting rpcsx-gpu\n"); - - if (bridgeHeader == nullptr) { - bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName); - } - bridgeHeader->pusherPid = ::getpid(); - rx::bridge = bridgeHeader; - - auto rpcsxGpuPath = getSelfDir() / "rpcsx-gpu"; - - if (!std::filesystem::is_regular_file(rpcsxGpuPath)) { - std::printf("failed to find rpcsx-gpu, continue without GPU emulation\n"); - return; - } - - g_gpuPid = ::fork(); - - if (g_gpuPid == 0) { - // TODO - const char *argv[] = {rpcsxGpuPath.c_str(), nullptr}; - - ::execv(rpcsxGpuPath.c_str(), const_cast(argv)); - } +static void runRpsxGpu() +{ + const char* cmdBufferName = "/rpcsx-gpu-cmds"; + amdgpu::bridge::BridgeHeader* bridgeHeader = + amdgpu::bridge::openShmCommandBuffer(cmdBufferName); + + if (bridgeHeader != nullptr && bridgeHeader->pullerPid > 0 && + isRpsxGpuPid(bridgeHeader->pullerPid)) + { + bridgeHeader->pusherPid = ::getpid(); + g_gpuPid = bridgeHeader->pullerPid; + rx::bridge = bridgeHeader; + return; + } + + std::printf("Starting rpcsx-gpu\n"); + + if (bridgeHeader == nullptr) + { + bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName); + } + bridgeHeader->pusherPid = ::getpid(); + rx::bridge = bridgeHeader; + + auto rpcsxGpuPath = getSelfDir() / "rpcsx-gpu"; + + if (!std::filesystem::is_regular_file(rpcsxGpuPath)) + { + std::printf("failed to find rpcsx-gpu, continue without GPU emulation\n"); + return; + } + + g_gpuPid = ::fork(); + + if (g_gpuPid == 0) + { + // TODO + const char* argv[] = {rpcsxGpuPath.c_str(), nullptr}; + + ::execv(rpcsxGpuPath.c_str(), const_cast(argv)); + } } -int main(int argc, const char *argv[]) { - if (argc == 2) { - if (std::strcmp(argv[1], "-h") == 0 || - std::strcmp(argv[1], "--help") == 0) { - usage(argv[0]); - return 1; - } - } - - if (argc < 2) { - usage(argv[0]); - return 1; - } - - setupSigHandlers(); - rx::vfs::initialize(); - - bool enableAudio = false; - bool asRoot = false; - - int argIndex = 1; - while (argIndex < argc) { - if (argv[argIndex] == std::string_view("--mount") || - argv[argIndex] == std::string_view("-m")) { - if (argc <= argIndex + 2) { - usage(argv[0]); - return 1; - } - - std::printf("mounting '%s' to virtual '%s'\n", argv[argIndex + 1], - argv[argIndex + 2]); - if (!std::filesystem::is_directory(argv[argIndex + 1])) { - std::fprintf(stderr, "Directory '%s' not exists\n", argv[argIndex + 1]); - return 1; - } - - rx::vfs::mount(argv[argIndex + 2], - createHostIoDevice(argv[argIndex + 1])); - argIndex += 3; - continue; - } - - if (argv[argIndex] == std::string_view("--trace")) { - argIndex++; - g_traceSyscalls = true; - continue; - } - - if (argv[argIndex] == std::string_view("--root")) { - argIndex++; - asRoot = true; - continue; - } - - if (argv[argIndex] == std::string_view("--override") || - argv[argIndex] == std::string_view("-o")) { - if (argc <= argIndex + 2) { - usage(argv[0]); - return 1; - } - - rx::linker::override(argv[argIndex + 1], argv[argIndex + 2]); - - argIndex += 3; - continue; - } - - if (argv[argIndex] == std::string_view("--enable-audio") || - argv[argIndex] == std::string_view("-a")) { - argIndex++; - enableAudio = true; - continue; - } - - break; - } - - if (argIndex >= argc) { - usage(argv[0]); - return 1; - } - - rx::thread::initialize(); - rx::vm::initialize(); - runRpsxGpu(); - - if (enableAudio) { - orbis::g_context.audioOut = orbis::knew(); - } - - // rx::vm::printHostStats(); - auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); - pthread_setname_np(pthread_self(), "10.MAINTHREAD"); - - std::thread{[] { - pthread_setname_np(pthread_self(), "Bridge"); - auto bridge = rx::bridge.header; - - std::vector fetchedCommands; - fetchedCommands.reserve(std::size(bridge->cacheCommands)); - - while (true) { - for (auto &command : bridge->cacheCommands) { - std::uint64_t value = command.load(std::memory_order::relaxed); - - if (value != 0) { - fetchedCommands.push_back(value); - command.store(0, std::memory_order::relaxed); - } - } - - if (fetchedCommands.empty()) { - continue; - } - - for (auto command : fetchedCommands) { - auto page = static_cast(command); - auto count = static_cast(command >> 32) + 1; - - auto pageFlags = - bridge->cachePages[page].load(std::memory_order::relaxed); - - auto address = - static_cast(page) * amdgpu::bridge::kHostPageSize; - auto origVmProt = rx::vm::getPageProtection(address); - int prot = 0; - - if (origVmProt & rx::vm::kMapProtCpuRead) { - prot |= PROT_READ; - } - if (origVmProt & rx::vm::kMapProtCpuWrite) { - prot |= PROT_WRITE; - } - if (origVmProt & rx::vm::kMapProtCpuExec) { - prot |= PROT_EXEC; - } - - if (pageFlags & amdgpu::bridge::kPageReadWriteLock) { - prot &= ~(PROT_READ | PROT_WRITE); - } else if (pageFlags & amdgpu::bridge::kPageWriteWatch) { - prot &= ~PROT_WRITE; - } - - // std::fprintf(stderr, "protection %lx-%lx\n", address, - // address + amdgpu::bridge::kHostPageSize * count); - if (::mprotect(reinterpret_cast(address), - amdgpu::bridge::kHostPageSize * count, prot)) { - perror("protection failed"); - std::abort(); - } - } - - fetchedCommands.clear(); - } - }}.detach(); - - int status = 0; - - initProcess->sysent = &orbis::ps4_sysvec; - initProcess->onSysEnter = onSysEnter; - initProcess->onSysExit = onSysExit; - initProcess->ops = &rx::procOpsTable; - - auto [baseId, mainThread] = initProcess->threadsMap.emplace(); - mainThread->tproc = initProcess; - mainThread->tid = initProcess->pid + baseId; - mainThread->state = orbis::ThreadState::RUNNING; - - auto executableModule = - rx::linker::loadModuleFile(argv[argIndex], mainThread); - - if (executableModule == nullptr) { - std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]); - std::abort(); - } - - executableModule->id = initProcess->modulesMap.insert(executableModule); - initProcess->processParam = executableModule->processParam; - initProcess->processParamSize = executableModule->processParamSize; - - if (executableModule->type == rx::linker::kElfTypeSceDynExec || - executableModule->type == rx::linker::kElfTypeSceExec) { - status = ps4Exec(mainThread, std::move(executableModule), - std::span(argv + argIndex, argc - argIndex), - std::span()); - } else { - std::fprintf(stderr, "Unexpected executable type\n"); - status = 1; - } - - // rx::vm::printHostStats(); - rx::vm::deinitialize(); - rx::thread::deinitialize(); - - return status; +int main(int argc, const char* argv[]) +{ + if (argc == 2) + { + if (std::strcmp(argv[1], "-h") == 0 || + std::strcmp(argv[1], "--help") == 0) + { + usage(argv[0]); + return 1; + } + } + + if (argc < 2) + { + usage(argv[0]); + return 1; + } + + setupSigHandlers(); + rx::vfs::initialize(); + + bool enableAudio = false; + bool asRoot = false; + + int argIndex = 1; + while (argIndex < argc) + { + if (argv[argIndex] == std::string_view("--mount") || + argv[argIndex] == std::string_view("-m")) + { + if (argc <= argIndex + 2) + { + usage(argv[0]); + return 1; + } + + std::printf("mounting '%s' to virtual '%s'\n", argv[argIndex + 1], + argv[argIndex + 2]); + if (!std::filesystem::is_directory(argv[argIndex + 1])) + { + std::fprintf(stderr, "Directory '%s' not exists\n", argv[argIndex + 1]); + return 1; + } + + rx::vfs::mount(argv[argIndex + 2], + createHostIoDevice(argv[argIndex + 1])); + argIndex += 3; + continue; + } + + if (argv[argIndex] == std::string_view("--trace")) + { + argIndex++; + g_traceSyscalls = true; + continue; + } + + if (argv[argIndex] == std::string_view("--root")) + { + argIndex++; + asRoot = true; + continue; + } + + if (argv[argIndex] == std::string_view("--override") || + argv[argIndex] == std::string_view("-o")) + { + if (argc <= argIndex + 2) + { + usage(argv[0]); + return 1; + } + + rx::linker::override(argv[argIndex + 1], argv[argIndex + 2]); + + argIndex += 3; + continue; + } + + if (argv[argIndex] == std::string_view("--enable-audio") || + argv[argIndex] == std::string_view("-a")) + { + argIndex++; + enableAudio = true; + continue; + } + + break; + } + + if (argIndex >= argc) + { + usage(argv[0]); + return 1; + } + + rx::thread::initialize(); + rx::vm::initialize(); + runRpsxGpu(); + + if (enableAudio) + { + orbis::g_context.audioOut = orbis::knew(); + } + + // rx::vm::printHostStats(); + auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); + pthread_setname_np(pthread_self(), "10.MAINTHREAD"); + + std::thread{[] { + pthread_setname_np(pthread_self(), "Bridge"); + auto bridge = rx::bridge.header; + + std::vector fetchedCommands; + fetchedCommands.reserve(std::size(bridge->cacheCommands)); + + while (true) + { + for (auto& command : bridge->cacheCommands) + { + std::uint64_t value = command.load(std::memory_order::relaxed); + + if (value != 0) + { + fetchedCommands.push_back(value); + command.store(0, std::memory_order::relaxed); + } + } + + if (fetchedCommands.empty()) + { + continue; + } + + for (auto command : fetchedCommands) + { + auto page = static_cast(command); + auto count = static_cast(command >> 32) + 1; + + auto pageFlags = + bridge->cachePages[page].load(std::memory_order::relaxed); + + auto address = + static_cast(page) * amdgpu::bridge::kHostPageSize; + auto origVmProt = rx::vm::getPageProtection(address); + int prot = 0; + + if (origVmProt & rx::vm::kMapProtCpuRead) + { + prot |= PROT_READ; + } + if (origVmProt & rx::vm::kMapProtCpuWrite) + { + prot |= PROT_WRITE; + } + if (origVmProt & rx::vm::kMapProtCpuExec) + { + prot |= PROT_EXEC; + } + + if (pageFlags & amdgpu::bridge::kPageReadWriteLock) + { + prot &= ~(PROT_READ | PROT_WRITE); + } + else if (pageFlags & amdgpu::bridge::kPageWriteWatch) + { + prot &= ~PROT_WRITE; + } + + // std::fprintf(stderr, "protection %lx-%lx\n", address, + // address + amdgpu::bridge::kHostPageSize * count); + if (::mprotect(reinterpret_cast(address), + amdgpu::bridge::kHostPageSize * count, prot)) + { + perror("protection failed"); + std::abort(); + } + } + + fetchedCommands.clear(); + } + }}.detach(); + + int status = 0; + + initProcess->sysent = &orbis::ps4_sysvec; + initProcess->onSysEnter = onSysEnter; + initProcess->onSysExit = onSysExit; + initProcess->ops = &rx::procOpsTable; + + auto [baseId, mainThread] = initProcess->threadsMap.emplace(); + mainThread->tproc = initProcess; + mainThread->tid = initProcess->pid + baseId; + mainThread->state = orbis::ThreadState::RUNNING; + + auto executableModule = + rx::linker::loadModuleFile(argv[argIndex], mainThread); + + if (executableModule == nullptr) + { + std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]); + std::abort(); + } + + executableModule->id = initProcess->modulesMap.insert(executableModule); + initProcess->processParam = executableModule->processParam; + initProcess->processParamSize = executableModule->processParamSize; + + if (executableModule->type == rx::linker::kElfTypeSceDynExec || + executableModule->type == rx::linker::kElfTypeSceExec) + { + status = ps4Exec(mainThread, std::move(executableModule), + std::span(argv + argIndex, argc - argIndex), + std::span()); + } + else + { + std::fprintf(stderr, "Unexpected executable type\n"); + status = 1; + } + + // rx::vm::printHostStats(); + rx::vm::deinitialize(); + rx::thread::deinitialize(); + + return status; } diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 77837a87..59cec8d2 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -27,648 +27,751 @@ using namespace orbis; -extern "C" void __register_frame(const void *); - -namespace { -static std::pair> -loadPrx(orbis::Thread *thread, std::string_view name, bool relocate, - std::map> &loadedObjects, - std::map> &loadedModules, - std::string_view expectedName) { - if (auto it = loadedObjects.find(expectedName); it != loadedObjects.end()) { - return {{}, it->second}; - } - - if (auto it = loadedObjects.find(name); it != loadedObjects.end()) { - return {{}, it->second}; - } - - auto module = rx::linker::loadModuleFile(name, thread); - - if (module == nullptr) { - if (!expectedName.empty()) { - loadedObjects[std::string(expectedName)] = nullptr; - } - - return {ErrorCode::NOENT, {}}; - } - - if (!expectedName.empty() && expectedName != module->soName) { - if (module->soName[0] != '\0') { - std::fprintf(stderr, - "Module name mismatch, expected '%s', loaded '%s' (%s)\n", - std::string(expectedName).c_str(), module->soName, - module->moduleName); - // std::abort(); - } - - std::strncpy(module->soName, std::string(expectedName).c_str(), - sizeof(module->soName)); - if (module->soName[sizeof(module->soName) - 1] != '\0') { - std::fprintf(stderr, "Too big needed name\n"); - std::abort(); - } - } - - loadedObjects[module->soName] = module.get(); - if (loadedModules.try_emplace(module->moduleName, module.get()).second) { - std::printf("Setting '%s' as '%s' module\n", module->soName, - module->moduleName); - } - - for (auto &needed : module->needed) { - auto [result, neededModule] = - loadPrx(thread, needed, relocate, loadedObjects, loadedModules, needed); - - if (result.isError() || neededModule == nullptr) { - std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); - } - } - - module->importedModules.clear(); - module->importedModules.reserve(module->neededModules.size()); - - for (auto mod : module->neededModules) { - if (auto it = loadedModules.find(std::string_view(mod.name)); - it != loadedModules.end()) { - module->importedModules.emplace_back(it->second); - continue; - } - - std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", - mod.name.c_str(), module->soName); - module->importedModules.push_back({}); - } - - if (relocate) { - auto result = module->relocate(thread->tproc); - if (result.isError()) { - return {result, module}; - } - } - - module->id = thread->tproc->modulesMap.insert(module); - std::fprintf(stderr, "'%s' ('%s') was loaded with id '%u'\n", - module->moduleName, module->soName, (unsigned)module->id); - return {{}, module}; -} - -static std::pair> -loadPrx(orbis::Thread *thread, std::string_view path, bool relocate) { - std::map> loadedObjects; - std::map> loadedModules; - - for (auto [id, module] : thread->tproc->modulesMap) { - loadedObjects[module->soName] = module; - loadedModules[module->moduleName] = module; - } - - std::string expectedName; - if (auto sep = path.rfind('/'); sep != std::string_view::npos) { - auto tmpExpectedName = path.substr(sep + 1); - - if (tmpExpectedName.ends_with(".sprx")) { - tmpExpectedName.remove_suffix(5); - } - - expectedName += tmpExpectedName; - - if (!expectedName.ends_with(".prx")) { - expectedName += ".prx"; - } - } - - return loadPrx(thread, path, relocate, loadedObjects, loadedModules, - expectedName); -} - -orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr, - orbis::size_t len, orbis::sint prot, orbis::sint flags, - orbis::sint fd, orbis::off_t pos) { - if (fd == -1) { - auto result = rx::vm::map(addr, len, prot, flags); - if (result == (void *)-1) { - return ErrorCode::NOMEM; - } - - thread->retval[0] = reinterpret_cast(result); - return {}; - } - - auto file = thread->tproc->fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - if (file->ops->mmap == nullptr) { - ORBIS_LOG_FATAL("unimplemented mmap", fd, (void *)addr, len, prot, flags, - pos); - return mmap(thread, addr, len, prot, flags, -1, 0); - } - - void *maddr = addr; - auto result = file->ops->mmap(file, &maddr, len, prot, flags, pos, thread); - - if (result != ErrorCode{}) { - return result; - } - - thread->retval[0] = reinterpret_cast(maddr); - return {}; -} - -orbis::SysResult dmem_mmap(orbis::Thread *thread, orbis::caddr_t addr, - orbis::size_t len, orbis::sint memoryType, - orbis::sint prot, sint flags, - orbis::off_t directMemoryStart) { - auto dmem = static_cast(orbis::g_context.dmemDevice.get()); - void *address = addr; - auto result = dmem->mmap(&address, len, prot, flags, directMemoryStart); - if (result != ErrorCode{}) { - return result; - } - - thread->retval[0] = reinterpret_cast(address); - return {}; -} - -orbis::SysResult munmap(orbis::Thread *, orbis::ptr addr, - orbis::size_t len) { - if (rx::vm::unmap(addr, len)) { - return {}; - } - return ErrorCode::INVAL; -} - -orbis::SysResult msync(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len, orbis::sint flags) { - return {}; -} - -orbis::SysResult mprotect(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len, orbis::sint prot) { - if (!rx::vm::protect((void *)addr, len, prot)) { - return ErrorCode::INVAL; - } - return {}; -} - -orbis::SysResult minherit(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len, orbis::sint inherit) { - return ErrorCode::INVAL; -} - -orbis::SysResult madvise(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len, orbis::sint behav) { - return ErrorCode::INVAL; -} - -orbis::SysResult mincore(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len, orbis::ptr vec) { - return ErrorCode::INVAL; -} - -orbis::SysResult mlock(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len) { - return {}; -} -orbis::SysResult mlockall(orbis::Thread *thread, orbis::sint how) { return {}; } -orbis::SysResult munlockall(orbis::Thread *thread) { return {}; } -orbis::SysResult munlock(orbis::Thread *thread, orbis::ptr addr, - orbis::size_t len) { - return {}; -} -orbis::SysResult virtual_query(orbis::Thread *thread, - orbis::ptr addr, orbis::sint flags, - orbis::ptr info, orbis::ulong infoSize) { - if (infoSize != sizeof(rx::vm::VirtualQueryInfo)) { - return ErrorCode::INVAL; - } - - if (!rx::vm::virtualQuery(addr, flags, (rx::vm::VirtualQueryInfo *)info)) { - return ErrorCode::FAULT; - } - return {}; -} - -orbis::SysResult -query_memory_protection(orbis::Thread *thread, orbis::ptr address, - orbis::ptr protection) { - if (rx::vm::queryProtection(address, &protection->startAddress, - &protection->endAddress, &protection->prot)) { - return {}; - } - return ErrorCode::INVAL; -} - -orbis::SysResult open(orbis::Thread *thread, orbis::ptr path, - orbis::sint flags, orbis::sint mode, - orbis::Ref *file) { - return rx::vfs::open(path, flags, mode, file, thread); -} - -orbis::SysResult shm_open(orbis::Thread *thread, const char *path, - orbis::sint flags, orbis::sint mode, - orbis::Ref *file) { - auto dev = static_cast(orbis::g_context.shmDevice.get()); - return dev->open(file, path, flags, mode, thread); -} - -orbis::SysResult mkdir(Thread *thread, ptr path, sint mode) { - ORBIS_LOG_TODO(__FUNCTION__, path, mode); - return rx::vfs::mkdir(path, mode, thread); -} -orbis::SysResult rmdir(Thread *thread, ptr path) { - ORBIS_LOG_TODO(__FUNCTION__, path); - return rx::vfs::rmdir(path, thread); -} -orbis::SysResult rename(Thread *thread, ptr from, ptr to) { - ORBIS_LOG_TODO(__FUNCTION__, from, to); - return rx::vfs::rename(from, to, thread); -} - -orbis::SysResult blockpool_open(orbis::Thread *thread, - orbis::Ref *file) { - auto dev = static_cast(orbis::g_context.blockpoolDevice.get()); - return dev->open(file, nullptr, 0, 0, thread); -} - -orbis::SysResult blockpool_map(orbis::Thread *thread, orbis::caddr_t addr, - orbis::size_t len, orbis::sint prot, - orbis::sint flags) { - auto blockpool = - static_cast(orbis::g_context.blockpoolDevice.get()); - void *address = addr; - auto result = blockpool->map(&address, len, prot, flags, thread); - if (result != ErrorCode{}) { - return result; - } - - thread->retval[0] = reinterpret_cast(address); - return {}; -} -orbis::SysResult blockpool_unmap(orbis::Thread *thread, orbis::caddr_t addr, - orbis::size_t len) { - auto blockpool = - static_cast(orbis::g_context.blockpoolDevice.get()); - return blockpool->unmap(addr, len, thread); -} - -orbis::SysResult socket(orbis::Thread *thread, orbis::ptr name, - orbis::sint domain, orbis::sint type, - orbis::sint protocol, Ref *file) { - return createSocket(file, name, domain, type, protocol); -} - -orbis::SysResult shm_unlink(orbis::Thread *thread, const char *path) { - auto dev = static_cast(orbis::g_context.shmDevice.get()); - return dev->unlink(path, thread); -} - -orbis::SysResult dynlib_get_obj_member(orbis::Thread *thread, - orbis::ModuleHandle handle, - orbis::uint64_t index, - orbis::ptr> addrp) { - std::lock_guard lock(thread->tproc->mtx); - auto module = thread->tproc->modulesMap.get(handle); - - if (module == nullptr) { - return ErrorCode::INVAL; - } - - switch (index) { - case 1: - *addrp = module->initProc; - return {}; - - case 8: - *addrp = module->moduleParam; - return {}; - } - - return ErrorCode::INVAL; -} - -ptr findSymbolById(orbis::Module *module, std::uint64_t id) { - for (auto sym : module->symbols) { - if (sym.id == id && sym.bind != orbis::SymbolBind::Local) { - return sym.address != 0 ? (ptr)module->base + sym.address : 0; - } - } - - return nullptr; -} - -orbis::SysResult dynlib_dlsym(orbis::Thread *thread, orbis::ModuleHandle handle, - orbis::ptr symbol, - orbis::ptr> addrp) { - std::printf("sys_dynlib_dlsym(%u, '%s')\n", (unsigned)handle, symbol); - std::lock_guard lock(thread->tproc->mtx); - auto module = thread->tproc->modulesMap.get(handle); - - if (module == nullptr) { - return ErrorCode::INVAL; - } - - std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, - module->moduleName, symbol); - - std::string_view symView(symbol); - - if (auto nid = rx::linker::decodeNid(symView)) { - if (auto addr = findSymbolById(module, *nid)) { - *addrp = addr; - return {}; - } - } - - std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, - module->moduleName, - rx::linker::encodeNid(rx::linker::encodeFid(symView)).string); - - if (auto addr = findSymbolById(module, rx::linker::encodeFid(symView))) { - *addrp = addr; - return {}; - } - - return ErrorCode::NOENT; -} -orbis::SysResult dynlib_do_copy_relocations(orbis::Thread *thread) { - // TODO - return {}; -} - -orbis::SysResult dynlib_load_prx(orbis::Thread *thread, - orbis::ptr name, - orbis::uint64_t arg1, - orbis::ptr pHandle, - orbis::uint64_t arg3) { - std::printf("sys_dynlib_load_prx: %s\n", name); - - std::lock_guard lock(thread->tproc->mtx); - - char _name[256]; - auto errorCode = ureadString(_name, sizeof(_name), name); - if (errorCode != ErrorCode{}) { - return errorCode; - } - - auto [result, module] = loadPrx(thread, _name, true); - if (result.isError()) { - return result; - } - - { - std::map> loadedModules; - - for (auto [id, module] : thread->tproc->modulesMap) { - // std::fprintf(stderr, "%u: %s\n", (unsigned)id, module->moduleName); - loadedModules[module->moduleName] = module; - } - - for (auto [id, module] : thread->tproc->modulesMap) { - module->importedModules.clear(); - module->importedModules.reserve(module->neededModules.size()); - - for (auto mod : module->neededModules) { - if (auto it = loadedModules.find(std::string_view(mod.name)); - it != loadedModules.end()) { - module->importedModules.emplace_back(it->second); - continue; - } - - module->importedModules.push_back({}); - } - - module->relocate(thread->tproc); - } - } - - *pHandle = module->id; - return {}; -} -orbis::SysResult dynlib_unload_prx(orbis::Thread *thread, - orbis::ModuleHandle handle) { - return ErrorCode::NOTSUP; -} - -SysResult thr_create(orbis::Thread *thread, orbis::ptr ctxt, - ptr arg, orbis::sint flags) { - return ErrorCode::NOTSUP; -} -SysResult thr_new(orbis::Thread *thread, orbis::ptr param, - orbis::sint param_size) { - thr_param _param; - auto result = uread(_param, param); - if (result != ErrorCode{}) { - return result; - } - - auto proc = thread->tproc; - std::lock_guard lock(proc->mtx); - auto [baseId, childThread] = proc->threadsMap.emplace(); - childThread->tproc = proc; - childThread->tid = proc->pid + baseId; - childThread->state = orbis::ThreadState::RUNQ; - childThread->stackStart = _param.stack_base; - childThread->stackEnd = _param.stack_base + _param.stack_size; - childThread->fsBase = reinterpret_cast(_param.tls_base); - - result = uwrite(_param.parent_tid, slong(childThread->tid)); - - if (result != ErrorCode{}) { - return result; - } - - // FIXME: implement scheduler - - ORBIS_LOG_NOTICE("Starting child thread", childThread->tid, - childThread->stackStart); - - auto stdthr = std::thread{[=, childThread = Ref(childThread)] { - stack_t ss; - - auto sigStackSize = std::max( - SIGSTKSZ, ::utils::alignUp(8 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); - - ss.ss_sp = malloc(sigStackSize); - if (ss.ss_sp == NULL) { - perror("malloc"); - ::exit(EXIT_FAILURE); - } - - ss.ss_size = sigStackSize; - ss.ss_flags = 0; - - if (sigaltstack(&ss, NULL) == -1) { - perror("sigaltstack"); - ::exit(EXIT_FAILURE); - } - - static_cast( - uwrite(_param.child_tid, slong(childThread->tid))); // TODO: verify - auto context = new ucontext_t{}; - - context->uc_mcontext.gregs[REG_RDI] = - reinterpret_cast(_param.arg); - context->uc_mcontext.gregs[REG_RSI] = - reinterpret_cast(_param.arg); - context->uc_mcontext.gregs[REG_RSP] = - reinterpret_cast(childThread->stackEnd); - context->uc_mcontext.gregs[REG_RIP] = - reinterpret_cast(_param.start_func); - - childThread->context = context; - childThread->state = orbis::ThreadState::RUNNING; - rx::thread::invoke(childThread.get()); - }}; - - if (pthread_setname_np(stdthr.native_handle(), - std::to_string(childThread->tid).c_str())) { - perror("pthread_setname_np"); - } - - childThread->handle = std::move(stdthr); - return {}; -} -SysResult thr_exit(orbis::Thread *thread, orbis::ptr state) { - std::printf("Requested exit of thread %u, state %p\n", (unsigned)thread->tid, - state); - if (state != nullptr) { - static_cast(uwrite(state, (orbis::slong)1)); - umtx_wake(thread, state, INT_MAX); - } - - // FIXME: implement exit - while (true) { - std::this_thread::sleep_for(std::chrono::seconds(60)); - } - return ErrorCode::NOTSUP; -} -SysResult thr_kill(orbis::Thread *thread, orbis::slong id, orbis::sint sig) { - return ErrorCode::NOTSUP; -} -SysResult thr_kill2(orbis::Thread *thread, orbis::pid_t pid, orbis::slong id, - orbis::sint sig) { - return ErrorCode::NOTSUP; -} -SysResult thr_suspend(orbis::Thread *thread, - orbis::ptr timeout) { - return ErrorCode::NOTSUP; -} -SysResult thr_wake(orbis::Thread *thread, orbis::slong id) { - return ErrorCode::NOTSUP; -} -SysResult thr_set_name(orbis::Thread *thread, orbis::slong id, - orbis::ptr name) { - ORBIS_LOG_WARNING(__FUNCTION__, name, id, thread->tid); - return {}; -} -orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) { - std::printf("Requested exit with status %d\n", status); - std::exit(status); -} - -SysResult processNeeded(Thread *thread) { - std::map> loadedObjects; - std::map> loadedModules; - std::set allNeeded; - - for (auto [id, module] : thread->tproc->modulesMap) { - loadedObjects[module->soName] = module; - loadedModules[module->moduleName] = module; - for (auto &needed : module->needed) { - allNeeded.insert(std::string(needed)); - } - } - - for (auto needed : allNeeded) { - auto [result, neededModule] = - loadPrx(thread, needed, false, loadedObjects, loadedModules, needed); - - if (result.isError() || neededModule == nullptr) { - std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); - continue; - } - } - - for (auto [id, module] : thread->tproc->modulesMap) { - module->importedModules.clear(); - module->importedModules.reserve(module->neededModules.size()); - - for (auto mod : module->neededModules) { - if (auto it = loadedModules.find(std::string_view(mod.name)); - it != loadedModules.end()) { - module->importedModules.emplace_back(it->second); - continue; - } - - std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", - mod.name.c_str(), module->soName); - module->importedModules.push_back({}); - } - - module->relocate(thread->tproc); - } - - return {}; -} - -SysResult registerEhFrames(Thread *thread) { - for (auto [id, module] : thread->tproc->modulesMap) { - if (module->ehFrame != nullptr) { - __register_frame(module->ehFrame); - } - } - - return {}; -} - -void where(Thread *thread) { - rx::printStackTrace((ucontext_t *)thread->context, thread, 2); -} +extern "C" void __register_frame(const void*); + +namespace +{ + static std::pair> + loadPrx(orbis::Thread* thread, std::string_view name, bool relocate, + std::map>& loadedObjects, + std::map>& loadedModules, + std::string_view expectedName) + { + if (auto it = loadedObjects.find(expectedName); it != loadedObjects.end()) + { + return {{}, it->second}; + } + + if (auto it = loadedObjects.find(name); it != loadedObjects.end()) + { + return {{}, it->second}; + } + + auto module = rx::linker::loadModuleFile(name, thread); + + if (module == nullptr) + { + if (!expectedName.empty()) + { + loadedObjects[std::string(expectedName)] = nullptr; + } + + return {ErrorCode::NOENT, {}}; + } + + if (!expectedName.empty() && expectedName != module->soName) + { + if (module->soName[0] != '\0') + { + std::fprintf(stderr, + "Module name mismatch, expected '%s', loaded '%s' (%s)\n", + std::string(expectedName).c_str(), module->soName, + module->moduleName); + // std::abort(); + } + + std::strncpy(module->soName, std::string(expectedName).c_str(), + sizeof(module->soName)); + if (module->soName[sizeof(module->soName) - 1] != '\0') + { + std::fprintf(stderr, "Too big needed name\n"); + std::abort(); + } + } + + loadedObjects[module->soName] = module.get(); + if (loadedModules.try_emplace(module->moduleName, module.get()).second) + { + std::printf("Setting '%s' as '%s' module\n", module->soName, + module->moduleName); + } + + for (auto& needed : module->needed) + { + auto [result, neededModule] = + loadPrx(thread, needed, relocate, loadedObjects, loadedModules, needed); + + if (result.isError() || neededModule == nullptr) + { + std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); + } + } + + module->importedModules.clear(); + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) + { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) + { + module->importedModules.emplace_back(it->second); + continue; + } + + std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", + mod.name.c_str(), module->soName); + module->importedModules.push_back({}); + } + + if (relocate) + { + auto result = module->relocate(thread->tproc); + if (result.isError()) + { + return {result, module}; + } + } + + module->id = thread->tproc->modulesMap.insert(module); + std::fprintf(stderr, "'%s' ('%s') was loaded with id '%u'\n", + module->moduleName, module->soName, (unsigned)module->id); + return {{}, module}; + } + + static std::pair> + loadPrx(orbis::Thread* thread, std::string_view path, bool relocate) + { + std::map> loadedObjects; + std::map> loadedModules; + + for (auto [id, module] : thread->tproc->modulesMap) + { + loadedObjects[module->soName] = module; + loadedModules[module->moduleName] = module; + } + + std::string expectedName; + if (auto sep = path.rfind('/'); sep != std::string_view::npos) + { + auto tmpExpectedName = path.substr(sep + 1); + + if (tmpExpectedName.ends_with(".sprx")) + { + tmpExpectedName.remove_suffix(5); + } + + expectedName += tmpExpectedName; + + if (!expectedName.ends_with(".prx")) + { + expectedName += ".prx"; + } + } + + return loadPrx(thread, path, relocate, loadedObjects, loadedModules, + expectedName); + } + + orbis::SysResult mmap(orbis::Thread* thread, orbis::caddr_t addr, + orbis::size_t len, orbis::sint prot, orbis::sint flags, + orbis::sint fd, orbis::off_t pos) + { + if (fd == -1) + { + auto result = rx::vm::map(addr, len, prot, flags); + if (result == (void*)-1) + { + return ErrorCode::NOMEM; + } + + thread->retval[0] = reinterpret_cast(result); + return {}; + } + + auto file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) + { + return ErrorCode::BADF; + } + + if (file->ops->mmap == nullptr) + { + ORBIS_LOG_FATAL("unimplemented mmap", fd, (void*)addr, len, prot, flags, + pos); + return mmap(thread, addr, len, prot, flags, -1, 0); + } + + void* maddr = addr; + auto result = file->ops->mmap(file, &maddr, len, prot, flags, pos, thread); + + if (result != ErrorCode{}) + { + return result; + } + + thread->retval[0] = reinterpret_cast(maddr); + return {}; + } + + orbis::SysResult dmem_mmap(orbis::Thread* thread, orbis::caddr_t addr, + orbis::size_t len, orbis::sint memoryType, + orbis::sint prot, sint flags, + orbis::off_t directMemoryStart) + { + auto dmem = static_cast(orbis::g_context.dmemDevice.get()); + void* address = addr; + auto result = dmem->mmap(&address, len, prot, flags, directMemoryStart); + if (result != ErrorCode{}) + { + return result; + } + + thread->retval[0] = reinterpret_cast(address); + return {}; + } + + orbis::SysResult munmap(orbis::Thread*, orbis::ptr addr, + orbis::size_t len) + { + if (rx::vm::unmap(addr, len)) + { + return {}; + } + return ErrorCode::INVAL; + } + + orbis::SysResult msync(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len, orbis::sint flags) + { + return {}; + } + + orbis::SysResult mprotect(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len, orbis::sint prot) + { + if (!rx::vm::protect((void*)addr, len, prot)) + { + return ErrorCode::INVAL; + } + return {}; + } + + orbis::SysResult minherit(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len, orbis::sint inherit) + { + return ErrorCode::INVAL; + } + + orbis::SysResult madvise(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len, orbis::sint behav) + { + return ErrorCode::INVAL; + } + + orbis::SysResult mincore(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len, orbis::ptr vec) + { + return ErrorCode::INVAL; + } + + orbis::SysResult mlock(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len) + { + return {}; + } + orbis::SysResult mlockall(orbis::Thread* thread, orbis::sint how) { return {}; } + orbis::SysResult munlockall(orbis::Thread* thread) { return {}; } + orbis::SysResult munlock(orbis::Thread* thread, orbis::ptr addr, + orbis::size_t len) + { + return {}; + } + orbis::SysResult virtual_query(orbis::Thread* thread, + orbis::ptr addr, orbis::sint flags, + orbis::ptr info, orbis::ulong infoSize) + { + if (infoSize != sizeof(rx::vm::VirtualQueryInfo)) + { + return ErrorCode::INVAL; + } + + if (!rx::vm::virtualQuery(addr, flags, (rx::vm::VirtualQueryInfo*)info)) + { + return ErrorCode::FAULT; + } + return {}; + } + + orbis::SysResult + query_memory_protection(orbis::Thread* thread, orbis::ptr address, + orbis::ptr protection) + { + if (rx::vm::queryProtection(address, &protection->startAddress, + &protection->endAddress, &protection->prot)) + { + return {}; + } + return ErrorCode::INVAL; + } + + orbis::SysResult open(orbis::Thread* thread, orbis::ptr path, + orbis::sint flags, orbis::sint mode, + orbis::Ref* file) + { + return rx::vfs::open(path, flags, mode, file, thread); + } + + orbis::SysResult shm_open(orbis::Thread* thread, const char* path, + orbis::sint flags, orbis::sint mode, + orbis::Ref* file) + { + auto dev = static_cast(orbis::g_context.shmDevice.get()); + return dev->open(file, path, flags, mode, thread); + } + + orbis::SysResult mkdir(Thread* thread, ptr path, sint mode) + { + ORBIS_LOG_TODO(__FUNCTION__, path, mode); + return rx::vfs::mkdir(path, mode, thread); + } + orbis::SysResult rmdir(Thread* thread, ptr path) + { + ORBIS_LOG_TODO(__FUNCTION__, path); + return rx::vfs::rmdir(path, thread); + } + orbis::SysResult rename(Thread* thread, ptr from, ptr to) + { + ORBIS_LOG_TODO(__FUNCTION__, from, to); + return rx::vfs::rename(from, to, thread); + } + + orbis::SysResult blockpool_open(orbis::Thread* thread, + orbis::Ref* file) + { + auto dev = static_cast(orbis::g_context.blockpoolDevice.get()); + return dev->open(file, nullptr, 0, 0, thread); + } + + orbis::SysResult blockpool_map(orbis::Thread* thread, orbis::caddr_t addr, + orbis::size_t len, orbis::sint prot, + orbis::sint flags) + { + auto blockpool = + static_cast(orbis::g_context.blockpoolDevice.get()); + void* address = addr; + auto result = blockpool->map(&address, len, prot, flags, thread); + if (result != ErrorCode{}) + { + return result; + } + + thread->retval[0] = reinterpret_cast(address); + return {}; + } + orbis::SysResult blockpool_unmap(orbis::Thread* thread, orbis::caddr_t addr, + orbis::size_t len) + { + auto blockpool = + static_cast(orbis::g_context.blockpoolDevice.get()); + return blockpool->unmap(addr, len, thread); + } + + orbis::SysResult socket(orbis::Thread* thread, orbis::ptr name, + orbis::sint domain, orbis::sint type, + orbis::sint protocol, Ref* file) + { + return createSocket(file, name, domain, type, protocol); + } + + orbis::SysResult shm_unlink(orbis::Thread* thread, const char* path) + { + auto dev = static_cast(orbis::g_context.shmDevice.get()); + return dev->unlink(path, thread); + } + + orbis::SysResult dynlib_get_obj_member(orbis::Thread* thread, + orbis::ModuleHandle handle, + orbis::uint64_t index, + orbis::ptr> addrp) + { + std::lock_guard lock(thread->tproc->mtx); + auto module = thread->tproc->modulesMap.get(handle); + + if (module == nullptr) + { + return ErrorCode::INVAL; + } + + switch (index) + { + case 1: + *addrp = module->initProc; + return {}; + + case 8: + *addrp = module->moduleParam; + return {}; + } + + return ErrorCode::INVAL; + } + + ptr findSymbolById(orbis::Module* module, std::uint64_t id) + { + for (auto sym : module->symbols) + { + if (sym.id == id && sym.bind != orbis::SymbolBind::Local) + { + return sym.address != 0 ? (ptr)module->base + sym.address : 0; + } + } + + return nullptr; + } + + orbis::SysResult dynlib_dlsym(orbis::Thread* thread, orbis::ModuleHandle handle, + orbis::ptr symbol, + orbis::ptr> addrp) + { + std::printf("sys_dynlib_dlsym(%u, '%s')\n", (unsigned)handle, symbol); + std::lock_guard lock(thread->tproc->mtx); + auto module = thread->tproc->modulesMap.get(handle); + + if (module == nullptr) + { + return ErrorCode::INVAL; + } + + std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, + module->moduleName, symbol); + + std::string_view symView(symbol); + + if (auto nid = rx::linker::decodeNid(symView)) + { + if (auto addr = findSymbolById(module, *nid)) + { + *addrp = addr; + return {}; + } + } + + std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, + module->moduleName, + rx::linker::encodeNid(rx::linker::encodeFid(symView)).string); + + if (auto addr = findSymbolById(module, rx::linker::encodeFid(symView))) + { + *addrp = addr; + return {}; + } + + return ErrorCode::NOENT; + } + orbis::SysResult dynlib_do_copy_relocations(orbis::Thread* thread) + { + // TODO + return {}; + } + + orbis::SysResult dynlib_load_prx(orbis::Thread* thread, + orbis::ptr name, + orbis::uint64_t arg1, + orbis::ptr pHandle, + orbis::uint64_t arg3) + { + std::printf("sys_dynlib_load_prx: %s\n", name); + + std::lock_guard lock(thread->tproc->mtx); + + char _name[256]; + auto errorCode = ureadString(_name, sizeof(_name), name); + if (errorCode != ErrorCode{}) + { + return errorCode; + } + + auto [result, module] = loadPrx(thread, _name, true); + if (result.isError()) + { + return result; + } + + { + std::map> loadedModules; + + for (auto [id, module] : thread->tproc->modulesMap) + { + // std::fprintf(stderr, "%u: %s\n", (unsigned)id, module->moduleName); + loadedModules[module->moduleName] = module; + } + + for (auto [id, module] : thread->tproc->modulesMap) + { + module->importedModules.clear(); + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) + { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) + { + module->importedModules.emplace_back(it->second); + continue; + } + + module->importedModules.push_back({}); + } + + module->relocate(thread->tproc); + } + } + + *pHandle = module->id; + return {}; + } + orbis::SysResult dynlib_unload_prx(orbis::Thread* thread, + orbis::ModuleHandle handle) + { + return ErrorCode::NOTSUP; + } + + SysResult thr_create(orbis::Thread* thread, orbis::ptr ctxt, + ptr arg, orbis::sint flags) + { + return ErrorCode::NOTSUP; + } + SysResult thr_new(orbis::Thread* thread, orbis::ptr param, + orbis::sint param_size) + { + thr_param _param; + auto result = uread(_param, param); + if (result != ErrorCode{}) + { + return result; + } + + auto proc = thread->tproc; + std::lock_guard lock(proc->mtx); + auto [baseId, childThread] = proc->threadsMap.emplace(); + childThread->tproc = proc; + childThread->tid = proc->pid + baseId; + childThread->state = orbis::ThreadState::RUNQ; + childThread->stackStart = _param.stack_base; + childThread->stackEnd = _param.stack_base + _param.stack_size; + childThread->fsBase = reinterpret_cast(_param.tls_base); + + result = uwrite(_param.parent_tid, slong(childThread->tid)); + + if (result != ErrorCode{}) + { + return result; + } + + // FIXME: implement scheduler + + ORBIS_LOG_NOTICE("Starting child thread", childThread->tid, + childThread->stackStart); + + auto stdthr = std::thread{[=, childThread = Ref(childThread)] { + stack_t ss; + + auto sigStackSize = std::max( + SIGSTKSZ, ::utils::alignUp(8 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); + + ss.ss_sp = malloc(sigStackSize); + if (ss.ss_sp == NULL) + { + perror("malloc"); + ::exit(EXIT_FAILURE); + } + + ss.ss_size = sigStackSize; + ss.ss_flags = 0; + + if (sigaltstack(&ss, NULL) == -1) + { + perror("sigaltstack"); + ::exit(EXIT_FAILURE); + } + + static_cast( + uwrite(_param.child_tid, slong(childThread->tid))); // TODO: verify + auto context = new ucontext_t{}; + + context->uc_mcontext.gregs[REG_RDI] = + reinterpret_cast(_param.arg); + context->uc_mcontext.gregs[REG_RSI] = + reinterpret_cast(_param.arg); + context->uc_mcontext.gregs[REG_RSP] = + reinterpret_cast(childThread->stackEnd); + context->uc_mcontext.gregs[REG_RIP] = + reinterpret_cast(_param.start_func); + + childThread->context = context; + childThread->state = orbis::ThreadState::RUNNING; + rx::thread::invoke(childThread.get()); + }}; + + if (pthread_setname_np(stdthr.native_handle(), + std::to_string(childThread->tid).c_str())) + { + perror("pthread_setname_np"); + } + + childThread->handle = std::move(stdthr); + return {}; + } + SysResult thr_exit(orbis::Thread* thread, orbis::ptr state) + { + std::printf("Requested exit of thread %u, state %p\n", (unsigned)thread->tid, + state); + if (state != nullptr) + { + static_cast(uwrite(state, (orbis::slong)1)); + umtx_wake(thread, state, INT_MAX); + } + + // FIXME: implement exit + while (true) + { + std::this_thread::sleep_for(std::chrono::seconds(60)); + } + return ErrorCode::NOTSUP; + } + SysResult thr_kill(orbis::Thread* thread, orbis::slong id, orbis::sint sig) + { + return ErrorCode::NOTSUP; + } + SysResult thr_kill2(orbis::Thread* thread, orbis::pid_t pid, orbis::slong id, + orbis::sint sig) + { + return ErrorCode::NOTSUP; + } + SysResult thr_suspend(orbis::Thread* thread, + orbis::ptr timeout) + { + return ErrorCode::NOTSUP; + } + SysResult thr_wake(orbis::Thread* thread, orbis::slong id) + { + return ErrorCode::NOTSUP; + } + SysResult thr_set_name(orbis::Thread* thread, orbis::slong id, + orbis::ptr name) + { + ORBIS_LOG_WARNING(__FUNCTION__, name, id, thread->tid); + return {}; + } + orbis::SysResult exit(orbis::Thread* thread, orbis::sint status) + { + std::printf("Requested exit with status %d\n", status); + std::exit(status); + } + + SysResult processNeeded(Thread* thread) + { + std::map> loadedObjects; + std::map> loadedModules; + std::set allNeeded; + + for (auto [id, module] : thread->tproc->modulesMap) + { + loadedObjects[module->soName] = module; + loadedModules[module->moduleName] = module; + for (auto& needed : module->needed) + { + allNeeded.insert(std::string(needed)); + } + } + + for (auto needed : allNeeded) + { + auto [result, neededModule] = + loadPrx(thread, needed, false, loadedObjects, loadedModules, needed); + + if (result.isError() || neededModule == nullptr) + { + std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); + continue; + } + } + + for (auto [id, module] : thread->tproc->modulesMap) + { + module->importedModules.clear(); + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) + { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) + { + module->importedModules.emplace_back(it->second); + continue; + } + + std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", + mod.name.c_str(), module->soName); + module->importedModules.push_back({}); + } + + module->relocate(thread->tproc); + } + + return {}; + } + + SysResult registerEhFrames(Thread* thread) + { + for (auto [id, module] : thread->tproc->modulesMap) + { + if (module->ehFrame != nullptr) + { + __register_frame(module->ehFrame); + } + } + + return {}; + } + + void where(Thread* thread) + { + rx::printStackTrace((ucontext_t*)thread->context, thread, 2); + } } // namespace ProcessOps rx::procOpsTable = { - .mmap = mmap, - .dmem_mmap = dmem_mmap, - .munmap = munmap, - .msync = msync, - .mprotect = mprotect, - .minherit = minherit, - .madvise = madvise, - .mincore = mincore, - .mlock = mlock, - .mlockall = mlockall, - .munlockall = munlockall, - .munlock = munlock, - .virtual_query = virtual_query, - .query_memory_protection = query_memory_protection, - .open = open, - .shm_open = shm_open, - .mkdir = mkdir, - .rmdir = rmdir, - .rename = rename, - .blockpool_open = blockpool_open, - .blockpool_map = blockpool_map, - .blockpool_unmap = blockpool_unmap, - .socket = socket, - .shm_unlink = shm_unlink, - .dynlib_get_obj_member = dynlib_get_obj_member, - .dynlib_dlsym = dynlib_dlsym, - .dynlib_do_copy_relocations = dynlib_do_copy_relocations, - .dynlib_load_prx = dynlib_load_prx, - .dynlib_unload_prx = dynlib_unload_prx, - .thr_create = thr_create, - .thr_new = thr_new, - .thr_exit = thr_exit, - .thr_kill = thr_kill, - .thr_kill2 = thr_kill2, - .thr_suspend = thr_suspend, - .thr_wake = thr_wake, - .thr_set_name = thr_set_name, - .exit = exit, - .processNeeded = processNeeded, - .registerEhFrames = registerEhFrames, - .where = where, + .mmap = mmap, + .dmem_mmap = dmem_mmap, + .munmap = munmap, + .msync = msync, + .mprotect = mprotect, + .minherit = minherit, + .madvise = madvise, + .mincore = mincore, + .mlock = mlock, + .mlockall = mlockall, + .munlockall = munlockall, + .munlock = munlock, + .virtual_query = virtual_query, + .query_memory_protection = query_memory_protection, + .open = open, + .shm_open = shm_open, + .mkdir = mkdir, + .rmdir = rmdir, + .rename = rename, + .blockpool_open = blockpool_open, + .blockpool_map = blockpool_map, + .blockpool_unmap = blockpool_unmap, + .socket = socket, + .shm_unlink = shm_unlink, + .dynlib_get_obj_member = dynlib_get_obj_member, + .dynlib_dlsym = dynlib_dlsym, + .dynlib_do_copy_relocations = dynlib_do_copy_relocations, + .dynlib_load_prx = dynlib_load_prx, + .dynlib_unload_prx = dynlib_unload_prx, + .thr_create = thr_create, + .thr_new = thr_new, + .thr_exit = thr_exit, + .thr_kill = thr_kill, + .thr_kill2 = thr_kill2, + .thr_suspend = thr_suspend, + .thr_wake = thr_wake, + .thr_set_name = thr_set_name, + .exit = exit, + .processNeeded = processNeeded, + .registerEhFrames = registerEhFrames, + .where = where, }; diff --git a/rpcsx-os/ops.hpp b/rpcsx-os/ops.hpp index 52f7b961..1a44fc60 100644 --- a/rpcsx-os/ops.hpp +++ b/rpcsx-os/ops.hpp @@ -2,6 +2,7 @@ #include "orbis/thread/ProcessOps.hpp" -namespace rx { -extern orbis::ProcessOps procOpsTable; +namespace rx +{ + extern orbis::ProcessOps procOpsTable; } diff --git a/rpcsx-os/orbis-kernel-config/orbis-config.hpp b/rpcsx-os/orbis-kernel-config/orbis-config.hpp index fa52bf94..7229a973 100644 --- a/rpcsx-os/orbis-kernel-config/orbis-config.hpp +++ b/rpcsx-os/orbis-kernel-config/orbis-config.hpp @@ -9,195 +9,213 @@ #include #include -namespace orbis { -using int8_t = std::int8_t; -using int16_t = std::int16_t; -using int32_t = std::int32_t; -using int64_t = std::int64_t; - -using uint8_t = std::uint8_t; -using uint16_t = std::uint16_t; -using uint32_t = std::uint32_t; -using uint64_t = std::uint64_t; - -using size_t = uint64_t; -using ssize_t = int64_t; -using off_t = int64_t; - -using sshort = int16_t; -using ushort = uint16_t; - -using uint = uint32_t; -using sint = int32_t; - -using slong = int64_t; -using ulong = uint64_t; - -using uintptr_t = uint64_t; -using intptr_t = int64_t; - -template using ptr = T *; -template using cptr = T *const; - -using caddr_t = ptr; - -[[nodiscard]] inline ErrorCode -ureadRaw(void *kernelAddress, ptr userAddress, size_t size) { - auto addr = reinterpret_cast(userAddress); - if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) - return ErrorCode::FAULT; - std::memcpy(kernelAddress, userAddress, size); - return {}; -} - -[[nodiscard]] inline ErrorCode -uwriteRaw(ptr userAddress, const void *kernelAddress, size_t size) { - auto addr = reinterpret_cast(userAddress); - if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) - return ErrorCode::FAULT; - std::memcpy(userAddress, kernelAddress, size); - return {}; -} - -[[nodiscard]] inline ErrorCode ureadString(char *kernelAddress, size_t size, - ptr userAddress) { - auto addr = reinterpret_cast(userAddress); - if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) - return ErrorCode::FAULT; - std::strncpy(kernelAddress, userAddress, size); - if (kernelAddress[size - 1] != '\0') { - kernelAddress[size - 1] = '\0'; - return ErrorCode::NAMETOOLONG; - } - - return {}; -} - -template [[nodiscard]] ErrorCode uread(T &result, ptr pointer) { - return ureadRaw(&result, pointer, sizeof(T)); -} - -template [[nodiscard]] ErrorCode uwrite(ptr pointer, T data) { - return uwriteRaw(pointer, &data, sizeof(T)); -} - -template - requires(std::is_arithmetic_v && std::is_arithmetic_v && - sizeof(T) > sizeof(U) && !std::is_same_v, bool>) -[[nodiscard]] ErrorCode uwrite(ptr pointer, U data) { - T converted = data; - return uwriteRaw(pointer, &converted, sizeof(T)); -} - -template -[[nodiscard]] ErrorCode uread(T *result, ptr pointer, std::size_t count) { - return ureadRaw(&result, pointer, sizeof(T) * count); -} - -template -[[nodiscard]] ErrorCode uwrite(ptr pointer, const T *data, - std::size_t count) { - return uwriteRaw(pointer, &data, sizeof(T) * count); -} - -inline uint64_t readRegister(void *context, RegisterId id) { - auto c = &reinterpret_cast(context)->uc_mcontext; - switch (id) { - case RegisterId::r15: - return c->gregs[REG_R15]; - case RegisterId::r14: - return c->gregs[REG_R14]; - case RegisterId::r13: - return c->gregs[REG_R13]; - case RegisterId::r12: - return c->gregs[REG_R12]; - case RegisterId::r11: - return c->gregs[REG_R11]; - case RegisterId::r10: - return c->gregs[REG_R10]; - case RegisterId::r9: - return c->gregs[REG_R9]; - case RegisterId::r8: - return c->gregs[REG_R8]; - case RegisterId::rdi: - return c->gregs[REG_RDI]; - case RegisterId::rsi: - return c->gregs[REG_RSI]; - case RegisterId::rbp: - return c->gregs[REG_RBP]; - case RegisterId::rbx: - return c->gregs[REG_RBX]; - case RegisterId::rdx: - return c->gregs[REG_RDX]; - case RegisterId::rcx: - return c->gregs[REG_RCX]; - case RegisterId::rax: - return c->gregs[REG_RAX]; - case RegisterId::rsp: - return c->gregs[REG_RSP]; - case RegisterId::rflags: - return c->gregs[REG_EFL]; - } - std::fprintf(stderr, "***ERROR*** Unhandled RegisterId %d\n", - static_cast(id)); - std::abort(); -} - -inline void writeRegister(void *context, RegisterId id, uint64_t value) { - auto c = &reinterpret_cast(context)->uc_mcontext; - switch (id) { - case RegisterId::r15: - c->gregs[REG_R15] = value; - return; - case RegisterId::r14: - c->gregs[REG_R14] = value; - return; - case RegisterId::r13: - c->gregs[REG_R13] = value; - return; - case RegisterId::r12: - c->gregs[REG_R12] = value; - return; - case RegisterId::r11: - c->gregs[REG_R11] = value; - return; - case RegisterId::r10: - c->gregs[REG_R10] = value; - return; - case RegisterId::r9: - c->gregs[REG_R9] = value; - return; - case RegisterId::r8: - c->gregs[REG_R8] = value; - return; - case RegisterId::rdi: - c->gregs[REG_RDI] = value; - return; - case RegisterId::rsi: - c->gregs[REG_RSI] = value; - return; - case RegisterId::rbp: - c->gregs[REG_RBP] = value; - return; - case RegisterId::rbx: - c->gregs[REG_RBX] = value; - return; - case RegisterId::rdx: - c->gregs[REG_RDX] = value; - return; - case RegisterId::rcx: - c->gregs[REG_RCX] = value; - return; - case RegisterId::rax: - c->gregs[REG_RAX] = value; - return; - case RegisterId::rsp: - c->gregs[REG_RSP] = value; - return; - case RegisterId::rflags: - c->gregs[REG_EFL] = value; - return; - } -} +namespace orbis +{ + using int8_t = std::int8_t; + using int16_t = std::int16_t; + using int32_t = std::int32_t; + using int64_t = std::int64_t; + + using uint8_t = std::uint8_t; + using uint16_t = std::uint16_t; + using uint32_t = std::uint32_t; + using uint64_t = std::uint64_t; + + using size_t = uint64_t; + using ssize_t = int64_t; + using off_t = int64_t; + + using sshort = int16_t; + using ushort = uint16_t; + + using uint = uint32_t; + using sint = int32_t; + + using slong = int64_t; + using ulong = uint64_t; + + using uintptr_t = uint64_t; + using intptr_t = int64_t; + + template + using ptr = T*; + template + using cptr = T* const; + + using caddr_t = ptr; + + [[nodiscard]] inline ErrorCode + ureadRaw(void* kernelAddress, ptr userAddress, size_t size) + { + auto addr = reinterpret_cast(userAddress); + if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) + return ErrorCode::FAULT; + std::memcpy(kernelAddress, userAddress, size); + return {}; + } + + [[nodiscard]] inline ErrorCode + uwriteRaw(ptr userAddress, const void* kernelAddress, size_t size) + { + auto addr = reinterpret_cast(userAddress); + if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) + return ErrorCode::FAULT; + std::memcpy(userAddress, kernelAddress, size); + return {}; + } + + [[nodiscard]] inline ErrorCode ureadString(char* kernelAddress, size_t size, + ptr userAddress) + { + auto addr = reinterpret_cast(userAddress); + if (addr < 0x40000 || addr + size > 0x100'0000'0000 || addr + size < addr) + return ErrorCode::FAULT; + std::strncpy(kernelAddress, userAddress, size); + if (kernelAddress[size - 1] != '\0') + { + kernelAddress[size - 1] = '\0'; + return ErrorCode::NAMETOOLONG; + } + + return {}; + } + + template + [[nodiscard]] ErrorCode uread(T& result, ptr pointer) + { + return ureadRaw(&result, pointer, sizeof(T)); + } + + template + [[nodiscard]] ErrorCode uwrite(ptr pointer, T data) + { + return uwriteRaw(pointer, &data, sizeof(T)); + } + + template + requires(std::is_arithmetic_v&& std::is_arithmetic_v && + sizeof(T) > sizeof(U) && !std::is_same_v, bool>) + [[nodiscard]] ErrorCode uwrite(ptr pointer, U data) + { + T converted = data; + return uwriteRaw(pointer, &converted, sizeof(T)); + } + + template + [[nodiscard]] ErrorCode uread(T* result, ptr pointer, std::size_t count) + { + return ureadRaw(&result, pointer, sizeof(T) * count); + } + + template + [[nodiscard]] ErrorCode uwrite(ptr pointer, const T* data, + std::size_t count) + { + return uwriteRaw(pointer, &data, sizeof(T) * count); + } + + inline uint64_t readRegister(void* context, RegisterId id) + { + auto c = &reinterpret_cast(context)->uc_mcontext; + switch (id) + { + case RegisterId::r15: + return c->gregs[REG_R15]; + case RegisterId::r14: + return c->gregs[REG_R14]; + case RegisterId::r13: + return c->gregs[REG_R13]; + case RegisterId::r12: + return c->gregs[REG_R12]; + case RegisterId::r11: + return c->gregs[REG_R11]; + case RegisterId::r10: + return c->gregs[REG_R10]; + case RegisterId::r9: + return c->gregs[REG_R9]; + case RegisterId::r8: + return c->gregs[REG_R8]; + case RegisterId::rdi: + return c->gregs[REG_RDI]; + case RegisterId::rsi: + return c->gregs[REG_RSI]; + case RegisterId::rbp: + return c->gregs[REG_RBP]; + case RegisterId::rbx: + return c->gregs[REG_RBX]; + case RegisterId::rdx: + return c->gregs[REG_RDX]; + case RegisterId::rcx: + return c->gregs[REG_RCX]; + case RegisterId::rax: + return c->gregs[REG_RAX]; + case RegisterId::rsp: + return c->gregs[REG_RSP]; + case RegisterId::rflags: + return c->gregs[REG_EFL]; + } + std::fprintf(stderr, "***ERROR*** Unhandled RegisterId %d\n", + static_cast(id)); + std::abort(); + } + + inline void writeRegister(void* context, RegisterId id, uint64_t value) + { + auto c = &reinterpret_cast(context)->uc_mcontext; + switch (id) + { + case RegisterId::r15: + c->gregs[REG_R15] = value; + return; + case RegisterId::r14: + c->gregs[REG_R14] = value; + return; + case RegisterId::r13: + c->gregs[REG_R13] = value; + return; + case RegisterId::r12: + c->gregs[REG_R12] = value; + return; + case RegisterId::r11: + c->gregs[REG_R11] = value; + return; + case RegisterId::r10: + c->gregs[REG_R10] = value; + return; + case RegisterId::r9: + c->gregs[REG_R9] = value; + return; + case RegisterId::r8: + c->gregs[REG_R8] = value; + return; + case RegisterId::rdi: + c->gregs[REG_RDI] = value; + return; + case RegisterId::rsi: + c->gregs[REG_RSI] = value; + return; + case RegisterId::rbp: + c->gregs[REG_RBP] = value; + return; + case RegisterId::rbx: + c->gregs[REG_RBX] = value; + return; + case RegisterId::rdx: + c->gregs[REG_RDX] = value; + return; + case RegisterId::rcx: + c->gregs[REG_RCX] = value; + return; + case RegisterId::rax: + c->gregs[REG_RAX] = value; + return; + case RegisterId::rsp: + c->gregs[REG_RSP] = value; + return; + case RegisterId::rflags: + c->gregs[REG_EFL] = value; + return; + } + } } // namespace orbis diff --git a/rpcsx-os/scheduler.hpp b/rpcsx-os/scheduler.hpp index 375c3e0a..8702be41 100644 --- a/rpcsx-os/scheduler.hpp +++ b/rpcsx-os/scheduler.hpp @@ -12,141 +12,167 @@ #include #include -namespace rx { -class Scheduler { - struct CpuState { - std::mutex mtx; - std::condition_variable cond; - orbis::Thread *task = nullptr; - ucontext_t cpuContext; - }; - - struct Task { - orbis::Thread *thread; - std::function wakeupCondFn; - }; - - std::mutex taskMtx; - std::condition_variable taskCond; - std::mutex queueMtx; - std::multimap> mQueue; - std::forward_list mCpuStates; - std::vector mCpus; - std::thread mThread; - std::atomic mExit{false}; - -public: - Scheduler(std::size_t smpCount) { - mCpus.resize(smpCount); - - for (std::size_t i = 0; i < smpCount; ++i) { - auto state = &mCpuStates.emplace_front(); - mCpus[i] = std::thread{[=, this] { cpuEntry(i, state); }}; - } - - mThread = std::thread{[this] { schedulerEntry(); }}; - } - - ~Scheduler() { - mExit = true; - taskCond.notify_one(); - - for (auto &cpuState : mCpuStates) { - cpuState.cond.notify_one(); - } - - mThread.join(); - - for (auto &cpu : mCpus) { - cpu.join(); - } - } - - void enqueue(orbis::Thread *thread) { - std::lock_guard lockQueue(queueMtx); - mQueue.emplace(thread->prio, Task{.thread = thread}); - taskCond.notify_one(); - } - - [[noreturn]] void - releaseThisCpu(orbis::Thread *thread, - std::function wakeupCondFn = nullptr) { - auto cpuContext = static_cast(thread->cpuContext); - thread->cpuContext = nullptr; - thread->cpuIndex = -1; - mQueue.emplace(thread->prio, Task{.thread = thread, - .wakeupCondFn = std::move(wakeupCondFn)}); - cpuContext->task = nullptr; - ::setcontext(&cpuContext->cpuContext); - __builtin_unreachable(); - } - -private: - [[noreturn]] void invoke(orbis::Thread *thread) { - auto ctxt = reinterpret_cast(thread->context); - ::setcontext(ctxt); - __builtin_unreachable(); - } - - orbis::Thread *fetchTask() { - std::lock_guard lockQueue(queueMtx); - decltype(mQueue)::iterator foundIt = mQueue.end(); - for (auto it = mQueue.begin(); it != mQueue.end(); ++it) { - auto &[prio, task] = *it; - if (task.wakeupCondFn != nullptr && !task.wakeupCondFn()) { - continue; - } - - if (foundIt == mQueue.end() || foundIt->first < task.thread->prio) { - foundIt = it; - } - } - - if (foundIt != mQueue.end()) { - auto result = foundIt->second.thread; - mQueue.erase(foundIt); - return result; - } - - return nullptr; - } - - void schedulerEntry() { - while (!mExit.load(std::memory_order::relaxed)) { - if (mQueue.empty()) { - continue; - } - - std::unique_lock lock(taskMtx); - taskCond.wait(lock); - - for (auto &cpu : mCpuStates) { - if (cpu.task == nullptr) { - cpu.task = fetchTask(); - } - } - } - } - - void cpuEntry(std::size_t cpuIndex, CpuState *state) { - ::getcontext(&state->cpuContext); - - while (!mExit.load(std::memory_order::relaxed)) { - auto task = std::exchange(state->task, nullptr); - if (task == nullptr) { - taskCond.notify_one(); - - std::unique_lock lock(state->mtx); - state->cond.wait(lock); - task = std::exchange(state->task, nullptr); - } - - if (task != nullptr) { - task->cpuIndex = cpuIndex; - task->cpuContext = state; - invoke(task); - } - } - } -}; +namespace rx +{ + class Scheduler + { + struct CpuState + { + std::mutex mtx; + std::condition_variable cond; + orbis::Thread* task = nullptr; + ucontext_t cpuContext; + }; + + struct Task + { + orbis::Thread* thread; + std::function wakeupCondFn; + }; + + std::mutex taskMtx; + std::condition_variable taskCond; + std::mutex queueMtx; + std::multimap> mQueue; + std::forward_list mCpuStates; + std::vector mCpus; + std::thread mThread; + std::atomic mExit{false}; + + public: + Scheduler(std::size_t smpCount) + { + mCpus.resize(smpCount); + + for (std::size_t i = 0; i < smpCount; ++i) + { + auto state = &mCpuStates.emplace_front(); + mCpus[i] = std::thread{[=, this] { cpuEntry(i, state); }}; + } + + mThread = std::thread{[this] { schedulerEntry(); }}; + } + + ~Scheduler() + { + mExit = true; + taskCond.notify_one(); + + for (auto& cpuState : mCpuStates) + { + cpuState.cond.notify_one(); + } + + mThread.join(); + + for (auto& cpu : mCpus) + { + cpu.join(); + } + } + + void enqueue(orbis::Thread* thread) + { + std::lock_guard lockQueue(queueMtx); + mQueue.emplace(thread->prio, Task{.thread = thread}); + taskCond.notify_one(); + } + + [[noreturn]] void + releaseThisCpu(orbis::Thread* thread, + std::function wakeupCondFn = nullptr) + { + auto cpuContext = static_cast(thread->cpuContext); + thread->cpuContext = nullptr; + thread->cpuIndex = -1; + mQueue.emplace(thread->prio, Task{.thread = thread, + .wakeupCondFn = std::move(wakeupCondFn)}); + cpuContext->task = nullptr; + ::setcontext(&cpuContext->cpuContext); + __builtin_unreachable(); + } + + private: + [[noreturn]] void invoke(orbis::Thread* thread) + { + auto ctxt = reinterpret_cast(thread->context); + ::setcontext(ctxt); + __builtin_unreachable(); + } + + orbis::Thread* fetchTask() + { + std::lock_guard lockQueue(queueMtx); + decltype(mQueue)::iterator foundIt = mQueue.end(); + for (auto it = mQueue.begin(); it != mQueue.end(); ++it) + { + auto& [prio, task] = *it; + if (task.wakeupCondFn != nullptr && !task.wakeupCondFn()) + { + continue; + } + + if (foundIt == mQueue.end() || foundIt->first < task.thread->prio) + { + foundIt = it; + } + } + + if (foundIt != mQueue.end()) + { + auto result = foundIt->second.thread; + mQueue.erase(foundIt); + return result; + } + + return nullptr; + } + + void schedulerEntry() + { + while (!mExit.load(std::memory_order::relaxed)) + { + if (mQueue.empty()) + { + continue; + } + + std::unique_lock lock(taskMtx); + taskCond.wait(lock); + + for (auto& cpu : mCpuStates) + { + if (cpu.task == nullptr) + { + cpu.task = fetchTask(); + } + } + } + } + + void cpuEntry(std::size_t cpuIndex, CpuState* state) + { + ::getcontext(&state->cpuContext); + + while (!mExit.load(std::memory_order::relaxed)) + { + auto task = std::exchange(state->task, nullptr); + if (task == nullptr) + { + taskCond.notify_one(); + + std::unique_lock lock(state->mtx); + state->cond.wait(lock); + task = std::exchange(state->task, nullptr); + } + + if (task != nullptr) + { + task->cpuIndex = cpuIndex; + task->cpuContext = state; + invoke(task); + } + } + } + }; } // namespace rx diff --git a/rpcsx-os/thread.cpp b/rpcsx-os/thread.cpp index 5f85c0ee..c00b9cbf 100644 --- a/rpcsx-os/thread.cpp +++ b/rpcsx-os/thread.cpp @@ -12,78 +12,89 @@ #include #include -thread_local orbis::Thread *rx::thread::g_current = nullptr; +thread_local orbis::Thread* rx::thread::g_current = nullptr; static auto setContext = [] { - struct SetContext : Xbyak::CodeGenerator { - SetContext() { - mov(rbp, rdi); - mov(rax, qword[rbp + REG_RAX * sizeof(unsigned long long)]); - mov(rdi, qword[rbp + REG_RDI * sizeof(unsigned long long)]); - mov(rdx, qword[rbp + REG_RDX * sizeof(unsigned long long)]); - mov(rcx, qword[rbp + REG_RCX * sizeof(unsigned long long)]); - mov(rbx, qword[rbp + REG_RBX * sizeof(unsigned long long)]); - mov(rsi, qword[rbp + REG_RSI * sizeof(unsigned long long)]); - mov(rsp, qword[rbp + REG_RSP * sizeof(unsigned long long)]); + struct SetContext : Xbyak::CodeGenerator + { + SetContext() + { + mov(rbp, rdi); + mov(rax, qword[rbp + REG_RAX * sizeof(unsigned long long)]); + mov(rdi, qword[rbp + REG_RDI * sizeof(unsigned long long)]); + mov(rdx, qword[rbp + REG_RDX * sizeof(unsigned long long)]); + mov(rcx, qword[rbp + REG_RCX * sizeof(unsigned long long)]); + mov(rbx, qword[rbp + REG_RBX * sizeof(unsigned long long)]); + mov(rsi, qword[rbp + REG_RSI * sizeof(unsigned long long)]); + mov(rsp, qword[rbp + REG_RSP * sizeof(unsigned long long)]); - mov(rbp, qword[rbp + REG_RIP * sizeof(unsigned long long)]); - call(rbp); - } - } static setContextStorage; + mov(rbp, qword[rbp + REG_RIP * sizeof(unsigned long long)]); + call(rbp); + } + } static setContextStorage; - return setContextStorage.getCode(); + return setContextStorage.getCode(); }(); static __attribute__((no_stack_protector)) void -handleSigSys(int sig, siginfo_t *info, void *ucontext) { - if (auto hostFs = _readgsbase_u64()) { - _writefsbase_u64(hostFs); - } +handleSigSys(int sig, siginfo_t* info, void* ucontext) +{ + if (auto hostFs = _readgsbase_u64()) + { + _writefsbase_u64(hostFs); + } - // rx::printStackTrace(reinterpret_cast(ucontext), - // rx::thread::g_current, 1); - auto prevContext = std::exchange(rx::thread::g_current->context, ucontext); - orbis::syscall_entry(rx::thread::g_current); - rx::thread::g_current->context = prevContext; - _writefsbase_u64(rx::thread::g_current->fsBase); + // rx::printStackTrace(reinterpret_cast(ucontext), + // rx::thread::g_current, 1); + auto prevContext = std::exchange(rx::thread::g_current->context, ucontext); + orbis::syscall_entry(rx::thread::g_current); + rx::thread::g_current->context = prevContext; + _writefsbase_u64(rx::thread::g_current->fsBase); } -void rx::thread::initialize() { - struct sigaction act {}; - act.sa_sigaction = handleSigSys; - act.sa_flags = SA_SIGINFO | SA_ONSTACK; +void rx::thread::initialize() +{ + struct sigaction act + { + }; + act.sa_sigaction = handleSigSys; + act.sa_flags = SA_SIGINFO | SA_ONSTACK; - if (sigaction(SIGSYS, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } + if (sigaction(SIGSYS, &act, NULL)) + { + perror("Error sigaction:"); + exit(-1); + } } void rx::thread::deinitialize() {} -void rx::thread::invoke(orbis::Thread *thread) { - g_current = thread; +void rx::thread::invoke(orbis::Thread* thread) +{ + g_current = thread; - sigset_t unblockSigs{}; - sigset_t oldSigmask{}; - sigaddset(&unblockSigs, SIGSYS); - if (pthread_sigmask(SIG_UNBLOCK, &unblockSigs, &oldSigmask)) { - perror("pthread_sigmask failed\n"); - exit(-1); - } + sigset_t unblockSigs{}; + sigset_t oldSigmask{}; + sigaddset(&unblockSigs, SIGSYS); + if (pthread_sigmask(SIG_UNBLOCK, &unblockSigs, &oldSigmask)) + { + perror("pthread_sigmask failed\n"); + exit(-1); + } - std::uint64_t hostFs = _readfsbase_u64(); - _writegsbase_u64(hostFs); + std::uint64_t hostFs = _readfsbase_u64(); + _writegsbase_u64(hostFs); - if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, - (void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) { - perror("prctl failed\n"); - exit(-1); - } + if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, + (void*)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) + { + perror("prctl failed\n"); + exit(-1); + } - _writefsbase_u64(thread->fsBase); - auto context = reinterpret_cast(thread->context); + _writefsbase_u64(thread->fsBase); + auto context = reinterpret_cast(thread->context); - setContext(context->uc_mcontext); - _writefsbase_u64(hostFs); + setContext(context->uc_mcontext); + _writefsbase_u64(hostFs); } diff --git a/rpcsx-os/thread.hpp b/rpcsx-os/thread.hpp index 74452e9f..69cd2bf9 100644 --- a/rpcsx-os/thread.hpp +++ b/rpcsx-os/thread.hpp @@ -2,10 +2,11 @@ #include "orbis/thread/Thread.hpp" -namespace rx::thread { -void initialize(); -void deinitialize(); +namespace rx::thread +{ + void initialize(); + void deinitialize(); -extern thread_local orbis::Thread *g_current; -void invoke(orbis::Thread *thread); + extern thread_local orbis::Thread* g_current; + void invoke(orbis::Thread* thread); } // namespace rx::thread diff --git a/rpcsx-os/vfs.cpp b/rpcsx-os/vfs.cpp index db6ce7d6..d2ea553f 100644 --- a/rpcsx-os/vfs.cpp +++ b/rpcsx-os/vfs.cpp @@ -11,127 +11,151 @@ static std::map, std::greater<>> sMountsMap; -struct DevFs : IoDevice { - std::map> devices; - - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - if (auto it = devices.find(path); it != devices.end()) { - return it->second->open(file, path, flags, mode, thread); - } - - std::fprintf(stderr, "device %s not exists\n", path); - return orbis::ErrorCode::NOENT; - } +struct DevFs : IoDevice +{ + std::map> devices; + + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + if (auto it = devices.find(path); it != devices.end()) + { + return it->second->open(file, path, flags, mode, thread); + } + + std::fprintf(stderr, "device %s not exists\n", path); + return orbis::ErrorCode::NOENT; + } }; static orbis::Ref sDevFs; -struct ProcFs : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - std::fprintf(stderr, "procfs access: %s\n", path); - std::abort(); - return orbis::ErrorCode::NOENT; - } +struct ProcFs : IoDevice +{ + orbis::ErrorCode open(orbis::Ref* file, const char* path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread* thread) override + { + std::fprintf(stderr, "procfs access: %s\n", path); + std::abort(); + return orbis::ErrorCode::NOENT; + } }; -void rx::vfs::initialize() { - sDevFs = orbis::knew(); - sMountsMap.emplace("/dev/", sDevFs); - sMountsMap.emplace("/proc/", orbis::knew()); +void rx::vfs::initialize() +{ + sDevFs = orbis::knew(); + sMountsMap.emplace("/dev/", sDevFs); + sMountsMap.emplace("/proc/", orbis::knew()); } -void rx::vfs::deinitialize() { - sDevFs = nullptr; - sMountsMap.clear(); +void rx::vfs::deinitialize() +{ + sDevFs = nullptr; + sMountsMap.clear(); } -void rx::vfs::addDevice(std::string name, IoDevice *device) { - sDevFs->devices[std::move(name)] = device; +void rx::vfs::addDevice(std::string name, IoDevice* device) +{ + sDevFs->devices[std::move(name)] = device; } static std::pair, std::string> -get(const std::filesystem::path &guestPath) { - std::string normalPath = std::filesystem::path(guestPath).lexically_normal(); - std::string_view path = normalPath; - orbis::Ref device; - std::string_view prefix; - - for (auto &mount : sMountsMap) { - if (!path.starts_with(mount.first)) { - continue; - } - - device = mount.second; - path.remove_prefix(mount.first.length()); - return {mount.second, std::string(path)}; - } - - return {}; +get(const std::filesystem::path& guestPath) +{ + std::string normalPath = std::filesystem::path(guestPath).lexically_normal(); + std::string_view path = normalPath; + orbis::Ref device; + std::string_view prefix; + + for (auto& mount : sMountsMap) + { + if (!path.starts_with(mount.first)) + { + continue; + } + + device = mount.second; + path.remove_prefix(mount.first.length()); + return {mount.second, std::string(path)}; + } + + return {}; } -orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath, - IoDevice *dev) { - auto mp = guestPath.lexically_normal().string(); - if (!mp.ends_with("/")) { - mp += "/"; - } +orbis::SysResult rx::vfs::mount(const std::filesystem::path& guestPath, + IoDevice* dev) +{ + auto mp = guestPath.lexically_normal().string(); + if (!mp.ends_with("/")) + { + mp += "/"; + } - auto [it, inserted] = sMountsMap.emplace(std::move(mp), dev); + auto [it, inserted] = sMountsMap.emplace(std::move(mp), dev); - if (!inserted) { - return orbis::ErrorCode::EXIST; - } + if (!inserted) + { + return orbis::ErrorCode::EXIST; + } - return {}; + return {}; } orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode, - orbis::Ref *file, - orbis::Thread *thread) { - auto [device, devPath] = get(path); - if (device == nullptr) { - return orbis::ErrorCode::NOENT; - } - return device->open(file, devPath.c_str(), flags, mode, thread); + orbis::Ref* file, + orbis::Thread* thread) +{ + auto [device, devPath] = get(path); + if (device == nullptr) + { + return orbis::ErrorCode::NOENT; + } + return device->open(file, devPath.c_str(), flags, mode, thread); } orbis::SysResult rx::vfs::mkdir(std::string_view path, int mode, - orbis::Thread *thread) { - auto [device, devPath] = get(path); - if (device == nullptr) { - return orbis::ErrorCode::NOENT; - } - return device->mkdir(devPath.c_str(), mode, thread); + orbis::Thread* thread) +{ + auto [device, devPath] = get(path); + if (device == nullptr) + { + return orbis::ErrorCode::NOENT; + } + return device->mkdir(devPath.c_str(), mode, thread); } -orbis::SysResult rx::vfs::rmdir(std::string_view path, orbis::Thread *thread) { - auto [device, devPath] = get(path); - if (device == nullptr) { - return orbis::ErrorCode::NOENT; - } - return device->rmdir(devPath.c_str(), thread); +orbis::SysResult rx::vfs::rmdir(std::string_view path, orbis::Thread* thread) +{ + auto [device, devPath] = get(path); + if (device == nullptr) + { + return orbis::ErrorCode::NOENT; + } + return device->rmdir(devPath.c_str(), thread); } orbis::SysResult rx::vfs::rename(std::string_view from, std::string_view to, - orbis::Thread *thread) { - auto [fromDevice, fromDevPath] = get(from); - if (fromDevice == nullptr) { - return orbis::ErrorCode::NOENT; - } - - auto [toDevice, toDevPath] = get(to); - if (toDevice == nullptr) { - return orbis::ErrorCode::NOENT; - } - - if (fromDevice != toDevice) { - std::fprintf(stderr, "cross fs rename operation: %s -> %s\n", - std::string(from).c_str(), std::string(to).c_str()); - std::abort(); - } - - return fromDevice->rename(fromDevPath.c_str(), toDevPath.c_str(), thread); + orbis::Thread* thread) +{ + auto [fromDevice, fromDevPath] = get(from); + if (fromDevice == nullptr) + { + return orbis::ErrorCode::NOENT; + } + + auto [toDevice, toDevPath] = get(to); + if (toDevice == nullptr) + { + return orbis::ErrorCode::NOENT; + } + + if (fromDevice != toDevice) + { + std::fprintf(stderr, "cross fs rename operation: %s -> %s\n", + std::string(from).c_str(), std::string(to).c_str()); + std::abort(); + } + + return fromDevice->rename(fromDevPath.c_str(), toDevPath.c_str(), thread); } diff --git a/rpcsx-os/vfs.hpp b/rpcsx-os/vfs.hpp index 6ba69a80..661c7dfb 100644 --- a/rpcsx-os/vfs.hpp +++ b/rpcsx-os/vfs.hpp @@ -7,14 +7,15 @@ struct IoDevice; -namespace rx::vfs { -void initialize(); -void deinitialize(); -void addDevice(std::string name, IoDevice *device); -orbis::SysResult mount(const std::filesystem::path &guestPath, IoDevice *dev); -orbis::SysResult open(std::string_view path, int flags, int mode, - orbis::Ref *file, orbis::Thread *thread); -orbis::SysResult mkdir(std::string_view path, int mode, orbis::Thread *thread); -orbis::SysResult rmdir(std::string_view path, orbis::Thread *thread); -orbis::SysResult rename(std::string_view from, std::string_view to, orbis::Thread *thread); +namespace rx::vfs +{ + void initialize(); + void deinitialize(); + void addDevice(std::string name, IoDevice* device); + orbis::SysResult mount(const std::filesystem::path& guestPath, IoDevice* dev); + orbis::SysResult open(std::string_view path, int flags, int mode, + orbis::Ref* file, orbis::Thread* thread); + orbis::SysResult mkdir(std::string_view path, int mode, orbis::Thread* thread); + orbis::SysResult rmdir(std::string_view path, orbis::Thread* thread); + orbis::SysResult rename(std::string_view from, std::string_view to, orbis::Thread* thread); } // namespace rx::vfs diff --git a/rpcsx-os/vm.cpp b/rpcsx-os/vm.cpp index 46b5e1bb..264e161b 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx-os/vm.cpp @@ -18,242 +18,299 @@ #include -namespace utils { -namespace { -void *map(void *address, std::size_t size, int prot, int flags, int fd = -1, - off_t offset = 0) { - return ::mmap(address, size, prot, flags, fd, offset); -} - -void *reserve(std::size_t size) { - return map(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS); -} - -bool reserve(void *address, std::size_t size) { - return map(address, size, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) != MAP_FAILED; -} - -bool protect(void *address, std::size_t size, int prot) { - return ::mprotect(address, size, prot) == 0; -} - -bool unmap(void *address, std::size_t size) { - return ::munmap(address, size) == 0; -} -} // namespace +namespace utils +{ + namespace + { + void* map(void* address, std::size_t size, int prot, int flags, int fd = -1, + off_t offset = 0) + { + return ::mmap(address, size, prot, flags, fd, offset); + } + + void* reserve(std::size_t size) + { + return map(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS); + } + + bool reserve(void* address, std::size_t size) + { + return map(address, size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) != MAP_FAILED; + } + + bool protect(void* address, std::size_t size, int prot) + { + return ::mprotect(address, size, prot) == 0; + } + + bool unmap(void* address, std::size_t size) + { + return ::munmap(address, size) == 0; + } + } // namespace } // namespace utils static std::mutex g_mtx; -std::string rx::vm::mapFlagsToString(std::int32_t flags) { - std::string result; - - if ((flags & kMapFlagShared) == kMapFlagShared) { - if (!result.empty()) { - result += " | "; - } - - result += "Shared"; - flags &= ~kMapFlagShared; - } - if ((flags & kMapFlagPrivate) == kMapFlagPrivate) { - if (!result.empty()) { - result += " | "; - } - - result += "Private"; - flags &= ~kMapFlagPrivate; - } - if ((flags & kMapFlagFixed) == kMapFlagFixed) { - if (!result.empty()) { - result += " | "; - } - - result += "Fixed"; - flags &= ~kMapFlagFixed; - } - if ((flags & kMapFlagRename) == kMapFlagRename) { - if (!result.empty()) { - result += " | "; - } - - result += "Rename"; - flags &= ~kMapFlagRename; - } - if ((flags & kMapFlagNoReserve) == kMapFlagNoReserve) { - if (!result.empty()) { - result += " | "; - } - - result += "NoReserve"; - flags &= ~kMapFlagNoReserve; - } - if ((flags & kMapFlagNoOverwrite) == kMapFlagNoOverwrite) { - if (!result.empty()) { - result += " | "; - } - - result += "NoOverwrite"; - flags &= ~kMapFlagNoOverwrite; - } - if ((flags & kMapFlagVoid) == kMapFlagVoid) { - if (!result.empty()) { - result += " | "; - } - - result += "Void"; - flags &= ~kMapFlagVoid; - } - if ((flags & kMapFlagHasSemaphore) == kMapFlagHasSemaphore) { - if (!result.empty()) { - result += " | "; - } - - result += "HasSemaphore"; - flags &= ~kMapFlagHasSemaphore; - } - if ((flags & kMapFlagStack) == kMapFlagStack) { - if (!result.empty()) { - result += " | "; - } - - result += "Stack"; - flags &= ~kMapFlagStack; - } - if ((flags & kMapFlagNoSync) == kMapFlagNoSync) { - if (!result.empty()) { - result += " | "; - } - - result += "NoSync"; - flags &= ~kMapFlagNoSync; - } - if ((flags & kMapFlagAnonymous) == kMapFlagAnonymous) { - if (!result.empty()) { - result += " | "; - } - - result += "Anonymous"; - flags &= ~kMapFlagAnonymous; - } - if ((flags & kMapFlagSystem) == kMapFlagSystem) { - if (!result.empty()) { - result += " | "; - } - - result += "System"; - flags &= ~kMapFlagSystem; - } - if ((flags & kMapFlagAllAvailable) == kMapFlagAllAvailable) { - if (!result.empty()) { - result += " | "; - } - - result += "AllAvailable"; - flags &= ~kMapFlagAllAvailable; - } - if ((flags & kMapFlagNoCore) == kMapFlagNoCore) { - if (!result.empty()) { - result += " | "; - } - - result += "NoCore"; - flags &= ~kMapFlagNoCore; - } - if ((flags & kMapFlagPrefaultRead) == kMapFlagPrefaultRead) { - if (!result.empty()) { - result += " | "; - } - - result += "PrefaultRead"; - flags &= ~kMapFlagPrefaultRead; - } - if ((flags & kMapFlagSelf) == kMapFlagSelf) { - if (!result.empty()) { - result += " | "; - } - - result += "Self"; - flags &= ~kMapFlagSelf; - } - - auto alignment = (flags & kMapFlagsAlignMask) >> kMapFlagsAlignShift; - flags &= ~kMapFlagsAlignMask; - - if (alignment != 0) { - if (!result.empty()) { - result += " | "; - } - - result += "Alignment(" + std::to_string(alignment) + ")"; - } - - if (flags != 0) { - if (!result.empty()) { - result += " | "; - } - - result += std::to_string(flags); - } - - return result; +std::string rx::vm::mapFlagsToString(std::int32_t flags) +{ + std::string result; + + if ((flags & kMapFlagShared) == kMapFlagShared) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Shared"; + flags &= ~kMapFlagShared; + } + if ((flags & kMapFlagPrivate) == kMapFlagPrivate) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Private"; + flags &= ~kMapFlagPrivate; + } + if ((flags & kMapFlagFixed) == kMapFlagFixed) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Fixed"; + flags &= ~kMapFlagFixed; + } + if ((flags & kMapFlagRename) == kMapFlagRename) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Rename"; + flags &= ~kMapFlagRename; + } + if ((flags & kMapFlagNoReserve) == kMapFlagNoReserve) + { + if (!result.empty()) + { + result += " | "; + } + + result += "NoReserve"; + flags &= ~kMapFlagNoReserve; + } + if ((flags & kMapFlagNoOverwrite) == kMapFlagNoOverwrite) + { + if (!result.empty()) + { + result += " | "; + } + + result += "NoOverwrite"; + flags &= ~kMapFlagNoOverwrite; + } + if ((flags & kMapFlagVoid) == kMapFlagVoid) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Void"; + flags &= ~kMapFlagVoid; + } + if ((flags & kMapFlagHasSemaphore) == kMapFlagHasSemaphore) + { + if (!result.empty()) + { + result += " | "; + } + + result += "HasSemaphore"; + flags &= ~kMapFlagHasSemaphore; + } + if ((flags & kMapFlagStack) == kMapFlagStack) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Stack"; + flags &= ~kMapFlagStack; + } + if ((flags & kMapFlagNoSync) == kMapFlagNoSync) + { + if (!result.empty()) + { + result += " | "; + } + + result += "NoSync"; + flags &= ~kMapFlagNoSync; + } + if ((flags & kMapFlagAnonymous) == kMapFlagAnonymous) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Anonymous"; + flags &= ~kMapFlagAnonymous; + } + if ((flags & kMapFlagSystem) == kMapFlagSystem) + { + if (!result.empty()) + { + result += " | "; + } + + result += "System"; + flags &= ~kMapFlagSystem; + } + if ((flags & kMapFlagAllAvailable) == kMapFlagAllAvailable) + { + if (!result.empty()) + { + result += " | "; + } + + result += "AllAvailable"; + flags &= ~kMapFlagAllAvailable; + } + if ((flags & kMapFlagNoCore) == kMapFlagNoCore) + { + if (!result.empty()) + { + result += " | "; + } + + result += "NoCore"; + flags &= ~kMapFlagNoCore; + } + if ((flags & kMapFlagPrefaultRead) == kMapFlagPrefaultRead) + { + if (!result.empty()) + { + result += " | "; + } + + result += "PrefaultRead"; + flags &= ~kMapFlagPrefaultRead; + } + if ((flags & kMapFlagSelf) == kMapFlagSelf) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Self"; + flags &= ~kMapFlagSelf; + } + + auto alignment = (flags & kMapFlagsAlignMask) >> kMapFlagsAlignShift; + flags &= ~kMapFlagsAlignMask; + + if (alignment != 0) + { + if (!result.empty()) + { + result += " | "; + } + + result += "Alignment(" + std::to_string(alignment) + ")"; + } + + if (flags != 0) + { + if (!result.empty()) + { + result += " | "; + } + + result += std::to_string(flags); + } + + return result; } -std::string rx::vm::mapProtToString(std::int32_t prot) { - std::string result; - - if ((prot & kMapProtCpuRead) == kMapProtCpuRead) { - if (!result.empty()) { - result += " | "; - } - result += "CpuRead"; - prot &= ~kMapProtCpuRead; - } - if ((prot & kMapProtCpuWrite) == kMapProtCpuWrite) { - if (!result.empty()) { - result += " | "; - } - result += "CpuWrite"; - prot &= ~kMapProtCpuWrite; - } - if ((prot & kMapProtCpuExec) == kMapProtCpuExec) { - if (!result.empty()) { - result += " | "; - } - result += "CpuExec"; - prot &= ~kMapProtCpuExec; - } - if ((prot & kMapProtGpuRead) == kMapProtGpuRead) { - if (!result.empty()) { - result += " | "; - } - result += "GpuRead"; - prot &= ~kMapProtGpuRead; - } - if ((prot & kMapProtGpuWrite) == kMapProtGpuWrite) { - if (!result.empty()) { - result += " | "; - } - result += "GpuWrite"; - prot &= ~kMapProtGpuWrite; - } - - if (prot != 0) { - if (!result.empty()) { - result += " | "; - } - - result += std::to_string(prot); - } - - return result; +std::string rx::vm::mapProtToString(std::int32_t prot) +{ + std::string result; + + if ((prot & kMapProtCpuRead) == kMapProtCpuRead) + { + if (!result.empty()) + { + result += " | "; + } + result += "CpuRead"; + prot &= ~kMapProtCpuRead; + } + if ((prot & kMapProtCpuWrite) == kMapProtCpuWrite) + { + if (!result.empty()) + { + result += " | "; + } + result += "CpuWrite"; + prot &= ~kMapProtCpuWrite; + } + if ((prot & kMapProtCpuExec) == kMapProtCpuExec) + { + if (!result.empty()) + { + result += " | "; + } + result += "CpuExec"; + prot &= ~kMapProtCpuExec; + } + if ((prot & kMapProtGpuRead) == kMapProtGpuRead) + { + if (!result.empty()) + { + result += " | "; + } + result += "GpuRead"; + prot &= ~kMapProtGpuRead; + } + if ((prot & kMapProtGpuWrite) == kMapProtGpuWrite) + { + if (!result.empty()) + { + result += " | "; + } + result += "GpuWrite"; + prot &= ~kMapProtGpuWrite; + } + + if (prot != 0) + { + if (!result.empty()) + { + result += " | "; + } + + result += std::to_string(prot); + } + + return result; } static constexpr std::uint64_t kPageMask = rx::vm::kPageSize - 1; static constexpr std::uint64_t kBlockShift = 32; static constexpr std::uint64_t kBlockSize = static_cast(1) - << kBlockShift; + << kBlockShift; static constexpr std::uint64_t kBlockMask = kBlockSize - 1; static constexpr std::uint64_t kPagesInBlock = kBlockSize / rx::vm::kPageSize; static constexpr std::uint64_t kFirstBlock = 0x00; @@ -263,551 +320,644 @@ static constexpr std::uint64_t kGroupSize = 64; static constexpr std::uint64_t kGroupMask = kGroupSize - 1; static constexpr std::uint64_t kGroupsInBlock = kPagesInBlock / kGroupSize; static constexpr std::uint64_t kMinAddress = - kFirstBlock * kBlockSize + rx::vm::kPageSize * 0x10; + kFirstBlock * kBlockSize + rx::vm::kPageSize * 0x10; static constexpr std::uint64_t kMaxAddress = (kLastBlock + 1) * kBlockSize - 1; static constexpr std::uint64_t kMemorySize = kBlockCount * kBlockSize; static int gMemoryShm = -1; -struct Group { - std::uint64_t allocated; - std::uint64_t readable; - std::uint64_t writable; - std::uint64_t executable; - std::uint64_t gpuReadable; - std::uint64_t gpuWritable; +struct Group +{ + std::uint64_t allocated; + std::uint64_t readable; + std::uint64_t writable; + std::uint64_t executable; + std::uint64_t gpuReadable; + std::uint64_t gpuWritable; }; -enum { - kReadable = rx::vm::kMapProtCpuRead, - kWritable = rx::vm::kMapProtCpuWrite, - kExecutable = rx::vm::kMapProtCpuExec, - kGpuReadable = rx::vm::kMapProtGpuRead, - kGpuWritable = rx::vm::kMapProtGpuWrite, +enum +{ + kReadable = rx::vm::kMapProtCpuRead, + kWritable = rx::vm::kMapProtCpuWrite, + kExecutable = rx::vm::kMapProtCpuExec, + kGpuReadable = rx::vm::kMapProtGpuRead, + kGpuWritable = rx::vm::kMapProtGpuWrite, - kAllocated = 1 << 3, + kAllocated = 1 << 3, }; inline constexpr std::uint64_t makePagesMask(std::uint64_t page, - std::uint64_t count) { - if (count == 64) { - return ~0ull << page; - } - - return ((1ull << count) - 1ull) << page; + std::uint64_t count) +{ + if (count == 64) + { + return ~0ull << page; + } + + return ((1ull << count) - 1ull) << page; } -struct Block { - Group groups[kGroupsInBlock]; - - void setFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t flags) { - modifyFlags(firstPage, pagesCount, flags, ~static_cast(0)); - } - - void addFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t flags) { - modifyFlags(firstPage, pagesCount, flags, 0); - } - - void removeFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t flags) { - modifyFlags(firstPage, pagesCount, 0, flags); - } - - unsigned getProtection(std::uint64_t page) const { - std::uint64_t groupIndex = page / kGroupSize; - auto mask = makePagesMask(page & kGroupMask, 1); - auto &group = groups[groupIndex]; - - if ((group.allocated & mask) == 0) { - return 0; - } - - unsigned result = 0; - - result |= (group.readable & mask) == mask ? kReadable : 0; - result |= (group.writable & mask) == mask ? kReadable | kWritable : 0; - - result |= (group.executable & mask) == mask ? kReadable | kExecutable : 0; - - result |= (group.gpuReadable & mask) == mask ? kGpuReadable : 0; - result |= (group.gpuWritable & mask) == mask ? kGpuWritable : 0; - - return result; - } - - void modifyFlags(std::uint64_t firstPage, std::uint64_t pagesCount, - std::uint32_t addFlags, std::uint32_t removeFlags) { - std::uint64_t groupIndex = firstPage / kGroupSize; - - std::uint64_t addAllocatedFlags = - (addFlags & kAllocated) ? ~static_cast(0) : 0; - std::uint64_t addReadableFlags = - (addFlags & kReadable) ? ~static_cast(0) : 0; - std::uint64_t addWritableFlags = - (addFlags & kWritable) ? ~static_cast(0) : 0; - std::uint64_t addExecutableFlags = - (addFlags & kExecutable) ? ~static_cast(0) : 0; - std::uint64_t addGpuReadableFlags = - (addFlags & kGpuReadable) ? ~static_cast(0) : 0; - std::uint64_t addGpuWritableFlags = - (addFlags & kGpuWritable) ? ~static_cast(0) : 0; - - std::uint64_t removeAllocatedFlags = - (removeFlags & kAllocated) ? ~static_cast(0) : 0; - std::uint64_t removeReadableFlags = - (removeFlags & kReadable) ? ~static_cast(0) : 0; - std::uint64_t removeWritableFlags = - (removeFlags & kWritable) ? ~static_cast(0) : 0; - std::uint64_t removeExecutableFlags = - (removeFlags & kExecutable) ? ~static_cast(0) : 0; - std::uint64_t removeGpuReadableFlags = - (removeFlags & kGpuReadable) ? ~static_cast(0) : 0; - std::uint64_t removeGpuWritableFlags = - (removeFlags & kGpuWritable) ? ~static_cast(0) : 0; - - if ((firstPage & kGroupMask) != 0) { - auto count = kGroupSize - (firstPage & kGroupMask); - - if (count > pagesCount) { - count = pagesCount; - } - - auto mask = makePagesMask(firstPage & kGroupMask, count); - pagesCount -= count; - - auto &group = groups[groupIndex++]; - - group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | - (addAllocatedFlags & mask); - group.readable = (group.readable & ~(removeReadableFlags & mask)) | - (addReadableFlags & mask); - group.writable = (group.writable & ~(removeWritableFlags & mask)) | - (addWritableFlags & mask); - group.executable = (group.executable & ~(removeExecutableFlags & mask)) | - (addExecutableFlags & mask); - group.gpuReadable = - (group.gpuReadable & ~(removeGpuReadableFlags & mask)) | - (addGpuReadableFlags & mask); - group.gpuWritable = - (group.gpuWritable & ~(removeGpuWritableFlags & mask)) | - (addGpuWritableFlags & mask); - } - - while (pagesCount >= kGroupSize) { - pagesCount -= kGroupSize; - - auto &group = groups[groupIndex++]; - - group.allocated = - (group.allocated & ~removeAllocatedFlags) | addAllocatedFlags; - group.readable = - (group.readable & ~removeReadableFlags) | addReadableFlags; - group.writable = - (group.writable & ~removeWritableFlags) | addWritableFlags; - group.executable = - (group.executable & ~removeExecutableFlags) | addExecutableFlags; - group.gpuReadable = - (group.gpuReadable & ~removeGpuReadableFlags) | addGpuReadableFlags; - group.gpuWritable = - (group.gpuWritable & ~removeGpuWritableFlags) | addGpuWritableFlags; - } - - if (pagesCount > 0) { - auto mask = makePagesMask(0, pagesCount); - auto &group = groups[groupIndex++]; - - group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | - (addAllocatedFlags & mask); - group.readable = (group.readable & ~(removeReadableFlags & mask)) | - (addReadableFlags & mask); - group.writable = (group.writable & ~(removeWritableFlags & mask)) | - (addWritableFlags & mask); - group.executable = (group.executable & ~(removeExecutableFlags & mask)) | - (addExecutableFlags & mask); - group.gpuReadable = - (group.gpuReadable & ~(removeGpuReadableFlags & mask)) | - (addGpuReadableFlags & mask); - group.gpuWritable = - (group.gpuWritable & ~(removeGpuWritableFlags & mask)) | - (addGpuWritableFlags & mask); - } - } - - bool isFreePages(std::uint64_t page, std::uint64_t count) { - auto groupIndex = page / kGroupSize; - - std::uint64_t foundCount = 0; - - { - auto pageInGroup = page % kGroupSize; - auto allocatedBits = groups[groupIndex].allocated; - auto freePages = std::countr_zero(allocatedBits >> pageInGroup); - - if (freePages < count && freePages + pageInGroup < kGroupSize) { - return false; - } - - foundCount += freePages; - } - - for (++groupIndex; groupIndex < kGroupsInBlock && foundCount < count; - ++groupIndex) { - auto allocatedBits = groups[groupIndex].allocated; - auto freePages = std::countr_zero(allocatedBits); - foundCount += freePages; - - if (freePages != kGroupSize) { - break; - } - } - - return foundCount >= count; - } - - std::uint64_t findFreePages(std::uint64_t count, std::uint64_t alignment) { - std::uint64_t foundCount = 0; - std::uint64_t foundPage = 0; - - if (alignment < kGroupSize * rx::vm::kPageSize) { - std::uint64_t groupAlignment = alignment >> rx::vm::kPageShift; - - for (std::uint64_t groupIndex = 0; - groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) { - auto allocatedBits = groups[groupIndex].allocated; - - if (foundCount != 0) { - // we already found block with free pages at the end - if (count - foundCount >= kGroupSize) { - // we need whole group. if it not empty, we need to try next range - if (allocatedBits != 0) { - foundCount = 0; - } else { - foundCount += kGroupSize; - } - } else { - if (allocatedBits == 0) { - // whole group is clear, fast path - foundCount += kGroupSize; - break; - } else { - // add free pages from beginning of the current group - foundCount += std::countr_zero(allocatedBits); - - if (foundCount >= count) { - break; - } - - // not enough free pages, need to try next range - foundCount = 0; - } - } - } - - if (foundCount == 0) { - if (~allocatedBits == 0) { - continue; - } - - if (count < kGroupSize) { - // For small allocations try to find free room from beggining of - // group - auto tmpAllocatedBits = allocatedBits; - std::uint64_t processedPages = 0; - - while (processedPages < kGroupSize) { - auto freeCount = std::countr_zero(tmpAllocatedBits); - if (freeCount + processedPages > kGroupSize) { - freeCount = kGroupSize - processedPages; - } - - processedPages += freeCount; - if (freeCount >= 64) { - tmpAllocatedBits = 0; - } else { - tmpAllocatedBits >>= freeCount; - } - - if (freeCount >= count || - (freeCount > 0 && processedPages >= kGroupSize)) { - foundPage = - groupIndex * kGroupSize + processedPages - freeCount; - foundCount = freeCount; - break; - } - - while (auto usedCount = std::countr_one(tmpAllocatedBits)) { - auto nextProcessedPages = - utils::alignUp(processedPages + usedCount, groupAlignment); - if (nextProcessedPages - processedPages >= 64) { - tmpAllocatedBits = 0; - } else { - tmpAllocatedBits >>= nextProcessedPages - processedPages; - } - processedPages = nextProcessedPages; - } - } - } else { - // this is big allocation, count free last pages in block, continue - // searching on next iterations - auto freeCount = std::countl_zero(allocatedBits); - auto alignedPageIndex = - utils::alignUp(kGroupSize - freeCount, groupAlignment); - freeCount = - kGroupSize - alignedPageIndex; // calc aligned free pages - - foundCount = freeCount; - foundPage = groupIndex * kGroupSize + alignedPageIndex; - } - } - } - } else { - std::uint64_t blockAlignment = - alignment / (kGroupSize * rx::vm::kPageSize); - - for (std::uint64_t groupIndex = 0; - groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) { - if (foundCount == 0) { - groupIndex = utils::alignUp(groupIndex, blockAlignment); - - if (groupIndex >= kGroupsInBlock) { - break; - } - } - - auto allocatedBits = groups[groupIndex].allocated; - - if (allocatedBits == 0) { - if (foundCount == 0) { - foundPage = groupIndex * kGroupSize; - } - - foundCount += kGroupSize; - } else { - if (foundCount == 0 && count < kGroupSize) { - auto freeCount = std::countr_zero(allocatedBits); - - if (freeCount >= count) { - foundPage = groupIndex * kGroupSize; - foundCount = freeCount; - break; - } - } - - foundCount = 0; - } - } - } - - if (foundCount >= count) { - assert(((foundPage << rx::vm::kPageShift) & (alignment - 1)) == 0); - return foundPage; - } - - return ~static_cast(0); - } +struct Block +{ + Group groups[kGroupsInBlock]; + + void setFlags(std::uint64_t firstPage, std::uint64_t pagesCount, + std::uint32_t flags) + { + modifyFlags(firstPage, pagesCount, flags, ~static_cast(0)); + } + + void addFlags(std::uint64_t firstPage, std::uint64_t pagesCount, + std::uint32_t flags) + { + modifyFlags(firstPage, pagesCount, flags, 0); + } + + void removeFlags(std::uint64_t firstPage, std::uint64_t pagesCount, + std::uint32_t flags) + { + modifyFlags(firstPage, pagesCount, 0, flags); + } + + unsigned getProtection(std::uint64_t page) const + { + std::uint64_t groupIndex = page / kGroupSize; + auto mask = makePagesMask(page & kGroupMask, 1); + auto& group = groups[groupIndex]; + + if ((group.allocated & mask) == 0) + { + return 0; + } + + unsigned result = 0; + + result |= (group.readable & mask) == mask ? kReadable : 0; + result |= (group.writable & mask) == mask ? kReadable | kWritable : 0; + + result |= (group.executable & mask) == mask ? kReadable | kExecutable : 0; + + result |= (group.gpuReadable & mask) == mask ? kGpuReadable : 0; + result |= (group.gpuWritable & mask) == mask ? kGpuWritable : 0; + + return result; + } + + void modifyFlags(std::uint64_t firstPage, std::uint64_t pagesCount, + std::uint32_t addFlags, std::uint32_t removeFlags) + { + std::uint64_t groupIndex = firstPage / kGroupSize; + + std::uint64_t addAllocatedFlags = + (addFlags & kAllocated) ? ~static_cast(0) : 0; + std::uint64_t addReadableFlags = + (addFlags & kReadable) ? ~static_cast(0) : 0; + std::uint64_t addWritableFlags = + (addFlags & kWritable) ? ~static_cast(0) : 0; + std::uint64_t addExecutableFlags = + (addFlags & kExecutable) ? ~static_cast(0) : 0; + std::uint64_t addGpuReadableFlags = + (addFlags & kGpuReadable) ? ~static_cast(0) : 0; + std::uint64_t addGpuWritableFlags = + (addFlags & kGpuWritable) ? ~static_cast(0) : 0; + + std::uint64_t removeAllocatedFlags = + (removeFlags & kAllocated) ? ~static_cast(0) : 0; + std::uint64_t removeReadableFlags = + (removeFlags & kReadable) ? ~static_cast(0) : 0; + std::uint64_t removeWritableFlags = + (removeFlags & kWritable) ? ~static_cast(0) : 0; + std::uint64_t removeExecutableFlags = + (removeFlags & kExecutable) ? ~static_cast(0) : 0; + std::uint64_t removeGpuReadableFlags = + (removeFlags & kGpuReadable) ? ~static_cast(0) : 0; + std::uint64_t removeGpuWritableFlags = + (removeFlags & kGpuWritable) ? ~static_cast(0) : 0; + + if ((firstPage & kGroupMask) != 0) + { + auto count = kGroupSize - (firstPage & kGroupMask); + + if (count > pagesCount) + { + count = pagesCount; + } + + auto mask = makePagesMask(firstPage & kGroupMask, count); + pagesCount -= count; + + auto& group = groups[groupIndex++]; + + group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | + (addAllocatedFlags & mask); + group.readable = (group.readable & ~(removeReadableFlags & mask)) | + (addReadableFlags & mask); + group.writable = (group.writable & ~(removeWritableFlags & mask)) | + (addWritableFlags & mask); + group.executable = (group.executable & ~(removeExecutableFlags & mask)) | + (addExecutableFlags & mask); + group.gpuReadable = + (group.gpuReadable & ~(removeGpuReadableFlags & mask)) | + (addGpuReadableFlags & mask); + group.gpuWritable = + (group.gpuWritable & ~(removeGpuWritableFlags & mask)) | + (addGpuWritableFlags & mask); + } + + while (pagesCount >= kGroupSize) + { + pagesCount -= kGroupSize; + + auto& group = groups[groupIndex++]; + + group.allocated = + (group.allocated & ~removeAllocatedFlags) | addAllocatedFlags; + group.readable = + (group.readable & ~removeReadableFlags) | addReadableFlags; + group.writable = + (group.writable & ~removeWritableFlags) | addWritableFlags; + group.executable = + (group.executable & ~removeExecutableFlags) | addExecutableFlags; + group.gpuReadable = + (group.gpuReadable & ~removeGpuReadableFlags) | addGpuReadableFlags; + group.gpuWritable = + (group.gpuWritable & ~removeGpuWritableFlags) | addGpuWritableFlags; + } + + if (pagesCount > 0) + { + auto mask = makePagesMask(0, pagesCount); + auto& group = groups[groupIndex++]; + + group.allocated = (group.allocated & ~(removeAllocatedFlags & mask)) | + (addAllocatedFlags & mask); + group.readable = (group.readable & ~(removeReadableFlags & mask)) | + (addReadableFlags & mask); + group.writable = (group.writable & ~(removeWritableFlags & mask)) | + (addWritableFlags & mask); + group.executable = (group.executable & ~(removeExecutableFlags & mask)) | + (addExecutableFlags & mask); + group.gpuReadable = + (group.gpuReadable & ~(removeGpuReadableFlags & mask)) | + (addGpuReadableFlags & mask); + group.gpuWritable = + (group.gpuWritable & ~(removeGpuWritableFlags & mask)) | + (addGpuWritableFlags & mask); + } + } + + bool isFreePages(std::uint64_t page, std::uint64_t count) + { + auto groupIndex = page / kGroupSize; + + std::uint64_t foundCount = 0; + + { + auto pageInGroup = page % kGroupSize; + auto allocatedBits = groups[groupIndex].allocated; + auto freePages = std::countr_zero(allocatedBits >> pageInGroup); + + if (freePages < count && freePages + pageInGroup < kGroupSize) + { + return false; + } + + foundCount += freePages; + } + + for (++groupIndex; groupIndex < kGroupsInBlock && foundCount < count; + ++groupIndex) + { + auto allocatedBits = groups[groupIndex].allocated; + auto freePages = std::countr_zero(allocatedBits); + foundCount += freePages; + + if (freePages != kGroupSize) + { + break; + } + } + + return foundCount >= count; + } + + std::uint64_t findFreePages(std::uint64_t count, std::uint64_t alignment) + { + std::uint64_t foundCount = 0; + std::uint64_t foundPage = 0; + + if (alignment < kGroupSize * rx::vm::kPageSize) + { + std::uint64_t groupAlignment = alignment >> rx::vm::kPageShift; + + for (std::uint64_t groupIndex = 0; + groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) + { + auto allocatedBits = groups[groupIndex].allocated; + + if (foundCount != 0) + { + // we already found block with free pages at the end + if (count - foundCount >= kGroupSize) + { + // we need whole group. if it not empty, we need to try next range + if (allocatedBits != 0) + { + foundCount = 0; + } + else + { + foundCount += kGroupSize; + } + } + else + { + if (allocatedBits == 0) + { + // whole group is clear, fast path + foundCount += kGroupSize; + break; + } + else + { + // add free pages from beginning of the current group + foundCount += std::countr_zero(allocatedBits); + + if (foundCount >= count) + { + break; + } + + // not enough free pages, need to try next range + foundCount = 0; + } + } + } + + if (foundCount == 0) + { + if (~allocatedBits == 0) + { + continue; + } + + if (count < kGroupSize) + { + // For small allocations try to find free room from beggining of + // group + auto tmpAllocatedBits = allocatedBits; + std::uint64_t processedPages = 0; + + while (processedPages < kGroupSize) + { + auto freeCount = std::countr_zero(tmpAllocatedBits); + if (freeCount + processedPages > kGroupSize) + { + freeCount = kGroupSize - processedPages; + } + + processedPages += freeCount; + if (freeCount >= 64) + { + tmpAllocatedBits = 0; + } + else + { + tmpAllocatedBits >>= freeCount; + } + + if (freeCount >= count || + (freeCount > 0 && processedPages >= kGroupSize)) + { + foundPage = + groupIndex * kGroupSize + processedPages - freeCount; + foundCount = freeCount; + break; + } + + while (auto usedCount = std::countr_one(tmpAllocatedBits)) + { + auto nextProcessedPages = + utils::alignUp(processedPages + usedCount, groupAlignment); + if (nextProcessedPages - processedPages >= 64) + { + tmpAllocatedBits = 0; + } + else + { + tmpAllocatedBits >>= nextProcessedPages - processedPages; + } + processedPages = nextProcessedPages; + } + } + } + else + { + // this is big allocation, count free last pages in block, continue + // searching on next iterations + auto freeCount = std::countl_zero(allocatedBits); + auto alignedPageIndex = + utils::alignUp(kGroupSize - freeCount, groupAlignment); + freeCount = + kGroupSize - alignedPageIndex; // calc aligned free pages + + foundCount = freeCount; + foundPage = groupIndex * kGroupSize + alignedPageIndex; + } + } + } + } + else + { + std::uint64_t blockAlignment = + alignment / (kGroupSize * rx::vm::kPageSize); + + for (std::uint64_t groupIndex = 0; + groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) + { + if (foundCount == 0) + { + groupIndex = utils::alignUp(groupIndex, blockAlignment); + + if (groupIndex >= kGroupsInBlock) + { + break; + } + } + + auto allocatedBits = groups[groupIndex].allocated; + + if (allocatedBits == 0) + { + if (foundCount == 0) + { + foundPage = groupIndex * kGroupSize; + } + + foundCount += kGroupSize; + } + else + { + if (foundCount == 0 && count < kGroupSize) + { + auto freeCount = std::countr_zero(allocatedBits); + + if (freeCount >= count) + { + foundPage = groupIndex * kGroupSize; + foundCount = freeCount; + break; + } + } + + foundCount = 0; + } + } + } + + if (foundCount >= count) + { + assert(((foundPage << rx::vm::kPageShift) & (alignment - 1)) == 0); + return foundPage; + } + + return ~static_cast(0); + } }; static Block gBlocks[kBlockCount]; -struct MapInfo { - orbis::Ref device; - std::uint64_t offset; - std::uint32_t flags; - char name[32]; +struct MapInfo +{ + orbis::Ref device; + std::uint64_t offset; + std::uint32_t flags; + char name[32]; - bool operator==(const MapInfo &) const = default; + bool operator==(const MapInfo&) const = default; }; static rx::MemoryTableWithPayload gMapInfo; -static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) { - auto blockIndex = startAddress >> kBlockShift; +static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) +{ + auto blockIndex = startAddress >> kBlockShift; - assert(endAddress > startAddress); - assert(blockIndex == (endAddress >> kBlockShift)); + assert(endAddress > startAddress); + assert(blockIndex == (endAddress >> kBlockShift)); - auto firstPage = (startAddress & kBlockMask) >> rx::vm::kPageShift; - auto pagesCount = (endAddress - startAddress + (rx::vm::kPageSize - 1)) >> - rx::vm::kPageShift; + auto firstPage = (startAddress & kBlockMask) >> rx::vm::kPageShift; + auto pagesCount = (endAddress - startAddress + (rx::vm::kPageSize - 1)) >> + rx::vm::kPageShift; - gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated); + gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated); } -void rx::vm::initialize() { - std::printf("Memory: initialization\n"); +void rx::vm::initialize() +{ + std::printf("Memory: initialization\n"); - gMemoryShm = - ::shm_open("/rpcsx-os-memory", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + gMemoryShm = + ::shm_open("/rpcsx-os-memory", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - if (gMemoryShm == -1) { - std::fprintf(stderr, "Memory: failed to open /rpcsx-os-memory\n"); - std::abort(); - } + if (gMemoryShm == -1) + { + std::fprintf(stderr, "Memory: failed to open /rpcsx-os-memory\n"); + std::abort(); + } - if (::ftruncate64(gMemoryShm, kMemorySize) < 0) { - std::fprintf(stderr, "Memory: failed to allocate /rpcsx-os-memory\n"); - std::abort(); - } + if (::ftruncate64(gMemoryShm, kMemorySize) < 0) + { + std::fprintf(stderr, "Memory: failed to allocate /rpcsx-os-memory\n"); + std::abort(); + } - reserve(0, kMinAddress); // unmapped area + reserve(0, kMinAddress); // unmapped area - utils::reserve(reinterpret_cast(kMinAddress), - kMaxAddress - kMinAddress); + utils::reserve(reinterpret_cast(kMinAddress), + kMaxAddress - kMinAddress); - // orbis::bridge.setUpSharedMemory(kMinAddress, kMemorySize, "/orbis-memory"); + // orbis::bridge.setUpSharedMemory(kMinAddress, kMemorySize, "/orbis-memory"); } -void rx::vm::deinitialize() { - std::printf("Memory: shutdown\n"); - ::close(gMemoryShm); - gMemoryShm = -1; - ::shm_unlink("/orbis-memory"); - - for (auto &block : gBlocks) { - block = {}; - } +void rx::vm::deinitialize() +{ + std::printf("Memory: shutdown\n"); + ::close(gMemoryShm); + gMemoryShm = -1; + ::shm_unlink("/orbis-memory"); + + for (auto& block : gBlocks) + { + block = {}; + } } constexpr auto kPhysicalMemorySize = 5568ull * 1024 * 1024; constexpr auto kFlexibleMemorySize = 448ull * 1024 * 1024; constexpr auto kMainDirectMemorySize = - kPhysicalMemorySize - kFlexibleMemorySize; - -void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, - std::int32_t flags, std::int32_t internalFlags, - IoDevice *device, std::uint64_t offset) { - std::fprintf(stderr, - "rx::vm::map(addr = %p, len = %" PRIu64 - ", prot = %s, flags = %s)\n", - addr, len, mapProtToString(prot).c_str(), - mapFlagsToString(flags).c_str()); - - auto pagesCount = (len + (kPageSize - 1)) >> kPageShift; - auto hitAddress = reinterpret_cast(addr); - - std::uint64_t alignment = (flags & kMapFlagsAlignMask) >> kMapFlagsAlignShift; - if (alignment == 0) { - alignment = kPageSize; - } else { - alignment = static_cast(1) << alignment; - } - - if (alignment < kPageSize) { - std::fprintf(stderr, "Memory error: wrong alignment %" PRId64 "\n", - alignment); - alignment = kPageSize; - } - - if (len > kBlockSize) { - std::fprintf(stderr, "Memory error: too big allocation %" PRId64 " pages\n", - pagesCount); - return MAP_FAILED; - } - - flags &= ~kMapFlagsAlignMask; - - if (hitAddress & (alignment - 1)) { - if (flags & kMapFlagStack) { - hitAddress = utils::alignDown(hitAddress - 1, alignment); - flags |= kMapFlagFixed; - flags &= ~kMapFlagStack; - } else { - hitAddress = utils::alignUp(hitAddress, alignment); - } - } - - std::lock_guard lock(g_mtx); - - std::uint64_t address = 0; - if ((flags & kMapFlagFixed) == kMapFlagFixed) { - address = hitAddress; - - auto blockIndex = address >> kBlockShift; - - if (blockIndex < kFirstBlock || blockIndex > kLastBlock) { - std::fprintf(stderr, - "Memory error: fixed mapping with wrong address %" PRIx64 - " pages\n", - address); - return MAP_FAILED; - } - } else if (hitAddress != 0) { - auto blockIndex = hitAddress >> kBlockShift; - auto page = (hitAddress & kBlockMask) >> kPageShift; - - if (blockIndex < kFirstBlock || blockIndex > kLastBlock) { - std::fprintf(stderr, - "Memory error: wrong hit address %" PRIx64 " pages\n", - hitAddress); - hitAddress = 0; - } else { - blockIndex -= kFirstBlock; - - if (gBlocks[blockIndex].isFreePages(page, pagesCount)) { - address = hitAddress; - } - } - } - - static constexpr auto kBadAddress = ~static_cast(0); - - if (address == 0 && hitAddress != 0) { - auto hitBlockIndex = hitAddress >> kBlockShift; - for (auto blockIndex = hitBlockIndex; blockIndex <= kLastBlock; - ++blockIndex) { - auto pageAddress = gBlocks[blockIndex - kFirstBlock].findFreePages( - pagesCount, alignment); - - if (pageAddress != kBadAddress) { - address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); - break; - } - } - } - - if (address == 0) { - // for (auto blockIndex = kFirstUserBlock; blockIndex <= kLastUserBlock; - // ++blockIndex) { - std::size_t blockIndex = 0; // system managed block - - auto pageAddress = - gBlocks[blockIndex - kFirstBlock].findFreePages(pagesCount, alignment); - - if (pageAddress != kBadAddress) { - address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); - // break; - } - // } - } - - if (address == 0) { - std::fprintf(stderr, - "Memory error: no free memory left for mapping of %" PRId64 - " pages\n", - pagesCount); - return MAP_FAILED; - } - - if (address & (alignment - 1)) { - std::fprintf(stderr, "Memory error: failed to map aligned address\n"); - std::abort(); - } - - if (address >= kMaxAddress || address > kMaxAddress - len) { - std::fprintf(stderr, "Memory error: out of memory\n"); - std::abort(); - } - - gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( - (address & kBlockMask) >> kPageShift, pagesCount, - (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated); - - int realFlags = MAP_FIXED | MAP_SHARED; - bool isAnon = (flags & kMapFlagAnonymous) == kMapFlagAnonymous; - flags &= ~(kMapFlagFixed | kMapFlagAnonymous); - - /* + kPhysicalMemorySize - kFlexibleMemorySize; + +void* rx::vm::map(void* addr, std::uint64_t len, std::int32_t prot, + std::int32_t flags, std::int32_t internalFlags, + IoDevice* device, std::uint64_t offset) +{ + std::fprintf(stderr, + "rx::vm::map(addr = %p, len = %" PRIu64 + ", prot = %s, flags = %s)\n", + addr, len, mapProtToString(prot).c_str(), + mapFlagsToString(flags).c_str()); + + auto pagesCount = (len + (kPageSize - 1)) >> kPageShift; + auto hitAddress = reinterpret_cast(addr); + + std::uint64_t alignment = (flags & kMapFlagsAlignMask) >> kMapFlagsAlignShift; + if (alignment == 0) + { + alignment = kPageSize; + } + else + { + alignment = static_cast(1) << alignment; + } + + if (alignment < kPageSize) + { + std::fprintf(stderr, "Memory error: wrong alignment %" PRId64 "\n", + alignment); + alignment = kPageSize; + } + + if (len > kBlockSize) + { + std::fprintf(stderr, "Memory error: too big allocation %" PRId64 " pages\n", + pagesCount); + return MAP_FAILED; + } + + flags &= ~kMapFlagsAlignMask; + + if (hitAddress & (alignment - 1)) + { + if (flags & kMapFlagStack) + { + hitAddress = utils::alignDown(hitAddress - 1, alignment); + flags |= kMapFlagFixed; + flags &= ~kMapFlagStack; + } + else + { + hitAddress = utils::alignUp(hitAddress, alignment); + } + } + + std::lock_guard lock(g_mtx); + + std::uint64_t address = 0; + if ((flags & kMapFlagFixed) == kMapFlagFixed) + { + address = hitAddress; + + auto blockIndex = address >> kBlockShift; + + if (blockIndex < kFirstBlock || blockIndex > kLastBlock) + { + std::fprintf(stderr, + "Memory error: fixed mapping with wrong address %" PRIx64 + " pages\n", + address); + return MAP_FAILED; + } + } + else if (hitAddress != 0) + { + auto blockIndex = hitAddress >> kBlockShift; + auto page = (hitAddress & kBlockMask) >> kPageShift; + + if (blockIndex < kFirstBlock || blockIndex > kLastBlock) + { + std::fprintf(stderr, + "Memory error: wrong hit address %" PRIx64 " pages\n", + hitAddress); + hitAddress = 0; + } + else + { + blockIndex -= kFirstBlock; + + if (gBlocks[blockIndex].isFreePages(page, pagesCount)) + { + address = hitAddress; + } + } + } + + static constexpr auto kBadAddress = ~static_cast(0); + + if (address == 0 && hitAddress != 0) + { + auto hitBlockIndex = hitAddress >> kBlockShift; + for (auto blockIndex = hitBlockIndex; blockIndex <= kLastBlock; + ++blockIndex) + { + auto pageAddress = gBlocks[blockIndex - kFirstBlock].findFreePages( + pagesCount, alignment); + + if (pageAddress != kBadAddress) + { + address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); + break; + } + } + } + + if (address == 0) + { + // for (auto blockIndex = kFirstUserBlock; blockIndex <= kLastUserBlock; + // ++blockIndex) { + std::size_t blockIndex = 0; // system managed block + + auto pageAddress = + gBlocks[blockIndex - kFirstBlock].findFreePages(pagesCount, alignment); + + if (pageAddress != kBadAddress) + { + address = (pageAddress << kPageShift) | (blockIndex * kBlockSize); + // break; + } + // } + } + + if (address == 0) + { + std::fprintf(stderr, + "Memory error: no free memory left for mapping of %" PRId64 + " pages\n", + pagesCount); + return MAP_FAILED; + } + + if (address & (alignment - 1)) + { + std::fprintf(stderr, "Memory error: failed to map aligned address\n"); + std::abort(); + } + + if (address >= kMaxAddress || address > kMaxAddress - len) + { + std::fprintf(stderr, "Memory error: out of memory\n"); + std::abort(); + } + + gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( + (address & kBlockMask) >> kPageShift, pagesCount, + (prot & (kMapProtCpuAll | kMapProtGpuAll)) | kAllocated); + + int realFlags = MAP_FIXED | MAP_SHARED; + bool isAnon = (flags & kMapFlagAnonymous) == kMapFlagAnonymous; + flags &= ~(kMapFlagFixed | kMapFlagAnonymous); + + /* if (flags & kMapFlagStack) { realFlags |= MAP_GROWSDOWN | MAP_STACK | MAP_ANONYMOUS | MAP_PRIVATE; offset = 0; @@ -817,258 +967,298 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, realFlags |= MAP_SHARED; } */ - if (flags) { - std::fprintf(stderr, " unhandled flags 0x%" PRIx32 "\n", flags); - } - - { - MapInfo info; - if (auto it = gMapInfo.queryArea(address); it != gMapInfo.end()) { - info = (*it).payload; - } - info.device = device; - info.flags = flags; - info.offset = offset; - - gMapInfo.map(address, address + len, info); - } - - if (internalFlags & kMapInternalReserveOnly) { - return reinterpret_cast(address); - } - - auto result = - utils::map(reinterpret_cast(address), len, prot & kMapProtCpuAll, - realFlags, gMemoryShm, address - kMinAddress); - - if (result != MAP_FAILED && isAnon) { - bool needReprotect = (prot & PROT_WRITE) == 0; - if (needReprotect) { - ::mprotect(result, len, PROT_WRITE); - } - std::memset(result, 0, len); - if (needReprotect) { - ::mprotect(result, len, prot & kMapProtCpuAll); - } - } - - rx::bridge.sendMemoryProtect(address, len, prot); - return result; + if (flags) + { + std::fprintf(stderr, " unhandled flags 0x%" PRIx32 "\n", flags); + } + + { + MapInfo info; + if (auto it = gMapInfo.queryArea(address); it != gMapInfo.end()) + { + info = (*it).payload; + } + info.device = device; + info.flags = flags; + info.offset = offset; + + gMapInfo.map(address, address + len, info); + } + + if (internalFlags & kMapInternalReserveOnly) + { + return reinterpret_cast(address); + } + + auto result = + utils::map(reinterpret_cast(address), len, prot & kMapProtCpuAll, + realFlags, gMemoryShm, address - kMinAddress); + + if (result != MAP_FAILED && isAnon) + { + bool needReprotect = (prot & PROT_WRITE) == 0; + if (needReprotect) + { + ::mprotect(result, len, PROT_WRITE); + } + std::memset(result, 0, len); + if (needReprotect) + { + ::mprotect(result, len, prot & kMapProtCpuAll); + } + } + + rx::bridge.sendMemoryProtect(address, len, prot); + return result; } -bool rx::vm::unmap(void *addr, std::uint64_t size) { - auto pages = (size + (kPageSize - 1)) >> kPageShift; - auto address = reinterpret_cast(addr); - - if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || - address > kMaxAddress - size) { - std::fprintf(stderr, "Memory error: unmap out of memory\n"); - return false; - } - - if ((address & kPageMask) != 0) { - std::fprintf(stderr, "Memory error: unmap unaligned address\n"); - return false; - } - - if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) { - std::fprintf( - stderr, - "Memory error: unmap cross block range. address 0x%lx, size=0x%lx\n", - address, size); - __builtin_trap(); - } - - std::lock_guard lock(g_mtx); - gBlocks[(address >> kBlockShift) - kFirstBlock].removeFlags( - (address & kBlockMask) >> kPageShift, pages, ~0); - rx::bridge.sendMemoryProtect(reinterpret_cast(addr), size, 0); - return utils::unmap(addr, size); +bool rx::vm::unmap(void* addr, std::uint64_t size) +{ + auto pages = (size + (kPageSize - 1)) >> kPageShift; + auto address = reinterpret_cast(addr); + + if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || + address > kMaxAddress - size) + { + std::fprintf(stderr, "Memory error: unmap out of memory\n"); + return false; + } + + if ((address & kPageMask) != 0) + { + std::fprintf(stderr, "Memory error: unmap unaligned address\n"); + return false; + } + + if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) + { + std::fprintf( + stderr, + "Memory error: unmap cross block range. address 0x%lx, size=0x%lx\n", + address, size); + __builtin_trap(); + } + + std::lock_guard lock(g_mtx); + gBlocks[(address >> kBlockShift) - kFirstBlock].removeFlags( + (address & kBlockMask) >> kPageShift, pages, ~0); + rx::bridge.sendMemoryProtect(reinterpret_cast(addr), size, 0); + return utils::unmap(addr, size); } -bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { - std::printf("rx::vm::protect(addr = %p, len = %" PRIu64 ", prot = %s)\n", - addr, size, mapProtToString(prot).c_str()); - - auto pages = (size + (kPageSize - 1)) >> kPageShift; - auto address = reinterpret_cast(addr); - if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || - address > kMaxAddress - size) { - std::fprintf(stderr, "Memory error: protect out of memory\n"); - return false; - } - - if ((address & kPageMask) != 0) { - std::fprintf(stderr, "Memory error: protect unaligned address\n"); - return false; - } - - if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) { - std::fprintf(stderr, "Memory error: protect cross block range\n"); - std::abort(); - } - - std::lock_guard lock(g_mtx); - - gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( - (address & kBlockMask) >> kPageShift, pages, - kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll))); - - rx::bridge.sendMemoryProtect(reinterpret_cast(addr), size, - prot); - return ::mprotect(addr, size, prot & kMapProtCpuAll) == 0; +bool rx::vm::protect(void* addr, std::uint64_t size, std::int32_t prot) +{ + std::printf("rx::vm::protect(addr = %p, len = %" PRIu64 ", prot = %s)\n", + addr, size, mapProtToString(prot).c_str()); + + auto pages = (size + (kPageSize - 1)) >> kPageShift; + auto address = reinterpret_cast(addr); + if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || + address > kMaxAddress - size) + { + std::fprintf(stderr, "Memory error: protect out of memory\n"); + return false; + } + + if ((address & kPageMask) != 0) + { + std::fprintf(stderr, "Memory error: protect unaligned address\n"); + return false; + } + + if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) + { + std::fprintf(stderr, "Memory error: protect cross block range\n"); + std::abort(); + } + + std::lock_guard lock(g_mtx); + + gBlocks[(address >> kBlockShift) - kFirstBlock].setFlags( + (address & kBlockMask) >> kPageShift, pages, + kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll))); + + rx::bridge.sendMemoryProtect(reinterpret_cast(addr), size, + prot); + return ::mprotect(addr, size, prot & kMapProtCpuAll) == 0; } -static std::int32_t getPageProtectionImpl(std::uint64_t address) { - return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( - (address & kBlockMask) >> rx::vm::kPageShift); +static std::int32_t getPageProtectionImpl(std::uint64_t address) +{ + return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( + (address & kBlockMask) >> rx::vm::kPageShift); } -bool rx::vm::queryProtection(const void *addr, std::uint64_t *startAddress, - std::uint64_t *endAddress, std::int32_t *prot) { - auto address = reinterpret_cast(addr); - if (address < kMinAddress || address >= kMaxAddress) { - return false; - } +bool rx::vm::queryProtection(const void* addr, std::uint64_t* startAddress, + std::uint64_t* endAddress, std::int32_t* prot) +{ + auto address = reinterpret_cast(addr); + if (address < kMinAddress || address >= kMaxAddress) + { + return false; + } - std::uint64_t start = address & ~kPageMask; - std::uint64_t end = start + kPageSize; + std::uint64_t start = address & ~kPageMask; + std::uint64_t end = start + kPageSize; - std::lock_guard lock(g_mtx); + std::lock_guard lock(g_mtx); - auto resultProt = getPageProtectionImpl(address); + auto resultProt = getPageProtectionImpl(address); - while (true) { - auto testAddr = start - kPageSize; - if (testAddr < kMinAddress) { - break; - } + while (true) + { + auto testAddr = start - kPageSize; + if (testAddr < kMinAddress) + { + break; + } - auto testProt = getPageProtectionImpl(testAddr); + auto testProt = getPageProtectionImpl(testAddr); - if (resultProt != testProt) { - break; - } + if (resultProt != testProt) + { + break; + } - start = testAddr; - } + start = testAddr; + } - while (true) { - auto testAddr = end; - if (testAddr >= kMaxAddress) { - break; - } + while (true) + { + auto testAddr = end; + if (testAddr >= kMaxAddress) + { + break; + } - auto testProt = getPageProtectionImpl(testAddr); + auto testProt = getPageProtectionImpl(testAddr); - if (resultProt != testProt) { - break; - } + if (resultProt != testProt) + { + break; + } - end = testAddr + kPageSize; - } + end = testAddr + kPageSize; + } - *startAddress = start; - *endAddress = end; - *prot = resultProt; + *startAddress = start; + *endAddress = end; + *prot = resultProt; - return true; + return true; } -unsigned rx::vm::getPageProtection(std::uint64_t address) { - if (address < kMinAddress || address >= kMaxAddress) { - std::fprintf(stderr, "Memory error: getPageProtection out of memory\n"); - return 0; - } +unsigned rx::vm::getPageProtection(std::uint64_t address) +{ + if (address < kMinAddress || address >= kMaxAddress) + { + std::fprintf(stderr, "Memory error: getPageProtection out of memory\n"); + return 0; + } - std::lock_guard lock(g_mtx); + std::lock_guard lock(g_mtx); - return getPageProtectionImpl(address); + return getPageProtectionImpl(address); } -bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, - VirtualQueryInfo *info) { - std::lock_guard lock(g_mtx); - - auto address = reinterpret_cast(addr); - auto it = gMapInfo.lowerBound(address); - - if (it == gMapInfo.end()) { - return false; - } - - auto queryInfo = *it; - - if ((flags & 1) == 0) { - if (queryInfo.endAddress <= address) { - return false; - } - } else { - if (queryInfo.beginAddress > address || queryInfo.endAddress <= address) { - return false; - } - } - - std::int32_t memoryType = 0; - std::uint32_t blockFlags = 0; - if (queryInfo.payload.device != nullptr) { - if (auto dmem = - dynamic_cast(queryInfo.payload.device.get())) { - auto dmemIt = dmem->allocations.queryArea(queryInfo.payload.offset); - if (dmemIt == dmem->allocations.end()) { - return false; - } - auto alloc = *dmemIt; - memoryType = alloc.payload.memoryType; - blockFlags = kBlockFlagDirectMemory; - } - // TODO - } - - std::int32_t prot = getPageProtectionImpl(queryInfo.beginAddress); - - *info = { - .start = queryInfo.beginAddress, - .end = queryInfo.endAddress, - .protection = prot, - .memoryType = memoryType, - .flags = blockFlags, - }; - - ORBIS_LOG_ERROR("virtualQuery", addr, flags, info->start, info->end, - info->protection, info->memoryType, info->flags); - - std::memcpy(info->name, queryInfo.payload.name, sizeof(info->name)); - return true; +bool rx::vm::virtualQuery(const void* addr, std::int32_t flags, + VirtualQueryInfo* info) +{ + std::lock_guard lock(g_mtx); + + auto address = reinterpret_cast(addr); + auto it = gMapInfo.lowerBound(address); + + if (it == gMapInfo.end()) + { + return false; + } + + auto queryInfo = *it; + + if ((flags & 1) == 0) + { + if (queryInfo.endAddress <= address) + { + return false; + } + } + else + { + if (queryInfo.beginAddress > address || queryInfo.endAddress <= address) + { + return false; + } + } + + std::int32_t memoryType = 0; + std::uint32_t blockFlags = 0; + if (queryInfo.payload.device != nullptr) + { + if (auto dmem = + dynamic_cast(queryInfo.payload.device.get())) + { + auto dmemIt = dmem->allocations.queryArea(queryInfo.payload.offset); + if (dmemIt == dmem->allocations.end()) + { + return false; + } + auto alloc = *dmemIt; + memoryType = alloc.payload.memoryType; + blockFlags = kBlockFlagDirectMemory; + } + // TODO + } + + std::int32_t prot = getPageProtectionImpl(queryInfo.beginAddress); + + *info = { + .start = queryInfo.beginAddress, + .end = queryInfo.endAddress, + .protection = prot, + .memoryType = memoryType, + .flags = blockFlags, + }; + + ORBIS_LOG_ERROR("virtualQuery", addr, flags, info->start, info->end, + info->protection, info->memoryType, info->flags); + + std::memcpy(info->name, queryInfo.payload.name, sizeof(info->name)); + return true; } void rx::vm::setName(std::uint64_t start, std::uint64_t size, - const char *name) { - std::lock_guard lock(g_mtx); + const char* name) +{ + std::lock_guard lock(g_mtx); - MapInfo info; - if (auto it = gMapInfo.queryArea(start); it != gMapInfo.end()) { - info = (*it).payload; - } + MapInfo info; + if (auto it = gMapInfo.queryArea(start); it != gMapInfo.end()) + { + info = (*it).payload; + } - std::strncpy(info.name, name, sizeof(info.name)); + std::strncpy(info.name, name, sizeof(info.name)); - gMapInfo.map(start, size, info); + gMapInfo.map(start, size, info); } -void rx::vm::printHostStats() { - FILE *maps = fopen("/proc/self/maps", "r"); +void rx::vm::printHostStats() +{ + FILE* maps = fopen("/proc/self/maps", "r"); - if (!maps) { - return; - } + if (!maps) + { + return; + } - char *line = nullptr; - std::size_t size = 0; - while (getline(&line, &size, maps) > 0) { - std::printf("%s", line); - } + char* line = nullptr; + std::size_t size = 0; + while (getline(&line, &size, maps) > 0) + { + std::printf("%s", line); + } - free(line); - fclose(maps); + free(line); + fclose(maps); } diff --git a/rpcsx-os/vm.hpp b/rpcsx-os/vm.hpp index 04e4461f..6656c0dc 100644 --- a/rpcsx-os/vm.hpp +++ b/rpcsx-os/vm.hpp @@ -4,80 +4,86 @@ #include #include -namespace rx::vm { -static constexpr std::uint64_t kPageShift = 14; -static constexpr std::uint64_t kPageSize = static_cast(1) - << kPageShift; +namespace rx::vm +{ + static constexpr std::uint64_t kPageShift = 14; + static constexpr std::uint64_t kPageSize = static_cast(1) + << kPageShift; -enum BlockFlags { - kBlockFlagFlexibleMemory = 1 << 0, - kBlockFlagDirectMemory = 1 << 1, - kBlockFlagStack = 1 << 2, - kBlockFlagPooledMemory = 1 << 3, - kBlockFlagCommited = 1 << 4, -}; + enum BlockFlags + { + kBlockFlagFlexibleMemory = 1 << 0, + kBlockFlagDirectMemory = 1 << 1, + kBlockFlagStack = 1 << 2, + kBlockFlagPooledMemory = 1 << 3, + kBlockFlagCommited = 1 << 4, + }; -enum MapFlags { - kMapFlagShared = 0x1, - kMapFlagPrivate = 0x2, - kMapFlagFixed = 0x10, - kMapFlagRename = 0x20, - kMapFlagNoReserve = 0x40, - kMapFlagNoOverwrite = 0x80, - kMapFlagVoid = 0x100, - kMapFlagHasSemaphore = 0x200, - kMapFlagStack = 0x400, - kMapFlagNoSync = 0x800, - kMapFlagAnonymous = 0x1000, - kMapFlagSystem = 0x2000, - kMapFlagAllAvailable = 0x4000, - kMapFlagNoCore = 0x20000, - kMapFlagPrefaultRead = 0x40000, - kMapFlagSelf = 0x80000, -}; + enum MapFlags + { + kMapFlagShared = 0x1, + kMapFlagPrivate = 0x2, + kMapFlagFixed = 0x10, + kMapFlagRename = 0x20, + kMapFlagNoReserve = 0x40, + kMapFlagNoOverwrite = 0x80, + kMapFlagVoid = 0x100, + kMapFlagHasSemaphore = 0x200, + kMapFlagStack = 0x400, + kMapFlagNoSync = 0x800, + kMapFlagAnonymous = 0x1000, + kMapFlagSystem = 0x2000, + kMapFlagAllAvailable = 0x4000, + kMapFlagNoCore = 0x20000, + kMapFlagPrefaultRead = 0x40000, + kMapFlagSelf = 0x80000, + }; -enum MapProt { - kMapProtCpuRead = 1, - kMapProtCpuWrite = 2, - kMapProtCpuExec = 4, - kMapProtCpuAll = 0x7, - kMapProtGpuRead = 0x10, - kMapProtGpuWrite = 0x20, - kMapProtGpuAll = 0x30, -}; + enum MapProt + { + kMapProtCpuRead = 1, + kMapProtCpuWrite = 2, + kMapProtCpuExec = 4, + kMapProtCpuAll = 0x7, + kMapProtGpuRead = 0x10, + kMapProtGpuWrite = 0x20, + kMapProtGpuAll = 0x30, + }; -enum MapInternalFlags { - kMapInternalReserveOnly = 1 << 0, -}; + enum MapInternalFlags + { + kMapInternalReserveOnly = 1 << 0, + }; -struct VirtualQueryInfo { - std::uint64_t start; - std::uint64_t end; - std::uint64_t offset; - std::int32_t protection; - std::int32_t memoryType; - std::uint32_t flags; - char name[32]; -}; + struct VirtualQueryInfo + { + std::uint64_t start; + std::uint64_t end; + std::uint64_t offset; + std::int32_t protection; + std::int32_t memoryType; + std::uint32_t flags; + char name[32]; + }; -static constexpr std::uint32_t kMapFlagsAlignShift = 24; -static constexpr std::uint32_t kMapFlagsAlignMask = 0x1f << kMapFlagsAlignShift; + static constexpr std::uint32_t kMapFlagsAlignShift = 24; + static constexpr std::uint32_t kMapFlagsAlignMask = 0x1f << kMapFlagsAlignShift; -std::string mapFlagsToString(std::int32_t flags); -std::string mapProtToString(std::int32_t prot); + std::string mapFlagsToString(std::int32_t flags); + std::string mapProtToString(std::int32_t prot); -void printHostStats(); -void initialize(); -void deinitialize(); -void *map(void *addr, std::uint64_t len, std::int32_t prot, std::int32_t flags, - std::int32_t internalFlags = 0, IoDevice *device = nullptr, - std::uint64_t offset = 0); -bool unmap(void *addr, std::uint64_t size); -bool protect(void *addr, std::uint64_t size, std::int32_t prot); + void printHostStats(); + void initialize(); + void deinitialize(); + void* map(void* addr, std::uint64_t len, std::int32_t prot, std::int32_t flags, + std::int32_t internalFlags = 0, IoDevice* device = nullptr, + std::uint64_t offset = 0); + bool unmap(void* addr, std::uint64_t size); + bool protect(void* addr, std::uint64_t size, std::int32_t prot); -void setName(std::uint64_t start, std::uint64_t size, const char *name); -bool virtualQuery(const void *addr, std::int32_t flags, VirtualQueryInfo *info); -bool queryProtection(const void *addr, std::uint64_t *startAddress, - std::uint64_t *endAddress, std::int32_t *prot); -unsigned getPageProtection(std::uint64_t address); + void setName(std::uint64_t start, std::uint64_t size, const char* name); + bool virtualQuery(const void* addr, std::int32_t flags, VirtualQueryInfo* info); + bool queryProtection(const void* addr, std::uint64_t* startAddress, + std::uint64_t* endAddress, std::int32_t* prot); + unsigned getPageProtection(std::uint64_t address); } // namespace rx::vm diff --git a/rx/include/rx/MemoryTable.hpp b/rx/include/rx/MemoryTable.hpp index a8538307..3c8fed50 100644 --- a/rx/include/rx/MemoryTable.hpp +++ b/rx/include/rx/MemoryTable.hpp @@ -5,383 +5,487 @@ #include #include -namespace rx { -struct AreaInfo { - std::uint64_t beginAddress; - std::uint64_t endAddress; -}; - -struct NoInvalidationHandle { - void handleInvalidation(std::uint64_t) {} -}; - -struct StdSetInvalidationHandle { - std::set> invalidated; - - void handleInvalidation(std::uint64_t address) { - invalidated.insert(address); - } -}; - -template -class MemoryAreaTable : public InvalidationHandleT { - enum class Kind { O, X }; - std::map mAreas; - -public: - class iterator { - using map_iterator = typename std::map::iterator; - map_iterator it; - - public: - iterator() = default; - iterator(map_iterator it) : it(it) {} - - AreaInfo operator*() const { return {it->first, std::next(it)->first}; } - - iterator &operator++() { - ++it; - ++it; - return *this; - } - - iterator &operator--() { - --it; - --it; - return *this; - } - - bool operator==(iterator other) const { return it == other.it; } - bool operator!=(iterator other) const { return it != other.it; } - }; - - iterator begin() { return iterator(mAreas.begin()); } - iterator end() { return iterator(mAreas.end()); } - - void clear() { mAreas.clear(); } - - AreaInfo queryArea(std::uint64_t address) const { - auto it = mAreas.lower_bound(address); - assert(it != mAreas.end()); - std::uint64_t endAddress = 0; - if (it->first != address) { - assert(it->second == Kind::X); - endAddress = it->first; - --it; - } else { - assert(it->second == Kind::O); - endAddress = std::next(it)->first; - } - - auto startAddress = std::uint64_t(it->first); - - return {startAddress, endAddress}; - } - - void map(std::uint64_t beginAddress, std::uint64_t endAddress) { - auto [beginIt, beginInserted] = mAreas.emplace(beginAddress, Kind::O); - auto [endIt, endInserted] = mAreas.emplace(endAddress, Kind::X); - - if (!beginInserted) { - if (beginIt->second == Kind::X) { - // it was close, extend to open - assert(beginIt != mAreas.begin()); - --beginIt; - } - } else if (beginIt != mAreas.begin()) { - auto prevRangePointIt = std::prev(beginIt); - - if (prevRangePointIt->second == Kind::O) { - // we found range start before inserted one, remove insertion and extend - // begin - this->handleInvalidation(beginIt->first); - mAreas.erase(beginIt); - beginIt = prevRangePointIt; - } - } - - if (!endInserted) { - if (endIt->second == Kind::O) { - // it was open, extend to close - assert(endIt != mAreas.end()); - ++endIt; - } - } else { - auto nextRangePointIt = std::next(endIt); - - if (nextRangePointIt != mAreas.end() && - nextRangePointIt->second == Kind::X) { - // we found range end after inserted one, remove insertion and extend - // end - this->handleInvalidation(std::prev(endIt)->first); - mAreas.erase(endIt); - endIt = nextRangePointIt; - } - } - - // eat everything in middle of the range - ++beginIt; - while (beginIt != endIt) { - this->handleInvalidation(std::prev(endIt)->first); - beginIt = mAreas.erase(beginIt); - } - } - - void unmap(std::uint64_t beginAddress, std::uint64_t endAddress) { - auto beginIt = mAreas.lower_bound(beginAddress); - - if (beginIt == mAreas.end()) { - return; - } - if (beginIt->first >= endAddress) { - if (beginIt->second != Kind::X) { - return; - } - - auto prevEnd = beginIt->first; - - --beginIt; - if (beginIt->first >= endAddress) { - return; - } - - if (beginIt->first < beginAddress) { - this->handleInvalidation(beginIt->first); - beginIt = mAreas.emplace(beginAddress, Kind::X).first; - } - - if (prevEnd > endAddress) { - mAreas.emplace(endAddress, Kind::O); - return; - } - } - - if (beginIt->first > beginAddress && beginIt->second == Kind::X) { - // we have found end after unmap begin, need to insert new end - this->handleInvalidation(std::prev(beginIt)->first); - auto newBeginIt = mAreas.emplace_hint(beginIt, beginAddress, Kind::X); - mAreas.erase(beginIt); - - if (newBeginIt == mAreas.end()) { - return; - } - - beginIt = std::next(newBeginIt); - } else if (beginIt->second == Kind::X) { - beginIt = ++beginIt; - } - - Kind lastKind = Kind::X; - while (beginIt != mAreas.end() && beginIt->first <= endAddress) { - lastKind = beginIt->second; - if (lastKind == Kind::O) { - this->handleInvalidation(std::prev(beginIt)->first); - } - beginIt = mAreas.erase(beginIt); - } - - if (lastKind != Kind::O) { - return; - } - - // Last removed was range open, need to insert new one at unmap end - mAreas.emplace_hint(beginIt, endAddress, Kind::O); - } - - std::size_t totalMemory() const { - std::size_t result = 0; - - for (auto it = mAreas.begin(), end = mAreas.end(); it != end; ++it) { - auto rangeBegin = it; - auto rangeEnd = ++it; - - result += rangeEnd->first - rangeBegin->first; - } - - return result; - } -}; - -template class MemoryTableWithPayload { - enum class Kind { O, X, XO }; - std::map> mAreas; - -public: - struct AreaInfo { - std::uint64_t beginAddress; - std::uint64_t endAddress; - PayloadT payload; - }; - - class iterator { - using map_iterator = - typename std::map>::iterator; - map_iterator it; - - public: - iterator() = default; - iterator(map_iterator it) : it(it) {} - - AreaInfo operator*() const { - return {it->first, std::next(it)->first, it->second.second}; - } - - iterator &operator++() { - ++it; - - if (it->second.first != Kind::XO) { - ++it; - } - - return *this; - } - - bool operator==(iterator other) const { return it == other.it; } - bool operator!=(iterator other) const { return it != other.it; } - }; - - iterator begin() { return iterator(mAreas.begin()); } - iterator end() { return iterator(mAreas.end()); } - - void clear() { mAreas.clear(); } - - iterator lowerBound(std::uint64_t address) { - auto it = mAreas.lower_bound(address); - - if (it == mAreas.end()) { - return it; - } - - if (it->first == address) { - if (it->second.first == Kind::X) { - ++it; - } - } else { - if (it->second.first != Kind::O) { - --it; - } - } - - return it; - } - - iterator queryArea(std::uint64_t address) { - auto it = mAreas.lower_bound(address); - - if (it == mAreas.end()) { - return it; - } - - std::uint64_t endAddress = 0; - - if (it->first == address) { - if (it->second.first == Kind::X) { - return mAreas.end(); - } - - endAddress = std::next(it)->first; - } else { - if (it->second.first == Kind::O) { - return mAreas.end(); - } - - endAddress = it->first; - --it; - } - - return endAddress < address ? mAreas.end() : it; - } - - void map(std::uint64_t beginAddress, std::uint64_t endAddress, - PayloadT payload, bool merge = true) { - assert(beginAddress < endAddress); - auto [beginIt, beginInserted] = - mAreas.emplace(beginAddress, std::pair{Kind::O, payload}); - auto [endIt, endInserted] = - mAreas.emplace(endAddress, std::pair{Kind::X, PayloadT{}}); - - bool seenOpen = false; - bool endCollision = false; - bool lastRemovedIsOpen = false; - PayloadT lastRemovedOpenPayload; - - if (!beginInserted || !endInserted) { - if (!beginInserted) { - if (beginIt->second.first == Kind::X) { - beginIt->second.first = Kind::XO; - } else { - seenOpen = true; - lastRemovedIsOpen = true; - lastRemovedOpenPayload = std::move(beginIt->second.second); - } - - beginIt->second.second = std::move(payload); - } - - if (!endInserted) { - if (endIt->second.first == Kind::O) { - endIt->second.first = Kind::XO; - } else { - endCollision = true; - } - - lastRemovedIsOpen = false; - } - } else if (beginIt != mAreas.begin()) { - auto prev = std::prev(beginIt); - - if (prev->second.first != Kind::X) { - beginIt->second.first = Kind::XO; - seenOpen = true; - lastRemovedIsOpen = true; - lastRemovedOpenPayload = prev->second.second; - } - } - - auto origBegin = beginIt; - ++beginIt; - while (beginIt != endIt) { - if (beginIt->second.first == Kind::X) { - lastRemovedIsOpen = false; - if (!seenOpen) { - origBegin->second.first = Kind::XO; - } - } else { - if (!seenOpen && beginIt->second.first == Kind::XO) { - origBegin->second.first = Kind::XO; - } - - seenOpen = true; - lastRemovedIsOpen = true; - lastRemovedOpenPayload = std::move(beginIt->second.second); - } - beginIt = mAreas.erase(beginIt); - } - - if (endCollision && !seenOpen) { - origBegin->second.first = Kind::XO; - } else if (lastRemovedIsOpen && !endCollision) { - endIt->second.first = Kind::XO; - endIt->second.second = std::move(lastRemovedOpenPayload); - } - - if (!merge) { - return; - } - - if (origBegin->second.first == Kind::XO) { - auto prevBegin = std::prev(origBegin); - - if (prevBegin->second.second == origBegin->second.second) { - mAreas.erase(origBegin); - } - } - - if (endIt->second.first == Kind::XO) { - if (endIt->second.second == origBegin->second.second) { - mAreas.erase(endIt); - } - } - } -}; +namespace rx +{ + struct AreaInfo + { + std::uint64_t beginAddress; + std::uint64_t endAddress; + }; + + struct NoInvalidationHandle + { + void handleInvalidation(std::uint64_t) {} + }; + + struct StdSetInvalidationHandle + { + std::set> invalidated; + + void handleInvalidation(std::uint64_t address) + { + invalidated.insert(address); + } + }; + + template + class MemoryAreaTable : public InvalidationHandleT + { + enum class Kind + { + O, + X + }; + std::map mAreas; + + public: + class iterator + { + using map_iterator = typename std::map::iterator; + map_iterator it; + + public: + iterator() = default; + iterator(map_iterator it) + : it(it) + { + } + + AreaInfo operator*() const { return {it->first, std::next(it)->first}; } + + iterator& operator++() + { + ++it; + ++it; + return *this; + } + + iterator& operator--() + { + --it; + --it; + return *this; + } + + bool operator==(iterator other) const { return it == other.it; } + bool operator!=(iterator other) const { return it != other.it; } + }; + + iterator begin() { return iterator(mAreas.begin()); } + iterator end() { return iterator(mAreas.end()); } + + void clear() { mAreas.clear(); } + + AreaInfo queryArea(std::uint64_t address) const + { + auto it = mAreas.lower_bound(address); + assert(it != mAreas.end()); + std::uint64_t endAddress = 0; + if (it->first != address) + { + assert(it->second == Kind::X); + endAddress = it->first; + --it; + } + else + { + assert(it->second == Kind::O); + endAddress = std::next(it)->first; + } + + auto startAddress = std::uint64_t(it->first); + + return {startAddress, endAddress}; + } + + void map(std::uint64_t beginAddress, std::uint64_t endAddress) + { + auto [beginIt, beginInserted] = mAreas.emplace(beginAddress, Kind::O); + auto [endIt, endInserted] = mAreas.emplace(endAddress, Kind::X); + + if (!beginInserted) + { + if (beginIt->second == Kind::X) + { + // it was close, extend to open + assert(beginIt != mAreas.begin()); + --beginIt; + } + } + else if (beginIt != mAreas.begin()) + { + auto prevRangePointIt = std::prev(beginIt); + + if (prevRangePointIt->second == Kind::O) + { + // we found range start before inserted one, remove insertion and extend + // begin + this->handleInvalidation(beginIt->first); + mAreas.erase(beginIt); + beginIt = prevRangePointIt; + } + } + + if (!endInserted) + { + if (endIt->second == Kind::O) + { + // it was open, extend to close + assert(endIt != mAreas.end()); + ++endIt; + } + } + else + { + auto nextRangePointIt = std::next(endIt); + + if (nextRangePointIt != mAreas.end() && + nextRangePointIt->second == Kind::X) + { + // we found range end after inserted one, remove insertion and extend + // end + this->handleInvalidation(std::prev(endIt)->first); + mAreas.erase(endIt); + endIt = nextRangePointIt; + } + } + + // eat everything in middle of the range + ++beginIt; + while (beginIt != endIt) + { + this->handleInvalidation(std::prev(endIt)->first); + beginIt = mAreas.erase(beginIt); + } + } + + void unmap(std::uint64_t beginAddress, std::uint64_t endAddress) + { + auto beginIt = mAreas.lower_bound(beginAddress); + + if (beginIt == mAreas.end()) + { + return; + } + if (beginIt->first >= endAddress) + { + if (beginIt->second != Kind::X) + { + return; + } + + auto prevEnd = beginIt->first; + + --beginIt; + if (beginIt->first >= endAddress) + { + return; + } + + if (beginIt->first < beginAddress) + { + this->handleInvalidation(beginIt->first); + beginIt = mAreas.emplace(beginAddress, Kind::X).first; + } + + if (prevEnd > endAddress) + { + mAreas.emplace(endAddress, Kind::O); + return; + } + } + + if (beginIt->first > beginAddress && beginIt->second == Kind::X) + { + // we have found end after unmap begin, need to insert new end + this->handleInvalidation(std::prev(beginIt)->first); + auto newBeginIt = mAreas.emplace_hint(beginIt, beginAddress, Kind::X); + mAreas.erase(beginIt); + + if (newBeginIt == mAreas.end()) + { + return; + } + + beginIt = std::next(newBeginIt); + } + else if (beginIt->second == Kind::X) + { + beginIt = ++beginIt; + } + + Kind lastKind = Kind::X; + while (beginIt != mAreas.end() && beginIt->first <= endAddress) + { + lastKind = beginIt->second; + if (lastKind == Kind::O) + { + this->handleInvalidation(std::prev(beginIt)->first); + } + beginIt = mAreas.erase(beginIt); + } + + if (lastKind != Kind::O) + { + return; + } + + // Last removed was range open, need to insert new one at unmap end + mAreas.emplace_hint(beginIt, endAddress, Kind::O); + } + + std::size_t totalMemory() const + { + std::size_t result = 0; + + for (auto it = mAreas.begin(), end = mAreas.end(); it != end; ++it) + { + auto rangeBegin = it; + auto rangeEnd = ++it; + + result += rangeEnd->first - rangeBegin->first; + } + + return result; + } + }; + + template + class MemoryTableWithPayload + { + enum class Kind + { + O, + X, + XO + }; + std::map> mAreas; + + public: + struct AreaInfo + { + std::uint64_t beginAddress; + std::uint64_t endAddress; + PayloadT payload; + }; + + class iterator + { + using map_iterator = + typename std::map>::iterator; + map_iterator it; + + public: + iterator() = default; + iterator(map_iterator it) + : it(it) + { + } + + AreaInfo operator*() const + { + return {it->first, std::next(it)->first, it->second.second}; + } + + iterator& operator++() + { + ++it; + + if (it->second.first != Kind::XO) + { + ++it; + } + + return *this; + } + + bool operator==(iterator other) const { return it == other.it; } + bool operator!=(iterator other) const { return it != other.it; } + }; + + iterator begin() { return iterator(mAreas.begin()); } + iterator end() { return iterator(mAreas.end()); } + + void clear() { mAreas.clear(); } + + iterator lowerBound(std::uint64_t address) + { + auto it = mAreas.lower_bound(address); + + if (it == mAreas.end()) + { + return it; + } + + if (it->first == address) + { + if (it->second.first == Kind::X) + { + ++it; + } + } + else + { + if (it->second.first != Kind::O) + { + --it; + } + } + + return it; + } + + iterator queryArea(std::uint64_t address) + { + auto it = mAreas.lower_bound(address); + + if (it == mAreas.end()) + { + return it; + } + + std::uint64_t endAddress = 0; + + if (it->first == address) + { + if (it->second.first == Kind::X) + { + return mAreas.end(); + } + + endAddress = std::next(it)->first; + } + else + { + if (it->second.first == Kind::O) + { + return mAreas.end(); + } + + endAddress = it->first; + --it; + } + + return endAddress < address ? mAreas.end() : it; + } + + void map(std::uint64_t beginAddress, std::uint64_t endAddress, + PayloadT payload, bool merge = true) + { + assert(beginAddress < endAddress); + auto [beginIt, beginInserted] = + mAreas.emplace(beginAddress, std::pair{Kind::O, payload}); + auto [endIt, endInserted] = + mAreas.emplace(endAddress, std::pair{Kind::X, PayloadT{}}); + + bool seenOpen = false; + bool endCollision = false; + bool lastRemovedIsOpen = false; + PayloadT lastRemovedOpenPayload; + + if (!beginInserted || !endInserted) + { + if (!beginInserted) + { + if (beginIt->second.first == Kind::X) + { + beginIt->second.first = Kind::XO; + } + else + { + seenOpen = true; + lastRemovedIsOpen = true; + lastRemovedOpenPayload = std::move(beginIt->second.second); + } + + beginIt->second.second = std::move(payload); + } + + if (!endInserted) + { + if (endIt->second.first == Kind::O) + { + endIt->second.first = Kind::XO; + } + else + { + endCollision = true; + } + + lastRemovedIsOpen = false; + } + } + else if (beginIt != mAreas.begin()) + { + auto prev = std::prev(beginIt); + + if (prev->second.first != Kind::X) + { + beginIt->second.first = Kind::XO; + seenOpen = true; + lastRemovedIsOpen = true; + lastRemovedOpenPayload = prev->second.second; + } + } + + auto origBegin = beginIt; + ++beginIt; + while (beginIt != endIt) + { + if (beginIt->second.first == Kind::X) + { + lastRemovedIsOpen = false; + if (!seenOpen) + { + origBegin->second.first = Kind::XO; + } + } + else + { + if (!seenOpen && beginIt->second.first == Kind::XO) + { + origBegin->second.first = Kind::XO; + } + + seenOpen = true; + lastRemovedIsOpen = true; + lastRemovedOpenPayload = std::move(beginIt->second.second); + } + beginIt = mAreas.erase(beginIt); + } + + if (endCollision && !seenOpen) + { + origBegin->second.first = Kind::XO; + } + else if (lastRemovedIsOpen && !endCollision) + { + endIt->second.first = Kind::XO; + endIt->second.second = std::move(lastRemovedOpenPayload); + } + + if (!merge) + { + return; + } + + if (origBegin->second.first == Kind::XO) + { + auto prevBegin = std::prev(origBegin); + + if (prevBegin->second.second == origBegin->second.second) + { + mAreas.erase(origBegin); + } + } + + if (endIt->second.first == Kind::XO) + { + if (endIt->second.second == origBegin->second.second) + { + mAreas.erase(endIt); + } + } + } + }; } // namespace rx