#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 "output.h"
#include "real.h"
#include "toplev.h"
#include "obstack.h"
#include "hashtab.h"
#include "c-pragma.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
#ifdef PFE
#include "pfe/pfe.h"
#include "pfe/pfe-header.h"
#include <assert.h>
struct varasm_status;
struct pool_constant;
struct constant_descriptor;
struct rtx_const;
static void freeze_thaw_pool_constant PARAMS ((struct varasm_status *));
static void freeze_thaw_constant_descriptor PARAMS ((struct constant_descriptor **, rtx));
static void freeze_thaw_rtx_const PARAMS ((struct rtx_const *, rtx));
static int symhash PARAMS ((const char *, int));
#define SYMHASH(LABEL) symhash (LABEL, 0)
#define flag_syntax_only (flag_syntax_only || pfe_operation == PFE_DUMP)
#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;
extern struct obstack permanent_obstack;
#define obstack_chunk_alloc xmalloc
struct addr_const;
struct constant_descriptor;
struct rtx_const;
struct pool_constant;
#define MAX_RTX_HASH_TABLE 61
struct varasm_status
{
struct constant_descriptor **x_const_rtx_hash_table;
struct pool_constant **x_const_rtx_sym_hash_table;
struct pool_constant *x_first_pool, *x_last_pool;
HOST_WIDE_INT x_pool_offset;
rtx x_const_double_chain;
rtx x_const_vector_chain;
};
#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)
#define const_double_chain (cfun->varasm->x_const_double_chain)
#define const_vector_chain (cfun->varasm->x_const_vector_chain)
int const_labelno;
int var_labelno;
int size_directive_output;
tree last_assemble_variable_decl;
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 int const_hash PARAMS ((tree));
static int compare_constant PARAMS ((tree,
struct constant_descriptor *));
static const unsigned char *compare_constant_1 PARAMS ((tree, const unsigned char *));
static struct constant_descriptor *record_constant PARAMS ((tree));
static void record_constant_1 PARAMS ((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 int const_hash_rtx PARAMS ((enum machine_mode, rtx));
static int compare_constant_rtx PARAMS ((enum machine_mode, rtx,
struct constant_descriptor *));
static struct constant_descriptor *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 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));
#endif
#endif
static void mark_pool_constant PARAMS ((struct pool_constant *));
static void mark_const_hash_entry PARAMS ((void *));
static int mark_const_str_htab_1 PARAMS ((void **, void *));
static void mark_const_str_htab PARAMS ((void *));
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 void const_str_htab_del PARAMS ((void *));
static void asm_emit_uninitialised PARAMS ((tree, const char*, int, int));
static void resolve_unique_section PARAMS ((tree, int));
static enum in_section { no_section, in_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 EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
} 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 const char *in_named_name;
struct in_named_entry
{
const char *name;
unsigned int flags;
bool declared;
};
static htab_t in_named_htab;
#ifdef EXTRA_SECTION_FUNCTIONS
EXTRA_SECTION_FUNCTIONS
#endif
void
text_section ()
{
if (in_section != in_text)
{
#ifdef TEXT_SECTION
TEXT_SECTION ();
#else
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
#endif
in_section = in_text;
}
}
void
data_section ()
{
if (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);
in_section = in_data;
}
}
void
force_data_section ()
{
in_section = no_section;
data_section ();
}
void
readonly_data_section ()
{
#ifdef READONLY_DATA_SECTION
READONLY_DATA_SECTION ();
#else
text_section ();
#endif
}
int
in_text_section ()
{
return in_section == in_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 *) xmalloc (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");
}
named_section_flags (name, flags);
}
static void
resolve_unique_section (decl, reloc)
tree decl;
int reloc ATTRIBUTE_UNUSED;
{
if (DECL_SECTION_NAME (decl) == NULL_TREE
&& (flag_function_sections
|| (targetm.have_named_sections
&& DECL_ONE_ONLY (decl))))
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;
{
ASM_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);
}
#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;
{
ASM_GLOBALIZE_LABEL (file, name);
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
{
#ifdef SELECT_SECTION
SELECT_SECTION (decl, reloc, DECL_ALIGN (decl));
#else
if (DECL_READONLY_SECTION (decl, reloc))
readonly_data_section ();
else
data_section ();
#endif
}
}
void
default_exception_section ()
{
if (targetm.have_named_sections)
named_section (NULL_TREE, ".gcc_except_table", 0);
else if (flag_pic)
data_section ();
else
readonly_data_section ();
}
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));
#ifdef REDO_SECTION_INFO_P
if (REDO_SECTION_INFO_P (decl))
ENCODE_SECTION_INFO (decl);
#endif
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 (!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);
#ifdef ENCODE_SECTION_INFO
ENCODE_SECTION_INFO (decl);
#endif
}
void
make_var_volatile (var)
tree var;
{
if (GET_CODE (DECL_RTL (var)) != MEM)
abort ();
MEM_VOLATILE_P (DECL_RTL (var)) = 1;
}
void
assemble_constant_align (exp)
tree exp;
{
int align;
align = TYPE_ALIGN (TREE_TYPE (exp));
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (exp, align);
#endif
if (align > BITS_PER_UNIT)
{
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
}
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);
function_section (decl);
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
if (align_functions_log > align)
{
#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;
STRIP_NAME_ENCODING (p, fnname);
name = permalloc (strlen (p) + 1);
strcpy (name, p);
if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
first_global_object_name = name;
else
weak_global_object_name = name;
}
globalize_decl (decl);
}
#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 ())
{
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 void
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 defined ASM_EMIT_BSS
if (! DECL_COMMON (decl))
destination = asm_dest_bss;
else
#endif
destination = asm_dest_common;
}
if (destination == asm_dest_bss)
globalize_decl (decl);
resolve_unique_section (decl, 0);
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;
}
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;
STRIP_NAME_ENCODING (p, name);
xname = permalloc (strlen (p) + 1);
strcpy (xname, 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 ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
#if ! defined ASM_EMIT_BSS
&& DECL_COMMON (decl)
#endif
&& DECL_SECTION_NAME (decl) == NULL_TREE
&& ! dont_output_data)
{
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
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);
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);
variable_section (decl, reloc);
#ifdef ASM_OUTPUT_ZEROFILL
if (! DECL_COALESCED (decl))
if (flag_no_common
&& ! dont_output_data
&& (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 ())
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 PFE
if (pfe_operation == PFE_DUMP)
return;
#endif
#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_global (name)
const char *name ATTRIBUTE_UNUSED;
{
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
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;
STRIP_NAME_ENCODING (real_name, 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);
}
ASM_OUTPUT_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 ();
}
}
#if 0
void
assemble_real (d, mode, align)
REAL_VALUE_TYPE d;
enum machine_mode mode;
unsigned int align;
{
struct assemble_real_args args;
args.d = &d;
args.mode = mode;
#ifdef BIGGEST_FIELD_ALIGNMENT
if (align >= BIGGEST_FIELD_ALIGNMENT)
;
else
#endif
if (0 && align < GET_MODE_ALIGNMENT (mode))
abort ();
if (do_float_handler (assemble_real_1, (PTR) &args))
return;
internal_error ("floating point trap outputting a constant");
}
#endif
rtx
immed_double_const (i0, i1, mode)
HOST_WIDE_INT i0, i1;
enum machine_mode mode;
{
rtx r;
if (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
{
int width = GET_MODE_BITSIZE (mode);
if (width < HOST_BITS_PER_WIDE_INT
&& ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1)))
!= ((HOST_WIDE_INT) (-1) << (width - 1))))
i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0;
else if (width == HOST_BITS_PER_WIDE_INT
&& ! (i1 == ~0 && i0 < 0))
i1 = 0;
else if (width > 2 * HOST_BITS_PER_WIDE_INT)
abort ();
if (width < HOST_BITS_PER_WIDE_INT
&& (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
i0 |= ((HOST_WIDE_INT) (-1) << width);
if (width <= HOST_BITS_PER_WIDE_INT)
i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
if ((i1 == 0 && i0 >= 0)
|| (i1 == ~0 && i0 < 0))
return GEN_INT (i0);
mode = VOIDmode;
}
if (cfun != 0)
for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
&& GET_MODE (r) == mode)
return r;
r = gen_rtx_CONST_DOUBLE (mode, i0, i1);
if (current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
}
return r;
}
rtx
immed_real_const_1 (d, mode)
REAL_VALUE_TYPE d;
enum machine_mode mode;
{
union real_extract u;
rtx r;
u.d = d;
if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_IDENTICAL (dconst0, d))
return CONST0_RTX (mode);
else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
return CONST1_RTX (mode);
else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst2, d))
return CONST2_RTX (mode);
if (sizeof u == sizeof (HOST_WIDE_INT))
return immed_double_const (u.i[0], 0, mode);
if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
return immed_double_const (u.i[0], u.i[1], mode);
if (cfun != 0)
for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
if (! memcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
&& GET_MODE (r) == mode)
return r;
r = rtx_alloc (CONST_DOUBLE);
PUT_MODE (r, mode);
memcpy ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u);
if (current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
}
else
CONST_DOUBLE_CHAIN (r) = NULL_RTX;
return r;
}
rtx
immed_real_const (exp)
tree exp;
{
return immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)));
}
rtx
immed_vector_const (exp)
tree exp;
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
HOST_WIDE_INT u1;
register rtx r;
int i, count = 0;
tree t;
int bad = 0;
for (t = TREE_VECTOR_CST_ELTS (exp); t; t = TREE_CHAIN (t))
count++;
for (r = const_vector_chain; r; r = CONST_VECTOR_CHAIN (r))
{
if (GET_MODE (r) == mode && count == CONST_VECTOR_NUNITS (r))
{
bad = 0;
for ( t = TREE_VECTOR_CST_ELTS (exp), i = 0;
t;
t = TREE_CHAIN (t), i++ )
{
if (TREE_CODE (TREE_VALUE (t)) == INTEGER_CST )
u1 = TREE_INT_CST_LOW (TREE_VALUE (t));
else if (TREE_CODE (TREE_VALUE (t)) == REAL_CST )
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST
(TREE_VALUE (t)), u1);
else
abort ();
if ( u1 != INTVAL (CONST_VECTOR_ELT (r, i)))
{
bad = 1;
break;
}
}
if ( !bad )
return r;
}
}
r = rtx_alloc (CONST_VECTOR);
PUT_MODE (r, mode);
XVEC (r, 0) = rtvec_alloc (count);
for (i = 0, t = TREE_VECTOR_CST_ELTS (exp); i < count;
i++, t = TREE_CHAIN (t))
{
if (TREE_CODE (TREE_VALUE (t)) == INTEGER_CST )
CONST_VECTOR_ELT (r, i) = GEN_INT (TREE_INT_CST_LOW (TREE_VALUE (t)));
else if (TREE_CODE (TREE_VALUE (t)) == REAL_CST )
{
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST (TREE_VALUE (t)), u1);
CONST_VECTOR_ELT (r, i) = GEN_INT (u1);
}
}
if (current_function_decl != 0)
{
CONST_VECTOR_CHAIN (r) = const_vector_chain;
const_vector_chain = r;
}
else
CONST_VECTOR_CHAIN (r) = NULL_RTX;
return r;
}
void
clear_const_double_mem ()
{
rtx r, next;
for (r = const_double_chain; r; r = next)
{
next = CONST_DOUBLE_CHAIN (r);
CONST_DOUBLE_CHAIN (r) = 0;
}
const_double_chain = 0;
for (r = const_vector_chain; r; r = next)
{
next = CONST_VECTOR_CHAIN (r);
CONST_VECTOR_CHAIN (r) = 0;
}
const_vector_chain = 0;
}
struct addr_const
{
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
{
ENUM_BITFIELD(kind) kind : 16;
ENUM_BITFIELD(machine_mode) mode : 16;
union {
union real_extract du;
struct addr_const addr;
struct {HOST_WIDE_INT high, low;} di;
struct {HOST_WIDE_INT veclo, vechi; } vec[16];
} un;
};
struct constant_descriptor
{
struct constant_descriptor *next;
const char *label;
rtx rtl;
union
{
unsigned char contents[1];
#ifdef HAVE_LONG_DOUBLE
long double d;
#else
double d;
#endif
} u;
};
#define HASHBITS 30
#define MAX_HASH_TABLE 1009
static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
#define STRHASH(x) ((hashval_t) ((long) (x) >> 3))
struct deferred_string
{
const char *label;
tree exp;
int labelno;
};
static htab_t const_str_htab;
static void
mark_const_hash_entry (ptr)
void *ptr;
{
struct constant_descriptor *desc = * (struct constant_descriptor **) ptr;
while (desc)
{
ggc_mark_rtx (desc->rtl);
desc = desc->next;
}
}
static int
mark_const_str_htab_1 (x, data)
void **x;
void *data ATTRIBUTE_UNUSED;
{
ggc_mark_tree (((struct deferred_string *) *x)->exp);
return 1;
}
static void
mark_const_str_htab (htab)
void *htab;
{
htab_traverse (*((htab_t *) htab), mark_const_str_htab_1, NULL);
}
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 void
const_str_htab_del (dfsp)
void *dfsp;
{
free (dfsp);
}
static int
const_hash (exp)
tree exp;
{
const char *p;
int len, hi, 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:
p = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
break;
case STRING_CST:
p = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
break;
case COMPLEX_CST:
return (const_hash (TREE_REALPART (exp)) * 5
+ const_hash (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;
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
hi = ((unsigned long) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
% MAX_HASH_TABLE;
else
hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
& ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_VALUE (link))
hi
= (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
return hi;
}
case ADDR_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 ();
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
}
return hi;
case PLUS_EXPR:
case MINUS_EXPR:
return (const_hash (TREE_OPERAND (exp, 0)) * 9
+ const_hash (TREE_OPERAND (exp, 1)));
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
default:
return (int) code % MAX_HASH_TABLE;
}
hi = len;
for (i = 0; i < len; i++)
hi = ((hi * 613) + (unsigned) (p[i]));
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
return hi;
}
static int
compare_constant (exp, desc)
tree exp;
struct constant_descriptor *desc;
{
return 0 != compare_constant_1 (exp, desc->u.contents);
}
static const unsigned char *
compare_constant_1 (exp, p)
tree exp;
const unsigned char *p;
{
const unsigned char *strp;
int len;
enum tree_code code = TREE_CODE (exp);
if (code != (enum tree_code) *p++)
return 0;
switch (code)
{
case INTEGER_CST:
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
strp = (unsigned char *) &TREE_INT_CST (exp);
len = sizeof TREE_INT_CST (exp);
break;
case REAL_CST:
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
strp = (unsigned char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
break;
case STRING_CST:
if (flag_writable_strings)
return 0;
if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
return 0;
strp = (const unsigned char *) TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
if (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
return 0;
p += sizeof TREE_STRING_LENGTH (exp);
break;
case COMPLEX_CST:
p = compare_constant_1 (TREE_REALPART (exp), p);
if (p == 0)
return 0;
return compare_constant_1 (TREE_IMAGPART (exp), p);
case VECTOR_CST:
{
tree t;
for ( t = TREE_VECTOR_CST_ELTS (exp); t; t = TREE_CHAIN (t))
{
p = compare_constant_1 (TREE_VALUE (t), p);
if ( p==0 )
return 0;
}
return p;
}
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
unsigned char *tmp = (unsigned char *) alloca (len);
get_set_constructor_bytes (exp, tmp, len);
strp = (unsigned char *) tmp;
if (memcmp ((char *) &xlen, p, sizeof xlen))
return 0;
p += sizeof xlen;
break;
}
else
{
tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
int have_purpose = 0;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link))
have_purpose = 1;
if (memcmp ((char *) &length, p, sizeof length))
return 0;
p += sizeof length;
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
type = TREE_TYPE (exp);
else
type = 0;
if (memcmp ((char *) &type, p, sizeof type))
return 0;
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
if (memcmp ((char *) &mode, p, sizeof mode))
return 0;
p += sizeof mode;
}
p += sizeof type;
if (memcmp ((char *) &have_purpose, p, sizeof have_purpose))
return 0;
p += sizeof have_purpose;
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
if (memcmp ((char *) &size, p, sizeof size))
return 0;
p += sizeof size;
}
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
{
if (TREE_VALUE (link))
{
if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
return 0;
}
else
{
tree zero = 0;
if (memcmp ((char *) &zero, p, sizeof zero))
return 0;
p += sizeof zero;
}
if (TREE_PURPOSE (link)
&& TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
{
if (memcmp ((char *) &TREE_PURPOSE (link), p,
sizeof TREE_PURPOSE (link)))
return 0;
p += sizeof TREE_PURPOSE (link);
}
else if (TREE_PURPOSE (link))
{
if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0)
return 0;
}
else if (have_purpose)
{
int zero = 0;
if (memcmp ((char *) &zero, p, sizeof zero))
return 0;
p += sizeof zero;
}
}
return p;
}
case ADDR_EXPR:
{
struct addr_const value;
decode_addr_const (exp, &value);
strp = (unsigned char *) &value.offset;
len = sizeof value.offset;
while (--len >= 0)
if (*p++ != *strp++)
return 0;
strp = (const unsigned char *) XSTR (value.base, 0);
len = strlen ((const char *) strp) + 1;
}
break;
case PLUS_EXPR:
case MINUS_EXPR:
case RANGE_EXPR:
p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
if (p == 0)
return 0;
return compare_constant_1 (TREE_OPERAND (exp, 1), p);
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return compare_constant_1 (TREE_OPERAND (exp, 0), p);
default:
{
tree new = (*lang_hooks.expand_constant) (exp);
if (new != exp)
return compare_constant_1 (new, p);
else
return 0;
}
}
while (--len >= 0)
if (*p++ != *strp++)
return 0;
return p;
}
static struct constant_descriptor *
record_constant (exp)
tree exp;
{
struct constant_descriptor *next = 0;
char *label = 0;
rtx rtl = 0;
int pad;
obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
obstack_grow (&permanent_obstack, (char *) &rtl, sizeof rtl);
pad = (offsetof (struct constant_descriptor, u)
- offsetof(struct constant_descriptor, rtl)
- sizeof(next->rtl));
if (pad > 0)
obstack_blank (&permanent_obstack, pad);
record_constant_1 (exp);
return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
}
static void
record_constant_1 (exp)
tree exp;
{
const unsigned char *strp;
int len;
enum tree_code code = TREE_CODE (exp);
obstack_1grow (&permanent_obstack, (unsigned int) code);
switch (code)
{
case INTEGER_CST:
obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
strp = (unsigned char *) &TREE_INT_CST (exp);
len = sizeof TREE_INT_CST (exp);
break;
case REAL_CST:
obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
strp = (unsigned char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
break;
case STRING_CST:
if (flag_writable_strings)
return;
obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
strp = (const unsigned char *) TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
sizeof TREE_STRING_LENGTH (exp));
break;
case COMPLEX_CST:
record_constant_1 (TREE_REALPART (exp));
record_constant_1 (TREE_IMAGPART (exp));
return;
case VECTOR_CST:
{
tree t;
for (t = TREE_VECTOR_CST_ELTS (exp); t; t = TREE_CHAIN (t))
record_constant_1 (TREE_VALUE (t));
return;
}
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
int nbytes = int_size_in_bytes (TREE_TYPE (exp));
obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
obstack_blank (&permanent_obstack, nbytes);
get_set_constructor_bytes
(exp, (unsigned char *) permanent_obstack.next_free-nbytes,
nbytes);
return;
}
else
{
tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
tree type;
int have_purpose = 0;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link))
have_purpose = 1;
obstack_grow (&permanent_obstack, (char *) &length, sizeof length);
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
type = TREE_TYPE (exp);
else
type = 0;
obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
obstack_grow (&permanent_obstack, &mode, sizeof mode);
obstack_grow (&permanent_obstack, (char *) &have_purpose,
sizeof have_purpose);
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
}
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
{
if (TREE_VALUE (link))
record_constant_1 (TREE_VALUE (link));
else
{
tree zero = 0;
obstack_grow (&permanent_obstack,
(char *) &zero, sizeof zero);
}
if (TREE_PURPOSE (link)
&& TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
obstack_grow (&permanent_obstack,
(char *) &TREE_PURPOSE (link),
sizeof TREE_PURPOSE (link));
else if (TREE_PURPOSE (link))
record_constant_1 (TREE_PURPOSE (link));
else if (have_purpose)
{
int zero = 0;
obstack_grow (&permanent_obstack,
(char *) &zero, sizeof zero);
}
}
}
return;
case ADDR_EXPR:
{
struct addr_const value;
decode_addr_const (exp, &value);
obstack_grow (&permanent_obstack,
(char *) &value.offset, sizeof value.offset);
switch (GET_CODE (value.base))
{
case SYMBOL_REF:
obstack_grow (&permanent_obstack, XSTR (value.base, 0),
strlen (XSTR (value.base, 0)) + 1);
break;
case LABEL_REF:
obstack_grow (&permanent_obstack, &XEXP (value.base, 0),
sizeof (rtx));
break;
default:
abort ();
}
}
return;
case PLUS_EXPR:
case MINUS_EXPR:
case RANGE_EXPR:
record_constant_1 (TREE_OPERAND (exp, 0));
record_constant_1 (TREE_OPERAND (exp, 1));
return;
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
record_constant_1 (TREE_OPERAND (exp, 0));
return;
default:
{
tree new = (*lang_hooks.expand_constant) (exp);
if (new != exp)
record_constant_1 (new);
return;
}
}
obstack_grow (&permanent_obstack, strp, len);
}
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:
abort ();
}
}
rtx
output_constant_def (exp, defer)
tree exp;
int defer;
{
int hash;
struct constant_descriptor *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) % MAX_HASH_TABLE;
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
break;
if (desc == 0)
{
labelno = const_labelno++;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
desc = record_constant (exp);
desc->next = const_hash_table[hash];
desc->label = GGC_STRDUP (label);
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;
#ifdef ENCODE_SECTION_INFO
if (! found)
{
if (TREE_CODE (exp) != INTEGER_CST)
ENCODE_SECTION_INFO (exp);
desc->rtl = rtl;
desc->label = XSTR (XEXP (desc->rtl, 0), 0);
}
#endif
#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 = copy_constant (exp);
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 *)
xmalloc (sizeof (struct deferred_string));
p->exp = copy_constant (exp);
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
{
#ifdef SELECT_SECTION
SELECT_SECTION (exp, reloc, align);
#else
if (((TREE_CODE (exp) == STRING_CST) && flag_writable_strings)
|| (flag_pic && reloc))
data_section ();
else
readonly_data_section ();
#endif
}
if (align > BITS_PER_UNIT)
{
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
ASM_OUTPUT_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 pool_constant
{
struct constant_descriptor *desc;
struct pool_constant *next, *next_sym;
rtx constant;
enum machine_mode mode;
int labelno;
unsigned int align;
HOST_WIDE_INT offset;
int mark;
};
#ifndef PFE
#define SYMHASH(LABEL) \
((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE)
#endif
void
init_varasm_status (f)
struct function *f;
{
struct varasm_status *p;
p = (struct varasm_status *) PFE_MALLOC (sizeof (struct varasm_status),
PFE_ALLOC_VARASM_STATUS);
f->varasm = p;
p->x_const_rtx_hash_table
= ((struct constant_descriptor **)
PFE_CALLOC (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *),
PFE_ALLOC_CONSTANT_DESCRIPTOR));
p->x_const_rtx_sym_hash_table
= ((struct pool_constant **)
PFE_CALLOC (MAX_RTX_HASH_TABLE, sizeof (struct pool_constant *),
PFE_ALLOC_RTX_SYM_HASH_TABLE));
p->x_first_pool = p->x_last_pool = 0;
p->x_pool_offset = 0;
p->x_const_double_chain = 0;
p->x_const_vector_chain = 0;
}
static void
mark_pool_constant (pc)
struct pool_constant *pc;
{
while (pc)
{
ggc_mark (pc);
ggc_mark_rtx (pc->constant);
ggc_mark_rtx (pc->desc->rtl);
pc = pc->next;
}
}
void
mark_varasm_status (p)
struct varasm_status *p;
{
if (p == NULL)
return;
mark_pool_constant (p->x_first_pool);
ggc_mark_rtx (p->x_const_double_chain);
ggc_mark_rtx (p->x_const_vector_chain);
}
void
free_varasm_status (f)
struct function *f;
{
struct varasm_status *p;
int i;
p = f->varasm;
for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
{
struct constant_descriptor *cd;
cd = p->x_const_rtx_hash_table[i];
while (cd)
{
struct constant_descriptor *next = cd->next;
PFE_FREE (cd);
cd = next;
}
}
PFE_FREE (p->x_const_rtx_hash_table);
PFE_FREE (p->x_const_rtx_sym_hash_table);
PFE_FREE (p);
f->varasm = NULL;
}
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)
{
value->mode = GET_MODE (x);
memcpy ((char *) &value->un.du,
(char *) &CONST_DOUBLE_LOW (x), sizeof value->un.du);
}
else
{
value->un.di.low = CONST_DOUBLE_LOW (x);
value->un.di.high = CONST_DOUBLE_HIGH (x);
}
break;
case CONST_VECTOR:
{
int units, i;
rtx elt;
units = CONST_VECTOR_NUNITS (x);
value->kind = RTX_VECTOR;
value->mode = mode;
for (i = 0; i < units; ++i)
{
elt = CONST_VECTOR_ELT (x, i);
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
{
value->un.vec[i].veclo = (HOST_WIDE_INT) INTVAL (elt);
value->un.vec[i].vechi = 0;
}
else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
{
value->un.vec[i].veclo = (HOST_WIDE_INT) CONST_DOUBLE_LOW (elt);
value->un.vec[i].vechi = (HOST_WIDE_INT) CONST_DOUBLE_HIGH (elt);
}
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_DOUBLE && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
case SYMBOL_REF:
value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
break;
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_DOUBLE
&& 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;
}
#ifndef PFE
static int
const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
int hi;
size_t i;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
hi = 0;
for (i = 0; i < sizeof value / sizeof (int); i++)
hi += ((int *) &value)[i];
hi &= (1 << HASHBITS) - 1;
hi %= MAX_RTX_HASH_TABLE;
return hi;
}
#endif
static int
compare_constant_rtx (mode, x, desc)
enum machine_mode mode;
rtx x;
struct constant_descriptor *desc;
{
int *p = (int *) desc->u.contents;
int *strp;
int len;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
strp = (int *) &value;
len = sizeof value / sizeof (int);
while (--len >= 0)
if (*p++ != *strp++)
return 0;
return 1;
}
static struct constant_descriptor *
record_constant_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
struct constant_descriptor *ptr;
ptr = ((struct constant_descriptor *)
PFE_CALLOC (1, (offsetof (struct constant_descriptor, u)
+ sizeof (struct rtx_const)),
PFE_ALLOC_CONSTANT_DESCRIPTOR));
decode_rtx_const (mode, x, (struct rtx_const *) ptr->u.contents);
return ptr;
}
rtx
mem_for_const_double (x)
rtx x;
{
enum machine_mode mode = GET_MODE (x);
struct constant_descriptor *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 *desc;
char label[256];
rtx def;
struct pool_constant *pool;
unsigned int align;
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 (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),
PFE_ALLOC_GGC_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;
#if 0
desc->label = found = GGC_STRDUP (label);
hash = SYMHASH (found);
pool->label = found;
pool->next_sym = const_rtx_sym_hash_table[hash];
const_rtx_sym_hash_table[hash] = pool;
}
def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
#ifdef PFE
if (PFE_FREEZING)
XSTR (XEXP (def, 0), 0) = found;
#endif
#endif
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, 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;
union real_extract u;
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;
}
#ifdef SELECT_RTX_SECTION
SELECT_RTX_SECTION (pool->mode, x, pool->align);
#else
readonly_data_section ();
#endif
#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);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
switch (GET_MODE_CLASS (pool->mode))
{
case MODE_FLOAT:
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
assemble_real (u.d, 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);
memcpy ((char *) &u,
(char *) &CONST_DOUBLE_LOW (elt),
sizeof u);
assemble_real (u.d, 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 ();
}
#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;
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 (insn = current_function_epilogue_delay_list;
insn;
insn = XEXP (insn, 1))
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':
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;
tree tem;
exp = (*lang_hooks.expand_constant) (exp);
switch (TREE_CODE (exp))
{
case ADDR_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:
case MINUS_EXPR:
reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
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 tree weak_decls;
void
declare_weak (decl)
tree decl;
{
if (! TREE_PUBLIC (decl))
error_with_decl (decl, "weak declaration of `%s' must be public");
else if (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");
DECL_WEAK (decl) = 1;
}
void
weak_finish ()
{
tree t;
for (t = weak_decls; t ; t = TREE_CHAIN (t))
{
tree decl = TREE_VALUE (t);
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
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) ; p = &TREE_CHAIN (t))
if (TREE_VALUE (t) == decl)
{
*p = TREE_CHAIN (t);
break;
}
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
ASM_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);
#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
TREE_ASM_WRITTEN (decl) = 1;
#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
TREE_ASM_WRITTEN (decl) = 1;
#else
warning ("alias definitions not supported in this configuration; ignored");
#endif
#endif
}
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 (128, const_str_htab_hash, const_str_htab_eq,
const_str_htab_del);
in_named_htab = htab_create (31, in_named_entry_hash,
in_named_entry_eq, NULL);
ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
mark_const_hash_entry);
ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
mark_const_str_htab);
ggc_add_tree_root (&weak_decls, 1);
const_alias_set = new_alias_set ();
}
unsigned int
default_section_type_flags (decl, name, reloc)
tree decl;
const char *name;
int reloc;
{
unsigned int flags;
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
flags = SECTION_CODE;
else if (decl && DECL_READONLY_SECTION (decl, reloc))
flags = 0;
else
flags = SECTION_WRITE;
if (decl && DECL_ONE_ONLY (decl))
flags |= SECTION_LINKONCE;
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)
flags |= SECTION_BSS;
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;
const char *type;
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';
*f = '\0';
if (flags & SECTION_BSS)
type = "nobits";
else
type = "progbits";
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s,%d\n",
name, flagchars, type, flags & SECTION_ENTSIZE);
else
fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
name, flagchars, type);
}
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);
}
#ifdef PFE
void
pfe_freeze_thaw_varasm_status (vp)
struct varasm_status **vp;
{
struct varasm_status *v = PFE_FREEZE_THAW_PTR (vp);
if (!v)
return;
freeze_thaw_pool_constant (v);
PFE_FREEZE_THAW_RTX (v->x_const_double_chain);
PFE_FREEZE_THAW_RTX (v->x_const_vector_chain);
}
static void
freeze_thaw_pool_constant (v)
struct varasm_status *v;
{
int i;
struct pool_constant **x_const_rtx_sym_hash_table, *pool;
struct constant_descriptor **x_const_rtx_hash_table;
pool = PFE_FREEZE_THAW_PTR (&v->x_first_pool);
pfe_freeze_thaw_ptr_fp (&v->x_last_pool);
x_const_rtx_sym_hash_table
= PFE_FREEZE_THAW_PTR (&v->x_const_rtx_sym_hash_table);
if (!x_const_rtx_sym_hash_table)
return;
x_const_rtx_hash_table = PFE_FREEZE_THAW_PTR (&v->x_const_rtx_hash_table);
for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
{
pfe_freeze_thaw_ptr_fp (&x_const_rtx_hash_table[i]);
pfe_freeze_thaw_ptr_fp (&x_const_rtx_sym_hash_table[i]);
}
while (pool)
{
if (PFE_FREEZING)
{
freeze_thaw_constant_descriptor (&pool->desc, pool->constant);
pfe_freeze_ptr (&pool->next_sym);
PFE_FREEZE_THAW_RTX (pool->constant);
}
else
{
PFE_FREEZE_THAW_RTX (pool->constant);
pfe_thaw_ptr (&pool->next_sym);
freeze_thaw_constant_descriptor (&pool->desc, pool->constant);
}
pool = PFE_FREEZE_THAW_PTR (&pool->next);
}
}
static void
freeze_thaw_constant_descriptor (descp, x)
struct constant_descriptor **descp;
rtx x;
{
struct constant_descriptor *desc = PFE_FREEZE_THAW_PTR (descp);
if (!desc)
return;
PFE_FREEZE_THAW_PTR (&desc->next);
pfe_freeze_thaw_ptr_fp (&desc->label);
PFE_FREEZE_THAW_RTX (desc->rtl);
freeze_thaw_rtx_const ((struct rtx_const *)desc->u.contents, x);
}
static void
freeze_thaw_rtx_const (value, x)
struct rtx_const *value;
rtx x;
{
switch (GET_CODE (x))
{
case CONST_DOUBLE:
break;
case CONST_VECTOR:
case CONST_INT:
break;
case SYMBOL_REF:
if (value->kind == RTX_INT && value->un.addr.base != 0)
pfe_freeze_thaw_ptr_fp (&value->un.addr.base);
else
PFE_FREEZE_THAW_RTX (value->un.addr.base);
break;
case LABEL_REF:
case PC:
case CONST:
PFE_FREEZE_THAW_RTX (value->un.addr.base);
break;
default:
abort ();
}
}
static int
symhash (label, add_to_total)
const char *label;
int add_to_total;
{
int len = 0, r = 0;
#define HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
while (*label)
{
++len;
r = HASHSTEP (r, *(char *)label++);
}
r += len + add_to_total;
r &= (1 << HASHBITS) - 1;
r %= MAX_RTX_HASH_TABLE;
return r;
}
static int
const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
size_t i;
int hi;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
switch (GET_CODE (x))
{
case CONST_VECTOR:
case CONST_INT:
case CONST_DOUBLE:
hi = 0;
for (i = 0; i < sizeof value / sizeof (int); i++)
hi += ((int *) &value)[i];
break;
case SYMBOL_REF:
if (value.kind == RTX_INT && value.un.addr.base != 0)
return SYMHASH ((const char *)value.un.addr.base);
else
return SYMHASH (XSTR (value.un.addr.base, 0));
case LABEL_REF:
hi = (int)value.kind + (int)value.mode;
if (value.kind == RTX_INT && value.un.addr.base != 0)
{
assert (GET_CODE(value.un.addr.base) == CODE_LABEL);
hi += CODE_LABEL_NUMBER (value.un.addr.base);
}
else
{
assert (GET_CODE(XEXP (value.un.addr.base, 0)) == CODE_LABEL);
hi += CODE_LABEL_NUMBER (XEXP (value.un.addr.base, 0));
}
break;
case PC:
hi = (int)value.kind + (int)value.mode;
break;
case CONST:
hi = (int)value.kind + (int)value.mode + value.un.addr.offset;
if (GET_CODE (value.un.addr.base) == SYMBOL_REF)
return symhash ((const char *)XSTR (value.un.addr.base, 0), hi);
break;
default:
hi = (int)value.kind + (int)value.mode;
break;
}
hi &= (1 << HASHBITS) - 1;
hi %= MAX_RTX_HASH_TABLE;
return hi;
}
DEFINE_CHECK_STRUCT_FUNCTION (pool_constant)
DEFINE_CHECK_STRUCT_FUNCTION (varasm_status)
DEFINE_CHECK_STRUCT_FUNCTION (constant_descriptor)
DEFINE_CHECK_STRUCT_FUNCTION (rtx_const)
#endif