#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "real.h"
#include "output.h"
#include "toplev.h"
#include "hashtab.h"
#include "c-pragma.h"
#include "c-tree.h"
#include "ggc.h"
#include "langhooks.h"
#include "tm_p.h"
#include "debug.h"
#include "target.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
#endif
#ifndef ASM_STABS_OP
#define ASM_STABS_OP "\t.stabs\t"
#endif
const char *first_global_object_name;
const char *weak_global_object_name;
struct addr_const;
struct constant_descriptor_rtx;
struct rtx_const;
struct pool_constant;
#define MAX_RTX_HASH_TABLE 61
struct varasm_status GTY(())
{
struct constant_descriptor_rtx ** GTY ((length ("MAX_RTX_HASH_TABLE")))
x_const_rtx_hash_table;
struct pool_constant ** GTY ((length ("MAX_RTX_HASH_TABLE")))
x_const_rtx_sym_hash_table;
struct pool_constant *x_first_pool;
struct pool_constant *x_last_pool;
HOST_WIDE_INT x_pool_offset;
};
#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
#define first_pool (cfun->varasm->x_first_pool)
#define last_pool (cfun->varasm->x_last_pool)
#define pool_offset (cfun->varasm->x_pool_offset)
static GTY(()) int const_labelno;
static GTY(()) int var_labelno;
int size_directive_output;
tree last_assemble_variable_decl;
int unexecuted_counter=0;
static HOST_WIDE_INT const_alias_set;
static const char *strip_reg_name PARAMS ((const char *));
static int contains_pointers_p PARAMS ((tree));
static void decode_addr_const PARAMS ((tree, struct addr_const *));
static unsigned int const_hash PARAMS ((tree));
static unsigned int const_hash_1 PARAMS ((tree));
static int compare_constant PARAMS ((tree, tree));
static tree copy_constant PARAMS ((tree));
static void output_constant_def_contents PARAMS ((tree, int, int));
static void decode_rtx_const PARAMS ((enum machine_mode, rtx,
struct rtx_const *));
static unsigned int const_hash_rtx PARAMS ((enum machine_mode, rtx));
static int compare_constant_rtx
PARAMS ((enum machine_mode, rtx, struct constant_descriptor_rtx *));
static struct constant_descriptor_rtx * record_constant_rtx
PARAMS ((enum machine_mode, rtx));
static struct pool_constant *find_pool_constant PARAMS ((struct function *, rtx));
static void mark_constant_pool PARAMS ((void));
static void mark_constants PARAMS ((rtx));
static int mark_constant PARAMS ((rtx *current_rtx, void *data));
static int output_addressed_constants PARAMS ((tree));
static void output_after_function_constants PARAMS ((void));
static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
static unsigned min_align PARAMS ((unsigned, unsigned));
static void output_constructor PARAMS ((tree, HOST_WIDE_INT,
unsigned int));
static void globalize_decl PARAMS ((tree));
static void maybe_assemble_visibility PARAMS ((tree));
static int in_named_entry_eq PARAMS ((const PTR, const PTR));
static hashval_t in_named_entry_hash PARAMS ((const PTR));
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss PARAMS ((FILE *, tree, const char *, int, int));
#endif
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_ALIGNED_BSS
static void asm_output_aligned_bss
PARAMS ((FILE *, tree, const char *, int, int)) ATTRIBUTE_UNUSED;
#endif
#endif
static hashval_t const_str_htab_hash PARAMS ((const void *x));
static int const_str_htab_eq PARAMS ((const void *x, const void *y));
static bool asm_emit_uninitialised PARAMS ((tree, const char*, int, int));
static void resolve_unique_section PARAMS ((tree, int, int));
static void mark_weak PARAMS ((tree));
int in_unlikely_text_section PARAMS ((void));
enum in_section { no_section, in_text, in_unlikely_executed_text, in_data, in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
#ifdef CTORS_SECTION_ASM_OP
, in_ctors
#endif
#ifdef DTORS_SECTION_ASM_OP
, in_dtors
#endif
#ifdef READONLY_DATA_SECTION_ASM_OP
, in_readonly_data
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
};
static GTY(()) enum in_section in_section = no_section;
#ifndef IN_NAMED_SECTION
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
#endif
static GTY(()) const char *in_named_name;
struct in_named_entry GTY(())
{
const char *name;
unsigned int flags;
bool declared;
};
static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
#ifdef EXTRA_SECTION_FUNCTIONS
EXTRA_SECTION_FUNCTIONS
#endif
void
text_section ()
{
if (in_section != in_text)
{
in_section = in_text;
#ifdef TEXT_SECTION
TEXT_SECTION ();
#else
#ifndef SECTION_FORMAT_STRING
#define SECTION_FORMAT_STRING "%s\n"
#endif
#ifndef HOT_TEXT_SECTION_NAME
#define HOT_TEXT_SECTION_NAME TEXT_SECTION_ASM_OP
#endif
fprintf (asm_out_file, SECTION_FORMAT_STRING, HOT_TEXT_SECTION_NAME);
#endif
}
}
void
unlikely_text_section ()
{
if (in_section != in_unlikely_executed_text)
{
in_section = in_unlikely_executed_text;
#ifdef UNLIKELY_TEXT_SECTION
UNLIKELY_TEXT_SECTION();
#else
#ifndef SECTION_FORMAT_STRING
#define SECTION_FORMAT_STRING "%s\n"
#endif
#ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME TEXT_SECTION_ASM_OP
#endif
fprintf (asm_out_file, SECTION_FORMAT_STRING,
UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
if (!unexecuted_counter)
fprintf (asm_out_file, "_%s_unexecuted_section:\n", cfun->name);
unexecuted_counter++;
#endif
}
}
void
data_section ()
{
if (in_section != in_data)
{
in_section = in_data;
if (flag_shared_data)
{
#ifdef SHARED_SECTION_ASM_OP
fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
#else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
#endif
}
else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
}
}
void
readonly_data_section ()
{
#ifdef READONLY_DATA_SECTION
READONLY_DATA_SECTION ();
#else
#ifdef READONLY_DATA_SECTION_ASM_OP
if (in_section != in_readonly_data)
{
in_section = in_readonly_data;
fputs (READONLY_DATA_SECTION_ASM_OP, asm_out_file);
fputc ('\n', asm_out_file);
}
#else
text_section ();
#endif
#endif
}
int
in_text_section ()
{
return in_section == in_text;
}
int
in_unlikely_text_section ()
{
return in_section == in_unlikely_executed_text;
}
int
in_data_section ()
{
return in_section == in_data;
}
static int
in_named_entry_eq (p1, p2)
const PTR p1;
const PTR p2;
{
const struct in_named_entry *old = p1;
const char *new = p2;
return strcmp (old->name, new) == 0;
}
static hashval_t
in_named_entry_hash (p)
const PTR p;
{
const struct in_named_entry *old = p;
return htab_hash_string (old->name);
}
unsigned int
get_named_section_flags (section)
const char *section;
{
struct in_named_entry **slot;
slot = (struct in_named_entry **)
htab_find_slot_with_hash (in_named_htab, section,
htab_hash_string (section), NO_INSERT);
return slot ? (*slot)->flags : 0;
}
bool
named_section_first_declaration (name)
const char *name;
{
struct in_named_entry **slot;
slot = (struct in_named_entry **)
htab_find_slot_with_hash (in_named_htab, name,
htab_hash_string (name), NO_INSERT);
if (! (*slot)->declared)
{
(*slot)->declared = true;
return true;
}
else
{
return false;
}
}
bool
set_named_section_flags (section, flags)
const char *section;
unsigned int flags;
{
struct in_named_entry **slot, *entry;
slot = (struct in_named_entry **)
htab_find_slot_with_hash (in_named_htab, section,
htab_hash_string (section), INSERT);
entry = *slot;
if (!entry)
{
entry = (struct in_named_entry *) ggc_alloc (sizeof (*entry));
*slot = entry;
entry->name = ggc_strdup (section);
entry->flags = flags;
entry->declared = false;
}
else if (entry->flags != flags)
return false;
return true;
}
void
named_section_flags (name, flags)
const char *name;
unsigned int flags;
{
if (in_section != in_named || strcmp (name, in_named_name) != 0)
{
if (! set_named_section_flags (name, flags))
abort ();
(*targetm.asm_out.named_section) (name, flags);
if (flags & SECTION_FORGET)
in_section = no_section;
else
{
in_named_name = ggc_strdup (name);
in_section = in_named;
}
}
}
void
named_section (decl, name, reloc)
tree decl;
const char *name;
int reloc;
{
unsigned int flags;
if (decl != NULL_TREE && !DECL_P (decl))
abort ();
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
flags = (* targetm.section_type_flags) (decl, name, reloc);
if (decl && ! set_named_section_flags (name, flags))
{
flags = get_named_section_flags (name);
if ((flags & SECTION_OVERRIDE) == 0)
error_with_decl (decl, "%s causes a section type conflict");
}
else if ((!decl) && ! set_named_section_flags (name, flags)
&& ((strcmp (name, HOT_TEXT_SECTION_NAME) == 0)
|| (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)))
{
flags = get_named_section_flags (name);
if ((flags & SECTION_OVERRIDE) == 0)
error_with_decl (decl, "%s causes a section type conflict");
}
named_section_flags (name, flags);
}
static void
resolve_unique_section (decl, reloc, flag_function_or_data_sections)
tree decl;
int reloc ATTRIBUTE_UNUSED;
int flag_function_or_data_sections;
{
if (DECL_SECTION_NAME (decl) == NULL_TREE
&& targetm.have_named_sections
&& (flag_function_or_data_sections
|| DECL_ONE_ONLY (decl)))
(*targetm.asm_out.unique_section) (decl, reloc);
}
#ifdef BSS_SECTION_ASM_OP
void
bss_section ()
{
if (in_section != in_bss)
{
#ifdef SHARED_BSS_SECTION_ASM_OP
if (flag_shared_data)
fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP);
else
#endif
fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
in_section = in_bss;
}
}
#ifdef ASM_OUTPUT_BSS
static void
asm_output_bss (file, decl, name, size, rounded)
FILE *file;
tree decl ATTRIBUTE_UNUSED;
const char *name;
int size ATTRIBUTE_UNUSED, rounded;
{
(*targetm.asm_out.globalize_label) (file, name);
bss_section ();
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (file, name, decl);
#else
ASM_OUTPUT_LABEL (file, name);
#endif
ASM_OUTPUT_SKIP (file, rounded ? rounded : 1);
}
#endif
#ifdef ASM_OUTPUT_ALIGNED_BSS
static void
asm_output_aligned_bss (file, decl, name, size, align)
FILE *file;
tree decl ATTRIBUTE_UNUSED;
const char *name;
int size, align;
{
bss_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (file, name, decl);
#else
ASM_OUTPUT_LABEL (file, name);
#endif
ASM_OUTPUT_SKIP (file, size ? size : 1);
}
#endif
#endif
void
function_section (decl)
tree decl;
{
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
named_section (decl, (char *) 0, 0);
else
text_section ();
}
void
variable_section (decl, reloc)
tree decl;
int reloc;
{
if (IN_NAMED_SECTION (decl))
named_section (decl, NULL, reloc);
else
(*targetm.asm_out.select_section) (decl, reloc, DECL_ALIGN (decl));
}
void
mergeable_string_section (decl, align, flags)
tree decl ATTRIBUTE_UNUSED;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
unsigned int flags ATTRIBUTE_UNUSED;
{
#ifdef HAVE_GAS_SHF_MERGE
if (flag_merge_constants
&& TREE_CODE (decl) == STRING_CST
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
&& align <= 256
&& TREE_STRING_LENGTH (decl) >= int_size_in_bytes (TREE_TYPE (decl)))
{
enum machine_mode mode;
unsigned int modesize;
const char *str;
int i, j, len, unit;
char name[30];
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
modesize = GET_MODE_BITSIZE (mode);
if (modesize >= 8 && modesize <= 256
&& (modesize & (modesize - 1)) == 0)
{
if (align < modesize)
align = modesize;
str = TREE_STRING_POINTER (decl);
len = TREE_STRING_LENGTH (decl);
unit = GET_MODE_SIZE (mode);
for (i = 0; i < len; i += unit)
{
for (j = 0; j < unit; j++)
if (str[i + j] != '\0')
break;
if (j == unit)
break;
}
if (i == len - unit)
{
sprintf (name, ".rodata.str%d.%d", modesize / 8,
(int) (align / 8));
flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
if (!i && modesize < align)
{
#ifdef ASM_OUTPUT_SECTION_START
named_section_flags (name, flags);
ASM_OUTPUT_SECTION_START (asm_out_file);
#else
readonly_data_section ();
#endif
return;
}
named_section_flags (name, flags);
return;
}
}
}
#endif
readonly_data_section ();
}
void
mergeable_constant_section (mode, align, flags)
enum machine_mode mode ATTRIBUTE_UNUSED;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
unsigned int flags ATTRIBUTE_UNUSED;
{
#ifdef HAVE_GAS_SHF_MERGE
unsigned int modesize = GET_MODE_BITSIZE (mode);
if (flag_merge_constants
&& mode != VOIDmode
&& mode != BLKmode
&& modesize <= align
&& align >= 8
&& align <= 256
&& (align & (align - 1)) == 0)
{
char name[24];
sprintf (name, ".rodata.cst%d", (int) (align / 8));
flags |= (align / 8) | SECTION_MERGE;
named_section_flags (name, flags);
return;
}
#endif
readonly_data_section ();
}
static const char *
strip_reg_name (name)
const char *name;
{
#ifdef REGISTER_PREFIX
if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
name += strlen (REGISTER_PREFIX);
#endif
if (name[0] == '%' || name[0] == '#')
name++;
return name;
}
int
decode_reg_name (asmspec)
const char *asmspec;
{
if (asmspec != 0)
{
int i;
asmspec = strip_reg_name (asmspec);
for (i = strlen (asmspec) - 1; i >= 0; i--)
if (! ISDIGIT (asmspec[i]))
break;
if (asmspec[0] != 0 && i < 0)
{
i = atoi (asmspec);
if (i < FIRST_PSEUDO_REGISTER && i >= 0)
return i;
else
return -2;
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (reg_names[i][0]
&& ! strcmp (asmspec, strip_reg_name (reg_names[i])))
return i;
#ifdef ADDITIONAL_REGISTER_NAMES
{
static const struct { const char *const name; const int number; } table[]
= ADDITIONAL_REGISTER_NAMES;
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
if (! strcmp (asmspec, table[i].name))
return table[i].number;
}
#endif
if (!strcmp (asmspec, "memory"))
return -4;
if (!strcmp (asmspec, "cc"))
return -3;
return -2;
}
return -1;
}
void
make_decl_rtl (decl, asmspec)
tree decl;
const char *asmspec;
{
int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
const char *name = 0;
const char *new_name = 0;
int reg_number;
rtx x;
if (TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL
|| (TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& !TREE_PUBLIC (decl)
&& !DECL_EXTERNAL (decl)
&& !DECL_REGISTER (decl)))
abort ();
else if (TREE_CODE (decl) == TYPE_DECL
|| TREE_CODE (decl) == LABEL_DECL)
abort ();
if (DECL_RTL_SET_P (decl))
{
if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
DECL_MODE (decl), 0));
(* targetm.encode_section_info) (decl, false);
return;
}
new_name = name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
reg_number = decode_reg_name (asmspec);
if (reg_number == -2)
{
char *starred = alloca (strlen (asmspec) + 2);
starred[0] = '*';
strcpy (starred + 1, asmspec);
new_name = starred;
}
if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
if (reg_number == -1)
error_with_decl (decl, "register name not specified for `%s'");
else if (reg_number < 0)
error_with_decl (decl, "invalid register name for `%s'");
else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
error_with_decl (decl,
"data type of `%s' isn't suitable for a register");
else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
error_with_decl (decl,
"register specified for `%s' isn't suitable for data type");
else
{
int nregs;
if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl))
{
DECL_INITIAL (decl) = 0;
error ("global register variable has initial value");
}
if (TREE_THIS_VOLATILE (decl))
warning ("volatile register variables don't work as you might wish");
SET_DECL_RTL (decl, gen_rtx_raw_REG (DECL_MODE (decl), reg_number));
ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
if (TREE_STATIC (decl))
{
#ifdef ASM_DECLARE_REGISTER_GLOBAL
ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
#endif
nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
while (nregs > 0)
globalize_reg (reg_number + --nregs);
}
return;
}
}
if (reg_number >= 0 || reg_number == -3)
error_with_decl (decl,
"register name given for non-register variable `%s'");
if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
&& DECL_INITIAL (decl) == NULL_TREE
&& DECL_COMMON (decl))
DECL_COMMON (decl) = 0;
if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
DECL_COMMON (decl) = 0;
if (!top_level && !TREE_PUBLIC (decl)
&& ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
&& asmspec == 0
&& name == IDENTIFIER_POINTER (DECL_NAME (decl)))
{
char *label;
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
var_labelno++;
new_name = label;
}
if (name != new_name)
{
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
}
if ((flag_volatile_global && TREE_CODE (decl) == VAR_DECL
&& TREE_PUBLIC (decl))
|| ((flag_volatile_static && TREE_CODE (decl) == VAR_DECL
&& (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
TREE_SIDE_EFFECTS (decl) = 1;
x = gen_rtx_MEM (DECL_MODE (decl), gen_rtx_SYMBOL_REF (Pmode, name));
SYMBOL_REF_WEAK (XEXP (x, 0)) = DECL_WEAK (decl);
SYMBOL_REF_WEAK_IMPORT (XEXP (x, 0)) = DECL_WEAK_IMPORT (decl);
if (TREE_CODE (decl) != FUNCTION_DECL)
set_mem_attributes (x, decl, 1);
SET_DECL_RTL (decl, x);
(* targetm.encode_section_info) (decl, true);
}
void
make_var_volatile (var)
tree var;
{
if (GET_CODE (DECL_RTL (var)) != MEM)
abort ();
MEM_VOLATILE_P (DECL_RTL (var)) = 1;
}
void
assemble_asm (string)
tree string;
{
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
string = TREE_OPERAND (string, 0);
fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
}
void
default_stabs_asm_out_destructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, XSTR (symbol, 0));
fputc ('\n', asm_out_file);
}
void
default_named_section_asm_out_destructor (symbol, priority)
rtx symbol;
int priority;
{
const char *section = ".dtors";
char buf[16];
if (priority != DEFAULT_INIT_PRIORITY)
{
sprintf (buf, ".dtors.%.5u",
MAX_INIT_PRIORITY - priority);
section = buf;
}
named_section_flags (section, SECTION_WRITE);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef DTORS_SECTION_ASM_OP
void
dtors_section ()
{
if (in_section != in_dtors)
{
in_section = in_dtors;
fputs (DTORS_SECTION_ASM_OP, asm_out_file);
fputc ('\n', asm_out_file);
}
}
void
default_dtor_section_asm_out_destructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
dtors_section ();
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#endif
void
default_stabs_asm_out_constructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, XSTR (symbol, 0));
fputc ('\n', asm_out_file);
}
void
default_named_section_asm_out_constructor (symbol, priority)
rtx symbol;
int priority;
{
const char *section = ".ctors";
char buf[16];
if (priority != DEFAULT_INIT_PRIORITY)
{
sprintf (buf, ".ctors.%.5u",
MAX_INIT_PRIORITY - priority);
section = buf;
}
named_section_flags (section, SECTION_WRITE);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef CTORS_SECTION_ASM_OP
void
ctors_section ()
{
if (in_section != in_ctors)
{
in_section = in_ctors;
fputs (CTORS_SECTION_ASM_OP, asm_out_file);
fputc ('\n', asm_out_file);
}
}
void
default_ctor_section_asm_out_constructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
ctors_section ();
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#endif
#ifndef CONSTANT_POOL_BEFORE_FUNCTION
#define CONSTANT_POOL_BEFORE_FUNCTION 1
#endif
void
assemble_start_function (decl, fnname)
tree decl;
const char *fnname;
{
int align;
app_disable ();
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
resolve_unique_section (decl, 0, flag_function_sections);
function_section (decl);
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align < force_align_functions_log)
align = force_align_functions_log;
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
if (align_functions_log > align
&& cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
align_functions_log, align_functions - 1);
#else
ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log);
#endif
}
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
#endif
(*debug_hooks->begin_function) (decl);
if (TREE_PUBLIC (decl) || DECL_PRIVATE_EXTERN (decl) || DECL_COALESCED (decl))
{
if (! first_global_object_name)
{
const char *p;
char *name;
p = (* targetm.strip_name_encoding) (fnname);
name = xstrdup (p);
if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
first_global_object_name = name;
else
weak_global_object_name = name;
}
globalize_decl (decl);
maybe_assemble_visibility (decl);
}
#ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME TEXT_SECTION_ASM_OP
#endif
#ifndef HOT_TEXT_SECTION_NAME
#define HOT_TEXT_SECTION_NAME TEXT_SECTION_ASM_OP
#endif
#ifndef SECTION_FORMAT_STRING
#define SECTION_FORMAT_STRING "%s\n"
#endif
unexecuted_counter = 0;
if (current_function_decl->decl.section_name)
fprintf (asm_out_file, SECTION_FORMAT_STRING,
TREE_STRING_POINTER (current_function_decl->decl.section_name));
else
fprintf (asm_out_file, SECTION_FORMAT_STRING, HOT_TEXT_SECTION_NAME);
#ifdef ASM_DECL_MARK_LIVE
if (TREE_LIVE (decl))
ASM_DECL_MARK_LIVE (fnname);
#endif
#ifdef ASM_DECLARE_FUNCTION_NAME
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif
}
void
assemble_end_function (decl, fnname)
tree decl;
const char *fnname;
{
#ifdef ASM_DECLARE_FUNCTION_SIZE
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
#endif
if (! CONSTANT_POOL_BEFORE_FUNCTION)
{
output_constant_pool (fnname, decl);
function_section (decl);
}
output_after_function_constants ();
}
void
assemble_zeros (size)
int size;
{
if (flag_syntax_only)
return;
#ifdef ASM_NO_SKIP_IN_TEXT
if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
|| (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
{
int i;
for (i = 0; i < size; i++)
assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
}
else
#endif
if (size > 0)
ASM_OUTPUT_SKIP (asm_out_file, size);
}
void
assemble_align (align)
int align;
{
if (align > BITS_PER_UNIT)
{
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
}
void
assemble_string (p, size)
const char *p;
int size;
{
int pos = 0;
int maximum = 2000;
while (pos < size)
{
int thissize = size - pos;
if (thissize > maximum)
thissize = maximum;
ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
pos += thissize;
p += thissize;
}
}
#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
#else
#if defined ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
#else
#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
#endif
#endif
#if defined ASM_OUTPUT_ALIGNED_BSS
#define ASM_EMIT_BSS(decl, name, size, rounded) \
ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
#else
#if defined ASM_OUTPUT_BSS
#define ASM_EMIT_BSS(decl, name, size, rounded) \
ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
#else
#undef ASM_EMIT_BSS
#endif
#endif
#if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
#define ASM_EMIT_COMMON(decl, name, size, rounded) \
ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
#else
#if defined ASM_OUTPUT_ALIGNED_COMMON
#define ASM_EMIT_COMMON(decl, name, size, rounded) \
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
#else
#define ASM_EMIT_COMMON(decl, name, size, rounded) \
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
#endif
#endif
static bool
asm_emit_uninitialised (decl, name, size, rounded)
tree decl;
const char *name;
int size ATTRIBUTE_UNUSED;
int rounded ATTRIBUTE_UNUSED;
{
enum
{
asm_dest_common,
asm_dest_bss,
asm_dest_local
}
destination = asm_dest_local;
if (TREE_PUBLIC (decl))
{
if (!DECL_COMMON (decl))
#ifdef ASM_EMIT_BSS
destination = asm_dest_bss;
#else
return false;
#endif
else
destination = asm_dest_common;
}
if (destination == asm_dest_bss)
globalize_decl (decl);
resolve_unique_section (decl, 0, flag_data_sections);
if (flag_shared_data)
{
switch (destination)
{
#ifdef ASM_OUTPUT_SHARED_BSS
case asm_dest_bss:
ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
return;
#endif
#ifdef ASM_OUTPUT_SHARED_COMMON
case asm_dest_common:
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
return;
#endif
#ifdef ASM_OUTPUT_SHARED_LOCAL
case asm_dest_local:
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
return;
#endif
default:
break;
}
}
switch (destination)
{
#ifdef ASM_EMIT_BSS
case asm_dest_bss:
ASM_EMIT_BSS (decl, name, size, rounded);
break;
#endif
case asm_dest_common:
ASM_EMIT_COMMON (decl, name, size, rounded);
break;
case asm_dest_local:
ASM_EMIT_LOCAL (decl, name, size, rounded);
break;
default:
abort ();
}
return true;
}
void
assemble_variable (decl, top_level, at_end, dont_output_data)
tree decl;
int top_level ATTRIBUTE_UNUSED;
int at_end ATTRIBUTE_UNUSED;
int dont_output_data;
{
const char *name;
unsigned int align;
int reloc = 0;
rtx decl_rtl;
last_assemble_variable_decl = 0;
if (DECL_EXTERNAL (decl))
return;
if (TREE_CODE (decl) == FUNCTION_DECL)
return;
if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
{
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (DECL_SIZE (decl) == 0)
layout_decl (decl, 0);
if (!dont_output_data && DECL_SIZE (decl) == 0)
{
error_with_file_and_line (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl),
"storage size of `%s' isn't known",
IDENTIFIER_POINTER (DECL_NAME (decl)));
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (TREE_ASM_WRITTEN (decl))
return;
decl_rtl = DECL_RTL (decl);
TREE_ASM_WRITTEN (decl) = 1;
if (flag_syntax_only)
return;
app_disable ();
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
error_with_decl (decl, "size of variable `%s' is too large");
return;
}
name = XSTR (XEXP (decl_rtl, 0), 0);
if (TREE_PUBLIC (decl) && DECL_NAME (decl)
&& ! first_global_object_name
&& ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node))
&& ! DECL_WEAK (decl)
&& ! DECL_ONE_ONLY (decl))
{
const char *p;
char *xname;
p = (* targetm.strip_name_encoding) (name);
xname = xstrdup (p);
first_global_object_name = xname;
}
align = DECL_ALIGN (decl);
if (dont_output_data && DECL_SIZE (decl) == 0
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
#ifndef MAX_OFILE_ALIGNMENT
#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
#endif
if (align > MAX_OFILE_ALIGNMENT)
{
warning_with_decl (decl,
"alignment of `%s' is greater than maximum object file alignment. Using %d",
MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
}
if (! DECL_USER_ALIGN (decl))
{
#ifdef DATA_ALIGNMENT
align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
#endif
#ifdef CONSTANT_ALIGNMENT
if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
#endif
}
DECL_ALIGN (decl) = align;
set_mem_align (decl_rtl, align);
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
#ifdef ASM_DECL_MARK_LIVE
if (TREE_LIVE (decl))
ASM_DECL_MARK_LIVE (name);
#endif
if (DECL_INITIAL (decl) == error_mark_node)
reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
else if (DECL_INITIAL (decl))
reloc = output_addressed_constants (DECL_INITIAL (decl));
resolve_unique_section (decl, reloc, flag_data_sections);
if (DECL_SECTION_NAME (decl) || dont_output_data)
;
else if (DECL_THREAD_LOCAL (decl))
{
if (DECL_COMMON (decl))
sorry ("thread-local COMMON data not implemented");
}
else if (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node
|| (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl))))
{
unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
unsigned HOST_WIDE_INT rounded = size;
if (size == 0)
rounded = 1;
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
warning_with_decl
(decl, "requested alignment for %s is greater than implemented alignment of %d",rounded);
#endif
if (asm_emit_uninitialised (decl, name, size, rounded))
return;
}
if ((TREE_PUBLIC (decl) || DECL_PRIVATE_EXTERN (decl)
|| DECL_COALESCED (decl))
&& DECL_NAME (decl))
globalize_decl (decl);
variable_section (decl, reloc);
#ifdef ASM_OUTPUT_ZEROFILL
if (flag_no_common
&& ! dont_output_data
&& ! DECL_COALESCED (decl)
&& (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
{
ASM_OUTPUT_ZEROFILL (asm_out_file, name,
tree_low_cst (DECL_SIZE_UNIT (decl), 1),
floor_log2 (align / BITS_PER_UNIT));
return;
}
#endif
if (in_text_section () || in_unlikely_text_section())
DECL_IN_TEXT_SECTION (decl) = 1;
if (align > BITS_PER_UNIT)
{
ASM_OUTPUT_ALIGN (asm_out_file,
floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
}
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
#else
ASM_OUTPUT_LABEL (asm_out_file, name);
#endif
if (!dont_output_data)
{
if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
output_constant (DECL_INITIAL (decl),
tree_low_cst (DECL_SIZE_UNIT (decl), 1),
align);
else
assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
}
}
static int
contains_pointers_p (type)
tree type;
{
switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
return 1;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
{
tree fields;
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
if (TREE_CODE (fields) == FIELD_DECL
&& contains_pointers_p (TREE_TYPE (fields)))
return 1;
return 0;
}
case ARRAY_TYPE:
return contains_pointers_p (TREE_TYPE (type));
default:
return 0;
}
}
void
assemble_external (decl)
tree decl ATTRIBUTE_UNUSED;
{
if (!asm_out_file)
abort ();
#ifdef ASM_OUTPUT_EXTERNAL
if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
{
rtx rtl = DECL_RTL (decl);
if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
&& ! SYMBOL_REF_USED (XEXP (rtl, 0)))
{
SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
}
}
#endif
}
void
assemble_external_libcall (fun)
rtx fun ATTRIBUTE_UNUSED;
{
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
if (! SYMBOL_REF_USED (fun))
{
SYMBOL_REF_USED (fun) = 1;
ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
}
#endif
}
void
assemble_label (name)
const char *name;
{
ASM_OUTPUT_LABEL (asm_out_file, name);
}
void
assemble_name (file, name)
FILE *file;
const char *name;
{
const char *real_name;
tree id;
real_name = (* targetm.strip_name_encoding) (name);
id = maybe_get_identifier (real_name);
if (id)
TREE_SYMBOL_REFERENCED (id) = 1;
if (name[0] == '*')
fputs (&name[1], file);
else
ASM_OUTPUT_LABELREF (file, name);
}
rtx
assemble_static_space (size)
int size;
{
char name[12];
const char *namestring;
rtx x;
#if 0
if (flag_shared_data)
data_section ();
#endif
ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
++const_labelno;
namestring = ggc_strdup (name);
x = gen_rtx_SYMBOL_REF (Pmode, namestring);
#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
BIGGEST_ALIGNMENT);
#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
#else
{
int rounded ATTRIBUTE_UNUSED
= ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
/ (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
}
#endif
#endif
return x;
}
#ifdef TRAMPOLINE_TEMPLATE
rtx
assemble_trampoline_template ()
{
char label[256];
const char *name;
int align;
#ifdef TRAMPOLINE_SECTION
TRAMPOLINE_SECTION ();
#else
readonly_data_section ();
#endif
align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
(*targetm.asm_out.internal_label) (asm_out_file, "LTRAMP", 0);
TRAMPOLINE_TEMPLATE (asm_out_file);
ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
name = ggc_strdup (label);
return gen_rtx_SYMBOL_REF (Pmode, name);
}
#endif
static inline unsigned
min_align (a, b)
unsigned int a, b;
{
return (a | b) & -(a | b);
}
const char *
integer_asm_op (size, aligned_p)
int size;
int aligned_p;
{
struct asm_int_op *ops;
if (aligned_p)
ops = &targetm.asm_out.aligned_op;
else
ops = &targetm.asm_out.unaligned_op;
switch (size)
{
case 1:
return targetm.asm_out.byte_op;
case 2:
return ops->hi;
case 4:
return ops->si;
case 8:
return ops->di;
case 16:
return ops->ti;
default:
return NULL;
}
}
void
assemble_integer_with_op (op, x)
const char *op;
rtx x;
{
fputs (op, asm_out_file);
output_addr_const (asm_out_file, x);
fputc ('\n', asm_out_file);
}
bool
default_assemble_integer (x, size, aligned_p)
rtx x ATTRIBUTE_UNUSED;
unsigned int size ATTRIBUTE_UNUSED;
int aligned_p ATTRIBUTE_UNUSED;
{
const char *op = integer_asm_op (size, aligned_p);
return op && (assemble_integer_with_op (op, x), true);
}
bool
assemble_integer (x, size, align, force)
rtx x;
unsigned int size;
unsigned int align;
int force;
{
int aligned_p;
aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));
if ((*targetm.asm_out.integer) (x, size, aligned_p))
return true;
if (size > 1)
{
enum machine_mode omode, imode;
unsigned int subalign;
unsigned int subsize, i;
subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
subalign = MIN (align, subsize * BITS_PER_UNIT);
omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0);
imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
for (i = 0; i < size; i += subsize)
{
rtx partial = simplify_subreg (omode, x, imode, i);
if (!partial || !assemble_integer (partial, subsize, subalign, 0))
break;
}
if (i == size)
return true;
if (i > 0)
abort ();
}
if (force)
abort ();
return false;
}
void
assemble_real (d, mode, align)
REAL_VALUE_TYPE d;
enum machine_mode mode;
unsigned int align;
{
long data[4];
long l;
unsigned int nalign = min_align (align, 32);
switch (BITS_PER_UNIT)
{
case 8:
switch (mode)
{
case SFmode:
REAL_VALUE_TO_TARGET_SINGLE (d, l);
assemble_integer (GEN_INT (l), 4, align, 1);
break;
case DFmode:
REAL_VALUE_TO_TARGET_DOUBLE (d, data);
assemble_integer (GEN_INT (data[0]), 4, align, 1);
assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
break;
case XFmode:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (d, data);
assemble_integer (GEN_INT (data[0]), 4, align, 1);
assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
assemble_integer (GEN_INT (data[2]), 4, nalign, 1);
break;
case TFmode:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (d, data);
assemble_integer (GEN_INT (data[0]), 4, align, 1);
assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
assemble_integer (GEN_INT (data[2]), 4, nalign, 1);
assemble_integer (GEN_INT (data[3]), 4, nalign, 1);
break;
default:
abort ();
}
break;
case 16:
switch (mode)
{
case HFmode:
REAL_VALUE_TO_TARGET_SINGLE (d, l);
assemble_integer (GEN_INT (l), 2, align, 1);
break;
case TQFmode:
REAL_VALUE_TO_TARGET_DOUBLE (d, data);
assemble_integer (GEN_INT (data[0]), 2, align, 1);
assemble_integer (GEN_INT (data[1]), 1, nalign, 1);
break;
default:
abort ();
}
break;
case 32:
switch (mode)
{
case QFmode:
REAL_VALUE_TO_TARGET_SINGLE (d, l);
assemble_integer (GEN_INT (l), 1, align, 1);
break;
case HFmode:
REAL_VALUE_TO_TARGET_DOUBLE (d, data);
assemble_integer (GEN_INT (data[0]), 1, align, 1);
assemble_integer (GEN_INT (data[1]), 1, nalign, 1);
break;
default:
abort ();
}
break;
default:
abort ();
}
}
struct addr_const GTY(())
{
rtx base;
HOST_WIDE_INT offset;
};
static void
decode_addr_const (exp, value)
tree exp;
struct addr_const *value;
{
tree target = TREE_OPERAND (exp, 0);
int offset = 0;
rtx x;
while (1)
{
if (TREE_CODE (target) == COMPONENT_REF
&& host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
{
offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
}
else if (TREE_CODE (target) == ARRAY_REF
|| TREE_CODE (target) == ARRAY_RANGE_REF)
{
offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
* tree_low_cst (TREE_OPERAND (target, 1), 0));
target = TREE_OPERAND (target, 0);
}
else
break;
}
switch (TREE_CODE (target))
{
case VAR_DECL:
case FUNCTION_DECL:
x = DECL_RTL (target);
break;
case LABEL_DECL:
x = gen_rtx_MEM (FUNCTION_MODE,
gen_rtx_LABEL_REF (VOIDmode,
label_rtx (TREE_OPERAND (exp, 0))));
break;
case REAL_CST:
case STRING_CST:
case COMPLEX_CST:
case VECTOR_CST:
case CONSTRUCTOR:
case INTEGER_CST:
x = output_constant_def (target, 1);
break;
default:
abort ();
}
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
value->base = x;
value->offset = offset;
}
enum kind { RTX_UNKNOWN, RTX_VECTOR, RTX_DOUBLE, RTX_INT, RTX_UNSPEC };
struct rtx_const GTY(())
{
ENUM_BITFIELD(kind) kind : 16;
ENUM_BITFIELD(machine_mode) mode : 16;
union rtx_const_un {
REAL_VALUE_TYPE GTY ((tag ("4"))) du;
struct addr_const GTY ((tag ("1"))) addr;
struct rtx_const_u_di {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
} GTY ((tag ("0"))) di;
struct rtx_const_int_vec {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
} GTY ((tag ("2"))) int_vec[16];
REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
} GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
};
struct constant_descriptor_tree GTY(())
{
struct constant_descriptor_tree *next;
const char *label;
rtx rtl;
tree value;
};
#define MAX_HASH_TABLE 1009
static GTY(()) struct constant_descriptor_tree *
const_hash_table[MAX_HASH_TABLE];
#define STRHASH(x) htab_hash_string (x)
struct deferred_string GTY(())
{
const char *label;
tree exp;
int labelno;
};
static GTY ((param_is (struct deferred_string))) htab_t const_str_htab;
static hashval_t
const_str_htab_hash (x)
const void *x;
{
return STRHASH (((const struct deferred_string *) x)->label);
}
static int
const_str_htab_eq (x, y)
const void *x;
const void *y;
{
return (((const struct deferred_string *) x)->label == (const char *) y);
}
static unsigned int
const_hash (exp)
tree exp;
{
return const_hash_1 (exp) % MAX_HASH_TABLE;
}
static unsigned int
const_hash_1 (exp)
tree exp;
{
const char *p;
unsigned int hi;
int len, i;
enum tree_code code = TREE_CODE (exp);
switch (code)
{
case INTEGER_CST:
p = (char *) &TREE_INT_CST (exp);
len = sizeof TREE_INT_CST (exp);
break;
case REAL_CST:
return real_hash (TREE_REAL_CST_PTR (exp));
case STRING_CST:
p = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
break;
case COMPLEX_CST:
return (const_hash_1 (TREE_REALPART (exp)) * 5
+ const_hash_1 (TREE_IMAGPART (exp)));
case VECTOR_CST:
{
int hash = 0;
tree t;
for ( t = TREE_VECTOR_CST_ELTS (exp); t; t = TREE_CHAIN (t))
hash += const_hash (TREE_VALUE (t)) * 11;
return hash;
}
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
char *tmp;
len = int_size_in_bytes (TREE_TYPE (exp));
tmp = (char *) alloca (len);
get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
p = tmp;
break;
}
else
{
tree link;
hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_VALUE (link))
hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
return hi;
}
case ADDR_EXPR:
case FDESC_EXPR:
{
struct addr_const value;
decode_addr_const (exp, &value);
if (GET_CODE (value.base) == SYMBOL_REF)
{
hi = value.offset;
p = XSTR (value.base, 0);
for (i = 0; p[i] != 0; i++)
hi = ((hi * 613) + (unsigned) (p[i]));
}
else if (GET_CODE (value.base) == LABEL_REF)
hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
else
abort ();
}
return hi;
case PLUS_EXPR:
case MINUS_EXPR:
return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
+ const_hash_1 (TREE_OPERAND (exp, 1)));
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
default:
return code;
}
hi = len;
for (i = 0; i < len; i++)
hi = ((hi * 613) + (unsigned) (p[i]));
return hi;
}
static int
compare_constant (t1, t2)
tree t1;
tree t2;
{
enum tree_code typecode;
if (t1 == NULL_TREE)
return t2 == NULL_TREE;
if (t2 == NULL_TREE)
return 0;
if (TREE_CODE (t1) != TREE_CODE (t2))
return 0;
switch (TREE_CODE (t1))
{
case INTEGER_CST:
if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
return 0;
return tree_int_cst_equal (t1, t2);
case REAL_CST:
if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
return 0;
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
case STRING_CST:
if (flag_writable_strings)
return 0;
if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
return 0;
return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
&& ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
TREE_STRING_LENGTH (t1)));
case COMPLEX_CST:
return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
&& compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
case VECTOR_CST:
{
tree t1e, t2e;
for (t1e = TREE_VECTOR_CST_ELTS (t1), t2e = TREE_VECTOR_CST_ELTS (t2);
t1e && t2e;
t1e = TREE_CHAIN (t1e), t2e = TREE_CHAIN (t2e))
{
if (!compare_constant (t1e, t2e))
return 0;
}
return 1;
}
case CONSTRUCTOR:
typecode = TREE_CODE (TREE_TYPE (t1));
if (typecode != TREE_CODE (TREE_TYPE (t2)))
return 0;
if (typecode == SET_TYPE)
{
int len = int_size_in_bytes (TREE_TYPE (t2));
unsigned char *tmp1, *tmp2;
if (int_size_in_bytes (TREE_TYPE (t1)) != len)
return 0;
tmp1 = (unsigned char *) alloca (len);
tmp2 = (unsigned char *) alloca (len);
if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
return 0;
if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
return 0;
return memcmp (tmp1, tmp2, len) != 0;
}
else
{
tree l1, l2;
if (typecode == ARRAY_TYPE)
{
HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
|| size_1 == -1
|| size_1 != int_size_in_bytes (TREE_TYPE (t2)))
return 0;
}
else
{
if (TREE_TYPE (t1) != TREE_TYPE (t2))
return 0;
}
for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
l1 && l2;
l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
{
if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
return 0;
if (typecode == ARRAY_TYPE)
{
if (! compare_constant (TREE_PURPOSE (l1),
TREE_PURPOSE (l2)))
return 0;
}
else
{
if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
return 0;
}
}
return l1 == NULL_TREE && l2 == NULL_TREE;
}
case ADDR_EXPR:
case FDESC_EXPR:
{
struct addr_const value1, value2;
decode_addr_const (t1, &value1);
decode_addr_const (t2, &value2);
return (value1.offset == value2.offset
&& strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
}
case PLUS_EXPR:
case MINUS_EXPR:
case RANGE_EXPR:
return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
&& compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
default:
{
tree nt1, nt2;
nt1 = (*lang_hooks.expand_constant) (t1);
nt2 = (*lang_hooks.expand_constant) (t2);
if (nt1 != t1 || nt2 != t2)
return compare_constant (nt1, nt2);
else
return 0;
}
}
abort ();
}
struct deferred_constant
{
struct deferred_constant *next;
tree exp;
int reloc;
int labelno;
};
static struct deferred_constant *deferred_constants;
static struct deferred_constant *after_function_constants;
static int defer_addressed_constants_flag;
void
defer_addressed_constants ()
{
defer_addressed_constants_flag++;
}
void
output_deferred_addressed_constants ()
{
struct deferred_constant *p, *next;
defer_addressed_constants_flag--;
if (defer_addressed_constants_flag > 0)
return;
for (p = deferred_constants; p; p = next)
{
output_constant_def_contents (p->exp, p->reloc, p->labelno);
next = p->next;
free (p);
}
deferred_constants = 0;
}
static void
output_after_function_constants ()
{
struct deferred_constant *p, *next;
for (p = after_function_constants; p; p = next)
{
output_constant_def_contents (p->exp, p->reloc, p->labelno);
next = p->next;
free (p);
}
after_function_constants = 0;
}
static tree
copy_constant (exp)
tree exp;
{
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
else
return copy_node (exp);
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
return copy_node (exp);
case COMPLEX_CST:
return build_complex (TREE_TYPE (exp),
copy_constant (TREE_REALPART (exp)),
copy_constant (TREE_IMAGPART (exp)));
case VECTOR_CST:
{
tree list = copy_list (TREE_VECTOR_CST_ELTS (exp));
tree t, l;
for ( t = TREE_VECTOR_CST_ELTS (exp), l = list; t;
t = TREE_CHAIN (t), l = TREE_CHAIN (l))
TREE_VALUE (l) = copy_constant (TREE_VALUE (t));
return build_vector (TREE_TYPE (exp), list);
}
case PLUS_EXPR:
case MINUS_EXPR:
return build (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)),
copy_constant (TREE_OPERAND (exp, 1)));
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
case CONSTRUCTOR:
{
tree copy = copy_node (exp);
tree list = copy_list (CONSTRUCTOR_ELTS (exp));
tree tail;
CONSTRUCTOR_ELTS (copy) = list;
for (tail = list; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
for (tail = list; tail; tail = TREE_CHAIN (tail))
TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
return copy;
}
default:
{
tree t;
t = (*lang_hooks.expand_constant) (exp);
if (t != exp)
return copy_constant (t);
else
abort ();
}
}
}
rtx
output_constant_def (exp, defer)
tree exp;
int defer;
{
int hash;
struct constant_descriptor_tree *desc;
struct deferred_string **defstr;
char label[256];
int reloc;
int found = 1;
int after_function = 0;
int labelno = -1;
rtx rtl;
if (TREE_CODE (exp) != INTEGER_CST && TREE_CST_RTL (exp)
&& (defer || !STRING_POOL_ADDRESS_P (XEXP (TREE_CST_RTL (exp), 0))))
return TREE_CST_RTL (exp);
reloc = output_addressed_constants (exp);
hash = const_hash (exp);
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc->value))
break;
if (desc == 0)
{
labelno = const_labelno++;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
desc = ggc_alloc (sizeof (*desc));
desc->next = const_hash_table[hash];
desc->label = ggc_strdup (label);
desc->value = copy_constant (exp);
const_hash_table[hash] = desc;
rtl = desc->rtl
= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
gen_rtx_SYMBOL_REF (Pmode, desc->label));
set_mem_attributes (rtl, exp, 1);
set_mem_alias_set (rtl, 0);
set_mem_alias_set (rtl, const_alias_set);
found = 0;
}
else
rtl = desc->rtl;
if (TREE_CODE (exp) != INTEGER_CST)
TREE_CST_RTL (exp) = rtl;
if (! found)
{
if (TREE_CODE (exp) != INTEGER_CST)
(*targetm.encode_section_info) (exp, true);
desc->rtl = rtl;
desc->label = XSTR (XEXP (desc->rtl, 0), 0);
}
#ifdef CONSTANT_AFTER_FUNCTION_P
if (current_function_decl != 0
&& CONSTANT_AFTER_FUNCTION_P (exp))
after_function = 1;
#endif
if (found
&& STRING_POOL_ADDRESS_P (XEXP (rtl, 0))
&& (!defer || defer_addressed_constants_flag || after_function))
{
defstr = (struct deferred_string **)
htab_find_slot_with_hash (const_str_htab, desc->label,
STRHASH (desc->label), NO_INSERT);
if (defstr)
{
found = 0;
labelno = (*defstr)->labelno;
STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 0;
htab_clear_slot (const_str_htab, (void **) defstr);
}
}
if (! found)
{
if (defer_addressed_constants_flag || after_function)
{
struct deferred_constant *p
= (struct deferred_constant *)
xmalloc (sizeof (struct deferred_constant));
p->exp = desc->value;
p->reloc = reloc;
p->labelno = labelno;
if (after_function)
{
p->next = after_function_constants;
after_function_constants = p;
}
else
{
p->next = deferred_constants;
deferred_constants = p;
}
}
else
{
if (! flag_syntax_only)
{
if (TREE_CODE (exp) != STRING_CST
|| !defer
|| flag_writable_strings
|| (defstr = (struct deferred_string **)
htab_find_slot_with_hash (const_str_htab,
desc->label,
STRHASH (desc->label),
INSERT)) == NULL)
output_constant_def_contents (exp, reloc, labelno);
else
{
struct deferred_string *p;
p = (struct deferred_string *)
ggc_alloc (sizeof (struct deferred_string));
p->exp = desc->value;
p->label = desc->label;
p->labelno = labelno;
*defstr = p;
STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 1;
}
}
}
}
return rtl;
}
static void
output_constant_def_contents (exp, reloc, labelno)
tree exp;
int reloc;
int labelno;
{
int align;
align = TYPE_ALIGN (TREE_TYPE (exp));
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (exp, align);
#endif
if (IN_NAMED_SECTION (exp))
named_section (exp, NULL, reloc);
else
(*targetm.asm_out.select_section) (exp, reloc, align);
if (align > BITS_PER_UNIT)
{
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
(*targetm.asm_out.internal_label) (asm_out_file, "LC", labelno);
output_constant (exp,
(TREE_CODE (exp) == STRING_CST
? MAX (TREE_STRING_LENGTH (exp),
int_size_in_bytes (TREE_TYPE (exp)))
: int_size_in_bytes (TREE_TYPE (exp))),
align);
}
struct constant_descriptor_rtx GTY(())
{
struct constant_descriptor_rtx *next;
rtx rtl;
struct rtx_const value;
};
struct pool_constant GTY(())
{
struct constant_descriptor_rtx *desc;
struct pool_constant *next;
struct pool_constant *next_sym;
rtx constant;
enum machine_mode mode;
int labelno;
unsigned int align;
HOST_WIDE_INT offset;
int mark;
};
#define SYMHASH(LABEL) (htab_hash_string (LABEL) % MAX_RTX_HASH_TABLE)
void
init_varasm_status (f)
struct function *f;
{
struct varasm_status *p;
p = (struct varasm_status *) ggc_alloc (sizeof (struct varasm_status));
f->varasm = p;
p->x_const_rtx_hash_table
= ((struct constant_descriptor_rtx **)
ggc_alloc_cleared (MAX_RTX_HASH_TABLE
* sizeof (struct constant_descriptor_rtx *)));
p->x_const_rtx_sym_hash_table
= ((struct pool_constant **)
ggc_alloc_cleared (MAX_RTX_HASH_TABLE
* sizeof (struct pool_constant *)));
p->x_first_pool = p->x_last_pool = 0;
p->x_pool_offset = 0;
}
static void
decode_rtx_const (mode, x, value)
enum machine_mode mode;
rtx x;
struct rtx_const *value;
{
memset (value, 0, sizeof (struct rtx_const));
value->kind = RTX_INT;
value->mode = mode;
switch (GET_CODE (x))
{
case CONST_DOUBLE:
value->kind = RTX_DOUBLE;
if (GET_MODE (x) != VOIDmode)
{
const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
value->mode = GET_MODE (x);
value->un.du.class = r->class;
value->un.du.sign = r->sign;
switch (r->class)
{
case rvc_zero:
case rvc_inf:
break;
case rvc_normal:
value->un.du.exp = r->exp;
case rvc_nan:
memcpy (value->un.du.sig, r->sig, sizeof (r->sig));
break;
default:
abort ();
}
}
else
{
value->un.di.low = CONST_DOUBLE_LOW (x);
value->un.di.high = CONST_DOUBLE_HIGH (x);
}
break;
case CONST_VECTOR:
{
int units, i;
units = CONST_VECTOR_NUNITS (x);
value->kind = RTX_VECTOR;
value->mode = mode;
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
{
for (i = 0; i < units; ++i)
{
rtx elt = CONST_VECTOR_ELT (x, i);
if (GET_CODE (elt) == CONST_INT)
{
value->un.int_vec[i].low = INTVAL (elt);
value->un.int_vec[i].high = 0;
}
else
{
value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
}
}
}
else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
{
for (i = 0; i < units; ++i)
{
const REAL_VALUE_TYPE *r
= CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
d->class = r->class;
d->sign = r->sign;
switch (r->class)
{
case rvc_zero:
case rvc_inf:
break;
case rvc_normal:
d->exp = r->exp;
case rvc_nan:
memcpy (d->sig, r->sig, sizeof (r->sig));
break;
default:
abort ();
}
}
}
else
abort ();
}
break;
case CONST_INT:
value->un.addr.offset = INTVAL (x);
break;
case SYMBOL_REF:
case LABEL_REF:
case PC:
value->un.addr.base = x;
break;
case CONST:
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
value->un.addr.base = XEXP (x, 0);
value->un.addr.offset = INTVAL (XEXP (x, 1));
}
else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
value->un.addr.base = XEXP (x, 0);
value->un.addr.offset = - INTVAL (XEXP (x, 1));
}
else
{
value->un.addr.base = x;
value->un.addr.offset = 0;
}
break;
default:
value->kind = RTX_UNKNOWN;
break;
}
if (value->kind == RTX_INT && value->un.addr.base != 0
&& GET_CODE (value->un.addr.base) == UNSPEC)
{
if (XVECLEN (value->un.addr.base, 0) == 1)
{
value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
}
}
if (value->kind >= RTX_INT && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
#if 0
case SYMBOL_REF:
value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
break;
#endif
case LABEL_REF:
value->un.addr.base = XEXP (value->un.addr.base, 0);
default:
break;
}
}
rtx
simplify_subtraction (x)
rtx x;
{
struct rtx_const val0, val1;
decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
if (val0.kind >= RTX_INT
&& val0.kind == val1.kind
&& val0.un.addr.base == val1.un.addr.base)
return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
return x;
}
static unsigned int
const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
union {
struct rtx_const value;
unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
} u;
unsigned int hi;
size_t i;
decode_rtx_const (mode, x, &u.value);
hi = 0;
for (i = 0; i < ARRAY_SIZE (u.data); i++)
hi = hi * 613 + u.data[i];
return hi % MAX_RTX_HASH_TABLE;
}
static int
compare_constant_rtx (mode, x, desc)
enum machine_mode mode;
rtx x;
struct constant_descriptor_rtx *desc;
{
struct rtx_const value;
decode_rtx_const (mode, x, &value);
return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0;
}
static struct constant_descriptor_rtx *
record_constant_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
struct constant_descriptor_rtx *ptr;
ptr = (struct constant_descriptor_rtx *) ggc_alloc (sizeof (*ptr));
decode_rtx_const (mode, x, &ptr->value);
return ptr;
}
rtx
mem_for_const_double (x)
rtx x;
{
enum machine_mode mode = GET_MODE (x);
struct constant_descriptor_rtx *desc;
for (desc = const_rtx_hash_table[const_hash_rtx (mode, x)]; desc;
desc = desc->next)
if (compare_constant_rtx (mode, x, desc))
return desc->rtl;
return 0;
}
rtx
force_const_mem (mode, x)
enum machine_mode mode;
rtx x;
{
int hash;
struct constant_descriptor_rtx *desc;
char label[256];
rtx def;
struct pool_constant *pool;
unsigned int align;
if ((*targetm.cannot_force_const_mem) (x))
return NULL_RTX;
hash = const_hash_rtx (mode, x);
for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
if (compare_constant_rtx (mode, x, desc))
return desc->rtl;
desc = record_constant_rtx (mode, x);
desc->next = const_rtx_hash_table[hash];
const_rtx_hash_table[hash] = desc;
align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (make_tree ((*lang_hooks.types.type_for_mode)
(mode, 0), x), align);
#endif
pool_offset += (align / BITS_PER_UNIT) - 1;
pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
if (GET_CODE (x) == LABEL_REF)
LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
pool->desc = desc;
pool->constant = x;
pool->mode = mode;
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
first_pool = pool;
else
last_pool->next = pool;
last_pool = pool;
pool_offset += GET_MODE_SIZE (mode);
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
++const_labelno;
pool->desc->rtl = def
= gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)));
set_mem_alias_set (def, const_alias_set);
set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1);
RTX_UNCHANGING_P (def) = 1;
hash = SYMHASH (XSTR (XEXP (def, 0), 0));
pool->next_sym = const_rtx_sym_hash_table[hash];
const_rtx_sym_hash_table[hash] = pool;
CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
current_function_uses_const_pool = 1;
return def;
}
static struct pool_constant *
find_pool_constant (f, addr)
struct function *f;
rtx addr;
{
struct pool_constant *pool;
const char *label = XSTR (addr, 0);
for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
pool = pool->next_sym)
if (XSTR (XEXP (pool->desc->rtl, 0), 0) == label)
return pool;
abort ();
}
rtx
get_pool_constant (addr)
rtx addr;
{
return (find_pool_constant (cfun, addr))->constant;
}
rtx
get_pool_constant_mark (addr, pmarked)
rtx addr;
bool *pmarked;
{
struct pool_constant *pool = find_pool_constant (cfun, addr);
*pmarked = (pool->mark != 0);
return pool->constant;
}
rtx
get_pool_constant_for_function (f, addr)
struct function *f;
rtx addr;
{
return (find_pool_constant (f, addr))->constant;
}
enum machine_mode
get_pool_mode (addr)
rtx addr;
{
return (find_pool_constant (cfun, addr))->mode;
}
enum machine_mode
get_pool_mode_for_function (f, addr)
struct function *f;
rtx addr;
{
return (find_pool_constant (f, addr))->mode;
}
int
get_pool_offset (addr)
rtx addr;
{
return (find_pool_constant (cfun, addr))->offset;
}
int
get_pool_size ()
{
return pool_offset;
}
void
output_constant_pool (fnname, fndecl)
const char *fnname ATTRIBUTE_UNUSED;
tree fndecl ATTRIBUTE_UNUSED;
{
struct pool_constant *pool;
rtx x;
REAL_VALUE_TYPE r;
mark_constant_pool ();
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
for (pool = first_pool; pool; pool = pool->next)
{
rtx tmp;
x = pool->constant;
if (! pool->mark)
continue;
tmp = x;
switch (GET_CODE (x))
{
case CONST:
if (GET_CODE (XEXP (x, 0)) != PLUS
|| GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
break;
tmp = XEXP (XEXP (x, 0), 0);
case LABEL_REF:
tmp = XEXP (x, 0);
if (INSN_DELETED_P (tmp)
|| (GET_CODE (tmp) == NOTE
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
{
abort ();
x = const0_rtx;
}
break;
default:
break;
}
(*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
pool->align, pool->labelno, done);
#endif
assemble_align (pool->align);
(*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
switch (GET_MODE_CLASS (pool->mode))
{
case MODE_FLOAT:
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
assemble_real (r, pool->mode, pool->align);
break;
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
break;
case MODE_VECTOR_FLOAT:
{
int i, units;
rtx elt;
if (GET_CODE (x) != CONST_VECTOR)
abort ();
units = CONST_VECTOR_NUNITS (x);
for (i = 0; i < units; i++)
{
elt = CONST_VECTOR_ELT (x, i);
REAL_VALUE_FROM_CONST_DOUBLE (r, elt);
assemble_real (r, GET_MODE_INNER (pool->mode), pool->align);
}
}
break;
case MODE_VECTOR_INT:
{
int i, units;
rtx elt;
if (GET_CODE (x) != CONST_VECTOR)
abort ();
units = CONST_VECTOR_NUNITS (x);
for (i = 0; i < units; i++)
{
elt = CONST_VECTOR_ELT (x, i);
assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
pool->align, 1);
}
}
break;
default:
abort ();
}
if (pool->align > GET_MODE_BITSIZE (pool->mode)
&& in_section == in_named
&& get_named_section_flags (in_named_name) & SECTION_MERGE)
assemble_align (pool->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ;
#endif
}
#ifdef ASM_OUTPUT_POOL_EPILOGUE
ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
first_pool = last_pool = 0;
}
static void
mark_constant_pool ()
{
rtx insn;
rtx link;
struct pool_constant *pool;
if (first_pool == 0 && htab_elements (const_str_htab) == 0)
return;
for (pool = first_pool; pool; pool = pool->next)
pool->mark = 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
mark_constants (PATTERN (insn));
for (link = current_function_epilogue_delay_list;
link;
link = XEXP (link, 1))
{
insn = XEXP (link, 0);
if (INSN_P (insn))
mark_constants (PATTERN (insn));
}
}
static void
mark_constants (x)
rtx x;
{
int i;
const char *format_ptr;
if (x == 0)
return;
if (GET_CODE (x) == SYMBOL_REF)
{
mark_constant (&x, NULL);
return;
}
if (INSN_P (x))
{
mark_constants (PATTERN (x));
return;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (x));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
{
switch (*format_ptr++)
{
case 'e':
mark_constants (XEXP (x, i));
break;
case 'E':
if (XVEC (x, i) != 0)
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_constants (XVECEXP (x, i, j));
}
break;
case 'S':
case 's':
case '0':
case 'i':
case 'w':
case 'n':
case 'u':
case 'B':
break;
default:
abort ();
}
}
}
static int
mark_constant (current_rtx, data)
rtx *current_rtx;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *current_rtx;
if (x == NULL_RTX)
return 0;
else if (GET_CODE (x) == SYMBOL_REF)
{
if (CONSTANT_POOL_ADDRESS_P (x))
{
struct pool_constant *pool = find_pool_constant (cfun, x);
if (pool->mark == 0)
{
pool->mark = 1;
for_each_rtx (&(pool->constant), &mark_constant, NULL);
}
else
return -1;
}
else if (STRING_POOL_ADDRESS_P (x))
{
struct deferred_string **defstr;
defstr = (struct deferred_string **)
htab_find_slot_with_hash (const_str_htab, XSTR (x, 0),
STRHASH (XSTR (x, 0)), NO_INSERT);
if (defstr)
{
struct deferred_string *p = *defstr;
STRING_POOL_ADDRESS_P (x) = 0;
output_constant_def_contents (p->exp, 0, p->labelno);
htab_clear_slot (const_str_htab, (void **) defstr);
}
}
}
return 0;
}
static int
output_addressed_constants (exp)
tree exp;
{
int reloc = 0, reloc2;
tree tem;
exp = (*lang_hooks.expand_constant) (exp);
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
case FDESC_EXPR:
for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);
tem = TREE_OPERAND (tem, 0))
;
if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
|| TREE_CODE (tem) == CONSTRUCTOR)
output_constant_def (tem, 0);
if (TREE_PUBLIC (tem))
reloc |= 2;
else
reloc |= 1;
break;
case PLUS_EXPR:
reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
break;
case MINUS_EXPR:
reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
reloc2 = output_addressed_constants (TREE_OPERAND (exp, 1));
if (reloc == 1 && reloc2 == 1)
reloc = 0;
else
reloc |= reloc2;
break;
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
break;
case CONSTRUCTOR:
for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
if (TREE_VALUE (tem) != 0)
reloc |= output_addressed_constants (TREE_VALUE (tem));
break;
default:
break;
}
return reloc;
}
tree
initializer_constant_valid_p (value, endtype)
tree value;
tree endtype;
{
value = (*lang_hooks.expand_constant) (value);
switch (TREE_CODE (value))
{
case CONSTRUCTOR:
if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
&& TREE_CONSTANT (value)
&& CONSTRUCTOR_ELTS (value))
return
initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
endtype);
return TREE_STATIC (value) ? null_pointer_node : 0;
case INTEGER_CST:
case VECTOR_CST:
case REAL_CST:
case STRING_CST:
case COMPLEX_CST:
return null_pointer_node;
case ADDR_EXPR:
case FDESC_EXPR:
return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
case CONVERT_EXPR:
case NOP_EXPR:
if (POINTER_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
if (FLOAT_TYPE_P (TREE_TYPE (value))
&& FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
if (inner == null_pointer_node)
return null_pointer_node;
break;
}
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
if (POINTER_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
if (integer_zerop (TREE_OPERAND (value, 0)))
return null_pointer_node;
else if (TYPE_PRECISION (TREE_TYPE (value))
<= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
}
if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
break;
case PLUS_EXPR:
if (! INTEGRAL_TYPE_P (endtype)
|| TYPE_PRECISION (endtype) >= POINTER_SIZE)
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
endtype);
if (valid0 == null_pointer_node)
return valid1;
if (valid1 == null_pointer_node)
return valid0;
}
break;
case MINUS_EXPR:
if (! INTEGRAL_TYPE_P (endtype)
|| TYPE_PRECISION (endtype) >= POINTER_SIZE)
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
endtype);
if (valid1 == null_pointer_node)
return valid0;
if (valid0 == valid1 && valid0 != 0)
return null_pointer_node;
if (valid0 && TREE_CODE (valid0) == STRING_CST &&
valid1 && TREE_CODE (valid1) == STRING_CST &&
TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
return null_pointer_node;
}
if (INTEGRAL_TYPE_P (endtype))
{
tree op0, op1;
op0 = TREE_OPERAND (value, 0);
op1 = TREE_OPERAND (value, 1);
while (TREE_CODE (op0) == NOP_EXPR
|| TREE_CODE (op0) == CONVERT_EXPR
|| TREE_CODE (op0) == NON_LVALUE_EXPR)
{
tree inner = TREE_OPERAND (op0, 0);
if (inner == error_mark_node
|| ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
|| (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
break;
op0 = inner;
}
while (TREE_CODE (op1) == NOP_EXPR
|| TREE_CODE (op1) == CONVERT_EXPR
|| TREE_CODE (op1) == NON_LVALUE_EXPR)
{
tree inner = TREE_OPERAND (op1, 0);
if (inner == error_mark_node
|| ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
|| (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
break;
op1 = inner;
}
if (TREE_CODE (op0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
&& TREE_CODE (op1) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
return null_pointer_node;
}
break;
default:
break;
}
return 0;
}
void
output_constant (exp, size, align)
tree exp;
HOST_WIDE_INT size;
unsigned int align;
{
enum tree_code code;
HOST_WIDE_INT thissize;
exp = (*lang_hooks.expand_constant) (exp);
if (size == 0 || flag_syntax_only)
return;
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
|| TREE_CODE (exp) == NON_LVALUE_EXPR
|| TREE_CODE (exp) == VIEW_CONVERT_EXPR)
exp = TREE_OPERAND (exp, 0);
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
{
assemble_zeros (size);
return;
}
if (TREE_CODE (exp) == FDESC_EXPR)
{
#ifdef ASM_OUTPUT_FDESC
HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
tree decl = TREE_OPERAND (exp, 0);
ASM_OUTPUT_FDESC (asm_out_file, decl, part);
#else
abort ();
#endif
return;
}
switch (code)
{
case CHAR_TYPE:
case BOOLEAN_TYPE:
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
size, align, 0))
error ("initializer for integer value is too complicated");
break;
case REAL_TYPE:
if (TREE_CODE (exp) != REAL_CST)
error ("initializer for floating value is not a floating constant");
assemble_real (TREE_REAL_CST (exp),
mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0),
align);
break;
case COMPLEX_TYPE:
output_constant (TREE_REALPART (exp), thissize / 2, align);
output_constant (TREE_IMAGPART (exp), thissize / 2,
min_align (align, BITS_PER_UNIT * (thissize / 2)));
break;
case ARRAY_TYPE:
case VECTOR_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
{
output_constructor (exp, size, align);
return;
}
else if (TREE_CODE (exp) == STRING_CST)
{
thissize = MIN (TREE_STRING_LENGTH (exp), size);
assemble_string (TREE_STRING_POINTER (exp), thissize);
}
else if (TREE_CODE (exp) == VECTOR_CST )
{
tree t;
for ( t = TREE_VECTOR_CST_ELTS (exp); t; t = TREE_CHAIN (t))
{
int eltsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_VALUE (t))), 1)
/ BITS_PER_UNIT;
int eltalign = min_align (align, BITS_PER_UNIT * eltsize);
output_constant (TREE_VALUE (t), eltsize, eltalign);
}
}
else
abort ();
break;
case RECORD_TYPE:
case UNION_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
output_constructor (exp, size, align);
else
abort ();
return;
case SET_TYPE:
if (TREE_CODE (exp) == INTEGER_CST)
assemble_integer (expand_expr (exp, NULL_RTX,
VOIDmode, EXPAND_INITIALIZER),
thissize, align, 1);
else if (TREE_CODE (exp) == CONSTRUCTOR)
{
unsigned char *buffer = (unsigned char *) alloca (thissize);
if (get_set_constructor_bytes (exp, buffer, thissize))
abort ();
assemble_string ((char *) buffer, thissize);
}
else
error ("unknown set constructor type");
return;
case ERROR_MARK:
return;
default:
abort ();
}
size -= thissize;
if (size > 0)
assemble_zeros (size);
}
static unsigned HOST_WIDE_INT
array_size_for_constructor (val)
tree val;
{
tree max_index, i;
if (TREE_CODE (val) == STRING_CST)
return TREE_STRING_LENGTH (val);
max_index = NULL_TREE;
for (i = CONSTRUCTOR_ELTS (val); i; i = TREE_CHAIN (i))
{
tree index = TREE_PURPOSE (i);
if (TREE_CODE (index) == RANGE_EXPR)
index = TREE_OPERAND (index, 1);
if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
max_index = index;
}
if (max_index == NULL_TREE)
return 0;
i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
convert (sizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
return tree_low_cst (i, 1);
}
static void
output_constructor (exp, size, align)
tree exp;
HOST_WIDE_INT size;
unsigned int align;
{
tree type = TREE_TYPE (exp);
tree link, field = 0;
tree min_index = 0;
HOST_WIDE_INT total_bytes = 0;
int byte_buffer_in_use = 0;
int byte = 0;
if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
abort ();
if (TREE_CODE (type) == RECORD_TYPE)
field = TYPE_FIELDS (type);
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) != 0)
min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
for (link = CONSTRUCTOR_ELTS (exp);
link;
link = TREE_CHAIN (link),
field = field ? TREE_CHAIN (field) : 0)
{
tree val = TREE_VALUE (link);
tree index = 0;
if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
&& TREE_PURPOSE (link) != 0)
field = TREE_PURPOSE (link);
else if (TREE_CODE (type) == ARRAY_TYPE)
index = TREE_PURPOSE (link);
if (val != 0)
STRIP_NOPS (val);
if (index && TREE_CODE (index) == RANGE_EXPR)
{
unsigned HOST_WIDE_INT fieldsize
= int_size_in_bytes (TREE_TYPE (type));
HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
HOST_WIDE_INT index;
unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
for (index = lo_index; index <= hi_index; index++)
{
if (val == 0)
assemble_zeros (fieldsize);
else
output_constant (val, fieldsize, align2);
total_bytes += fieldsize;
}
}
else if (field == 0 || !DECL_BIT_FIELD (field))
{
unsigned HOST_WIDE_INT fieldsize;
HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
unsigned int align2;
if (index != 0)
pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
* (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
if (byte_buffer_in_use)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte_buffer_in_use = 0;
}
if ((field != 0 || index != 0) && pos != total_bytes)
{
assemble_zeros (pos - total_bytes);
total_bytes = pos;
}
align2 = min_align (align, BITS_PER_UNIT * pos);
if (field)
{
fieldsize = 0;
if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (field))
&& ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
{
fieldsize = array_size_for_constructor (val);
if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
abort ();
}
else if (DECL_SIZE_UNIT (field))
{
if (host_integerp (DECL_SIZE_UNIT (field), 1))
fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
}
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (type));
if (val == 0)
assemble_zeros (fieldsize);
else
output_constant (val, fieldsize, align2);
total_bytes += fieldsize;
}
else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
error ("invalid initial value for member `%s'",
IDENTIFIER_POINTER (DECL_NAME (field)));
else
{
HOST_WIDE_INT next_offset = int_bit_position (field);
HOST_WIDE_INT end_offset
= (next_offset + tree_low_cst (DECL_SIZE (field), 1));
if (val == 0)
val = integer_zero_node;
if (next_offset / BITS_PER_UNIT != total_bytes)
{
if (byte_buffer_in_use)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte_buffer_in_use = 0;
}
if (next_offset / BITS_PER_UNIT != total_bytes)
{
assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
total_bytes = next_offset / BITS_PER_UNIT;
}
}
if (! byte_buffer_in_use)
byte = 0;
while (next_offset < end_offset)
{
int this_time;
int shift;
HOST_WIDE_INT value;
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
while (next_byte != total_bytes)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte = 0;
}
this_time = MIN (end_offset - next_offset,
BITS_PER_UNIT - next_bit);
if (BYTES_BIG_ENDIAN)
{
shift = end_offset - next_offset - this_time;
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
{
this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
shift = HOST_BITS_PER_WIDE_INT;
}
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
{
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
else
abort ();
byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< (BITS_PER_UNIT - this_time - next_bit));
}
else
{
shift = next_offset - int_bit_position (field);
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
this_time = (HOST_BITS_PER_WIDE_INT - shift);
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
{
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
else
abort ();
byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< next_bit);
}
next_offset += this_time;
byte_buffer_in_use = 1;
}
}
}
if (byte_buffer_in_use)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
}
if (total_bytes < size)
assemble_zeros (size - total_bytes);
}
static GTY(()) tree weak_decls;
static void
mark_weak (decl)
tree decl;
{
DECL_WEAK (decl) = 1;
if (DECL_RTL_SET_P (decl)
&& GET_CODE (DECL_RTL (decl)) == MEM
&& XEXP (DECL_RTL (decl), 0)
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
}
void
merge_weak (newdecl, olddecl)
tree newdecl;
tree olddecl;
{
if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
return;
if (DECL_WEAK (newdecl))
{
tree wd;
if (TREE_ASM_WRITTEN (olddecl))
error_with_decl (newdecl,
"weak declaration of `%s' must precede definition");
else if (TREE_USED (olddecl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
warning_with_decl (newdecl, "weak declaration of `%s' after first use results in unspecified behavior");
if (SUPPORTS_WEAK)
{
for (wd = weak_decls; wd; wd = TREE_CHAIN (wd))
if (TREE_VALUE (wd) == newdecl)
{
TREE_VALUE (wd) = olddecl;
break;
}
}
mark_weak (olddecl);
}
else
mark_weak (newdecl);
}
void
declare_weak (decl)
tree decl;
{
if (! TREE_PUBLIC (decl))
error_with_decl (decl, "weak declaration of `%s' must be public");
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
error_with_decl (decl, "weak declaration of `%s' must precede definition");
else if (SUPPORTS_WEAK)
{
if (! DECL_WEAK (decl))
weak_decls = tree_cons (NULL, decl, weak_decls);
}
else
warning_with_decl (decl, "weak declaration of `%s' not supported");
mark_weak (decl);
}
void
weak_finish ()
{
tree t;
for (t = weak_decls; t; t = TREE_CHAIN (t))
{
tree decl = TREE_VALUE (t);
#if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#endif
if (! TREE_USED (decl))
continue;
#ifdef ASM_WEAKEN_DECL
ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
#else
#ifdef ASM_WEAKEN_LABEL
ASM_WEAKEN_LABEL (asm_out_file, name);
#else
#ifdef ASM_OUTPUT_WEAK_ALIAS
warning ("only weak aliases are supported in this configuration");
return;
#endif
#endif
#endif
}
}
static void
globalize_decl (decl)
tree decl;
{
const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
if (DECL_WEAK (decl))
{
tree *p, t;
#ifdef ASM_WEAKEN_DECL
ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
#else
ASM_WEAKEN_LABEL (asm_out_file, name);
#endif
for (p = &weak_decls; (t = *p) ; )
{
if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
*p = TREE_CHAIN (t);
else
p = &TREE_CHAIN (t);
}
return;
}
#endif
#ifdef ASM_WEAK_DEFINITIONIZE_LABEL
if (DECL_COALESCED (decl) && flag_weak_coalesced_definitions)
ASM_WEAK_DEFINITIONIZE_LABEL (asm_out_file, name);
#endif
#ifdef ASM_PRIVATE_EXTERNIZE_LABEL
if (DECL_PRIVATE_EXTERN (decl) ||
(!flag_export_coalesced && !TREE_PUBLIC (decl) && DECL_COALESCED (decl)))
{
ASM_PRIVATE_EXTERNIZE_LABEL (asm_out_file, name);
return;
}
#endif
(*targetm.asm_out.globalize_label) (asm_out_file, name);
}
void
assemble_alias (decl, target)
tree decl, target ATTRIBUTE_UNUSED;
{
const char *name;
make_decl_rtl (decl, NULL);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#ifdef ASM_OUTPUT_DEF
if (TREE_PUBLIC (decl))
{
globalize_decl (decl);
maybe_assemble_visibility (decl);
}
#ifdef ASM_OUTPUT_DEF_FROM_DECLS
ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
#else
ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
#endif
#else
#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
if (! DECL_WEAK (decl))
warning ("only weak aliases are supported in this configuration");
#ifdef ASM_WEAKEN_DECL
ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
#else
ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
#endif
#else
warning ("alias definitions not supported in this configuration; ignored");
#endif
#endif
TREE_USED (decl) = 1;
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
}
void
default_assemble_visibility (decl, vis)
tree decl;
int vis;
{
static const char * const visibility_types[] = {
NULL, "internal", "hidden", "protected"
};
const char *name, *type;
name = (* targetm.strip_name_encoding)
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
type = visibility_types[vis];
#ifdef HAVE_GAS_HIDDEN
fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
#else
warning ("visibility attribute not supported in this configuration; ignored");
#endif
}
static void
maybe_assemble_visibility (decl)
tree decl;
{
enum symbol_visibility vis = decl_visibility (decl);
if (vis != VISIBILITY_DEFAULT)
(* targetm.asm_out.visibility) (decl, vis);
}
int
supports_one_only ()
{
if (SUPPORTS_ONE_ONLY)
return 1;
return SUPPORTS_WEAK;
}
void
make_decl_one_only (decl)
tree decl;
{
if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
abort ();
TREE_PUBLIC (decl) = 1;
if (TREE_CODE (decl) == VAR_DECL
&& (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
DECL_COMMON (decl) = 1;
else if (SUPPORTS_ONE_ONLY)
{
#ifdef MAKE_DECL_ONE_ONLY
MAKE_DECL_ONE_ONLY (decl);
#endif
DECL_ONE_ONLY (decl) = 1;
}
else if (SUPPORTS_WEAK)
DECL_WEAK (decl) = 1;
else
abort ();
}
void
init_varasm_once ()
{
const_str_htab = htab_create_ggc (128, const_str_htab_hash,
const_str_htab_eq, NULL);
in_named_htab = htab_create_ggc (31, in_named_entry_hash,
in_named_entry_eq, NULL);
const_alias_set = new_alias_set ();
}
enum tls_model
decl_tls_model (decl)
tree decl;
{
enum tls_model kind;
tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
bool is_local;
if (attr)
{
attr = TREE_VALUE (TREE_VALUE (attr));
if (TREE_CODE (attr) != STRING_CST)
abort ();
if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
kind = TLS_MODEL_LOCAL_EXEC;
else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
kind = TLS_MODEL_INITIAL_EXEC;
else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
kind = TLS_MODEL_GLOBAL_DYNAMIC;
else
abort ();
return kind;
}
is_local = (*targetm.binds_local_p) (decl);
if (!flag_pic)
{
if (is_local)
kind = TLS_MODEL_LOCAL_EXEC;
else
kind = TLS_MODEL_INITIAL_EXEC;
}
else if (optimize && is_local)
kind = TLS_MODEL_LOCAL_DYNAMIC;
else
kind = TLS_MODEL_GLOBAL_DYNAMIC;
if (kind < flag_tls_default)
kind = flag_tls_default;
return kind;
}
enum symbol_visibility
decl_visibility (decl)
tree decl;
{
tree attr = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
if (attr)
{
const char *which = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
if (strcmp (which, "default") == 0)
return VISIBILITY_DEFAULT;
if (strcmp (which, "internal") == 0)
return VISIBILITY_INTERNAL;
if (strcmp (which, "hidden") == 0)
return VISIBILITY_HIDDEN;
if (strcmp (which, "protected") == 0)
return VISIBILITY_PROTECTED;
abort ();
}
return VISIBILITY_DEFAULT;
}
unsigned int
default_section_type_flags (decl, name, reloc)
tree decl;
const char *name;
int reloc;
{
return default_section_type_flags_1 (decl, name, reloc, flag_pic);
}
unsigned int
default_section_type_flags_1 (decl, name, reloc, shlib)
tree decl;
const char *name;
int reloc;
int shlib;
{
unsigned int flags;
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0;
else
flags = SECTION_WRITE;
if (decl && DECL_ONE_ONLY (decl))
flags |= SECTION_LINKONCE;
if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
flags |= SECTION_TLS | SECTION_WRITE;
if (strcmp (name, ".bss") == 0
|| strncmp (name, ".bss.", 5) == 0
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0
|| strcmp (name, ".sbss") == 0
|| strncmp (name, ".sbss.", 6) == 0
|| strncmp (name, ".gnu.linkonce.sb.", 17) == 0
|| strcmp (name, ".tbss") == 0
|| strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
flags |= SECTION_BSS;
if (strcmp (name, ".tdata") == 0
|| strcmp (name, ".tbss") == 0
|| strncmp (name, ".gnu.linkonce.td.", 17) == 0
|| strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
flags |= SECTION_TLS;
if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS))
&& (strcmp (name, ".init_array") == 0
|| strcmp (name, ".fini_array") == 0
|| strcmp (name, ".preinit_array") == 0))
flags |= SECTION_NOTYPE;
return flags;
}
void
default_no_named_section (name, flags)
const char *name ATTRIBUTE_UNUSED;
unsigned int flags ATTRIBUTE_UNUSED;
{
abort ();
}
void
default_elf_asm_named_section (name, flags)
const char *name;
unsigned int flags;
{
char flagchars[10], *f = flagchars;
if (! named_section_first_declaration (name))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
return;
}
if (!(flags & SECTION_DEBUG))
*f++ = 'a';
if (flags & SECTION_WRITE)
*f++ = 'w';
if (flags & SECTION_CODE)
*f++ = 'x';
if (flags & SECTION_SMALL)
*f++ = 's';
if (flags & SECTION_MERGE)
*f++ = 'M';
if (flags & SECTION_STRINGS)
*f++ = 'S';
if (flags & SECTION_TLS)
*f++ = 'T';
*f = '\0';
fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
if (!(flags & SECTION_NOTYPE))
{
const char *type;
if (flags & SECTION_BSS)
type = "nobits";
else
type = "progbits";
fprintf (asm_out_file, ",@%s", type);
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
}
putc ('\n', asm_out_file);
}
void
default_coff_asm_named_section (name, flags)
const char *name;
unsigned int flags;
{
char flagchars[8], *f = flagchars;
if (flags & SECTION_WRITE)
*f++ = 'w';
if (flags & SECTION_CODE)
*f++ = 'x';
*f = '\0';
fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
}
void
default_pe_asm_named_section (name, flags)
const char *name;
unsigned int flags;
{
default_coff_asm_named_section (name, flags);
if (flags & SECTION_LINKONCE)
{
fprintf (asm_out_file, "\t.linkonce %s\n",
(flags & SECTION_CODE ? "discard" : "same_size"));
}
}
void
assemble_vtable_entry (symbol, offset)
rtx symbol;
HOST_WIDE_INT offset;
{
fputs ("\t.vtable_entry ", asm_out_file);
output_addr_const (asm_out_file, symbol);
fputs (", ", asm_out_file);
fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, offset);
fputc ('\n', asm_out_file);
}
void
assemble_vtable_inherit (child, parent)
rtx child, parent;
{
fputs ("\t.vtable_inherit ", asm_out_file);
output_addr_const (asm_out_file, child);
fputs (", ", asm_out_file);
output_addr_const (asm_out_file, parent);
fputc ('\n', asm_out_file);
}
void
default_select_section (decl, reloc, align)
tree decl;
int reloc;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
{
bool readonly = false;
if (DECL_P (decl))
{
if (decl_readonly_section (decl, reloc))
readonly = true;
}
else if (TREE_CODE (decl) == CONSTRUCTOR)
{
if (! ((flag_pic && reloc)
|| !TREE_READONLY (decl)
|| TREE_SIDE_EFFECTS (decl)
|| !TREE_CONSTANT (decl)))
readonly = true;
}
else if (TREE_CODE (decl) == STRING_CST)
readonly = !flag_writable_strings;
else if (! (flag_pic && reloc))
readonly = true;
if (readonly)
readonly_data_section ();
else
data_section ();
}
enum section_category
{
SECCAT_TEXT,
SECCAT_RODATA,
SECCAT_RODATA_MERGE_STR,
SECCAT_RODATA_MERGE_STR_INIT,
SECCAT_RODATA_MERGE_CONST,
SECCAT_SRODATA,
SECCAT_DATA,
SECCAT_DATA_REL,
SECCAT_DATA_REL_LOCAL,
SECCAT_DATA_REL_RO,
SECCAT_DATA_REL_RO_LOCAL,
SECCAT_SDATA,
SECCAT_TDATA,
SECCAT_BSS,
SECCAT_SBSS,
SECCAT_TBSS
};
static enum section_category
categorize_decl_for_section PARAMS ((tree, int, int));
static enum section_category
categorize_decl_for_section (decl, reloc, shlib)
tree decl;
int reloc;
int shlib;
{
enum section_category ret;
if (TREE_CODE (decl) == FUNCTION_DECL)
return SECCAT_TEXT;
else if (TREE_CODE (decl) == STRING_CST)
{
if (flag_writable_strings)
return SECCAT_DATA;
else
return SECCAT_RODATA_MERGE_STR;
}
else if (TREE_CODE (decl) == VAR_DECL)
{
if (DECL_INITIAL (decl) == NULL
|| DECL_INITIAL (decl) == error_mark_node)
ret = SECCAT_BSS;
else if (! TREE_READONLY (decl)
|| TREE_SIDE_EFFECTS (decl)
|| ! TREE_CONSTANT (DECL_INITIAL (decl)))
{
if (shlib && (reloc & 2))
ret = SECCAT_DATA_REL;
else if (shlib && reloc)
ret = SECCAT_DATA_REL_LOCAL;
else
ret = SECCAT_DATA;
}
else if (shlib && (reloc & 2))
ret = SECCAT_DATA_REL_RO;
else if (shlib && reloc)
ret = SECCAT_DATA_REL_RO_LOCAL;
else if (reloc || flag_merge_constants < 2)
ret = SECCAT_RODATA;
else if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
ret = SECCAT_RODATA_MERGE_STR_INIT;
else
ret = SECCAT_RODATA_MERGE_CONST;
}
else if (TREE_CODE (decl) == CONSTRUCTOR)
{
if ((shlib && reloc)
|| TREE_SIDE_EFFECTS (decl)
|| ! TREE_CONSTANT (decl))
ret = SECCAT_DATA;
else
ret = SECCAT_RODATA;
}
else
ret = SECCAT_RODATA;
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
{
if (ret == SECCAT_BSS)
ret = SECCAT_TBSS;
else
ret = SECCAT_TDATA;
}
else if ((*targetm.in_small_data_p) (decl))
{
if (ret == SECCAT_BSS)
ret = SECCAT_SBSS;
else if (targetm.have_srodata_section && ret == SECCAT_RODATA)
ret = SECCAT_SRODATA;
else
ret = SECCAT_SDATA;
}
return ret;
}
bool
decl_readonly_section (decl, reloc)
tree decl;
int reloc;
{
return decl_readonly_section_1 (decl, reloc, flag_pic);
}
bool
decl_readonly_section_1 (decl, reloc, shlib)
tree decl;
int reloc;
int shlib;
{
switch (categorize_decl_for_section (decl, reloc, shlib))
{
case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST:
case SECCAT_SRODATA:
return true;
break;
default:
return false;
break;
}
}
void
default_elf_select_section (decl, reloc, align)
tree decl;
int reloc;
unsigned HOST_WIDE_INT align;
{
default_elf_select_section_1 (decl, reloc, align, flag_pic);
}
void
default_elf_select_section_1 (decl, reloc, align, shlib)
tree decl;
int reloc;
unsigned HOST_WIDE_INT align;
int shlib;
{
switch (categorize_decl_for_section (decl, reloc, shlib))
{
case SECCAT_TEXT:
abort ();
case SECCAT_RODATA:
readonly_data_section ();
break;
case SECCAT_RODATA_MERGE_STR:
mergeable_string_section (decl, align, 0);
break;
case SECCAT_RODATA_MERGE_STR_INIT:
mergeable_string_section (DECL_INITIAL (decl), align, 0);
break;
case SECCAT_RODATA_MERGE_CONST:
mergeable_constant_section (DECL_MODE (decl), align, 0);
break;
case SECCAT_SRODATA:
named_section (NULL_TREE, ".sdata2", reloc);
break;
case SECCAT_DATA:
data_section ();
break;
case SECCAT_DATA_REL:
named_section (NULL_TREE, ".data.rel", reloc);
break;
case SECCAT_DATA_REL_LOCAL:
named_section (NULL_TREE, ".data.rel.local", reloc);
break;
case SECCAT_DATA_REL_RO:
named_section (NULL_TREE, ".data.rel.ro", reloc);
break;
case SECCAT_DATA_REL_RO_LOCAL:
named_section (NULL_TREE, ".data.rel.ro.local", reloc);
break;
case SECCAT_SDATA:
named_section (NULL_TREE, ".sdata", reloc);
break;
case SECCAT_TDATA:
named_section (NULL_TREE, ".tdata", reloc);
break;
case SECCAT_BSS:
#ifdef BSS_SECTION_ASM_OP
bss_section ();
#else
named_section (NULL_TREE, ".bss", reloc);
#endif
break;
case SECCAT_SBSS:
named_section (NULL_TREE, ".sbss", reloc);
break;
case SECCAT_TBSS:
named_section (NULL_TREE, ".tbss", reloc);
break;
default:
abort ();
}
}
void
default_unique_section (decl, reloc)
tree decl;
int reloc;
{
default_unique_section_1 (decl, reloc, flag_pic);
}
void
default_unique_section_1 (decl, reloc, shlib)
tree decl;
int reloc;
int shlib;
{
bool one_only = DECL_ONE_ONLY (decl);
const char *prefix, *name;
size_t nlen, plen;
char *string;
switch (categorize_decl_for_section (decl, reloc, shlib))
{
case SECCAT_TEXT:
prefix = one_only ? ".gnu.linkonce.t." : ".text.";
break;
case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST:
prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
break;
case SECCAT_SRODATA:
prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
break;
case SECCAT_DATA:
case SECCAT_DATA_REL:
case SECCAT_DATA_REL_LOCAL:
case SECCAT_DATA_REL_RO:
case SECCAT_DATA_REL_RO_LOCAL:
prefix = one_only ? ".gnu.linkonce.d." : ".data.";
break;
case SECCAT_SDATA:
prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
break;
case SECCAT_BSS:
prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
break;
case SECCAT_SBSS:
prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
break;
case SECCAT_TDATA:
prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
break;
case SECCAT_TBSS:
prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
break;
default:
abort ();
}
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = (* targetm.strip_name_encoding) (name);
nlen = strlen (name);
string = alloca (nlen + plen + 1);
memcpy (string, prefix, plen);
memcpy (string + plen, name, nlen + 1);
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
}
void
default_select_rtx_section (mode, x, align)
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx x;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
{
if (flag_pic)
switch (GET_CODE (x))
{
case CONST:
case SYMBOL_REF:
case LABEL_REF:
data_section ();
return;
default:
break;
}
readonly_data_section ();
}
void
default_elf_select_rtx_section (mode, x, align)
enum machine_mode mode;
rtx x;
unsigned HOST_WIDE_INT align;
{
if (flag_pic)
switch (GET_CODE (x))
{
case CONST:
case SYMBOL_REF:
named_section (NULL_TREE, ".data.rel.ro", 3);
return;
case LABEL_REF:
named_section (NULL_TREE, ".data.rel.ro.local", 1);
return;
default:
break;
}
mergeable_constant_section (mode, align, 0);
}
const char *
default_strip_name_encoding (str)
const char *str;
{
return str + (*str == '*');
}
bool
default_binds_local_p (exp)
tree exp;
{
return default_binds_local_p_1 (exp, flag_pic);
}
bool
default_binds_local_p_1 (exp, shlib)
tree exp;
int shlib;
{
bool local_p;
if (!DECL_P (exp))
local_p = true;
else if (! TREE_PUBLIC (exp))
local_p = true;
else if (decl_visibility (exp) != VISIBILITY_DEFAULT)
local_p = true;
else if (DECL_EXTERNAL (exp))
local_p = false;
else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
local_p = false;
else if (shlib)
local_p = false;
else if (DECL_COMMON (exp)
&& (DECL_INITIAL (exp) == NULL
|| DECL_INITIAL (exp) == error_mark_node))
local_p = false;
else
local_p = true;
return local_p;
}
bool
default_valid_pointer_mode (mode)
enum machine_mode mode;
{
return (mode == ptr_mode || mode == Pmode);
}
#ifdef GLOBAL_ASM_OP
void
default_globalize_label (stream, name)
FILE * stream;
const char *name;
{
fputs (GLOBAL_ASM_OP, stream);
assemble_name (stream, name);
putc ('\n', stream);
}
#endif
int
darwin_named_section_is (name)
const char* name;
{
return (in_section == in_named
&& strcmp (in_named_name, name) == 0);
}
void
default_internal_label (stream, prefix, labelno)
FILE *stream;
const char *prefix;
unsigned long labelno;
{
char *const buf = alloca (40 + strlen (prefix));
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
ASM_OUTPUT_LABEL (stream, buf);
}
#include "gt-varasm.h"