/* Intrinsics for LoongArch BASE operations.
   Copyright (C) 2021-2023 Free Software Foundation, Inc.
   Contributed by Loongson Ltd.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.

GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#ifndef _GCC_LOONGARCH_BASE_INTRIN_H
#define _GCC_LOONGARCH_BASE_INTRIN_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct drdtime
{
  unsigned long dvalue;
  unsigned long dtimeid;
} __drdtime_t;

typedef struct rdtime
{
  unsigned int value;
  unsigned int timeid;
} __rdtime_t;

#ifdef __loongarch64
extern __inline __drdtime_t
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__rdtime_d (void)
{
  __drdtime_t __drdtime;
  __asm__ volatile (
    "rdtime.d\t%[val],%[tid]\n\t"
    : [val]"=&r"(__drdtime.dvalue),[tid]"=&r"(__drdtime.dtimeid)
    :);
  return __drdtime;
}
#endif

extern __inline __rdtime_t
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__rdtimeh_w (void)
{
  __rdtime_t __rdtime;
  __asm__ volatile (
    "rdtimeh.w\t%[val],%[tid]\n\t"
    : [val]"=&r"(__rdtime.value),[tid]"=&r"(__rdtime.timeid)
    :);
  return __rdtime;
}

extern __inline __rdtime_t
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__rdtimel_w (void)
{
  __rdtime_t __rdtime;
  __asm__ volatile (
    "rdtimel.w\t%[val],%[tid]\n\t"
    : [val]"=&r"(__rdtime.value),[tid]"=&r"(__rdtime.timeid)
    :);
  return __rdtime;
}

/* Assembly instruction format:	rj, fcsr.  */
/* Data types in instruction templates:  USI, UQI.  */
#define __movfcsr2gr(/*ui5*/ _1) __builtin_loongarch_movfcsr2gr ((_1));

/* Assembly instruction format:	fcsr, rj.  */
/* Data types in instruction templates:  VOID, UQI, USI.  */
#define __movgr2fcsr(/*ui5*/ _1, _2) \
  __builtin_loongarch_movgr2fcsr ((_1), (unsigned int) _2);

#if defined __loongarch64
/* Assembly instruction format:	ui5, rj, si12.  */
/* Data types in instruction templates:  VOID, USI, UDI, SI.  */
#define __cacop_d(/*ui5*/ _1, /*unsigned long int*/ _2, /*si12*/ _3) \
  ((void) __builtin_loongarch_cacop_d ((_1), (unsigned long int) (_2), (_3)))
#else
#error "Unsupported ABI."
#endif

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  USI, USI.  */
extern __inline unsigned int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__cpucfg (unsigned int _1)
{
  return (unsigned int) __builtin_loongarch_cpucfg ((unsigned int) _1);
}

#ifdef __loongarch64
/* Assembly instruction format:	rj, rk.  */
/* Data types in instruction templates:  DI, DI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__asrtle_d (long int _1, long int _2)
{
  __builtin_loongarch_asrtle_d ((long int) _1, (long int) _2);
}

/* Assembly instruction format:	rj, rk.  */
/* Data types in instruction templates:  DI, DI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__asrtgt_d (long int _1, long int _2)
{
  __builtin_loongarch_asrtgt_d ((long int) _1, (long int) _2);
}
#endif

#if defined __loongarch64
/* Assembly instruction format:	rd, rj, ui5.  */
/* Data types in instruction templates:  DI, DI, UQI.  */
#define __lddir_d(/*long int*/ _1, /*ui5*/ _2) \
  ((long int) __builtin_loongarch_lddir_d ((long int) (_1), (_2)))
#else
#error "Unsupported ABI."
#endif

#if defined __loongarch64
/* Assembly instruction format:	rj, ui5.  */
/* Data types in instruction templates:  VOID, DI, UQI.  */
#define __ldpte_d(/*long int*/ _1, /*ui5*/ _2) \
  ((void) __builtin_loongarch_ldpte_d ((long int) (_1), (_2)))
#else
#error "Unsupported ABI."
#endif

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, QI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crc_w_b_w (char _1, int _2)
{
  return (int) __builtin_loongarch_crc_w_b_w ((char) _1, (int) _2);
}

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, HI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crc_w_h_w (short _1, int _2)
{
  return (int) __builtin_loongarch_crc_w_h_w ((short) _1, (int) _2);
}

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, SI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crc_w_w_w (int _1, int _2)
{
  return (int) __builtin_loongarch_crc_w_w_w ((int) _1, (int) _2);
}

#ifdef __loongarch64
/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, DI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crc_w_d_w (long int _1, int _2)
{
  return (int) __builtin_loongarch_crc_w_d_w ((long int) _1, (int) _2);
}
#endif

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, QI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crcc_w_b_w (char _1, int _2)
{
  return (int) __builtin_loongarch_crcc_w_b_w ((char) _1, (int) _2);
}

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, HI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crcc_w_h_w (short _1, int _2)
{
  return (int) __builtin_loongarch_crcc_w_h_w ((short) _1, (int) _2);
}

/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, SI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crcc_w_w_w (int _1, int _2)
{
  return (int) __builtin_loongarch_crcc_w_w_w ((int) _1, (int) _2);
}

#ifdef __loongarch64
/* Assembly instruction format:	rd, rj, rk.  */
/* Data types in instruction templates:  SI, DI, SI.  */
extern __inline int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__crcc_w_d_w (long int _1, int _2)
{
  return (int) __builtin_loongarch_crcc_w_d_w ((long int) _1, (int) _2);
}
#endif

/* Assembly instruction format:	rd, ui14.  */
/* Data types in instruction templates:  USI, USI.  */
#define __csrrd_w(/*ui14*/ _1) \
  ((unsigned int) __builtin_loongarch_csrrd_w ((_1)))

/* Assembly instruction format:	rd, ui14.  */
/* Data types in instruction templates:  USI, USI, USI.  */
#define __csrwr_w(/*unsigned int*/ _1, /*ui14*/ _2) \
  ((unsigned int) __builtin_loongarch_csrwr_w ((unsigned int) (_1), (_2)))

/* Assembly instruction format:	rd, rj, ui14.  */
/* Data types in instruction templates:  USI, USI, USI, USI.  */
#define __csrxchg_w(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) \
  ((unsigned int) __builtin_loongarch_csrxchg_w ((unsigned int) (_1), \
					       (unsigned int) (_2), (_3)))

#ifdef __loongarch64
/* Assembly instruction format:	rd, ui14.  */
/* Data types in instruction templates:  UDI, USI.  */
#define __csrrd_d(/*ui14*/ _1) \
  ((unsigned long int) __builtin_loongarch_csrrd_d ((_1)))

/* Assembly instruction format:	rd, ui14.  */
/* Data types in instruction templates:  UDI, UDI, USI.  */
#define __csrwr_d(/*unsigned long int*/ _1, /*ui14*/ _2) \
  ((unsigned long int) __builtin_loongarch_csrwr_d ((unsigned long int) (_1), \
						   (_2)))

/* Assembly instruction format:	rd, rj, ui14.  */
/* Data types in instruction templates:  UDI, UDI, UDI, USI.  */
#define __csrxchg_d(/*unsigned long int*/ _1, /*unsigned long int*/ _2, \
		   /*ui14*/ _3) \
  ((unsigned long int) __builtin_loongarch_csrxchg_d ( \
    (unsigned long int) (_1), (unsigned long int) (_2), (_3)))
#endif

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  UQI, USI.  */
extern __inline unsigned char
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrrd_b (unsigned int _1)
{
  return (unsigned char) __builtin_loongarch_iocsrrd_b ((unsigned int) _1);
}

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  UHI, USI.  */
extern __inline unsigned char
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrrd_h (unsigned int _1)
{
  return (unsigned short) __builtin_loongarch_iocsrrd_h ((unsigned int) _1);
}

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  USI, USI.  */
extern __inline unsigned int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrrd_w (unsigned int _1)
{
  return (unsigned int) __builtin_loongarch_iocsrrd_w ((unsigned int) _1);
}

#ifdef __loongarch64
/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  UDI, USI.  */
extern __inline unsigned long int
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrrd_d (unsigned int _1)
{
  return (unsigned long int) __builtin_loongarch_iocsrrd_d ((unsigned int) _1);
}
#endif

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  VOID, UQI, USI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrwr_b (unsigned char _1, unsigned int _2)
{
  __builtin_loongarch_iocsrwr_b ((unsigned char) _1, (unsigned int) _2);
}

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  VOID, UHI, USI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrwr_h (unsigned short _1, unsigned int _2)
{
  __builtin_loongarch_iocsrwr_h ((unsigned short) _1, (unsigned int) _2);
}

/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  VOID, USI, USI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrwr_w (unsigned int _1, unsigned int _2)
{
  __builtin_loongarch_iocsrwr_w ((unsigned int) _1, (unsigned int) _2);
}

#ifdef __loongarch64
/* Assembly instruction format:	rd, rj.  */
/* Data types in instruction templates:  VOID, UDI, USI.  */
extern __inline void
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__iocsrwr_d (unsigned long int _1, unsigned int _2)
{
  __builtin_loongarch_iocsrwr_d ((unsigned long int) _1, (unsigned int) _2);
}
#endif

/* Assembly instruction format:	ui15.  */
/* Data types in instruction templates:  USI.  */
#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar ((_1))

/* Assembly instruction format:	ui15.  */
/* Data types in instruction templates:  USI.  */
#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar ((_1))

/* Assembly instruction format:	ui15.  */
/* Data types in instruction templates:  USI.  */
#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall ((_1))

/* Assembly instruction format:	ui15.  */
/* Data types in instruction templates:  USI.  */
#define __break(/*ui15*/ _1) __builtin_loongarch_break ((_1))

#ifdef __cplusplus
}
#endif
#endif /* _GCC_LOONGARCH_BASE_INTRIN_H */
