/* Subroutines for the gcc driver.
Copyright (C) 2021-2024 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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. */
#define IN_TARGET_CODE 1
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "obstack.h"
#include "diagnostic-core.h"
#include "opts.h"
#include "loongarch-opts.h"
#include "loongarch-driver.h"
/* This flag is set to 1 if we believe that the user might be avoiding
linking (implicitly) against something from the startfile search paths. */
static int no_link = 0;
/* Use the public obstack from the gcc driver (defined in gcc.c).
This is for allocating space for the returned string. */
extern struct obstack opts_obstack;
const char*
la_driver_init (int argc ATTRIBUTE_UNUSED, const char **argv ATTRIBUTE_UNUSED)
{
/* Initialize all fields of la_target. */
loongarch_init_target (&la_target, M_OPT_UNSET, M_OPT_UNSET, M_OPT_UNSET,
M_OPT_UNSET, M_OPT_UNSET, M_OPT_UNSET, M_OPT_UNSET,
M_OPT_UNSET, 0, 0);
return "";
}
const char*
driver_set_no_link (int argc ATTRIBUTE_UNUSED,
const char **argv ATTRIBUTE_UNUSED)
{
no_link = 1;
return "";
}
const char*
driver_set_m_parm (int argc, const char **argv)
{
gcc_assert (argc == 2);
#define LARCH_DRIVER_PARSE_PARM(OPT_IDX, NAME, OPTSTR_LIST, \
OPT_IDX_LO, OPT_IDX_HI) \
if (strcmp (argv[0], OPTSTR_##NAME) == 0) \
for (int i = (OPT_IDX_LO); i < (OPT_IDX_HI); i++) \
{ \
if ((OPTSTR_LIST)[i] != 0) \
if (strcmp (argv[1], (OPTSTR_LIST)[i]) == 0) \
{ \
(OPT_IDX) = i; \
return 0; \
} \
}
LARCH_DRIVER_PARSE_PARM (la_target.abi.base, ABI_BASE, \
loongarch_abi_base_strings, 0, N_ABI_BASE_TYPES)
LARCH_DRIVER_PARSE_PARM (la_target.isa.fpu, ISA_EXT_FPU, \
loongarch_isa_ext_strings, 0, N_ISA_EXT_FPU_TYPES)
LARCH_DRIVER_PARSE_PARM (la_target.isa.simd, ISA_EXT_SIMD, \
loongarch_isa_ext_strings, 0, N_ISA_EXT_TYPES)
LARCH_DRIVER_PARSE_PARM (la_target.cpu_arch, ARCH, \
loongarch_arch_strings, 0, N_ARCH_TYPES)
LARCH_DRIVER_PARSE_PARM (la_target.cpu_tune, TUNE, \
loongarch_tune_strings, 0, N_TUNE_TYPES)
LARCH_DRIVER_PARSE_PARM (la_target.cmodel, CMODEL, \
loongarch_cmodel_strings, 0, N_CMODEL_TYPES)
gcc_unreachable ();
}
static void
driver_record_deferred_opts (struct loongarch_flags *flags)
{
unsigned int i;
cl_deferred_option *opt;
vec *v = (vec *) la_deferred_options;
gcc_assert (flags);
/* Initialize flags */
flags->flt = M_OPT_UNSET;
flags->flt_str = NULL;
flags->sx[0] = flags->sx[1] = 0;
int sx_flag_idx = 0;
if (v)
FOR_EACH_VEC_ELT (*v, i, opt)
{
switch (opt->opt_index)
{
case OPT_mlsx:
flags->sx[sx_flag_idx++] = ISA_EXT_SIMD_LSX
* (opt->value ? 1 : -1);
break;
case OPT_mlasx:
flags->sx[sx_flag_idx++] = ISA_EXT_SIMD_LASX
* (opt->value ? 1 : -1);
break;
case OPT_msoft_float:
flags->flt = ISA_EXT_NONE;
flags->flt_str = OPTSTR_SOFT_FLOAT;
break;
case OPT_msingle_float:
flags->flt = ISA_EXT_FPU32;
flags->flt_str = OPTSTR_SINGLE_FLOAT;
break;
case OPT_mdouble_float:
flags->flt = ISA_EXT_FPU64;
flags->flt_str = OPTSTR_DOUBLE_FLOAT;
break;
default:
gcc_unreachable ();
}
gcc_assert (sx_flag_idx <= 2);
}
}
const char*
driver_get_normalized_m_opts (int argc, const char **argv ATTRIBUTE_UNUSED)
{
if (argc != 0)
return " %eget_normalized_m_opts requires no argument.\n";
struct loongarch_flags flags;
driver_record_deferred_opts (&flags);
loongarch_config_target (&la_target, &flags, !no_link);
/* Output normalized option strings. */
obstack_blank (&opts_obstack, 0);
#undef APPEND_LTR
#define APPEND_LTR(S) \
obstack_grow (&opts_obstack, (const void*) (S), \
sizeof ((S)) / sizeof (char) -1)
#undef APPEND_VAL
#define APPEND_VAL(S) \
obstack_grow (&opts_obstack, (const void*) (S), strlen ((S)))
#undef APPEND_OPT
#define APPEND_OPT(NAME) \
APPEND_LTR (" %