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

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

/*!
 * @file A tool that detects out-of-bounds (OOB) memory accesses in kernels
 */

#ifndef BOUNDS_CHECK_H_
#define BOUNDS_CHECK_H_

#include "hlif_basic_defs.h"
#include "block_2d.h"

#if defined(__cplusplus)
#include "gtpin_api.h"
using namespace gtpin;
#endif

#pragma pack(push, 8)

/* ============================================================================================= */
// Struct MemRange
/* ============================================================================================= */
/// Range in the memory address space
typedef struct MemRange
{
    uintptr_t   base;   ///< Base address of the range
    size_t      size;   ///< Size of the range in bytes

    #if defined(__cplusplus)
    constexpr MemRange(uintptr_t b = 0, size_t s = 0) : base(b), size(s) {}     ///< Constructor
    constexpr MemRange(const AddrRange& r) : base(r.Base()), size(r.Size()) {}  ///< Constructor
    #endif
} MemRange;

/* ============================================================================================= */
// Struct MemBounds
/* ============================================================================================= */
/// Flexible (variable size) array of memory ranges that represent bounds of available memory resources
typedef struct MemBounds
{
    uint32_t    numRanges;  ///< Number of elements in the 'ranges' array
    MemRange    ranges[1];  ///< Flexible array of memory ranges

    #if defined(__cplusplus)
    /// @return Size of this structure in bytes
    constexpr size_t SizeOf() const
    { return (sizeof(MemBounds) - sizeof(MemRange) + (numRanges * sizeof(MemRange))); }
    
    /// Given a number of memory ranges, return size of this structure in bytes
    static constexpr size_t SizeOf(uint32_t numRanges)
    { return (sizeof(MemBounds) - sizeof(MemRange) + (numRanges * sizeof(MemRange))); }
    #endif

} MemBounds;

/* ============================================================================================= */
// Struct BoundsCheckArgs
/* ============================================================================================= */
/// Common arguments of HLI functions that detect OOB violations in memory access instructions
typedef struct BoundsCheckArgs
{
    struct
    {
        uint32_t    numAddresses;          ///< Number of elements in the address payload of the instruction
        uint32_t    dataSize;              ///< Size, in bytes, of the memory range referenced by the corresponding address
        uint32_t    surfaceSize;           ///< Size, in bytes, of the available memory space for a surface access.
                                           ///< This value is valid for stateful (BTS), bindless (SS), and SLM accesses only.
                                           ///< For other address models, it is set to UINT32_MAX.
    } in;
    struct
    {
        uint32_t    oobCount;              ///< Counter of detected OOB violations
    }out;

    #if defined(__cplusplus)
    /// Constructor
    BoundsCheckArgs(uint32_t nAddr = 0, uint32_t dSize = 0, uint32_t sSize = 0) :
        in({ nAddr, dSize, sSize }), out({ 0 }) {}
    #endif
} BoundsCheckArgs;

/* ============================================================================================= */
// Function CheckA64Access
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the FLAT A64 memory access
 * @param[in]       allocatedBuffers    Array of global global memory buffers available to the kernel
 * @param[in]       addr                Base address of the accessed memory range
 * @param[in]       accessMask          Per-channel mask of memory accesses
 * @param[in][out]  boundsCheckArgs     Information about memory access instruction and results of the bounds check
 */
IGC_STACK_CALL void CheckA64Access(__global const MemBounds* allocatedBuffers,
                                   uint64_t addr,
                                   uint32_t accessMask,
                                   __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckA64AccessFunc = GtHliFunction<void, const MemBounds*, uint64_t, uint32_t, BoundsCheckArgs*>;
#endif

/* ============================================================================================= */
// Function CheckA32Access
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the FLAT A32 memory access
 * @copydetails CheckA64Access
 */
IGC_STACK_CALL void CheckA32Access(__global const MemBounds* allocatedBuffers,
                                   uint32_t addr,
                                   uint32_t accessMask,
                                   __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckA32AccessFunc = GtHliFunction<void, const MemBounds*, uint32_t, uint32_t, BoundsCheckArgs*>;
#endif

/* ============================================================================================= */
// Function CheckSurfaceAccess
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the surface (BTS/SLM/scratch) memory access
 * @param[in]       offset              Offset of the accessed memory range within the surface space
 * @param[in]       accessMask          Per-channel mask of memory accesses
 * @param[in][out]  boundsCheckArgs     Information about memory access instruction and results of the bounds check
 */
IGC_STACK_CALL void CheckSurfaceAccess(uint32_t offset, uint32_t accessMask, __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckSurfaceAccessFunc = GtHliFunction<void, uint32_t, uint32_t, BoundsCheckArgs*>;
#endif

/* ============================================================================================= */
// Function CheckA64ScatteredAccess
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the scattered FLAT A64 memory access
 * @param[in]       allocatedBuffers    Array of global memory buffers available to the kernel
 * @param[in]       addrPayload         Array of base addresses of accessed memory ranges
 * @param[in]       accessMask          Per-channel mask of memory accesses
 * @param[in][out]  boundsCheckArgs     Information about memory access instruction and results of the bounds check
 */
IGC_STACK_CALL void CheckA64ScatteredAccess(__global const MemBounds* allocatedBuffers,
                                            __global const uint64_t* addrPayload,
                                            uint32_t accessMask,
                                            __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckA64ScatteredAccessFunc = GtHliFunction<void, const MemBounds*, const uint64_t*, uint32_t, BoundsCheckArgs*>;
#endif

/* ============================================================================================= */
// Function CheckA32ScatteredAccess
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the scattered FLAT A32 memory access
 * @copydetails CheckA64ScatteredAccess
 */
IGC_STACK_CALL void CheckA32ScatteredAccess(__global const MemBounds* allocatedBuffers,
                                            __global const uint32_t* addrPayload,
                                            uint32_t accessMask,
                                            __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckA32ScatteredAccessFunc = GtHliFunction<void, const MemBounds*, const uint32_t*, uint32_t, BoundsCheckArgs*>;
#endif

/* ============================================================================================= */
// Function CheckSurfaceScatteredAccess
/* ============================================================================================= */
/*!
 * @brief HLI function that detects OOB violations in the scattered surface (BTS/SLM/scratch) memory access
 * @param[in]       offsets         Array of offsets of accessed memory ranges within the surface space
 * @param[in]       accessMask          Per-channel mask of memory accesses
 * @param[in][out]  boundsCheckArgs     Information about memory access instruction and results of the bounds check
 */
IGC_STACK_CALL void CheckSurfaceScatteredAccess(__global const uint32_t* offsets,
                                                uint32_t accessMask,
                                                __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckSurfaceScatteredAccessFunc = GtHliFunction<void, const uint32_t*, uint32_t, BoundsCheckArgs*>;
#endif

/*!
 * @brief HLI function that detects OOB violations in the block 2D memory access
 * @param[in]       allocatedBuffers    Array of global memory buffers available to the kernel
 * @param[in]       block               Pointer to the block 2D structure representing the accessed memory range
 * @param[in]       accessMask          Per-channel mask of memory accesses
 * @param[in][out]  boundsCheckArgs     Information about memory access instruction and results of the bounds check
 */
IGC_STACK_CALL void CheckBlock2DAccess(__global const MemBounds* allocatedBuffers,
                                       __global const Block2D* block,
                                       uint32_t accessMask,
                                       __global BoundsCheckArgs* boundsCheckArgs);
#if defined(__cplusplus)
using CheckBlock2DAccessFunc = GtHliFunction<void, const MemBounds*, const uint64_t*, uint32_t, BoundsCheckArgs*>;
#endif

#pragma pack(pop)

#endif