/* d-port.cc -- D frontend interface to the gcc back-end.
   Copyright (C) 2013-2023 Free Software Foundation, Inc.
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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "dmd/root/port.h"
#include "dmd/target.h"
#include "tree.h"
/* Implements the Port interface defined by the frontend.
   A mini library for doing compiler/system specific things.  */
/* Compare the first N bytes of S1 and S2 without regard to the case.  */
int
Port::memicmp (const char *s1, const char *s2, d_size_t n)
{
  int result = 0;
  for (d_size_t i = 0; i < n; i++)
    {
      char c1 = s1[i];
      char c2 = s2[i];
      result = c1 - c2;
      if (result)
	{
	  result = TOUPPER (c1) - TOUPPER (c2);
	  if (result)
	    break;
	}
    }
  return result;
}
/* Convert all characters in S to uppercase.  */
char *
Port::strupr (char *s)
{
  char *t = s;
  while (*s)
    {
      *s = TOUPPER (*s);
      s++;
    }
  return t;
}
/* Return true if the real_t value from string BUFFER overflows
   as a result of rounding down to float mode.  */
bool
Port::isFloat32LiteralOutOfRange (const char *buffer)
{
  real_t r;
  real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
  return r == target.RealProperties.infinity;
}
/* Return true if the real_t value from string BUFFER overflows
   as a result of rounding down to double mode.  */
bool
Port::isFloat64LiteralOutOfRange (const char *buffer)
{
  real_t r;
  real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
  return r == target.RealProperties.infinity;
}
/* Fetch a little-endian 16-bit value from BUFFER.  */
unsigned
Port::readwordLE (const void *buffer)
{
  const unsigned char *p = (const unsigned char *) buffer;
  return ((unsigned) p[1] << 8) | (unsigned) p[0];
}
/* Fetch a big-endian 16-bit value from BUFFER.  */
unsigned
Port::readwordBE (const void *buffer)
{
  const unsigned char *p = (const unsigned char *) buffer;
  return ((unsigned) p[0] << 8) | (unsigned) p[1];
}
/* Fetch a little-endian 32-bit value from BUFFER.  */
unsigned
Port::readlongLE (const void *buffer)
{
  const unsigned char *p = (const unsigned char *) buffer;
  return (((unsigned) p[3] << 24)
	  | ((unsigned) p[2] << 16)
	  | ((unsigned) p[1] << 8)
	  | (unsigned) p[0]);
}
/* Fetch a big-endian 32-bit value from BUFFER.  */
unsigned
Port::readlongBE (const void *buffer)
{
  const unsigned char *p = (const unsigned char *) buffer;
  return (((unsigned) p[0] << 24)
	  | ((unsigned) p[1] << 16)
	  | ((unsigned) p[2] << 8)
	  | (unsigned) p[3]);
}
/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness.  */
void
Port::valcpy (void *buffer, uint64_t value, d_size_t sz)
{
  gcc_assert (((d_size_t) buffer) % sz == 0);
  switch (sz)
    {
    case 1:
      *(uint8_t *) buffer = (uint8_t) value;
      break;
    case 2:
      *(uint16_t *) buffer = (uint16_t) value;
      break;
    case 4:
      *(uint32_t *) buffer = (uint32_t) value;
      break;
    case 8:
      *(uint64_t *) buffer = (uint64_t) value;
      break;
    default:
      gcc_unreachable ();
    }
}