/*========================== begin_copyright_notice ============================
Copyright (C) 2024-2026 Intel Corporation

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/

/*!
 * @file Library of High-Level Instrumentation (HLI) functions used by the memory_check tool
 */

#include "hlif_basic_defs.h"
#include "memory_check.h"

/*!
 * @brief HLI function that initializes shared local memory
 * @see memory_check.h for details
 */
IGC_STACK_CALL void InitSlm(__global const SlmInitArg* arg, __local uint32_t* slm)
{
    uint32_t numOfDwordElements = arg->in.size >> 2;

    for (uint32_t i = 0; i != numOfDwordElements; ++i)
    {
        slm[i] = UNINITIALIZED_MEMORY_PATTERN;
    }

    barrier(CLK_LOCAL_MEM_FENCE);
}

/*!
 * @brief HLI function that detects uninitialized Shared Local Memory read accesses
 *        Only accesses that are a multiplication of dword are supported
 * @see memory_check.h for details
 */
IGC_STACK_CALL void CheckSlmReadAccess(__global const uint32_t* offsets,
                                       uint32_t accessMask,
                                       __global MemoryCheckArgs* memoryCheckArgs,
                                       __local uint32_t* slm)
{
    if (accessMask != 0)
    {
        uint32_t numOfElements = memoryCheckArgs->in.numAccesses;
        uint32_t dataSize      = memoryCheckArgs->in.dataSize;

        if (dataSize & 0x3)
        {
            return;
        }

        for (uint32_t eIndx = 0; eIndx != numOfElements; ++eIndx)
        {
            if ((accessMask & (0x1 << eIndx)) != 0)
            {
                uint32_t numOfDwordSubElements = dataSize >> 2;

                uint32_t offset = offsets[eIndx];
                uint32_t index = offset >> 2;

                for (uint32_t i = 0; i < numOfDwordSubElements; ++i)
                {
                    uint32_t data = slm[index + i];
                    if (data == UNINITIALIZED_MEMORY_PATTERN)
                    {
                        atomic_inc(&(memoryCheckArgs->out.umrCount));
                    }
                }
            }
        }
    }
}

/*!
 * @brief HLI function that detects uninitialized global memory read accesses done in A64 mode
 *        Only accesses that are a multiplication of dword are supported
 * @see memory_check.h for details
 */
IGC_STACK_CALL void CheckUgmA64ReadAccess(__global const uint64_t* addresses,
                                          uint32_t accessMask,
                                          __global MemoryCheckArgs* memoryCheckArgs)
{
    if (accessMask != 0)
    {
        uint32_t numOfElements = memoryCheckArgs->in.numAccesses;
        uint32_t dataSize      = memoryCheckArgs->in.dataSize;

        if (dataSize & 0x3)
        {
            return;
        }

        for (uint32_t eIndx = 0; eIndx != numOfElements; ++eIndx)
        {
            if ((accessMask & (0x1 << eIndx)) != 0)
            {
                uint32_t numOfDwordSubElements = dataSize >> 2;

                uint64_t addr = addresses[eIndx];

                for (uint32_t i = 0; i < numOfDwordSubElements; ++i)
                {
                    uint32_t data = *(uint32_t*)addr;
                    if (data == UNINITIALIZED_MEMORY_PATTERN)
                    {
                        atomic_inc(&(memoryCheckArgs->out.umrCount));
                    }
                    addr += 4;
                }
            }
        }
    }
}

/*!
 * @brief HLI function that detects uninitialized memory read accesses
 *        Only accesses that are a multiplication of dword are supported
 * @see memory_check.h for details
 */
IGC_STACK_CALL void CheckReadAccess(__global const uint32_t* dstPayload,
                                    uint32_t accessMask,
                                    __global MemoryCheckArgs* memoryCheckArgs)
{
    if (accessMask != 0)
    {
        uint32_t numOfElements = memoryCheckArgs->in.numAccesses;
        uint32_t dataSize      = memoryCheckArgs->in.dataSize;

        if (dataSize & 0x3)
        {
            return;
        }

        for (uint32_t eIndx = 0; eIndx != numOfElements; ++eIndx)
        {
            if ((accessMask & (0x1 << eIndx)) != 0)
            {
                uint32_t numOfDwordSubElements = dataSize >> 2;

                for (uint32_t i = 0; i < numOfDwordSubElements; ++i)
                {
                    uint32_t data = dstPayload[eIndx * numOfDwordSubElements + i];
                    if (data == UNINITIALIZED_MEMORY_PATTERN)
                    {
                        atomic_inc(&(memoryCheckArgs->out.umrCount));
                    }
                }
            }
        }
    }
}
