Blame sysdeps/mips/tst-abi-interlink.c

Packit 6c4009
/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sys/prctl.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
Packit 6c4009
#if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE
Packit 6c4009
# define HAVE_PRCTL_FP_MODE 1
Packit 6c4009
# define FR1_MODE (PR_FP_MODE_FR)
Packit 6c4009
# define FRE_MODE (PR_FP_MODE_FR | PR_FP_MODE_FRE)
Packit 6c4009
#else
Packit 6c4009
# define HAVE_PRCTL_FP_MODE 0
Packit 6c4009
# define FR1_MODE 0x1
Packit 6c4009
# define FRE_MODE 0x2
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define STR_VAL(VAL) #VAL
Packit 6c4009
#define N_STR(VAL) STR_VAL(VAL)
Packit 6c4009
Packit 6c4009
#define START_STATE(NAME) 					\
Packit 6c4009
case s_ ## NAME: 						\
Packit 6c4009
  {								\
Packit 6c4009
    switch (obj) 						\
Packit 6c4009
      {
Packit 6c4009
Packit 6c4009
#define END_STATE						\
Packit 6c4009
      default:							\
Packit 6c4009
        return false;						\
Packit 6c4009
      }								\
Packit 6c4009
  break;							\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#define NEXT(OBJ, NEXT_STATE)					\
Packit 6c4009
case o_ ## OBJ: 						\
Packit 6c4009
  current_fp_state = s_ ## NEXT_STATE;				\
Packit 6c4009
  break;
Packit 6c4009
Packit 6c4009
#define NEXT_REQ_FR1(OBJ, NEXT_STATE)				\
Packit 6c4009
case o_ ## OBJ:							\
Packit 6c4009
  {								\
Packit 6c4009
    if (has_fr1)						\
Packit 6c4009
      current_fp_state = s_ ## NEXT_STATE;			\
Packit 6c4009
    else							\
Packit 6c4009
      return false;						\
Packit 6c4009
  }								\
Packit 6c4009
  break;
Packit 6c4009
Packit 6c4009
#define NEXT_REQ_FR0(OBJ, NEXT_STATE) 				\
Packit 6c4009
case o_ ## OBJ:							\
Packit 6c4009
  {								\
Packit 6c4009
    if (!is_r6							\
Packit 6c4009
        || (is_r6 && has_fr1 && has_fre))			\
Packit 6c4009
      current_fp_state = s_ ## NEXT_STATE;			\
Packit 6c4009
    else 							\
Packit 6c4009
      return false;						\
Packit 6c4009
  }								\
Packit 6c4009
  break;
Packit 6c4009
Packit 6c4009
#define NEXT_REQ_FRE(OBJ, NEXT_STATE)				\
Packit 6c4009
case o_ ## OBJ: 						\
Packit 6c4009
  {								\
Packit 6c4009
    if (has_fr1 && has_fre)					\
Packit 6c4009
      current_fp_state = s_ ## NEXT_STATE;			\
Packit 6c4009
    else							\
Packit 6c4009
      return false;						\
Packit 6c4009
  }								\
Packit 6c4009
  break;
Packit 6c4009
Packit 6c4009
#define NEXT_NO_MODE_CHANGE(OBJ, NEXT_STATE)			\
Packit 6c4009
case o_ ## OBJ: 						\
Packit 6c4009
  {								\
Packit 6c4009
    if (current_mode_valid_p (s_ ## NEXT_STATE))			\
Packit 6c4009
      {								\
Packit 6c4009
	current_fp_state = s_ ## NEXT_STATE;			\
Packit 6c4009
	cant_change_mode = true;				\
Packit 6c4009
      }								\
Packit 6c4009
    else							\
Packit 6c4009
      return false;						\
Packit 6c4009
  }								\
Packit 6c4009
  break;
Packit 6c4009
Packit 6c4009
static const char * const shared_lib_names[] =
Packit 6c4009
  {
Packit 6c4009
    "tst-abi-fpanymod.so", "tst-abi-fpsoftmod.so", "tst-abi-fpsinglemod.so",
Packit 6c4009
    "tst-abi-fp32mod.so", "tst-abi-fp64mod.so", "tst-abi-fp64amod.so",
Packit 6c4009
    "tst-abi-fpxxmod.so", "tst-abi-fpxxomod.so"
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
struct fp_mode_req
Packit 6c4009
{
Packit 6c4009
  int mode1;
Packit 6c4009
  int mode2;
Packit 6c4009
  int mode3;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
enum fp_obj
Packit 6c4009
{
Packit 6c4009
  o_any,
Packit 6c4009
  o_soft,
Packit 6c4009
  o_single,
Packit 6c4009
  o_fp32,
Packit 6c4009
  o_fp64,
Packit 6c4009
  o_fp64a,
Packit 6c4009
  o_fpxx,
Packit 6c4009
  o_fpxxo,
Packit 6c4009
  o_max
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
enum fp_state
Packit 6c4009
{
Packit 6c4009
  s_any,
Packit 6c4009
  s_soft,
Packit 6c4009
  s_single,
Packit 6c4009
  s_fp32,
Packit 6c4009
  s_fpxx,
Packit 6c4009
  s_fpxxo,
Packit 6c4009
  s_fp64a,
Packit 6c4009
  s_fp64,
Packit 6c4009
  s_fpxxo_fpxx,
Packit 6c4009
  s_fp32_fpxx,
Packit 6c4009
  s_fp32_fpxxo,
Packit 6c4009
  s_fp32_fpxxo_fpxx,
Packit 6c4009
  s_fp32_fp64a_fpxx,
Packit 6c4009
  s_fp32_fp64a_fpxxo,
Packit 6c4009
  s_fp32_fp64a_fpxxo_fpxx,
Packit 6c4009
  s_fp64a_fp32,
Packit 6c4009
  s_fp64a_fpxx,
Packit 6c4009
  s_fp64a_fpxxo,
Packit 6c4009
  s_fp64a_fp64,
Packit 6c4009
  s_fp64a_fp64_fpxx,
Packit 6c4009
  s_fp64a_fp64_fpxxo,
Packit 6c4009
  s_fp64a_fpxx_fpxxo,
Packit 6c4009
  s_fp64a_fp64_fpxxo_fpxx,
Packit 6c4009
  s_fp64_fpxx,
Packit 6c4009
  s_fp64_fpxxo,
Packit 6c4009
  s_fp64_fpxx_fpxxo
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int current_fp_mode;
Packit 6c4009
static bool cant_change_mode = false;
Packit 6c4009
static bool has_fr1 = false;
Packit 6c4009
static bool has_fre = false;
Packit 6c4009
static bool is_r6 = false;
Packit 6c4009
static unsigned int fp_obj_count[o_max];
Packit 6c4009
void * shared_lib_ptrs[o_max];
Packit 6c4009
static enum fp_state current_fp_state = s_any;
Packit 6c4009
static enum fp_obj test_objects[FPABI_COUNT] = { FPABI_LIST };
Packit 6c4009
Packit 6c4009
/* This function will return the valid FP modes for the specified state.  */
Packit 6c4009
Packit 6c4009
static struct fp_mode_req
Packit 6c4009
compute_fp_modes (enum fp_state state)
Packit 6c4009
{
Packit 6c4009
  struct fp_mode_req requirements;
Packit 6c4009
Packit 6c4009
  requirements.mode1 = -1;
Packit 6c4009
  requirements.mode2 = -1;
Packit 6c4009
  requirements.mode3 = -1;
Packit 6c4009
Packit 6c4009
  switch (state)
Packit 6c4009
    {
Packit 6c4009
    case s_single:
Packit 6c4009
      {
Packit 6c4009
        if (is_r6)
Packit 6c4009
	  requirements.mode1 = FR1_MODE;
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    requirements.mode1 = 0;
Packit 6c4009
	    requirements.mode2 = FR1_MODE;
Packit 6c4009
	  }
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    case s_fp32:
Packit 6c4009
    case s_fp32_fpxx:
Packit 6c4009
    case s_fp32_fpxxo:
Packit 6c4009
    case s_fp32_fpxxo_fpxx:
Packit 6c4009
      {
Packit 6c4009
	if (is_r6)
Packit 6c4009
	  requirements.mode1 = FRE_MODE;
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    requirements.mode1 = 0;
Packit 6c4009
	    requirements.mode2 = FRE_MODE;
Packit 6c4009
	  }
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    case s_fpxx:
Packit 6c4009
    case s_fpxxo:
Packit 6c4009
    case s_fpxxo_fpxx:
Packit 6c4009
    case s_any:
Packit 6c4009
    case s_soft:
Packit 6c4009
      {
Packit 6c4009
	if (is_r6)
Packit 6c4009
	  {
Packit 6c4009
	    requirements.mode1 = FR1_MODE;
Packit 6c4009
	    requirements.mode2 = FRE_MODE;
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    requirements.mode1 = 0;
Packit 6c4009
	    requirements.mode2 = FR1_MODE;
Packit 6c4009
	    requirements.mode3 = FRE_MODE;
Packit 6c4009
	  }
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    case s_fp64a:
Packit 6c4009
    case s_fp64a_fpxx:
Packit 6c4009
    case s_fp64a_fpxxo:
Packit 6c4009
    case s_fp64a_fpxx_fpxxo:
Packit 6c4009
      {
Packit 6c4009
	requirements.mode1 = FR1_MODE;
Packit 6c4009
	requirements.mode2 = FRE_MODE;
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    case s_fp64:
Packit 6c4009
    case s_fp64_fpxx:
Packit 6c4009
    case s_fp64_fpxxo:
Packit 6c4009
    case s_fp64_fpxx_fpxxo:
Packit 6c4009
    case s_fp64a_fp64:
Packit 6c4009
    case s_fp64a_fp64_fpxx:
Packit 6c4009
    case s_fp64a_fp64_fpxxo:
Packit 6c4009
    case s_fp64a_fp64_fpxxo_fpxx:
Packit 6c4009
      {
Packit 6c4009
	requirements.mode1 = FR1_MODE;
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    case s_fp64a_fp32:
Packit 6c4009
    case s_fp32_fp64a_fpxx:
Packit 6c4009
    case s_fp32_fp64a_fpxxo:
Packit 6c4009
    case s_fp32_fp64a_fpxxo_fpxx:
Packit 6c4009
      {
Packit 6c4009
        requirements.mode1 = FRE_MODE;
Packit 6c4009
        break;
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
  return requirements;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Check the current mode is suitable for the specified state.  */
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
current_mode_valid_p (enum fp_state s)
Packit 6c4009
{
Packit 6c4009
  struct fp_mode_req req = compute_fp_modes (s);
Packit 6c4009
  return (req.mode1 == current_fp_mode
Packit 6c4009
	  || req.mode2 == current_fp_mode
Packit 6c4009
	  || req.mode3 == current_fp_mode);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Run the state machine by adding a new object.  */
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
set_next_fp_state (enum fp_obj obj)
Packit 6c4009
{
Packit 6c4009
  cant_change_mode = false;
Packit 6c4009
  switch (current_fp_state)
Packit 6c4009
    {
Packit 6c4009
Packit 6c4009
    START_STATE(soft)
Packit 6c4009
    NEXT(soft,soft)
Packit 6c4009
    NEXT(any,soft)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(single)
Packit 6c4009
    NEXT(single,single)
Packit 6c4009
    NEXT(any,single)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(any)
Packit 6c4009
    NEXT_REQ_FR0(fp32, fp32)
Packit 6c4009
    NEXT(fpxx, fpxx)
Packit 6c4009
    NEXT(fpxxo, fpxxo)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64)
Packit 6c4009
    NEXT(any,any)
Packit 6c4009
    NEXT(soft,soft)
Packit 6c4009
    NEXT(single,single)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32)
Packit 6c4009
    NEXT_REQ_FR0(fp32,fp32)
Packit 6c4009
    NEXT(fpxx, fp32_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp32_fpxxo)
Packit 6c4009
    NEXT_REQ_FRE(fp64a, fp64a_fp32)
Packit 6c4009
    NEXT(any,fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxx)
Packit 6c4009
    NEXT_REQ_FR0(fp32, fp32_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fpxx)
Packit 6c4009
    NEXT(fpxxo, fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx,fpxx)
Packit 6c4009
    NEXT(any,fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo,fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any,fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a)
Packit 6c4009
    NEXT_REQ_FRE(fp32, fp64a_fp32)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64a_fp64)
Packit 6c4009
    NEXT(fpxxo, fp64a_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp64a_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a)
Packit 6c4009
    NEXT(any, fp64a)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fp64)
Packit 6c4009
    NEXT(fpxxo, fp64_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64)
Packit 6c4009
    NEXT(any, fp64)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fpxxo_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxx)
Packit 6c4009
    NEXT_REQ_FR0(fp32, fp32_fpxx)
Packit 6c4009
    NEXT(fpxx, fp32_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT(any, fp32_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp32_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp32_fpxxo_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp32)
Packit 6c4009
    NEXT_REQ_FRE(fp32, fp64a_fp32)
Packit 6c4009
    NEXT_REQ_FRE(fp64a, fp64a_fp32)
Packit 6c4009
    NEXT(fpxxo, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT(any, fp64a_fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxx)
Packit 6c4009
    NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(any, fp64a_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64a_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64a_fpxx_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64_fpxx)
Packit 6c4009
    NEXT(any, fp64_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64_fpxx_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fp64)
Packit 6c4009
    NEXT(fpxxo, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64a_fp64)
Packit 6c4009
    NEXT(any, fp64a_fp64)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(any, fp64a_fp64_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxx)
Packit 6c4009
    NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx, fp32_fp64a_fpxx)
Packit 6c4009
    NEXT(any, fp32_fp64a_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (obj != o_max)
Packit 6c4009
    fp_obj_count[obj]++;
Packit 6c4009
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Run the state machine by removing an object.  */
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
remove_object (enum fp_obj obj)
Packit 6c4009
{
Packit 6c4009
  if (obj == o_max)
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  fp_obj_count[obj]--;
Packit 6c4009
Packit 6c4009
  /* We can't change fp state until all the objects
Packit 6c4009
     of a particular type have been unloaded.  */
Packit 6c4009
  if (fp_obj_count[obj] != 0)
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  switch (current_fp_state)
Packit 6c4009
    {
Packit 6c4009
    START_STATE(soft)
Packit 6c4009
    NEXT(soft,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(single)
Packit 6c4009
    NEXT(single,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(any)
Packit 6c4009
    NEXT(any,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32)
Packit 6c4009
    NEXT (fp32,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxx)
Packit 6c4009
    NEXT (fpxx,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxxo)
Packit 6c4009
    NEXT (fpxxo,any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a)
Packit 6c4009
    NEXT(fp64a, any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64)
Packit 6c4009
    NEXT(fp64, any)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx, fpxxo)
Packit 6c4009
    NEXT(fpxxo, fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxx)
Packit 6c4009
    NEXT(fp32, fpxx)
Packit 6c4009
    NEXT(fpxx, fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxxo)
Packit 6c4009
    NEXT(fp32, fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT(fp32, fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp32_fpxx)
Packit 6c4009
    NEXT(fpxx, fp32_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp32)
Packit 6c4009
    NEXT(fp32, fp64a)
Packit 6c4009
    NEXT(fp64a, fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxx)
Packit 6c4009
    NEXT(fp64a, fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxxo)
Packit 6c4009
    NEXT(fp64a, fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64a)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT(fp64a, fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64a_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64)
Packit 6c4009
    NEXT(fp64, fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64)
Packit 6c4009
    NEXT(fp64, fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT(fp64, fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxxo, fp64_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64)
Packit 6c4009
    NEXT(fp64a, fp64)
Packit 6c4009
    NEXT(fp64, fp64a)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(fp64a, fp64_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a_fp64)
Packit 6c4009
    NEXT(fp64, fp64a_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT(fp64a, fp64_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64a_fp64)
Packit 6c4009
    NEXT(fp64, fp64a_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp64a_fp64_fpxxo_fpxx)
Packit 6c4009
    NEXT(fp64a, fp64_fpxx_fpxxo)
Packit 6c4009
    NEXT(fpxx, fp64a_fp64_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64a_fp64_fpxx)
Packit 6c4009
    NEXT(fp64, fp64a_fpxx_fpxxo)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxx)
Packit 6c4009
    NEXT(fp32, fp64a_fpxx)
Packit 6c4009
    NEXT(fp64a, fp32_fpxx)
Packit 6c4009
    NEXT(fpxx, fp64a_fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT(fp32, fp64a_fpxxo)
Packit 6c4009
    NEXT(fp64a, fp32_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp64a_fp32)
Packit 6c4009
    END_STATE
Packit 6c4009
Packit 6c4009
    START_STATE(fp32_fp64a_fpxxo_fpxx)
Packit 6c4009
    NEXT(fp32, fp64a_fpxx_fpxxo)
Packit 6c4009
    NEXT(fp64a, fp32_fpxxo_fpxx)
Packit 6c4009
    NEXT(fpxx, fp32_fp64a_fpxxo)
Packit 6c4009
    NEXT(fpxxo, fp32_fp64a_fpxx)
Packit 6c4009
    END_STATE
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
mode_transition_valid_p (void)
Packit 6c4009
{
Packit 6c4009
  int prev_fp_mode;
Packit 6c4009
Packit 6c4009
  /* Get the current fp mode.  */
Packit 6c4009
  prev_fp_mode = current_fp_mode;
Packit 6c4009
#if HAVE_PRCTL_FP_MODE
Packit 6c4009
  current_fp_mode = prctl (PR_GET_FP_MODE);
Packit 6c4009
Packit 6c4009
  /* If the prctl call fails assume the core only has FR0 mode support.  */
Packit 6c4009
  if (current_fp_mode == -1)
Packit 6c4009
    current_fp_mode = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (!current_mode_valid_p (current_fp_state))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* Check if mode changes are not allowed but a mode change happened.  */
Packit 6c4009
  if (cant_change_mode
Packit 6c4009
      && current_fp_mode != prev_fp_mode)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Load OBJ and check that it was/was not loaded correctly.  */
Packit 6c4009
bool
Packit 6c4009
load_object (enum fp_obj obj)
Packit 6c4009
{
Packit 6c4009
  bool should_load = set_next_fp_state (obj);
Packit 6c4009
Packit 6c4009
  shared_lib_ptrs[obj] = dlopen (shared_lib_names[obj], RTLD_LAZY);
Packit 6c4009
Packit 6c4009
  /* If we expected an error and the load was successful then fail.  */
Packit 6c4009
  if (!should_load && (shared_lib_ptrs[obj] != 0))
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  if (should_load && (shared_lib_ptrs[obj] == 0))
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  if (!mode_transition_valid_p ())
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Remove an object and check the state remains valid.  */
Packit 6c4009
bool
Packit 6c4009
unload_object (enum fp_obj obj)
Packit 6c4009
{
Packit 6c4009
  if (!shared_lib_ptrs[obj])
Packit 6c4009
    return true;
Packit 6c4009
Packit 6c4009
  remove_object (obj);
Packit 6c4009
Packit 6c4009
  if (dlclose (shared_lib_ptrs[obj]) != 0)
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  shared_lib_ptrs[obj] = 0;
Packit 6c4009
Packit 6c4009
  if (!mode_transition_valid_p ())
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Load every permuation of OBJECTS.  */
Packit 6c4009
static bool
Packit 6c4009
test_permutations (enum fp_obj objects[], int count)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  for (i = 0 ; i < count ; i++)
Packit 6c4009
    {
Packit 6c4009
      if (!load_object (objects[i]))
Packit 6c4009
	return false;
Packit 6c4009
Packit 6c4009
      if (count > 1)
Packit 6c4009
	{
Packit 6c4009
	  enum fp_obj new_objects[count - 1];
Packit 6c4009
	  int j;
Packit 6c4009
	  int k = 0;
Packit 6c4009
Packit 6c4009
	  for (j = 0 ; j < count ; j++)
Packit 6c4009
	    {
Packit 6c4009
	      if (j != i)
Packit 6c4009
		new_objects[k++] = objects[j];
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (!test_permutations (new_objects, count - 1))
Packit 6c4009
	    return false;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (!unload_object (objects[i]))
Packit 6c4009
	return false;
Packit 6c4009
    }
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
#if HAVE_PRCTL_FP_MODE
Packit 6c4009
  /* Determine available hardware support and current mode.  */
Packit 6c4009
  current_fp_mode = prctl (PR_GET_FP_MODE);
Packit 6c4009
Packit 6c4009
  /* If the prctl call fails assume the core only has FR0 mode support.  */
Packit 6c4009
  if (current_fp_mode == -1)
Packit 6c4009
    current_fp_mode = 0;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (prctl (PR_SET_FP_MODE, 0) != 0)
Packit 6c4009
	{
Packit 6c4009
	  if (errno == ENOTSUP)
Packit 6c4009
	    is_r6 = true;
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      printf ("unexpected error from PR_SET_FP_MODE, 0: %m\n");
Packit 6c4009
	      return 1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR) != 0)
Packit 6c4009
	{
Packit 6c4009
	  if (errno != ENOTSUP)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("unexpected error from PR_SET_FP_MODE, "
Packit 6c4009
		      "PR_FP_MODE_FR: %m\n");
Packit 6c4009
	      return 1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	has_fr1 = true;
Packit 6c4009
Packit 6c4009
      if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR | PR_FP_MODE_FRE) != 0)
Packit 6c4009
	{
Packit 6c4009
	  if (errno != ENOTSUP)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("unexpected error from PR_SET_FP_MODE, "
Packit 6c4009
		      "PR_FP_MODE_FR | PR_FP_MODE_FRE: %m\n");
Packit 6c4009
	      return 1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	has_fre = true;
Packit 6c4009
Packit 6c4009
      if (prctl (PR_SET_FP_MODE, current_fp_mode) != 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("unable to restore initial FP mode: %m\n");
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if ((is_r6 && !(current_fp_mode & PR_FP_MODE_FR))
Packit 6c4009
      || (!has_fr1 && (current_fp_mode & PR_FP_MODE_FR))
Packit 6c4009
      || (!has_fre && (current_fp_mode & PR_FP_MODE_FRE)))
Packit 6c4009
    {
Packit 6c4009
      puts ("Inconsistency detected between initial FP mode "
Packit 6c4009
	    "and supported FP modes\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
#else
Packit 6c4009
  current_fp_mode = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Set up the initial state from executable and LDSO.  Assumptions:
Packit 6c4009
     1) All system libraries have the same ABI as ld.so.
Packit 6c4009
     2) Due to the fact that ld.so is tested by invoking it directly
Packit 6c4009
        rather than via an interpreter, there is no point in varying
Packit 6c4009
	the ABI of the test program.  Instead the ABI only varies for
Packit 6c4009
	the shared libraries which get loaded.  */
Packit 6c4009
  if (!set_next_fp_state (FPABI_NATIVE))
Packit 6c4009
    {
Packit 6c4009
      puts ("Unable to enter initial ABI state\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Compare the computed state with the hardware state.  */
Packit 6c4009
  if (!mode_transition_valid_p ())
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  /* Run all possible test permutations.  */
Packit 6c4009
  if (!test_permutations (test_objects, FPABI_COUNT))
Packit 6c4009
    {
Packit 6c4009
      puts ("Mode checks failed\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../../test-skeleton.c"