// Compiler for PHP (aka KPHP)
// Copyright (c) 2024 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#ifndef TYPE
# ifdef __clang__
#   define TYPE(name) // .type not supported
# else
#   define TYPE(name) .type name, @function;
# endif
#endif

#define ALIGNARG(log2) 1 << log2

// Define an entry point visible from C/C++.
#define ENTRY_P2ALIGN(name, alignment)    \
  .globl name;             \
  TYPE(name)                              \
  .align ALIGNARG(alignment);             \
  name:

// Common entry 16 byte aligns
#define ENTRY(name) ENTRY_P2ALIGN(name, 4)
#define END(name) .size name, .- name;

// Number of general registers
#define NUM_GENERAL_REG 23

// Register size
#define GREG_SIZE  8

// General registers
#define GREG_R8       0
#define GREG_R9       1
#define GREG_R10      2
#define GREG_R11      3
#define GREG_R12      4
#define GREG_R13      5
#define GREG_R14      6
#define GREG_R15      7
#define GREG_RDI      8
#define GREG_RSI      9
#define GREG_RBP      10
#define GREG_RBX      11
#define GREG_RDX      12
#define GREG_RAX      13
#define GREG_RCX      14
#define GREG_RSP      15
#define GREG_RIP      16
#define GREG_EFL      17
#define GREG_CSGSFS   18
#define GREG_ERR      19
#define GREG_TRAPNO   20
#define GREG_OLDMASK  21
#define GREG_CR2      22

// KPHP user context layout

/*  struct kcontext_t {               OFFSET*/
/*    uint64_t     flags                0   */
/*    kcontext_t*  link                 8   */
/*    kstack_t     stack                16  */
/*    struct kmcontext_t mcontext {         */
/*      kgregset_t  gregs               32  */  #define KCONTEXT_MCONTEXT_GREGS (32)
/*      kfpregset_t fpregs              216 */  #define KCONTEXT_MCONTEXT_FPREGS (KCONTEXT_MCONTEXT_GREGS + (GREG_SIZE * NUM_GENERAL_REG))
/*      uint64_t    reserved1[8]        224 */
/*    }                                     */
/*    struct kfpstate fpregs_mem {          */
/*      uint16_t cwd                    288 */  #define KCONTEXT_FPREGS_MEM (KCONTEXT_MCONTEXT_FPREGS + 8 + (8 * 8))
/*      uint16_t swd                    290 */
/*      uint16_t ftw                    292 */
/*      uint16_t fop                    294 */
/*      uint16_t rip                    296 */
/*      uint16_t rdp                    298 */
/*      uint16_t mxcsr                  300 */ #define KCONTEXT_FPREGS_MEM_MXCSR (KCONTEXT_FPREGS_MEM + (2 * 6))
/*      uint16_t mxcr_mask                  */
/*      kfpxreg st[8]                       */
/*      kxmmreg xmm[16]                     */
/*      uint32_t reserved1[24]              */
/*    }                                     */
/*  }                                       */

// Offset of register inside context
#define KCONTEXT_MCONTEXT_GREG_OFFSET(reg) (KCONTEXT_MCONTEXT_GREGS + ((reg) * GREG_SIZE))
#define oRBP        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RBP)
#define oRSP        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RSP)
#define oRBX        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RBX)
#define oR8         KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R8)
#define oR9         KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R9)
#define oR10        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R10)
#define oR11        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R11)
#define oR12        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R12)
#define oR13        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R13)
#define oR14        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R14)
#define oR15        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_R15)
#define oRDI        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RDI)
#define oRSI        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RSI)
#define oRDX        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RDX)
#define oRAX        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RAX)
#define oRCX        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RCX)
#define oRIP        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_RIP)
#define oEFL        KCONTEXT_MCONTEXT_GREG_OFFSET(GREG_EFL)
#define oFPREGS     KCONTEXT_MCONTEXT_FPREGS
#define oFPREGSMEM  KCONTEXT_FPREGS_MEM
#define oMXCSR      KCONTEXT_FPREGS_MEM_MXCSR
