Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/* Common hooks for ATMEL AVR.
   Copyright (C) 1998-2020 Free Software Foundation, Inc.

   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
   <http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "common/common-target.h"
#include "common/common-target-def.h"
#include "opts.h"
#include "diagnostic.h"

/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
static const struct default_options avr_option_optimization_table[] =
  {
    // With -fdelete-null-pointer-checks option, the compiler assumes
    // that dereferencing of a null pointer would halt the program.
    // For AVR this assumption is not true and a program can safely
    // dereference null pointers.  Changes made by this option may not
    // work properly for AVR.  So disable this option.
    { OPT_LEVELS_ALL, OPT_fdelete_null_pointer_checks, NULL, 0 },
    // The only effect of -fcaller-saves might be that it triggers
    // a frame without need when it tries to be smart around calls.
    { OPT_LEVELS_ALL, OPT_fcaller_saves, NULL, 0 },
    { OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_mgas_isr_prologues, NULL, 1 },
    { OPT_LEVELS_1_PLUS, OPT_mmain_is_OS_task, NULL, 1 },
    // Stick to the "old" placement of the subreg lowering pass.
    { OPT_LEVELS_1_PLUS, OPT_fsplit_wide_types_early, NULL, 1 },
    /* Allow optimizer to introduce store data races. This used to be the
       default -- it was changed because bigger targets did not see any
       performance decrease. For the AVR though, disallowing data races
       introduces additional code in LIM and increases reg pressure.  */
    { OPT_LEVELS_ALL, OPT_fallow_store_data_races, NULL, 1 },

#if defined (WITH_DOUBLE64)
    { OPT_LEVELS_ALL, OPT_mdouble_, NULL, 64 },
#elif defined (WITH_DOUBLE32)
    { OPT_LEVELS_ALL, OPT_mdouble_, NULL, 32 },
#else
#error "align this with config.gcc"
#endif

#if defined (WITH_LONG_DOUBLE64)
    { OPT_LEVELS_ALL, OPT_mlong_double_, NULL, 64 },
#elif defined (WITH_LONG_DOUBLE32)
    { OPT_LEVELS_ALL, OPT_mlong_double_, NULL, 32 },
#else
#error "align this with config.gcc"
#endif

    { OPT_LEVELS_NONE, 0, NULL, 0 }
  };


/* Implement `TARGET_HANDLE_OPTION'.  */

/* This is the same logic that driver-avr.c:avr_double_lib() applies
   during DRIVER_SELF_SPECS, but this time we complain about -mdouble=
   and -mlong-double= that are not provided by --with-double= resp.
   --with-long-double=  */

static bool
avr_handle_option (struct gcc_options *opts, struct gcc_options*,
                   const struct cl_decoded_option *decoded, location_t loc)
{
  int value = decoded->value;

  switch (decoded->opt_index)
    {
    case OPT_mdouble_:
      if (value == 64)
        {
#if !defined (HAVE_DOUBLE64)
          error_at (loc, "option %<-mdouble=64%> is only available if "
                    "configured %<--with-double={64|64,32|32,64}%>");
#endif
          opts->x_avr_long_double = 64;
        }
      else if (value == 32)
        {
#if !defined (HAVE_DOUBLE32)
          error_at (loc, "option %<-mdouble=32%> is only available if "
                    "configured %<--with-double={32|32,64|64,32}%>");
#endif
        }
      else
        gcc_unreachable();

#if defined (HAVE_LONG_DOUBLE_IS_DOUBLE)
      opts->x_avr_long_double = value;
#endif
      break; // -mdouble=

    case OPT_mlong_double_:
      if (value == 64)
        {
#if !defined (HAVE_LONG_DOUBLE64)
          error_at (loc, "option %<-mlong-double=64%> is only available if "
                    "configured %<--with-long-double={64|64,32|32,64}%>, "
                    "or %<--with-long-double=double%> together with "
                    "%<--with-double={64|64,32|32,64}%>");
#endif
        }
      else if (value == 32)
        {
#if !defined (HAVE_LONG_DOUBLE32)
          error_at (loc, "option %<-mlong-double=32%> is only available if "
                    "configured %<--with-long-double={32|32,64|64,32}%>, "
                    "or %<--with-long-double=double%> together with "
                    "%<--with-double={32|32,64|64,32}%>");
#endif
          opts->x_avr_double = 32;
        }
      else
        gcc_unreachable();

#if defined (HAVE_LONG_DOUBLE_IS_DOUBLE)
      opts->x_avr_double = value;
#endif
      break; // -mlong-double=
    }

  return true;
}


#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION avr_handle_option

#undef TARGET_OPTION_OPTIMIZATION_TABLE
#define TARGET_OPTION_OPTIMIZATION_TABLE avr_option_optimization_table

#undef TARGET_EXCEPT_UNWIND_INFO
#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info

struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;