#include "config.h"
#include "system.h"
#include <setjmp.h>
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "expr.h"
#include "output.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "defaults.h"
#include "real.h"
#include "toplev.h"
#include "dbxout.h"
#include "sdbout.h"
#include "obstack.h"
#include "c-pragma.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
#endif
#ifndef ASM_STABS_OP
#define ASM_STABS_OP ".stabs"
#endif
#ifdef NO_DOLLAR_IN_LABEL
#ifdef NO_DOT_IN_LABEL
#define CHKR_PREFIX "chkr_prefix_"
#else
#define CHKR_PREFIX "chkr."
#endif
#else
#define CHKR_PREFIX "chkr$"
#endif
#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
extern FILE *asm_out_file;
char *first_global_object_name;
#if defined (NEXT_PDO)
char *second_global_object_name;
#endif
char *weak_global_object_name;
extern struct obstack *current_obstack;
extern struct obstack *saveable_obstack;
extern struct obstack *rtl_obstack;
extern struct obstack permanent_obstack;
#define obstack_chunk_alloc xmalloc
int const_labelno;
int var_labelno;
int size_directive_output;
tree last_assemble_variable_decl;
static int function_defined;
struct addr_const;
struct constant_descriptor;
struct rtx_const;
struct pool_constant;
static const char *strip_reg_name PROTO((const char *));
static int contains_pointers_p PROTO((tree));
static void decode_addr_const PROTO((tree, struct addr_const *));
static int const_hash PROTO((tree));
static int compare_constant PROTO((tree,
struct constant_descriptor *));
static char *compare_constant_1 PROTO((tree, char *));
static struct constant_descriptor *record_constant PROTO((tree));
static void record_constant_1 PROTO((tree));
static tree copy_constant PROTO((tree));
static void output_constant_def_contents PROTO((tree, int, int));
static void decode_rtx_const PROTO((enum machine_mode, rtx,
struct rtx_const *));
static int const_hash_rtx PROTO((enum machine_mode, rtx));
static int compare_constant_rtx PROTO((enum machine_mode, rtx,
struct constant_descriptor *));
static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
rtx));
static struct pool_constant *find_pool_constant PROTO((rtx));
static void mark_constant_pool PROTO((void));
static void mark_constants PROTO((rtx));
static int output_addressed_constants PROTO((tree));
static void output_after_function_constants PROTO((void));
static void output_constructor PROTO((tree, int));
static void remove_from_pending_weak_list PROTO ((char *));
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss PROTO((FILE *, tree, char *, int, int));
#endif
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_ALIGNED_BSS
static void asm_output_aligned_bss PROTO((FILE *, tree, char *, int, int));
#endif
#endif
static enum in_section { no_section, in_text, in_data, in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
#ifdef EH_FRAME_SECTION_ASM_OP
, in_eh_frame
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
} in_section = no_section;
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
static char *in_named_name;
#ifdef EXTRA_SECTION_FUNCTIONS
EXTRA_SECTION_FUNCTIONS
#endif
void
text_section ()
{
if (in_section != in_text)
{
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
in_section = in_text;
#ifdef NEXT_SEMANTICS
try_section_alias ();
#endif
}
}
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;
#ifdef NEXT_SEMANTICS
try_section_alias ();
#endif
}
}
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;
}
void
named_section (decl, name, reloc)
tree decl;
const char *name;
int reloc ATTRIBUTE_UNUSED;
{
if (decl != NULL_TREE
&& TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
abort ();
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
if (in_section != in_named || strcmp (name, in_named_name))
{
#ifdef ASM_OUTPUT_SECTION_NAME
ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name, reloc);
#else
abort ();
#endif
in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
strcpy (in_named_name, name);
in_section = in_named;
}
}
#ifdef ASM_OUTPUT_SECTION_NAME
#ifndef UNIQUE_SECTION
#define UNIQUE_SECTION(DECL,RELOC) \
do { \
int len; \
char *name, *string; \
\
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
\
STRIP_NAME_ENCODING (name, name); \
\
len = strlen (name) + 1; \
string = alloca (len + 1); \
sprintf (string, ".%s", name); \
\
DECL_SECTION_NAME (DECL) = build_string (len, string); \
} while (0)
#endif
#ifndef UNIQUE_SECTION_P
#define UNIQUE_SECTION_P(DECL) 0
#endif
#endif
#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;
char *name;
int size, 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;
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
#ifdef EH_FRAME_SECTION_ASM_OP
void
eh_frame_section ()
{
if (in_section != in_eh_frame)
{
fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
in_section = in_eh_frame;
}
}
#endif
void
function_section (decl)
tree decl;
{
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
named_section (decl, (char *) 0, 0);
else
#ifdef HAVE_COALESCED_SYMBOLS
if (DECL_COALESCED (decl))
coalesced_text_section ();
else
#endif
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);
#else
if (DECL_READONLY_SECTION (decl, reloc))
readonly_data_section ();
else
data_section ();
#endif
}
}
void
exception_section ()
{
#if defined (EXCEPTION_SECTION)
EXCEPTION_SECTION ();
#else
#ifdef ASM_OUTPUT_SECTION_NAME
named_section (NULL_TREE, ".gcc_except_table", 0);
#else
if (flag_pic)
data_section ();
else
readonly_data_section ();
#endif
#endif
}
void
make_function_rtl (decl)
tree decl;
{
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *new_name = name;
if (decl_function_context (decl) != 0
&& DECL_INITIAL (decl) != 0
&& DECL_RTL (decl) == 0)
{
char *label;
name = IDENTIFIER_POINTER (DECL_NAME (decl));
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
name = obstack_copy0 (saveable_obstack, label, strlen (label));
var_labelno++;
}
else
{
if (flag_prefix_function_name)
{
new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1);
strcpy (new_name, CHKR_PREFIX);
strcpy (new_name + CHKR_PREFIX_SIZE, name);
name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name));
}
}
if (DECL_RTL (decl) == 0)
{
DECL_RTL (decl)
= gen_rtx_MEM (DECL_MODE (decl),
gen_rtx_SYMBOL_REF (Pmode, name));
#ifdef ENCODE_SECTION_INFO
ENCODE_SECTION_INFO (decl);
#endif
}
else
{
#ifdef REDO_SECTION_INFO_P
if (REDO_SECTION_INFO_P (decl))
ENCODE_SECTION_INFO (decl);
#endif
}
function_defined = 1;
}
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 (! (asmspec[i] >= '0' && asmspec[i] <= '9'))
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 struct { const char *name; int number; } table[]
= ADDITIONAL_REGISTER_NAMES;
for (i = 0; i < (int)(sizeof (table) / sizeof (table[0])); 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, top_level)
tree decl;
const char *asmspec;
int top_level;
{
register char *name = 0;
int reg_number;
reg_number = decode_reg_name (asmspec);
if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
if (reg_number == -2)
{
name = (char *) obstack_alloc (saveable_obstack,
strlen (asmspec) + 2);
name[0] = '*';
strcpy (&name[1], asmspec);
}
if (DECL_RTL (decl) == 0)
{
if (TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl) && reg_number == -1)
error_with_decl (decl,
"register name not specified for `%s'");
else if (TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl) && reg_number < 0)
error_with_decl (decl,
"invalid register name for `%s'");
else if ((reg_number >= 0 || reg_number == -3)
&& (TREE_CODE (decl) == FUNCTION_DECL
&& ! DECL_REGISTER (decl)))
error_with_decl (decl,
"register name given for non-register variable `%s'");
else if (TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl)
&& TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
error_with_decl (decl,
"data type of `%s' isn't suitable for a register");
else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)
&& ! HARD_REGNO_MODE_OK (reg_number,
TYPE_MODE (TREE_TYPE (decl))))
error_with_decl (decl,
"register number for `%s' isn't suitable for data type");
else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
int nregs;
if (DECL_INITIAL (decl) != 0 && top_level)
{
DECL_INITIAL (decl) = 0;
error ("global register variable has initial value");
}
if (fixed_regs[reg_number] == 0
&& function_defined && top_level)
error ("global register variable follows a function definition");
if (TREE_THIS_VOLATILE (decl))
warning ("volatile register variables don't work as you might wish");
DECL_RTL (decl)
= gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
if (top_level)
{
nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
while (nregs > 0)
#ifdef MACHO_PIC
global_regs[reg_number + --nregs] = 1;
init_reg_sets_1 ();
#else
globalize_reg (reg_number + --nregs);
#endif
}
}
else 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 (DECL_RTL (decl) == 0)
{
if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
{
char *label;
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
name = obstack_copy0 (saveable_obstack, label, strlen (label));
var_labelno++;
}
if (name == 0)
abort ();
if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
{
char *new_name;
new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE
+ 1);
strcpy (new_name, CHKR_PREFIX);
strcpy (new_name + CHKR_PREFIX_SIZE, name);
name = obstack_copy0 (saveable_obstack,
new_name, strlen (new_name));
}
DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
gen_rtx_SYMBOL_REF (Pmode, name));
MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
&& TREE_PUBLIC (decl))
TREE_SIDE_EFFECTS (decl) = 1;
else if (flag_volatile_static && TREE_CODE (decl) == VAR_DECL
&& (TREE_PUBLIC (decl) || TREE_STATIC (decl)))
TREE_SIDE_EFFECTS (decl) = 1;
if (TREE_SIDE_EFFECTS (decl))
MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
if (TREE_READONLY (decl))
RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
AGGREGATE_TYPE_P (TREE_TYPE (decl)));
#ifdef ENCODE_SECTION_INFO
ENCODE_SECTION_INFO (decl);
#endif
}
}
else
{
if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
{
rtx rtl = DECL_RTL (decl);
PUT_MODE (rtl, DECL_MODE (decl));
}
#ifdef REDO_SECTION_INFO_P
if (REDO_SECTION_INFO_P (decl))
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));
}
#if 0
#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))
#ifndef ASM_OUTPUT_CONSTRUCTOR
#define ASM_OUTPUT_CONSTRUCTOR(file, name)
#endif
#ifndef ASM_OUTPUT_DESTRUCTOR
#define ASM_OUTPUT_DESTRUCTOR(file, name)
#endif
#endif
#endif
void
assemble_destructor (name)
char *name;
{
#ifdef ASM_OUTPUT_DESTRUCTOR
ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
#else
if (flag_gnu_linker)
{
fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
#endif
}
void
assemble_constructor (name)
char *name;
{
#ifdef ASM_OUTPUT_CONSTRUCTOR
ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
#else
if (flag_gnu_linker)
{
fprintf (asm_out_file, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
#endif
}
void
assemble_gc_entry (name)
char *name;
{
#ifdef ASM_OUTPUT_GC_ENTRY
ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
#else
if (flag_gnu_linker)
{
fprintf (asm_out_file, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
#endif
}
#ifndef CONSTANT_POOL_BEFORE_FUNCTION
#define CONSTANT_POOL_BEFORE_FUNCTION 1
#endif
void
assemble_start_function (decl, fnname)
tree decl;
char *fnname;
{
int align;
#ifdef HAVE_COALESCED_SYMBOLS
int original_write_symbols = write_symbols;
if (write_symbols == DBX_DEBUG && DECL_COALESCED (decl))
write_symbols = NO_DEBUG;
#endif
app_disable ();
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
#ifdef ASM_OUTPUT_SECTION_NAME
if ((flag_function_sections
&& DECL_SECTION_NAME (decl) == NULL_TREE)
|| UNIQUE_SECTION_P (decl))
UNIQUE_SECTION (decl, 0);
#endif
function_section (decl);
#ifdef MACHOPIC_DEFINE_DECL
#ifdef HAVE_COALESCED_SYMBOLS
if (DECL_COALESCED (decl))
{
if (DECL_SECTION_NAME (decl) == NULL_TREE)
coalesced_text_section ();
}
else
#endif
MACHOPIC_DEFINE_DECL (decl, fnname);
#endif
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_mark_begin_function ();
#endif
#ifdef DBX_DEBUGGING_INFO
if (write_symbols == DBX_DEBUG)
dbxout_begin_function (decl);
#endif
if (TREE_PUBLIC (decl)
#ifdef HAVE_COALESCED_SYMBOLS
|| DECL_COALESCED (decl)
#endif
)
{
if (! first_global_object_name)
{
char *p;
char **name;
if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
name = &first_global_object_name;
else
name = &weak_global_object_name;
STRIP_NAME_ENCODING (p, fnname);
*name = permalloc (strlen (p) + 1);
strcpy (*name, p);
}
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
{
ASM_WEAKEN_LABEL (asm_out_file, fnname);
remove_from_pending_weak_list
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
else
#endif
#ifdef ASM_PRIVATE_EXTERNIZE_LABEL
if (DECL_PRIVATE_EXTERN (decl))
ASM_PRIVATE_EXTERNIZE_LABEL (asm_out_file, fnname);
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
}
#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
#ifdef HAVE_COALESCED_SYMBOLS
if (original_write_symbols != NO_DEBUG)
{
write_symbols = original_write_symbols;
dbxout_begin_function (decl);
}
#endif
}
void
assemble_end_function (decl, fnname)
tree decl;
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 - 20; i += 20)
{
#ifdef ASM_BYTE_OP
fprintf (asm_out_file,
"%s 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
#else
fprintf (asm_out_file,
"\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
#endif
}
if (i < size)
{
#ifdef ASM_BYTE_OP
fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);
#else
fprintf (asm_out_file, "\tbyte 0");
#endif
i++;
for (; i < size; i++)
fprintf (asm_out_file, ",0");
fprintf (asm_out_file, "\n");
}
}
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;
}
}
void
assemble_variable (decl, top_level, at_end, dont_output_data)
tree decl;
int top_level ATTRIBUTE_UNUSED;
int at_end;
int dont_output_data;
{
register char *name;
unsigned int align;
tree size_tree;
int reloc = 0;
enum in_section saved_in_section;
#ifdef HAVE_COALESCED_SYMBOLS
int postpone_dbx = 0;
#endif
last_assemble_variable_decl = 0;
if (GET_CODE (DECL_RTL (decl)) == REG)
{
if (TREE_ASM_WRITTEN (decl))
return;
TREE_ASM_WRITTEN (decl) = 1;
if (flag_syntax_only)
return;
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
&& top_level)
dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && top_level
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0);
#endif
return;
}
if (DECL_EXTERNAL (decl))
return;
if (TREE_CODE (decl) == FUNCTION_DECL)
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;
TREE_ASM_WRITTEN (decl) = 1;
if (flag_syntax_only)
return;
#ifdef HAVE_COALESCED_SYMBOLS
if (write_symbols == DBX_DEBUG && DECL_COALESCED (decl))
{
postpone_dbx = 1;
write_symbols = NO_DEBUG;
}
#endif
app_disable ();
if (! dont_output_data)
{
int size;
if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
goto finish;
size_tree = size_binop (CEIL_DIV_EXPR,
DECL_SIZE (decl), size_int (BITS_PER_UNIT));
size = TREE_INT_CST_LOW (size_tree);
if (TREE_INT_CST_HIGH (size_tree) != 0
|| size != TREE_INT_CST_LOW (size_tree))
{
error_with_decl (decl, "size of variable `%s' is too large");
goto finish;
}
}
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
#ifdef MACHO_PIC
if (GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
name = IDENTIFIER_POINTER (DECL_NAME (decl));
#ifdef HAVE_COALESCED_SYMBOLS
if (! DECL_COALESCED (decl))
#endif
if (TREE_STATIC (decl)
&& (!DECL_COMMON (decl) || !TREE_PUBLIC (decl))
|| DECL_INITIAL (decl))
machopic_define_name (name);
#endif
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))
{
char *p;
STRIP_NAME_ENCODING (p, name);
first_global_object_name = permalloc (strlen (p) + 1);
strcpy (first_global_object_name, p);
}
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;
}
#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;
if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
&& DECL_COMMON (decl)
#endif
&& DECL_SECTION_NAME (decl) == 0
&& ! dont_output_data)
{
int size = TREE_INT_CST_LOW (size_tree);
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_BSS)
if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded)
warning_with_decl
(decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
#endif
#ifdef DBX_DEBUGGING_INFO
if (write_symbols == DBX_DEBUG && top_level)
dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && top_level
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0);
#endif
#if 0
if (flag_shared_data)
data_section ();
#endif
if (TREE_PUBLIC (decl)
#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
&& DECL_COMMON (decl)
#endif
)
{
#ifdef ASM_OUTPUT_SHARED_COMMON
if (flag_shared_data)
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
else
#endif
{
#ifdef ASM_OUTPUT_ALIGNED_DECL_COMMON
ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size,
DECL_ALIGN (decl));
#else
#ifdef ASM_OUTPUT_ALIGNED_COMMON
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
#endif
#endif
}
}
#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
else if (TREE_PUBLIC (decl))
{
#ifdef ASM_OUTPUT_SHARED_BSS
if (flag_shared_data)
ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
else
#endif
{
#ifdef ASM_OUTPUT_ALIGNED_BSS
ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
#endif
}
}
#endif
else
{
#ifdef ASM_OUTPUT_SHARED_LOCAL
if (flag_shared_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
{
#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size,
DECL_ALIGN (decl));
#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
#endif
}
}
goto finish;
}
if ((TREE_PUBLIC (decl)
#ifdef HAVE_COALESCED_SYMBOLS
|| DECL_COALESCED (decl)
#endif
) && DECL_NAME (decl))
{
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
{
ASM_WEAKEN_LABEL (asm_out_file, name);
remove_from_pending_weak_list
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
else
#endif
#ifdef ASM_PRIVATE_EXTERNIZE_LABEL
if (DECL_PRIVATE_EXTERN (decl))
ASM_PRIVATE_EXTERNIZE_LABEL (asm_out_file, name);
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
#if defined (NEXT_PDO)
else if (!second_global_object_name
&& strncmp(name, "_OBJC_", 6) && TREE_PUBLIC (decl))
{
second_global_object_name = permalloc (strlen (name) + 1);
strcpy (second_global_object_name, name);
}
#endif
#if 0
for (d = equivalents; d; d = TREE_CHAIN (d))
{
tree e = TREE_VALUE (d);
if (TREE_PUBLIC (e) && DECL_NAME (e))
#ifdef ASM_PRIVATE_EXTERNIZE_LABEL
if (DECL_PRIVATE_EXTERN (decl))
ASM_PRIVATE_EXTERNIZE_LABEL (asm_out_file,
XSTR (XEXP (DECL_RTL (e), 0), 0));
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file,
XSTR (XEXP (DECL_RTL (e), 0), 0));
}
#endif
if (DECL_INITIAL (decl) == error_mark_node)
reloc = contains_pointers_p (TREE_TYPE (decl));
else if (DECL_INITIAL (decl))
reloc = output_addressed_constants (DECL_INITIAL (decl));
#ifdef ASM_OUTPUT_SECTION_NAME
if ((flag_data_sections != 0
&& DECL_SECTION_NAME (decl) == NULL_TREE)
|| UNIQUE_SECTION_P (decl))
UNIQUE_SECTION (decl, reloc);
#endif
variable_section (decl, reloc);
if (in_text_section ())
DECL_IN_TEXT_SECTION (decl) = 1;
saved_in_section = in_section;
#ifdef DBX_DEBUGGING_INFO
if (write_symbols == DBX_DEBUG && top_level)
dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && top_level
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0);
#endif
if (in_section != saved_in_section)
variable_section (decl, reloc);
#ifdef ASM_OUTPUT_ZEROFILL
#ifdef HAVE_COALESCED_SYMBOLS
if (! DECL_COALESCED (decl))
#endif
if (flag_no_common
&& ! dont_output_data
&& (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
{
ASM_OUTPUT_ZEROFILL (asm_out_file, name,
int_size_in_bytes (TREE_TYPE (decl)),
floor_log2 (align / BITS_PER_UNIT));
goto finish;
}
#endif
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))
output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
else
assemble_zeros (TREE_INT_CST_LOW (size_tree));
}
finish:
#ifdef HAVE_COALESCED_SYMBOLS
if (postpone_dbx)
{
write_symbols = DBX_DEBUG;
if (top_level && ! rtti_var_p (decl))
dbxout_symbol (decl, 0);
}
#endif
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG && top_level)
{
saved_in_section = in_section;
dbxout_symbol (decl, 0);
if (in_section != saved_in_section)
variable_section (decl, reloc);
}
#else
;
#endif
}
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;
{
#ifdef ASM_OUTPUT_EXTERNAL
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
&& 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)
char *name;
{
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
void
assemble_label (name)
char *name;
{
#ifdef MACHO_PIC
if (!(name[0] == '*' && name[1] == 'L'))
machopic_define_name (name);
#endif
ASM_OUTPUT_LABEL (asm_out_file, name);
}
void
assemble_name (file, name)
FILE *file;
char *name;
{
char *real_name;
tree id;
STRIP_NAME_ENCODING (real_name, name);
if (flag_prefix_function_name
&& ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
real_name = real_name + CHKR_PREFIX_SIZE;
id = maybe_get_identifier (real_name);
if (id)
TREE_SYMBOL_REFERENCED (id) = 1;
if (name[0] == '*')
#ifdef MACHO_PIC
{
int len = strlen (name);
if (len > 6 && !strcmp("$stub", name+len-5))
machopic_validate_stub_or_non_lazy_ptr (name, 1);
else if (len > 7 && !strcmp("$stub\"", name+len-6))
machopic_validate_stub_or_non_lazy_ptr (name, 1);
else if (len > 14 && !strcmp ("$non_lazy_ptr", name+len-13))
machopic_validate_stub_or_non_lazy_ptr (name, 0);
#endif
fputs (&name[1], file);
#ifdef MACHO_PIC
}
#endif
else
ASM_OUTPUT_LABELREF (file, name);
}
rtx
assemble_static_space (size)
int size;
{
char name[12];
char *namestring;
rtx x;
#if 0
if (flag_shared_data)
data_section ();
#endif
ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
++const_labelno;
namestring = (char *) obstack_alloc (saveable_obstack,
strlen (name) + 2);
strcpy (namestring, 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];
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
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
return gen_rtx_SYMBOL_REF (Pmode, name);
}
#endif
int
assemble_integer (x, size, force)
rtx x;
int size;
int force;
{
switch (size)
{
#ifdef ASM_OUTPUT_CHAR
case 1:
ASM_OUTPUT_CHAR (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_SHORT
case 2:
ASM_OUTPUT_SHORT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_INT
case 4:
ASM_OUTPUT_INT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_DOUBLE_INT
case 8:
ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_QUADRUPLE_INT
case 16:
ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x);
return 1;
#endif
}
#ifdef ASM_OUTPUT_BYTE
if (size == 1 && GET_CODE (x) == CONST_INT)
{
ASM_OUTPUT_BYTE (asm_out_file, INTVAL (x));
return 1;
}
#endif
if (size > UNITS_PER_WORD)
{
int i;
enum machine_mode mode
= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
rtx word;
for (i = 0; i < size / UNITS_PER_WORD; i++)
{
word = operand_subword (x, i, 0, mode);
if (word == 0)
break;
if (! assemble_integer (word, UNITS_PER_WORD, 0))
break;
}
if (i == size / UNITS_PER_WORD)
return 1;
if (i > 0)
abort ();
}
if (force)
abort ();
return 0;
}
void
assemble_real (d, mode)
REAL_VALUE_TYPE d;
enum machine_mode mode;
{
jmp_buf output_constant_handler;
if (setjmp (output_constant_handler))
{
error ("floating point trap outputting a constant");
#ifdef REAL_IS_NOT_DOUBLE
bzero ((char *) &d, sizeof d);
d = dconst0;
#else
d = 0;
#endif
}
set_float_handler (output_constant_handler);
switch (mode)
{
#ifdef ASM_OUTPUT_BYTE_FLOAT
case QFmode:
ASM_OUTPUT_BYTE_FLOAT (asm_out_file, d);
break;
#endif
#ifdef ASM_OUTPUT_SHORT_FLOAT
case HFmode:
ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
break;
#endif
#ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
case TQFmode:
ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
break;
#endif
#ifdef ASM_OUTPUT_FLOAT
case SFmode:
ASM_OUTPUT_FLOAT (asm_out_file, d);
break;
#endif
#ifdef ASM_OUTPUT_DOUBLE
case DFmode:
ASM_OUTPUT_DOUBLE (asm_out_file, d);
break;
#endif
#ifdef ASM_OUTPUT_LONG_DOUBLE
case XFmode:
case TFmode:
ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d);
break;
#endif
default:
abort ();
}
set_float_handler (NULL_PTR);
}
static rtx const_double_chain = 0;
#ifdef MACHO_PIC
int
const_double_mem_used ()
{
return (const_double_chain != 0);
}
#endif
rtx
immed_double_const (i0, i1, mode)
HOST_WIDE_INT i0, i1;
enum machine_mode mode;
{
register 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 (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
&& (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;
}
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;
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1);
pop_obstacks ();
if (outer_function_chain == 0 && current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
}
CONST_DOUBLE_MEM (r) = const0_rtx;
return r;
}
rtx
immed_real_const_1 (d, mode)
REAL_VALUE_TYPE d;
enum machine_mode mode;
{
union real_extract u;
register rtx r;
u.d = d;
if (REAL_VALUES_IDENTICAL (dconst0, d))
return CONST0_RTX (mode);
else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
return CONST1_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);
for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
&& GET_MODE (r) == mode)
return r;
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
r = rtx_alloc (CONST_DOUBLE);
PUT_MODE (r, mode);
bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
pop_obstacks ();
if (outer_function_chain == 0 && current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
}
CONST_DOUBLE_MEM (r) = const0_rtx;
return r;
}
rtx
immed_real_const (exp)
tree exp;
{
return immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)));
}
static rtx const_vector_chain;
rtx
immed_vector_const (exp)
tree exp;
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
HOST_WIDE_INT u[4];
register rtx r;
int in_current_obstack;
if (TREE_CODE (TREE_VECTOR_CST_0 (exp)) == INTEGER_CST)
{
u[0] = TREE_INT_CST_LOW (TREE_VECTOR_CST_0 (exp));
u[1] = TREE_INT_CST_LOW (TREE_VECTOR_CST_1 (exp));
u[2] = TREE_INT_CST_LOW (TREE_VECTOR_CST_2 (exp));
u[3] = TREE_INT_CST_LOW (TREE_VECTOR_CST_3 (exp));
}
else if (TREE_CODE (TREE_VECTOR_CST_0 (exp)) == REAL_CST)
{
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST (TREE_VECTOR_CST_0 (exp)), u[0]);
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST (TREE_VECTOR_CST_1 (exp)), u[1]);
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST (TREE_VECTOR_CST_2 (exp)), u[2]);
REAL_VALUE_TO_TARGET_SINGLE (TREE_REAL_CST (TREE_VECTOR_CST_3 (exp)), u[3]);
}
else
abort ();
for (r = const_vector_chain; r; r = CONST_VECTOR_CHAIN (r))
if (! bcmp ((char *) &CONST_VECTOR_0 (r), (char *) &u, sizeof u)
&& GET_MODE (r) == mode)
return r;
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
r = rtx_alloc (CONST_VECTOR);
PUT_MODE (r, mode);
bcopy ((char *) &u, (char *) &CONST_VECTOR_0 (r), sizeof u);
pop_obstacks ();
if (outer_function_chain == 0 && current_function_decl != 0)
{
CONST_VECTOR_CHAIN (r) = const_vector_chain;
const_vector_chain = r;
}
CONST_VECTOR_MEM (r) = const0_rtx;
return r;
}
void
clear_const_double_mem ()
{
register rtx r, next;
if (outer_function_chain != 0)
return;
for (r = const_double_chain; r; r = next)
{
next = CONST_DOUBLE_CHAIN (r);
CONST_DOUBLE_CHAIN (r) = 0;
CONST_DOUBLE_MEM (r) = cc0_rtx;
}
const_double_chain = 0;
for (r = const_vector_chain; r; r = next)
{
next = CONST_VECTOR_CHAIN (r);
CONST_VECTOR_CHAIN (r) = 0;
CONST_VECTOR_MEM (r) = cc0_rtx;
}
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;
{
register tree target = TREE_OPERAND (exp, 0);
register int offset = 0;
register rtx x;
while (1)
{
if (TREE_CODE (target) == COMPONENT_REF
&& (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1)))
== INTEGER_CST))
{
offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) / BITS_PER_UNIT;
target = TREE_OPERAND (target, 0);
}
else if (TREE_CODE (target) == ARRAY_REF)
{
if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST
|| TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST)
abort ();
offset += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target)))
* TREE_INT_CST_LOW (TREE_OPERAND (target, 1)))
/ BITS_PER_UNIT);
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 = TREE_CST_RTL (target);
break;
default:
abort ();
}
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
value->base = x;
value->offset = offset;
}
struct constant_descriptor
{
struct constant_descriptor *next;
char *label;
char contents[1];
};
#define HASHBITS 30
#define MAX_HASH_TABLE 1009
static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
static int
const_hash (exp)
tree exp;
{
register char *p;
register int len, hi, i;
register enum tree_code code = TREE_CODE (exp);
switch (code)
{
case INTEGER_CST:
p = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (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:
return (const_hash (TREE_VECTOR_CST_LOW (exp)) * 11
+ const_hash (TREE_VECTOR_CST_HIGH (exp)));
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
len = int_size_in_bytes (TREE_TYPE (exp));
p = (char *) alloca (len);
get_set_constructor_bytes (exp, (unsigned char *) p, len);
break;
}
else
{
register 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;
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:
abort ();
}
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->contents);
}
static char *
compare_constant_1 (exp, p)
tree exp;
char *p;
{
register char *strp;
register int len;
register 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 = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
break;
case REAL_CST:
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
strp = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
break;
case STRING_CST:
if (flag_writable_strings)
return 0;
if (*p++ != TYPE_MODE (TREE_TYPE (exp)))
return 0;
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
if (bcmp ((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:
p = compare_constant_1 (TREE_VECTOR_CST_LOW (exp), p);
if (p == 0)
return 0;
return compare_constant_1 (TREE_VECTOR_CST_HIGH (exp), p);
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
strp = (char *) alloca (len);
get_set_constructor_bytes (exp, (unsigned char *) strp, len);
if (bcmp ((char *) &xlen, p, sizeof xlen))
return 0;
p += sizeof xlen;
break;
}
else
{
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
int have_purpose = 0;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link))
have_purpose = 1;
if (bcmp ((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 (bcmp ((char *) &type, p, sizeof type))
return 0;
p += sizeof type;
if (bcmp ((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 (bcmp ((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 (bcmp ((char *) &zero, p, sizeof zero))
return 0;
p += sizeof zero;
}
if (TREE_PURPOSE (link)
&& TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
{
if (bcmp ((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 (bcmp ((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 = (char *) &value.offset;
len = sizeof value.offset;
while (--len >= 0)
if (*p++ != *strp++)
return 0;
strp = XSTR (value.base, 0);
len = strlen (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:
abort ();
}
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;
obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
record_constant_1 (exp);
return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
}
static void
record_constant_1 (exp)
tree exp;
{
register char *strp;
register int len;
register 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 = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
break;
case REAL_CST:
obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
strp = (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 = 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:
record_constant_1 (TREE_VECTOR_CST_LOW (exp));
record_constant_1 (TREE_VECTOR_CST_HIGH (exp));
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
{
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (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);
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);
obstack_grow (&permanent_obstack, XSTR (value.base, 0),
strlen (XSTR (value.base, 0)) + 1);
}
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:
abort ();
}
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:
return build_vector (TREE_TYPE (exp),
copy_constant (TREE_VECTOR_CST_0 (exp)),
copy_constant (TREE_VECTOR_CST_1 (exp)),
copy_constant (TREE_VECTOR_CST_2 (exp)),
copy_constant (TREE_VECTOR_CST_3 (exp)));
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)
tree exp;
{
register int hash;
register struct constant_descriptor *desc;
char label[256];
char *found = 0;
int reloc;
register rtx def;
if (TREE_CST_RTL (exp))
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))
{
found = desc->label;
break;
}
if (found == 0)
{
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
desc = record_constant (exp);
desc->next = const_hash_table[hash];
desc->label
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
const_hash_table[hash] = desc;
}
else
{
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
}
push_obstacks_nochange ();
if (TREE_PERMANENT (exp))
end_temporary_allocation ();
def = gen_rtx_SYMBOL_REF (Pmode, desc->label);
TREE_CST_RTL (exp)
= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
MEM_SET_IN_STRUCT_P (TREE_CST_RTL (exp), 1);
pop_obstacks ();
#ifdef ENCODE_SECTION_INFO
ENCODE_SECTION_INFO (exp);
#endif
if (found == 0)
{
int after_function = 0;
#ifdef CONSTANT_AFTER_FUNCTION_P
if (current_function_decl != 0
&& CONSTANT_AFTER_FUNCTION_P (exp))
after_function = 1;
#endif
if (defer_addressed_constants_flag || after_function)
{
struct deferred_constant *p;
p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
push_obstacks_nochange ();
suspend_momentary ();
p->exp = copy_constant (exp);
pop_obstacks ();
p->reloc = reloc;
p->labelno = const_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)
output_constant_def_contents (exp, reloc, const_labelno);
++const_labelno;
}
}
return TREE_CST_RTL (exp);
}
static void
output_constant_def_contents (exp, reloc, labelno)
tree exp;
int reloc;
int labelno;
{
int align;
if (IN_NAMED_SECTION (exp))
named_section (exp, NULL, reloc);
else
{
#ifdef SELECT_SECTION
SELECT_SECTION (exp, reloc);
#else
if (((TREE_CODE (exp) == STRING_CST) && flag_writable_strings)
|| (flag_pic && reloc))
data_section ();
else
readonly_data_section ();
#endif
}
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));
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
output_constant (exp,
(TREE_CODE (exp) == STRING_CST
? TREE_STRING_LENGTH (exp)
: int_size_in_bytes (TREE_TYPE (exp))));
}
#define MAX_RTX_HASH_TABLE 61
static struct constant_descriptor **const_rtx_hash_table;
struct pool_constant
{
struct constant_descriptor *desc;
struct pool_constant *next;
enum machine_mode mode;
rtx constant;
int labelno;
int align;
int offset;
int mark;
};
static struct pool_constant *first_pool, *last_pool;
static int pool_offset;
struct pool_sym
{
char *label;
struct pool_constant *pool;
struct pool_sym *next;
};
static struct pool_sym **const_rtx_sym_hash_table;
#define SYMHASH(LABEL) \
((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE)
void
init_const_rtx_hash_table ()
{
const_rtx_hash_table
= ((struct constant_descriptor **)
oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
const_rtx_sym_hash_table
= ((struct pool_sym **)
oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
bzero ((char *) const_rtx_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
bzero ((char *) const_rtx_sym_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
first_pool = last_pool = 0;
pool_offset = 0;
}
void
save_varasm_status (p, context)
struct function *p;
tree context;
{
p->const_rtx_hash_table = const_rtx_hash_table;
p->const_rtx_sym_hash_table = const_rtx_sym_hash_table;
p->first_pool = first_pool;
p->last_pool = last_pool;
p->pool_offset = pool_offset;
p->const_double_chain = const_double_chain;
if (context == NULL_TREE)
const_double_chain = 0;
}
void
restore_varasm_status (p)
struct function *p;
{
const_rtx_hash_table = p->const_rtx_hash_table;
const_rtx_sym_hash_table = p->const_rtx_sym_hash_table;
first_pool = p->first_pool;
last_pool = p->last_pool;
pool_offset = p->pool_offset;
const_double_chain = p->const_double_chain;
}
enum kind { RTX_DOUBLE, RTX_VECTOR, RTX_INT };
struct rtx_const
{
#ifdef ONLY_INT_FIELDS
unsigned int kind : 16;
unsigned int mode : 16;
#else
enum kind kind : 16;
enum machine_mode mode : 16;
#endif
union {
union real_extract du;
struct addr_const addr;
struct {HOST_WIDE_INT high, low;} di;
struct {HOST_WIDE_INT v0, v1, v2, v3; } dv;
} un;
};
static void
decode_rtx_const (mode, x, value)
enum machine_mode mode;
rtx x;
struct rtx_const *value;
{
{
int *p = (int *) value;
int *end = (int *) (value + 1);
while (p < end)
*p++ = 0;
}
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);
bcopy ((char *) &CONST_DOUBLE_LOW (x),
(char *) &value->un.du, 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:
value->kind = RTX_VECTOR;
if (GET_MODE (x) != VOIDmode)
{
value->mode = GET_MODE (x);
bcopy ((char *) &CONST_VECTOR_0 (x),
(char *) &value->un.dv, sizeof value->un.dv);
}
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;
#ifdef NEXT_SEMANTICS
case SIGN_EXTEND:
decode_rtx_const (mode, XEXP (x, 0), value);
return;
#endif
case CONST:
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS)
{
value->un.addr.base = XEXP (x, 0);
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
abort ();
value->un.addr.offset = INTVAL (XEXP (x, 1));
}
else if (GET_CODE (x) == MINUS)
{
value->un.addr.base = XEXP (x, 0);
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
abort ();
value->un.addr.offset = - INTVAL (XEXP (x, 1));
}
else
abort ();
break;
default:
abort ();
}
if (value->kind == RTX_INT && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
case SYMBOL_REF:
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.un.addr.base == val1.un.addr.base)
return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
return x;
}
static int
const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
register int hi;
register 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;
}
static int
compare_constant_rtx (mode, x, desc)
enum machine_mode mode;
rtx x;
struct constant_descriptor *desc;
{
register int *p = (int *) desc->contents;
register int *strp;
register 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;
char *label;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
obstack_grow (saveable_obstack, &ptr, sizeof ptr);
obstack_grow (saveable_obstack, &label, sizeof label);
obstack_grow (saveable_obstack, &value, sizeof value);
return (struct constant_descriptor *) obstack_finish (saveable_obstack);
}
rtx
force_const_mem (mode, x)
enum machine_mode mode;
rtx x;
{
register int hash;
register struct constant_descriptor *desc;
char label[256];
char *found = 0;
rtx def;
if (outer_function_chain == 0)
if (GET_CODE (x) == CONST_DOUBLE
&& GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
&& GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
return CONST_DOUBLE_MEM (x);
hash = const_hash_rtx (mode, x);
for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
if (compare_constant_rtx (mode, x, desc))
{
found = desc->label;
break;
}
if (found == 0)
{
register struct pool_constant *pool;
register struct pool_sym *sym;
int align;
desc = record_constant_rtx (mode, x);
desc->next = const_rtx_hash_table[hash];
const_rtx_hash_table[hash] = desc;
align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
align * BITS_PER_UNIT) / BITS_PER_UNIT;
#endif
pool_offset += align - 1;
pool_offset &= ~ (align - 1);
if (rtl_obstack != saveable_obstack
&& (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
{
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
if (GET_CODE (x) == CONST)
x = gen_rtx_CONST (GET_MODE (x),
gen_rtx_PLUS (GET_MODE (x),
XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1)));
else
x = GEN_INT (INTVAL (x));
pop_obstacks ();
}
pool = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
pool->desc = desc;
pool->constant = x;
pool->mode = mode;
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
first_pool = pool;
else
last_pool->next = pool;
last_pool = pool;
pool_offset += GET_MODE_SIZE (mode);
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
++const_labelno;
desc->label = found
= (char *) obstack_copy0 (saveable_obstack, label, strlen (label));
hash = SYMHASH (found);
sym = (struct pool_sym *) savealloc (sizeof (struct pool_sym));
sym->label = found;
sym->pool = pool;
sym->next = const_rtx_sym_hash_table[hash];
const_rtx_sym_hash_table[hash] = sym;
}
def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
RTX_UNCHANGING_P (def) = 1;
CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
current_function_uses_const_pool = 1;
if (outer_function_chain == 0)
if (GET_CODE (x) == CONST_DOUBLE)
{
if (CONST_DOUBLE_MEM (x) == cc0_rtx)
{
CONST_DOUBLE_CHAIN (x) = const_double_chain;
const_double_chain = x;
}
CONST_DOUBLE_MEM (x) = def;
}
return def;
}
static struct pool_constant *
find_pool_constant (addr)
rtx addr;
{
struct pool_sym *sym;
char *label = XSTR (addr, 0);
for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
if (sym->label == label)
return sym->pool;
abort ();
}
rtx
get_pool_constant (addr)
rtx addr;
{
return (find_pool_constant (addr))->constant;
}
enum machine_mode
get_pool_mode (addr)
rtx addr;
{
return (find_pool_constant (addr))->mode;
}
int
get_pool_offset (addr)
rtx addr;
{
return (find_pool_constant (addr))->offset;
}
int
get_pool_size ()
{
return pool_offset;
}
void
output_constant_pool (fnname, fndecl)
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)
{
x = pool->constant;
if (! pool->mark)
continue;
if (((GET_CODE (x) == LABEL_REF
&& (INSN_DELETED_P (XEXP (x, 0))
|| GET_CODE (XEXP (x, 0)) == NOTE)))
|| (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
&& (INSN_DELETED_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
|| GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == NOTE)))
x = const0_rtx;
#ifdef SELECT_RTX_SECTION
SELECT_RTX_SECTION (pool->mode, x);
#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
if (pool->align > 1)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (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 ();
bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
assemble_real (u.d, pool->mode);
break;
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (pool->mode), 1);
break;
case MODE_VECTOR:
{
HOST_WIDE_INT v[4];
int i;
bcopy ((char *) &CONST_VECTOR_0 (x), (char *) v, sizeof v);
for (i = 0; i < 4; i++)
assemble_integer (gen_rtx (CONST_INT, SImode, v[i]),
GET_MODE_SIZE (SImode), 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 ()
{
register rtx insn;
struct pool_constant *pool;
if (first_pool == 0)
return;
for (pool = first_pool; pool; pool = pool->next)
pool->mark = 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
mark_constants (PATTERN (insn));
for (insn = current_function_epilogue_delay_list;
insn;
insn = XEXP (insn, 1))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
mark_constants (PATTERN (insn));
for (pool = first_pool; pool; pool = pool->next)
{
struct pool_sym *sym;
char *label;
if (!pool->mark)
continue;
label = XSTR (pool->constant, 0);
for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym;
sym = sym->next)
if (sym->label == label)
sym->pool->mark = 1;
}
}
static void
mark_constants (x)
register rtx x;
{
register int i;
register char *format_ptr;
if (x == 0)
return;
if (GET_CODE (x) == SYMBOL_REF)
{
if (CONSTANT_POOL_ADDRESS_P (x))
find_pool_constant (x)->mark = 1;
return;
}
else if (GET_CODE (x) == CONST_DOUBLE)
return;
if (GET_RTX_CLASS (GET_CODE (x)) == 'i')
{
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)
{
register 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
output_addressed_constants (exp)
tree exp;
{
int reloc = 0;
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
{
register tree constant = TREE_OPERAND (exp, 0);
while (TREE_CODE (constant) == COMPONENT_REF)
{
constant = TREE_OPERAND (constant, 0);
}
if (TREE_CODE_CLASS (TREE_CODE (constant)) == 'c'
|| TREE_CODE (constant) == CONSTRUCTOR)
output_constant_def (constant);
}
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:
{
register tree link;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_VALUE (link) != 0)
reloc |= output_addressed_constants (TREE_VALUE (link));
}
break;
default:
break;
}
return reloc;
}
void
output_constant (exp, size)
register tree exp;
register int size;
{
register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
if (lang_expand_constant)
exp = (*lang_expand_constant) (exp);
if (size == 0 || flag_syntax_only)
return;
while ((TREE_CODE (exp) == NOP_EXPR
&& (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
|| AGGREGATE_TYPE_P (TREE_TYPE (exp))))
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
{
assemble_zeros (size);
return;
}
switch (code)
{
case CHAR_TYPE:
case BOOLEAN_TYPE:
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
size, 0))
error ("initializer for integer value is too complicated");
size = 0;
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));
size = 0;
break;
case COMPLEX_TYPE:
output_constant (TREE_REALPART (exp), size / 2);
output_constant (TREE_IMAGPART (exp), size / 2);
size -= (size / 2) * 2;
break;
case VECTOR_TYPE:
if (TREE_CODE (exp) == VECTOR_CST)
{
output_constant (TREE_VECTOR_CST_0 (exp), size / 4);
output_constant (TREE_VECTOR_CST_1 (exp), size / 4);
output_constant (TREE_VECTOR_CST_2 (exp), size / 4);
output_constant (TREE_VECTOR_CST_3 (exp), size / 4);
size = 0;
}
else
abort ();
break;
case ARRAY_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
{
output_constructor (exp, size);
return;
}
else if (TREE_CODE (exp) == STRING_CST)
{
int excess = 0;
if (size > TREE_STRING_LENGTH (exp))
{
excess = size - TREE_STRING_LENGTH (exp);
size = TREE_STRING_LENGTH (exp);
}
assemble_string (TREE_STRING_POINTER (exp), size);
size = excess;
}
else
abort ();
break;
case RECORD_TYPE:
case UNION_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
output_constructor (exp, size);
else
abort ();
return;
case SET_TYPE:
if (TREE_CODE (exp) == INTEGER_CST)
assemble_integer (expand_expr (exp, NULL_RTX,
VOIDmode, EXPAND_INITIALIZER),
size, 1);
else if (TREE_CODE (exp) == CONSTRUCTOR)
{
unsigned char *buffer = (unsigned char *) alloca (size);
if (get_set_constructor_bytes (exp, buffer, size))
abort ();
assemble_string ((char *) buffer, size);
}
else
error ("unknown set constructor type");
return;
default:
break;
}
if (size > 0)
assemble_zeros (size);
}
static void
output_constructor (exp, size)
tree exp;
int size;
{
register tree link, field = 0;
HOST_WIDE_INT min_index = 0;
int total_bytes = 0;
int byte_buffer_in_use = 0;
register int byte;
if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
abort ();
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
field = TYPE_FIELDS (TREE_TYPE (exp));
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (exp)) != 0)
min_index
= TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (exp))));
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 (TREE_TYPE (exp)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
{
if (TREE_PURPOSE (link) != 0)
field = TREE_PURPOSE (link);
}
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
index = TREE_PURPOSE (link);
if (val != 0)
STRIP_NOPS (val);
if (index && TREE_CODE (index) == RANGE_EXPR)
{
register int fieldsize
= int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
HOST_WIDE_INT index;
for (index = lo_index; index <= hi_index; index++)
{
if (val == 0)
assemble_zeros (fieldsize);
else
output_constant (val, fieldsize);
total_bytes += fieldsize;
}
}
else if (field == 0 || !DECL_BIT_FIELD (field))
{
register int fieldsize;
int bitpos = (field ? (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
/ BITS_PER_UNIT)
: 0);
if (index != 0)
bitpos = (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (val)))
/ BITS_PER_UNIT
* (TREE_INT_CST_LOW (index) - min_index));
if (byte_buffer_in_use)
{
ASM_OUTPUT_BYTE (asm_out_file, byte);
total_bytes++;
byte_buffer_in_use = 0;
}
if ((field != 0 || index != 0) && bitpos != total_bytes)
{
assemble_zeros (bitpos - total_bytes);
total_bytes = bitpos;
}
if (field)
{
if (TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
abort ();
if (TREE_INT_CST_LOW (DECL_SIZE (field)) > 100000)
{
tree size_tree = size_binop (CEIL_DIV_EXPR,
DECL_SIZE (field),
size_int (BITS_PER_UNIT));
fieldsize = TREE_INT_CST_LOW (size_tree);
}
else
{
fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field));
fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
}
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
if (val == 0)
assemble_zeros (fieldsize);
else
output_constant (val, fieldsize);
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
{
int next_offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
int end_offset
= (next_offset + TREE_INT_CST_LOW (DECL_SIZE (field)));
if (val == 0)
val = integer_zero_node;
if (next_offset / BITS_PER_UNIT != total_bytes)
{
if (byte_buffer_in_use)
{
ASM_OUTPUT_BYTE (asm_out_file, byte);
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;
int next_byte = next_offset / BITS_PER_UNIT;
int next_bit = next_offset % BITS_PER_UNIT;
while (next_byte != total_bytes)
{
ASM_OUTPUT_BYTE (asm_out_file, byte);
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 -= (HOST_BITS_PER_WIDE_INT - shift);
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) 1 << this_time) - 1))
<< (BITS_PER_UNIT - this_time - next_bit));
}
else
{
shift = (next_offset
- TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
{
this_time -= (HOST_BITS_PER_WIDE_INT - shift);
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) 1 << this_time) - 1))
<< next_bit);
}
next_offset += this_time;
byte_buffer_in_use = 1;
}
}
}
if (byte_buffer_in_use)
{
ASM_OUTPUT_BYTE (asm_out_file, byte);
total_bytes++;
}
if (total_bytes < size)
assemble_zeros (size - total_bytes);
}
#ifdef HANDLE_PRAGMA_WEAK
int
add_weak (name, value)
char *name;
char *value;
{
struct weak_syms *weak;
weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms));
if (weak == NULL)
return 0;
weak->next = weak_decls;
weak->name = name;
weak->value = value;
weak_decls = weak;
return 1;
}
#endif
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)
DECL_WEAK (decl) = 1;
#ifdef HANDLE_PRAGMA_WEAK
add_weak (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
#endif
}
#ifdef HANDLE_PRAGMA_WEAK
struct weak_syms * weak_decls;
#endif
void
weak_finish ()
{
#ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK)
{
struct weak_syms *t;
for (t = weak_decls; t; t = t->next)
{
if (t->name)
{
ASM_WEAKEN_LABEL (asm_out_file, t->name);
if (t->value)
ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
}
}
}
#endif
}
static void
remove_from_pending_weak_list (name)
char *name;
{
#ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK)
{
struct weak_syms *t;
for (t = weak_decls; t; t = t->next)
{
if (t->name && strcmp (name, t->name) == 0)
t->name = NULL;
}
}
#endif
}
void
assemble_alias (decl, target)
tree decl, target ATTRIBUTE_UNUSED;
{
char *name;
make_decl_rtl (decl, (char *) 0, 1);
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
#ifdef ASM_OUTPUT_DEF
if (TREE_PUBLIC (decl))
{
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
{
ASM_WEAKEN_LABEL (asm_out_file, name);
remove_from_pending_weak_list
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
TREE_ASM_WRITTEN (decl) = 1;
#else
#ifdef ASM_OUTPUT_WEAK_ALIAS
if (! DECL_WEAK (decl))
warning ("only weak aliases are supported in this configuration");
ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
TREE_ASM_WRITTEN (decl) = 1;
#else
warning ("alias definitions not supported in this configuration; ignored");
#endif
#endif
}
#ifndef SUPPORTS_ONE_ONLY
#ifdef MAKE_DECL_ONE_ONLY
#define SUPPORTS_ONE_ONLY 1
#else
#define SUPPORTS_ONE_ONLY 0
#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 ();
}