#include "config.h"
#include "system.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "basic-block.h"
#include "regs.h"
#include "insn-config.h"
#include "recog.h"
#include "reload.h"
#include "real.h"
#include "toplev.h"
#include "output.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
void init_reg_sets_1 PROTO((void));
static void init_reg_modes PROTO((void));
#ifdef AUTO_INC_DEC
#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
#define FORBIDDEN_INC_DEC_CLASSES
#endif
#endif
char fixed_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET fixed_reg_set;
static char initial_fixed_regs[] = FIXED_REGISTERS;
char call_used_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET call_used_reg_set;
HARD_REG_SET losing_caller_save_reg_set;
static char initial_call_used_regs[] = CALL_USED_REGISTERS;
char call_fixed_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET call_fixed_reg_set;
int n_non_fixed_regs;
char global_regs[FIRST_PSEUDO_REGISTER];
#ifdef REG_ALLOC_ORDER
int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;
#endif
HARD_REG_SET reg_class_contents[N_REG_CLASSES];
#define N_REG_INTS \
((FIRST_PSEUDO_REGISTER + (HOST_BITS_PER_INT - 1)) / HOST_BITS_PER_INT)
static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
= REG_CLASS_CONTENTS;
int reg_class_size[N_REG_CLASSES];
enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES];
enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES];
enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
char *reg_names[] = REGISTER_NAMES;
enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
static int move_cost[N_REG_CLASSES][N_REG_CLASSES];
static int may_move_cost[N_REG_CLASSES][N_REG_CLASSES];
#ifdef FORBIDDEN_INC_DEC_CLASSES
static int forbidden_inc_dec_class[N_REG_CLASSES];
static char *in_inc_dec;
#endif
#ifdef HAVE_SECONDARY_RELOADS
static rtx top_of_stack[MAX_MACHINE_MODE];
#endif
struct reg_info_data {
struct reg_info_data *next;
size_t min_index;
size_t max_index;
char used_p;
reg_info data[1];
};
static struct reg_info_data *reg_info_head;
void
init_reg_sets ()
{
register int i, j;
for (i = 0; i < N_REG_CLASSES; i++)
{
CLEAR_HARD_REG_SET (reg_class_contents[i]);
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (int_reg_class_contents[i][j / HOST_BITS_PER_INT]
& ((unsigned) 1 << (j % HOST_BITS_PER_INT)))
SET_HARD_REG_BIT (reg_class_contents[i], j);
}
bcopy (initial_fixed_regs, fixed_regs, sizeof fixed_regs);
bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);
bzero (global_regs, sizeof global_regs);
INIT_ONCE_REG_SET ();
}
#ifndef MACHO_PIC
static
#endif
void
init_reg_sets_1 ()
{
register unsigned int i, j;
#ifdef CONDITIONAL_REGISTER_USAGE
CONDITIONAL_REGISTER_USAGE;
#endif
#ifdef MACHO_PIC
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
{
if (call_used_regs[i] && ! fixed_regs[i])
warning ("call-clobbered register used for global register variable");
fixed_regs[i] = 1;
call_used_regs[i] = 1;
}
#endif
bzero ((char *) reg_class_size, sizeof reg_class_size);
for (i = 0; i < N_REG_CLASSES; i++)
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
reg_class_size[i]++;
for (i = 0; i < N_REG_CLASSES; i++)
{
for (j = 0; j < N_REG_CLASSES; j++)
{
#ifdef HARD_REG_SET
register
#endif
HARD_REG_SET c;
register int k;
COPY_HARD_REG_SET (c, reg_class_contents[i]);
IOR_HARD_REG_SET (c, reg_class_contents[j]);
for (k = 0; k < N_REG_CLASSES; k++)
{
GO_IF_HARD_REG_SUBSET (reg_class_contents[k], c,
subclass1);
continue;
subclass1:
GO_IF_HARD_REG_SUBSET (reg_class_contents[k],
reg_class_contents[(int) reg_class_subunion[i][j]],
subclass2);
reg_class_subunion[i][j] = (enum reg_class) k;
subclass2:
;
}
}
}
for (i = 0; i < N_REG_CLASSES; i++)
{
for (j = 0; j < N_REG_CLASSES; j++)
{
#ifdef HARD_REG_SET
register
#endif
HARD_REG_SET c;
register int k;
COPY_HARD_REG_SET (c, reg_class_contents[i]);
IOR_HARD_REG_SET (c, reg_class_contents[j]);
for (k = 0; k < N_REG_CLASSES; k++)
GO_IF_HARD_REG_SUBSET (c, reg_class_contents[k], superclass);
superclass:
reg_class_superunion[i][j] = (enum reg_class) k;
}
}
for (i = 0; i < N_REG_CLASSES; i++)
{
for (j = 0; j < N_REG_CLASSES; j++)
{
reg_class_superclasses[i][j] = LIM_REG_CLASSES;
reg_class_subclasses[i][j] = LIM_REG_CLASSES;
}
}
for (i = 0; i < N_REG_CLASSES; i++)
{
if (i == (int) NO_REGS)
continue;
for (j = i + 1; j < N_REG_CLASSES; j++)
{
enum reg_class *p;
GO_IF_HARD_REG_SUBSET (reg_class_contents[i], reg_class_contents[j],
subclass);
continue;
subclass:
p = ®_class_superclasses[i][0];
while (*p != LIM_REG_CLASSES) p++;
*p = (enum reg_class) j;
p = ®_class_subclasses[j][0];
while (*p != LIM_REG_CLASSES) p++;
*p = (enum reg_class) i;
}
}
CLEAR_HARD_REG_SET (fixed_reg_set);
CLEAR_HARD_REG_SET (call_used_reg_set);
CLEAR_HARD_REG_SET (call_fixed_reg_set);
bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
n_non_fixed_regs = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (fixed_regs[i])
SET_HARD_REG_BIT (fixed_reg_set, i);
else
n_non_fixed_regs++;
if (call_used_regs[i])
SET_HARD_REG_BIT (call_used_reg_set, i);
if (call_fixed_regs[i])
SET_HARD_REG_BIT (call_fixed_reg_set, i);
if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
}
for (i = 0; i < N_REG_CLASSES; i++)
for (j = 0; j < N_REG_CLASSES; j++)
{
int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j);
enum reg_class *p1, *p2;
for (p2 = ®_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++)
if (*p2 != i)
cost = MAX (cost, REGISTER_MOVE_COST (i, *p2));
for (p1 = ®_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++)
{
if (*p1 != j)
cost = MAX (cost, REGISTER_MOVE_COST (*p1, j));
for (p2 = ®_class_subclasses[j][0];
*p2 != LIM_REG_CLASSES; p2++)
if (*p1 != *p2)
cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2));
}
move_cost[i][j] = cost;
if (reg_class_subset_p (i, j))
cost = 0;
may_move_cost[i][j] = cost;
}
}
static void
init_reg_modes ()
{
register int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
if (reg_raw_mode[i] == VOIDmode)
reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
}
}
void
init_regs ()
{
init_reg_sets_1 ();
init_reg_modes ();
#ifdef HAVE_SECONDARY_RELOADS
{
int i;
for (i = 0; i < MAX_MACHINE_MODE; i++)
top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx);
}
#endif
}
#ifdef HAVE_SECONDARY_RELOADS
int
memory_move_secondary_cost (mode, class, in)
enum machine_mode mode;
enum reg_class class;
int in;
{
enum reg_class altclass;
int partial_cost = 0;
rtx mem = top_of_stack[(int) mode];
if (in)
{
#ifdef SECONDARY_INPUT_RELOAD_CLASS
altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem);
#else
altclass = NO_REGS;
#endif
}
else
{
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem);
#else
altclass = NO_REGS;
#endif
}
if (altclass == NO_REGS)
return 0;
if (in)
partial_cost = REGISTER_MOVE_COST (altclass, class);
else
partial_cost = REGISTER_MOVE_COST (class, altclass);
if (class == altclass)
return partial_cost;
return memory_move_secondary_cost (mode, altclass, in) + partial_cost;
}
#endif
enum machine_mode
choose_hard_reg_mode (regno, nregs)
int regno;
int nregs;
{
enum machine_mode found_mode = VOIDmode, mode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_NREGS (regno, mode) == nregs
&& HARD_REGNO_MODE_OK (regno, mode))
found_mode = mode;
if (found_mode != VOIDmode)
return found_mode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_NREGS (regno, mode) == nregs
&& HARD_REGNO_MODE_OK (regno, mode))
found_mode = mode;
if (found_mode != VOIDmode)
return found_mode;
if (HARD_REGNO_NREGS (regno, CCmode) == nregs
&& HARD_REGNO_MODE_OK (regno, CCmode))
return CCmode;
return VOIDmode;
}
void
fix_register (name, fixed, call_used)
char *name;
int fixed, call_used;
{
int i;
if ((i = decode_reg_name (name)) >= 0)
{
if ((i == STACK_POINTER_REGNUM
#ifdef HARD_FRAME_POINTER_REGNUM
|| i == HARD_FRAME_POINTER_REGNUM
#else
|| i == FRAME_POINTER_REGNUM
#endif
)
&& (fixed == 0 || call_used == 0))
{
static char* what_option[2][2] = {
{ "call-saved", "call-used" },
{ "no-such-option", "fixed" }};
error ("can't use '%s' as a %s register", name,
what_option[fixed][call_used]);
}
else
{
fixed_regs[i] = fixed;
call_used_regs[i] = call_used;
}
}
else
{
warning ("unknown register name: %s", name);
}
}
void
globalize_reg (i)
int i;
{
if (global_regs[i])
{
warning ("register used for two global register variables");
return;
}
if (call_used_regs[i] && ! fixed_regs[i])
warning ("call-clobbered register used for global register variable");
global_regs[i] = 1;
if (fixed_regs[i])
return;
fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
n_non_fixed_regs--;
SET_HARD_REG_BIT (fixed_reg_set, i);
SET_HARD_REG_BIT (call_used_reg_set, i);
SET_HARD_REG_BIT (call_fixed_reg_set, i);
}
struct costs
{
int cost[N_REG_CLASSES];
int mem_cost;
};
static struct costs *costs;
static struct costs init_cost;
static struct costs op_costs[MAX_RECOG_OPERANDS];
static char *prefclass;
static char *altclass;
static char *prefclass_buffer;
static char *altclass_buffer;
static int loop_depth;
static int loop_cost;
static rtx scan_one_insn PROTO((rtx, int));
static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
char *, const char **, rtx));
static int copy_cost PROTO((rtx, enum machine_mode,
enum reg_class, int));
static void record_address_regs PROTO((rtx, enum reg_class, int));
#ifdef FORBIDDEN_INC_DEC_CLASSES
static int auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));
#endif
static void reg_scan_mark_refs PROTO((rtx, rtx, int, int));
enum reg_class
reg_preferred_class (regno)
int regno;
{
if (prefclass == 0)
return GENERAL_REGS;
return (enum reg_class) prefclass[regno];
}
enum reg_class
reg_alternate_class (regno)
int regno;
{
if (prefclass == 0)
return ALL_REGS;
return (enum reg_class) altclass[regno];
}
void
regclass_init ()
{
int i;
init_cost.mem_cost = 10000;
for (i = 0; i < N_REG_CLASSES; i++)
init_cost.cost[i] = 10000;
prefclass = 0;
}
static rtx
scan_one_insn (insn, pass)
rtx insn;
int pass;
{
enum rtx_code code = GET_CODE (insn);
enum rtx_code pat_code;
const char *constraints[MAX_RECOG_OPERANDS];
enum machine_mode modes[MAX_RECOG_OPERANDS];
char subreg_changes_size[MAX_RECOG_OPERANDS];
rtx set, note;
int i, j;
if (code == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));
return insn;
}
if (GET_RTX_CLASS (code) != 'i')
return insn;
pat_code = GET_CODE (PATTERN (insn));
if (pat_code == USE
|| pat_code == CLOBBER
|| pat_code == ASM_INPUT
|| pat_code == ADDR_VEC
|| pat_code == ADDR_DIFF_VEC)
return insn;
set = single_set (insn);
extract_insn (insn);
for (i = 0; i < recog_n_operands; i++)
{
constraints[i] = recog_constraints[i];
modes[i] = recog_operand_mode[i];
}
memset (subreg_changes_size, 0, sizeof (subreg_changes_size));
if (set != 0 && GET_CODE (SET_DEST (set)) == REG
&& GET_CODE (SET_SRC (set)) == MEM
&& (note = find_reg_note (insn, REG_EQUIV,
NULL_RTX)) != 0
&& GET_CODE (XEXP (note, 0)) == MEM)
{
costs[REGNO (SET_DEST (set))].mem_cost
-= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
GENERAL_REGS, 1)
* loop_cost);
record_address_regs (XEXP (SET_SRC (set), 0),
BASE_REG_CLASS, loop_cost * 2);
return insn;
}
if (pass == 0 && optimize
&& recog_n_operands >= 3
&& recog_constraints[1][0] == '0'
&& recog_constraints[1][1] == 0
&& CONSTANT_P (recog_operand[1])
&& ! rtx_equal_p (recog_operand[0], recog_operand[1])
&& ! rtx_equal_p (recog_operand[0], recog_operand[2])
&& GET_CODE (recog_operand[0]) == REG
&& MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
recog_operand_mode[1]))
{
rtx previnsn = prev_real_insn (insn);
rtx dest
= gen_lowpart (recog_operand_mode[1],
recog_operand[0]);
rtx newinsn
= emit_insn_before (gen_move_insn (dest,
recog_operand[1]),
insn);
if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
{
int b;
for (b = 0; b < n_basic_blocks; b++)
if (insn == BLOCK_HEAD (b))
BLOCK_HEAD (b) = newinsn;
}
REG_N_SETS (REGNO (recog_operand[0]))++;
*recog_operand_loc[1] = recog_operand[0];
for (i = recog_n_dups - 1; i >= 0; i--)
if (recog_dup_num[i] == 1)
*recog_dup_loc[i] = recog_operand[0];
return PREV_INSN (newinsn);
}
for (i = 0; i < recog_n_operands; i++)
{
op_costs[i] = init_cost;
if (GET_CODE (recog_operand[i]) == SUBREG)
{
rtx inner = SUBREG_REG (recog_operand[i]);
if (GET_MODE_SIZE (modes[i]) != GET_MODE_SIZE (GET_MODE (inner)))
subreg_changes_size[i] = 1;
recog_operand[i] = inner;
}
if (GET_CODE (recog_operand[i]) == MEM)
record_address_regs (XEXP (recog_operand[i], 0),
BASE_REG_CLASS, loop_cost * 2);
else if (constraints[i][0] == 'p')
record_address_regs (recog_operand[i],
BASE_REG_CLASS, loop_cost * 2);
}
for (i = 0; i < recog_n_operands - 1; i++)
if (constraints[i][0] == '%')
{
const char *xconstraints[MAX_RECOG_OPERANDS];
int j;
for (j = 0; j < recog_n_operands; j++)
xconstraints[j] = constraints[j];
xconstraints[i] = constraints[i+1];
xconstraints[i+1] = constraints[i];
record_reg_classes (recog_n_alternatives, recog_n_operands,
recog_operand, modes, subreg_changes_size,
xconstraints, insn);
}
record_reg_classes (recog_n_alternatives, recog_n_operands, recog_operand,
modes, subreg_changes_size, constraints, insn);
for (i = 0; i < recog_n_operands; i++)
if (GET_CODE (recog_operand[i]) == REG
&& REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (recog_operand[i]);
struct costs *p = &costs[regno], *q = &op_costs[i];
p->mem_cost += q->mem_cost * loop_cost;
for (j = 0; j < N_REG_CLASSES; j++)
p->cost[j] += q->cost[j] * loop_cost;
}
return insn;
}
void
regclass (f, nregs)
rtx f;
int nregs;
{
#ifdef REGISTER_CONSTRAINTS
register rtx insn;
register int i;
int pass;
#if defined (FORBIDDEN_INC_DEC_CLASSES) && defined (hppa) && !defined (NEXT_PDO)
static int init_forbidden = FALSE;
#endif
init_recog ();
costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = (char *) alloca (nregs);
#if defined (hppa) && !defined (NEXT_PDO)
if (! init_forbidden ) {
init_forbidden = TRUE;
#endif
for (i = 0; i < N_REG_CLASSES; i++)
{
rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
register int j;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
{
REGNO (r) = j;
for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE;
m = (enum machine_mode) ((int) m + 1))
if (HARD_REGNO_MODE_OK (j, m))
{
PUT_MODE (r, m);
if ((0
#ifdef SECONDARY_RELOAD_CLASS
|| (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
!= NO_REGS)
#else
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
!= NO_REGS)
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
!= NO_REGS)
#endif
#endif
)
&& ! auto_inc_dec_reg_p (r, m))
forbidden_inc_dec_class[i] = 1;
}
}
}
#if defined (hppa) && !defined (NEXT_PDO)
}
#endif
#endif
for (pass = 0; pass <= flag_expensive_optimizations; pass++)
{
bzero ((char *) costs, nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
bzero (in_inc_dec, nregs);
#endif
loop_depth = 0, loop_cost = 1;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
insn = scan_one_insn (insn, pass);
}
if (pass == 0)
{
prefclass = prefclass_buffer;
altclass = altclass_buffer;
}
for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
{
register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
enum reg_class best = ALL_REGS, alt = NO_REGS;
register int class;
register struct costs *p = &costs[i];
for (class = (int) ALL_REGS - 1; class > 0; class--)
{
if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))
> reg_class_size[class]
#ifdef FORBIDDEN_INC_DEC_CLASSES
|| (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
)
;
else if (p->cost[class] < best_cost)
{
best_cost = p->cost[class];
best = (enum reg_class) class;
}
else if (p->cost[class] == best_cost)
best = reg_class_subunion[(int)best][class];
}
if (pass == 1 || ! flag_expensive_optimizations)
for (class = 0; class < N_REG_CLASSES; class++)
if (p->cost[class] < p->mem_cost
&& (reg_class_size[(int) reg_class_subunion[(int) alt][class]]
> reg_class_size[(int) alt])
#ifdef FORBIDDEN_INC_DEC_CLASSES
&& ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
)
alt = reg_class_subunion[(int) alt][class];
if (alt == best)
alt = NO_REGS;
prefclass[i] = (int) best;
altclass[i] = (int) alt;
}
}
#endif
free (costs);
}
#ifdef REGISTER_CONSTRAINTS
static void
record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
constraints, insn)
int n_alts;
int n_ops;
rtx *ops;
enum machine_mode *modes;
char *subreg_changes_size;
const char **constraints;
rtx insn;
{
int alt;
int i, j;
rtx set;
for (alt = 0; alt < n_alts; alt++)
{
struct costs this_op_costs[MAX_RECOG_OPERANDS];
int alt_fail = 0;
int alt_cost = 0;
enum reg_class classes[MAX_RECOG_OPERANDS];
int class;
for (i = 0; i < n_ops; i++)
{
const char *p = constraints[i];
rtx op = ops[i];
enum machine_mode mode = modes[i];
int allows_addr = 0;
int allows_mem = 0;
int win = 0;
unsigned char c;
classes[i] = NO_REGS;
if (*p == 0)
{
if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
bzero ((char *) &this_op_costs[i], sizeof this_op_costs[i]);
continue;
}
while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
p++;
if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
{
j = p[0] - '0';
classes[i] = classes[j];
if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER)
{
if (rtx_equal_p (ops[j], op))
win = 1;
else if (classes[j] != NO_REGS)
alt_cost += copy_cost (op, mode, classes[j], 1), win = 1;
}
else if (GET_CODE (ops[j]) != REG
|| REGNO (ops[j]) < FIRST_PSEUDO_REGISTER)
{
if (classes[j] == NO_REGS)
alt_fail = 1;
else
alt_cost += copy_cost (ops[j], mode, classes[j], 1);
}
else
{
this_op_costs[i] = this_op_costs[j];
if (REGNO (ops[i]) != REGNO (ops[j])
&& ! find_reg_note (insn, REG_DEAD, op))
alt_cost += 2;
while (*p && *p++ != ',')
;
constraints[i] = p;
continue;
}
}
while (*p && (c = *p++) != ',')
switch (c)
{
case '*':
p++;
break;
case '?':
alt_cost += 2;
case '!': case '#': case '&':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
break;
case 'p':
allows_addr = 1;
win = address_operand (op, GET_MODE (op));
classes[i]
= reg_class_subunion[(int) classes[i]]
[(int) BASE_REG_CLASS];
break;
case 'm': case 'o': case 'V':
allows_mem = 1;
if (GET_CODE (op) == MEM)
win = 1;
break;
case '<':
if (GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == PRE_DEC
|| GET_CODE (XEXP (op, 0)) == POST_DEC))
win = 1;
break;
case '>':
if (GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == PRE_INC
|| GET_CODE (XEXP (op, 0)) == POST_INC))
win = 1;
break;
case 'E':
#ifndef REAL_ARITHMETIC
if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
|| HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
&& GET_MODE (op) != VOIDmode && ! flag_pretend_float)
break;
#endif
if (GET_CODE (op) == CONST_DOUBLE)
win = 1;
break;
case 'F':
if (GET_CODE (op) == CONST_DOUBLE)
win = 1;
break;
case 'G':
case 'H':
if (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
win = 1;
break;
case 's':
if (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
break;
case 'i':
if (CONSTANT_P (op)
#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
#endif
)
win = 1;
break;
case 'n':
if (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
win = 1;
break;
#ifdef EXTRA_CONSTANT_CONSTRAINTS
case 'A':
case 'B':
case 'C':
case 'D':
#endif
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
if (GET_CODE (op) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (op), c))
win = 1;
break;
case 'X':
win = 1;
break;
#ifdef EXTRA_CONSTRAINT
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
if (EXTRA_CONSTRAINT (op, c))
win = 1;
break;
#endif
case 'g':
if (GET_CODE (op) == MEM
|| (CONSTANT_P (op)
#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
#endif
))
win = 1;
allows_mem = 1;
case 'r':
classes[i]
= reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
break;
default:
classes[i]
= reg_class_subunion[(int) classes[i]]
[(int) REG_CLASS_FROM_LETTER (c)];
}
constraints[i] = p;
#ifdef CLASS_CANNOT_CHANGE_SIZE
if (subreg_changes_size[i]
&& (reg_class_subunion[(int) CLASS_CANNOT_CHANGE_SIZE]
[(int) classes[i]]
== CLASS_CANNOT_CHANGE_SIZE))
classes[i] = NO_REGS;
#endif
if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
{
if (classes[i] == NO_REGS)
{
alt_fail = 1;
}
else
{
struct costs *pp = &this_op_costs[i];
for (class = 0; class < N_REG_CLASSES; class++)
pp->cost[class] = may_move_cost[class][(int) classes[i]];
pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1)
- allows_mem);
if (prefclass)
alt_cost
+= may_move_cost[(unsigned char)prefclass[REGNO (op)]][(int) classes[i]];
}
}
else if (win
|| (GET_CODE (op) == REG
&& reg_fits_class_p (op, classes[i], 0, GET_MODE (op))))
;
else if (classes[i] != NO_REGS)
{
if (recog_op_type[i] != OP_OUT)
alt_cost += copy_cost (op, mode, classes[i], 1);
if (recog_op_type[i] != OP_IN)
alt_cost += copy_cost (op, mode, classes[i], 0);
}
else if (CONSTANT_P (op) && (allows_addr || allows_mem))
alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
else
alt_fail = 1;
}
if (alt_fail)
continue;
for (i = 0; i < n_ops; i++)
if (GET_CODE (ops[i]) == REG
&& REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
{
struct costs *pp = &op_costs[i], *qq = &this_op_costs[i];
int scale = 1 + (recog_op_type[i] == OP_INOUT);
pp->mem_cost = MIN (pp->mem_cost,
(qq->mem_cost + alt_cost) * scale);
for (class = 0; class < N_REG_CLASSES; class++)
pp->cost[class] = MIN (pp->cost[class],
(qq->cost[class] + alt_cost) * scale);
}
}
if ((set = single_set (insn)) != 0
&& ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
&& GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG)
for (i = 0; i <= 1; i++)
if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (ops[!i]);
enum machine_mode mode = GET_MODE (ops[!i]);
int class;
int nr;
if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0
&& (reg_class_size[(unsigned char)prefclass[regno]]
== CLASS_MAX_NREGS (prefclass[regno], mode)))
op_costs[i].cost[(unsigned char)prefclass[regno]] = -1;
else if (regno < FIRST_PSEUDO_REGISTER)
for (class = 0; class < N_REG_CLASSES; class++)
if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
&& reg_class_size[class] == CLASS_MAX_NREGS (class, mode))
{
if (reg_class_size[class] == 1)
op_costs[i].cost[class] = -1;
else
{
for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
{
if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
break;
}
if (nr == HARD_REGNO_NREGS(regno,mode))
op_costs[i].cost[class] = -1;
}
}
}
}
static int
copy_cost (x, mode, class, to_p)
rtx x;
enum machine_mode mode;
enum reg_class class;
int to_p;
{
#ifdef HAVE_SECONDARY_RELOADS
enum reg_class secondary_class = NO_REGS;
#endif
if (GET_CODE (x) == SCRATCH)
return 0;
class = PREFERRED_RELOAD_CLASS (x, class);
#ifdef HAVE_SECONDARY_RELOADS
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (to_p == 1)
secondary_class = SECONDARY_INPUT_RELOAD_CLASS (class, mode, x);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (! to_p)
secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x);
#endif
if (secondary_class != NO_REGS)
return (move_cost[(int) secondary_class][(int) class]
+ copy_cost (x, mode, secondary_class, 2));
#endif
if (GET_CODE (x) == MEM || class == NO_REGS)
return MEMORY_MOVE_COST (mode, class, to_p);
else if (GET_CODE (x) == REG)
return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
else
return 2;
}
static void
record_address_regs (x, class, scale)
rtx x;
enum reg_class class;
int scale;
{
register enum rtx_code code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST:
case CC0:
case PC:
case SYMBOL_REF:
case LABEL_REF:
return;
case PLUS:
{
rtx arg0 = XEXP (x, 0);
rtx arg1 = XEXP (x, 1);
register enum rtx_code code0 = GET_CODE (arg0);
register enum rtx_code code1 = GET_CODE (arg1);
if (code0 == SUBREG)
arg0 = SUBREG_REG (arg0), code0 = GET_CODE (arg0);
if (code1 == SUBREG)
arg1 = SUBREG_REG (arg1), code1 = GET_CODE (arg1);
if (MAX_REGS_PER_ADDRESS == 1)
record_address_regs (arg0, class, scale);
else if (INDEX_REG_CLASS == BASE_REG_CLASS)
{
record_address_regs (arg0, class, scale);
if (! CONSTANT_P (arg1))
record_address_regs (arg1, class, scale);
}
else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
record_address_regs (arg0, class, scale);
else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
record_address_regs (arg0, INDEX_REG_CLASS, scale);
#ifdef REG_OK_FOR_BASE_P
else if (code0 == REG && code1 == REG
&& REGNO (arg0) < FIRST_PSEUDO_REGISTER
&& (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0)))
record_address_regs (arg1,
REG_OK_FOR_BASE_P (arg0)
? INDEX_REG_CLASS : BASE_REG_CLASS,
scale);
else if (code0 == REG && code1 == REG
&& REGNO (arg1) < FIRST_PSEUDO_REGISTER
&& (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1)))
record_address_regs (arg0,
REG_OK_FOR_BASE_P (arg1)
? INDEX_REG_CLASS : BASE_REG_CLASS,
scale);
#endif
else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0)))
|| code1 == MULT)
{
record_address_regs (arg0, BASE_REG_CLASS, scale);
record_address_regs (arg1, INDEX_REG_CLASS, scale);
}
else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1)))
|| code0 == MULT)
{
record_address_regs (arg0, INDEX_REG_CLASS, scale);
record_address_regs (arg1, BASE_REG_CLASS, scale);
}
else
{
record_address_regs (arg0, BASE_REG_CLASS, scale / 2);
record_address_regs (arg0, INDEX_REG_CLASS, scale / 2);
record_address_regs (arg1, BASE_REG_CLASS, scale / 2);
record_address_regs (arg1, INDEX_REG_CLASS, scale / 2);
}
}
break;
case POST_INC:
case PRE_INC:
case POST_DEC:
case PRE_DEC:
#ifdef FORBIDDEN_INC_DEC_CLASSES
if (GET_CODE (XEXP (x, 0)) == REG
&& REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
in_inc_dec[REGNO (XEXP (x, 0))] = 1;
#endif
record_address_regs (XEXP (x, 0), class, 2 * scale);
break;
case REG:
{
register struct costs *pp = &costs[REGNO (x)];
register int i;
pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
for (i = 0; i < N_REG_CLASSES; i++)
pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2;
}
break;
default:
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
record_address_regs (XEXP (x, i), class, scale);
}
}
}
#ifdef FORBIDDEN_INC_DEC_CLASSES
static int
auto_inc_dec_reg_p (reg, mode)
rtx reg;
enum machine_mode mode;
{
if (HAVE_POST_INCREMENT
&& memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
return 1;
if (HAVE_POST_DECREMENT
&& memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
return 1;
if (HAVE_PRE_INCREMENT
&& memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
return 1;
if (HAVE_PRE_DECREMENT
&& memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
return 1;
return 0;
}
#endif
#endif
static short *renumber = (short *)0;
static size_t regno_allocated = 0;
void
allocate_reg_info (num_regs, new_p, renumber_p)
size_t num_regs;
int new_p;
int renumber_p;
{
size_t size_info;
size_t size_renumber;
size_t min = (new_p) ? 0 : reg_n_max;
struct reg_info_data *reg_data;
struct reg_info_data *reg_next;
if (num_regs > regno_allocated)
{
size_t old_allocated = regno_allocated;
regno_allocated = num_regs + (num_regs / 20);
size_renumber = regno_allocated * sizeof (short);
if (!reg_n_info)
{
VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info");
renumber = (short *) xmalloc (size_renumber);
prefclass_buffer = (char *) xmalloc (regno_allocated);
altclass_buffer = (char *) xmalloc (regno_allocated);
}
else
{
VARRAY_GROW (reg_n_info, regno_allocated);
if (new_p)
{
free ((char *)renumber);
free ((char *)prefclass_buffer);
free ((char *)altclass_buffer);
renumber = (short *) xmalloc (size_renumber);
prefclass_buffer = (char *) xmalloc (regno_allocated);
altclass_buffer = (char *) xmalloc (regno_allocated);
}
else
{
renumber = (short *) xrealloc ((char *)renumber, size_renumber);
prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer,
regno_allocated);
altclass_buffer = (char *) xrealloc ((char *)altclass_buffer,
regno_allocated);
}
}
size_info = (regno_allocated - old_allocated) * sizeof (reg_info)
+ sizeof (struct reg_info_data) - sizeof (reg_info);
reg_data = (struct reg_info_data *) xcalloc (size_info, 1);
reg_data->min_index = old_allocated;
reg_data->max_index = regno_allocated - 1;
reg_data->next = reg_info_head;
reg_info_head = reg_data;
}
reg_n_max = num_regs;
if (min < num_regs)
{
for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
{
size_t min_index = reg_data->min_index;
size_t max_index = reg_data->max_index;
reg_next = reg_data->next;
if (min <= max_index)
{
size_t max = max_index;
size_t local_min = min - min_index;
size_t i;
if (min < min_index)
local_min = 0;
if (!reg_data->used_p)
reg_data->used_p = 1;
else
bzero ((char *) ®_data->data[local_min],
sizeof (reg_info) * (max - min_index - local_min + 1));
for (i = min_index+local_min; i <= max; i++)
{
VARRAY_REG (reg_n_info, i) = ®_data->data[i-min_index];
REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
renumber[i] = -1;
prefclass_buffer[i] = (char) NO_REGS;
altclass_buffer[i] = (char) NO_REGS;
}
}
}
}
if (prefclass)
{
prefclass = prefclass_buffer;
altclass = altclass_buffer;
}
if (renumber_p)
reg_renumber = renumber;
MAX_REGNO_REG_SET (num_regs, new_p, renumber_p);
}
void
free_reg_info ()
{
if (reg_n_info)
{
struct reg_info_data *reg_data;
struct reg_info_data *reg_next;
VARRAY_FREE (reg_n_info);
for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
{
reg_next = reg_data->next;
free ((char *)reg_data);
}
free (prefclass_buffer);
free (altclass_buffer);
prefclass_buffer = (char *)0;
altclass_buffer = (char *)0;
reg_info_head = (struct reg_info_data *)0;
renumber = (short *)0;
}
regno_allocated = 0;
reg_n_max = 0;
}
int max_parallel;
void
reg_scan (f, nregs, repeat)
rtx f;
int nregs;
int repeat;
{
register rtx insn;
allocate_reg_info (nregs, TRUE, FALSE);
max_parallel = 3;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN
|| GET_CODE (insn) == CALL_INSN
|| GET_CODE (insn) == JUMP_INSN)
{
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& XVECLEN (PATTERN (insn), 0) > max_parallel)
max_parallel = XVECLEN (PATTERN (insn), 0);
reg_scan_mark_refs (PATTERN (insn), insn, 0, 0);
if (REG_NOTES (insn))
reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
}
}
void
reg_scan_update(first, last, old_max_regno)
rtx first;
rtx last;
int old_max_regno;
{
register rtx insn;
allocate_reg_info (max_reg_num (), FALSE, FALSE);
for (insn = first; insn != last; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN
|| GET_CODE (insn) == CALL_INSN
|| GET_CODE (insn) == JUMP_INSN)
{
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& XVECLEN (PATTERN (insn), 0) > max_parallel)
max_parallel = XVECLEN (PATTERN (insn), 0);
reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno);
if (REG_NOTES (insn))
reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno);
}
}
static void
reg_scan_mark_refs (x, insn, note_flag, min_regno)
rtx x;
rtx insn;
int note_flag;
int min_regno;
{
register enum rtx_code code;
register rtx dest;
register rtx note;
code = GET_CODE (x);
switch (code)
{
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case CC0:
case PC:
case SYMBOL_REF:
case LABEL_REF:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return;
case REG:
{
register int regno = REGNO (x);
if (regno >= min_regno)
{
REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
if (!note_flag)
REGNO_LAST_UID (regno) = INSN_UID (insn);
if (REGNO_FIRST_UID (regno) == 0)
REGNO_FIRST_UID (regno) = INSN_UID (insn);
}
}
break;
case EXPR_LIST:
if (XEXP (x, 0))
reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
if (XEXP (x, 1))
reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case INSN_LIST:
if (XEXP (x, 1))
reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case SET:
for (dest = SET_DEST (x);
GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTEND;
dest = XEXP (dest, 0))
;
if (GET_CODE (dest) == REG
&& REGNO (dest) >= min_regno)
REG_N_SETS (REGNO (dest))++;
if (GET_CODE (SET_DEST (x)) == REG
&& REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
&& REGNO (SET_DEST (x)) >= min_regno
&& REG_N_SETS (REGNO (SET_DEST (x))) == 1
&& ! REG_USERVAR_P (SET_DEST (x))
&& ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
&& ((GET_CODE (SET_SRC (x)) == REG
&& REGNO_POINTER_FLAG (REGNO (SET_SRC (x))))
|| ((GET_CODE (SET_SRC (x)) == PLUS
|| GET_CODE (SET_SRC (x)) == LO_SUM)
&& GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& GET_CODE (XEXP (SET_SRC (x), 0)) == REG
&& REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0))))
|| GET_CODE (SET_SRC (x)) == CONST
|| GET_CODE (SET_SRC (x)) == SYMBOL_REF
|| GET_CODE (SET_SRC (x)) == LABEL_REF
|| (GET_CODE (SET_SRC (x)) == HIGH
&& (GET_CODE (XEXP (SET_SRC (x), 0)) == CONST
|| GET_CODE (XEXP (SET_SRC (x), 0)) == SYMBOL_REF
|| GET_CODE (XEXP (SET_SRC (x), 0)) == LABEL_REF))
|| ((GET_CODE (SET_SRC (x)) == PLUS
|| GET_CODE (SET_SRC (x)) == LO_SUM)
&& (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST
|| GET_CODE (XEXP (SET_SRC (x), 1)) == SYMBOL_REF
|| GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF))
|| ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
&& (GET_CODE (XEXP (note, 0)) == CONST
|| GET_CODE (XEXP (note, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (note, 0)) == LABEL_REF))))
REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
default:
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
else if (fmt[i] == 'E' && XVEC (x, i) != 0)
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
}
}
}
}
}
int
reg_class_subset_p (c1, c2)
register enum reg_class c1;
register enum reg_class c2;
{
if (c1 == c2) return 1;
if (c2 == ALL_REGS)
win:
return 1;
GO_IF_HARD_REG_SUBSET (reg_class_contents[(int)c1],
reg_class_contents[(int)c2],
win);
return 0;
}
int
reg_classes_intersect_p (c1, c2)
register enum reg_class c1;
register enum reg_class c2;
{
#ifdef HARD_REG_SET
register
#endif
HARD_REG_SET c;
if (c1 == c2) return 1;
if (c1 == ALL_REGS || c2 == ALL_REGS)
return 1;
COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]);
AND_HARD_REG_SET (c, reg_class_contents[(int) c2]);
GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose);
return 1;
lose:
return 0;
}
void
regset_release_memory ()
{
bitmap_release_memory ();
}