Files
mercury/runtime/mercury_regs.c
Zoltan Somogyi 8190c16181 Get Mercury to work with gcc 3.4. This required fixing several problems.
Estimated hours taken: 16
Branches: main

Get Mercury to work with gcc 3.4. This required fixing several problems.

One problem that caused errors is that gcc 3.4 is smart enough to figure out
that in LLDS grades with gcc gotos, the C functions containing our code are
not referred to, and so it optimizes them away. The fix is to ensure that
mercury_<module>_init is defined always to call those functions, even if
the macro that usually controls this, MR_MAY_NEED_INITIALIZATION, is not
defined. The mercury_<module>_init won't be called from the init_modules
function in the program's _init.c file, so there is no impact on initialization
time, but gcc doesn't know this when compiling a module's .c file, so
it doesn't optimize away the code we need. The cost of this change is thus
only a small amount of code space. It is worth paying this cost even with
compilers other than gcc 3.4 for simplicity. Actually, this size increase seems
to be slightly smaller than the size reduction due to the better optimization
capabilities of gcc 3.4 compared to gcc 3.2.2.

A second problem is that gcc 3.4 warns about casts in lvalues being a
deprecated feature. This gave lots of warnings, since we used to define
several Mercury abstract machine registers, including MR_succip, MR_hp, MR_sp,
MR_maxfr and MR_curfr using lvalue casts. The fix is to have two macros
for each of these abstract machine registers, one of type MR_Word that you can
assign to (e.g. MR_sp_word), and one of the original type that is of the right
type but not an lvalue (e.g. MR_sp). The lvalue itself can't be made the right
type, because MR_sp isn't a variable in its own right, but possibly defined
to be a machine register. The machine register could made the right type,
but only at the cost of a lot of complexity.

This problem doesn't apply to the special-purpose Mercury abstract machine
registers that can't be allocated to machine registers. Instead of #defining
these to slots in MR_fake_reg, we make them global variables of the natural
type. This should also make it easier to debug code using these registers.
We treat these global variables as if they were machine registers in that
MR_save_registers copies values from these global variables to slots reserved
for them in the MR_fake_reg array, to allow code to loop over all Mercury
abstract machine registers. These saved slots must of course be of type
MR_Word, so we again need two macros to refer to them, a lvalue of type
MR_Word and an rvalue with the right type.

A third problem is that gcc 3.4 warns about conditionals in lvalues being a
deprecated feature. This gave a few warnings, since we used to define
MR_virtual_reg and MR_saved_reg using lvalues using conditionals. The fix
is to have one macro (MR_virtual_reg_value) for use in rvalues and a
separate macro which uses an if-then-else instead of a conditional
expression (MR_virtual_reg_assign), for assignments.

A fourth problem is that gcc 3.4 warns about comma operators in lvalues
being a deprecated feature. This gave warnings in the few places where
we refer to MR_r(N) for values of N that can map to fake registers directly,
since in those cases we preceded the reference to the fake_reg array with
a range check of the array index. The fix to this is to move the test to
compile time for compiler-generated code. Hand-written code never refers
to MR_r(N) for these values, and is very unlikely to do so in the future;
instead, it refers to the underlying fake_reg array directly, since that way
it doesn't have to worry about which fake registers have their own MR_rN macro
and which don't. Therefore no check mechanism for hand-written code is
necessary. This change mean that changing the number of MR_rN registers
now requires change to the compiler as well as to the runtime system.

A fifth problem is that gcc 3.4 by default assumes -fstrict-aliasing at -O2.
Since we cast between integers and pointers of different types all the time,
and changing that is not practical, at least in the short term, we need to
disable -fstrict-aliasing when we enable -O2.

NEWS:
	Note that Mercury now works with gcc 3.4.

configure.in:
scripts/mgnuc.in:
	Detect whether the compiler supports -fstrict-aliasing, and if so,
	whether it assumes it by default with -O2. If the answer is yes to
	both, make mgnuc specify -fno-strict-aliasing when it specifies -O2.
	By including it in CFLAGS_FOR_OPT, which gets put into Mercury.config,
	we also get -f-no-strict-aliasing when mmc invokes the C compiler
	directly.

compiler/llds_out.m:
	Don't generate #ifdef MR_MAY_NEED_INITIALIZATION around the definitions
	and calls to the bunch functions, which call the functions we don't
	want the C compiler to optimize away.

	Generate the newly required lvalues on the left sides of assignments.

	We still have code to generate LVALUE_CASTs in some cases, but I don't
	think those cases ever arise.

	Add a compile-time check of register numbers. Ideally, the code
	generator should use stack slots instead of registers beyond the max
	number, but I don't recall us ever bumping into this limit by accident.

compiler/fact_table.m:
	Use the newly required lvalues on the left sides of assignments
	in some hand-written C code included in generated .c files.

runtime/mercury_regs.h:
	Make the changes described above to fix the second, third and fourth
	problems. We still use comma operators in lvalues when counting
	references to registers, but it is OK to require anyone who wants
	to enable this feature to use a compiler version that supports comma
	operators in lvalues or to ignore the warnings.

	Use the same mapping from Mercury abstract machine registers to
	the register count array as to the MR_fake_reg array.

	Have this mapping depend as little as possible on whether we need a
	real machine register to store MR_engine base, even if it costs a
	wasted slot in MR_fake_reg.

	Fix an old inconsistency: treat the Mercury abstract machine registers
	used for trailing the same way as the other Mercury abstract machine
	registers, by making MR_save_registers/MR_restore_registers copy them
	to and from their global variable homes.

	Document the requirement for the match between the runtime's and the
	compiler's notions of the maximum MR_rN register number. This
	requirement makes it harder for users to increase the number of
	virtual registers, but as far as I know noone has wanted to do this.

	Change the names of some of the macros to make them clearer.

	Reorder some parts of this file, and add some documentation, also
	in the interest of clarity.

runtime/mercury_regorder.h:
	Delete this file after moving its contents, in much modified form,
	to mercury_regs.h. mercury_regorder.h was always logically part of
	mercury_regs.h, but was separated out to make it easier to change
	the mapping from Mercury abstract machine registers to machine
	registers. However, the cost of incompatibility caused by any such
	changes would be much greater that any likely performance benefit.

runtime/Mmakefile:
	Remove the reference to mercury_regorder.h.

runtime/mercury_regs.[ch]:
runtime/mercury_memory_zones.[ch]:
	Move some functionality dealing with registers from
	mercury_memory_zones to mercury_regs, since it belongs there.

runtime/mercury_regs.[ch]:
	Add a function to make it easiler to debug changes to map from
	Mercury abstract machine to MR_fake_reg slots.

runtime/mercury_regs.[ch]:
runtime/mercury_wrapper.c:
	Move the code to print counts of register uses from mercury_wrapper.c
	to mercury_regs.c.

	Make mercury_wrapper.c call the debugging function in mercury_regs.c
	if -X is specified in MERCURY_OPTIONS.

runtime/mercury_bootstrap.h:
	Move the old MR_saved_reg and MR_virtual_reg macros from mercury_regs.h
	to mercury_bootstrap.h to prevent their accidental use. Since
	they shouldn't be used by user code, move them to the section
	that is not enabled by default.

runtime/mercury_stacks.[ch]:
	Add _word versions of the macros for stack slots, for the same reason
	why we need them for Mercury abstract machine registers, and use them.

	Add global variables for the Mercury abstract machine registers
	for the gen, cut and pneg stacks.

runtime/mercury_heap.h:
	Change the macros for allocating memory to assign to MR_hp_word instead
	of MR_hp.

runtime/mercury_string.h:
	Change the macros for allocating strings to accomodate the updates to
	mercury_heap.h. Also change the expected type of the target to make it
	MR_String instead of MR_ConstString, since the latter requires casts in
	the caller.

runtime/mercury_trail.h:
runtime/mercury_types.h:
	Move the definition of the type MR_TrailEntry from mercury_trail.h
	to mercury_types.h, since it is now used in mercury_regs.h.

runtime/mercury_accurate_gc.c:
runtime/mercury_agc_debug.c:
runtime/mercury_calls.h:
runtime/mercury_context.[ch]:
runtime/mercury_deconstruct_macros.h:
runtime/mercury_deep_copy_body.h:
runtime/mercury_engine.[ch]:
runtime/mercury_hand_compare_body.h:
runtime/mercury_hand_unify_body.h:
runtime/mercury_ho_call.c:
runtime/mercury_layout_util.c:
runtime/mercury_make_type_info_body.h:
runtime/mercury_minimal_model.c:
runtime/mercury_ml_deconstruct_body.h:
runtime/mercury_ml_functor_body.h:
runtime/mercury_stack_layout.h:
runtime/mercury_type_desc.c:
runtime/mercury_type_info.c:
runtime/mercury_unify_compare_body.h:
runtime/mercury_wrapper.c:
	Conform to the changes in the rest of the runtime.

	In some cases, fix inconsistencies in indentation.

runtime/mercury_stack_trace.c:
	Add some conditionally compiled debugging code controlled by the macro
	MR_ADDR_DEBUG, to help debug some problems with stored stack pointers.

runtime/mercury_grade.h:
	Increment the binary compatibility version number. This is needed to
	avoid potential problems when a Mercury module and the debugger are
	compiled with different versions of the macros in mercury_regs.h.

library/exception.m:
	Update the code that assigns to abstract machine registers.

library/array.m:
library/construct.m:
library/dir.m:
library/io.m:
library/string.m:
	Conform to the new definitions of allocation macros.

library/time.m:
	Delete an unnecessary #include.

trace/mercury_trace.c:
trace/mercury_trace_declarative.c:
trace/mercury_trace_util.c:
	Conform to the changes in the rest of the runtime.

tests/hard_coded/qual_test_is_imported.m:
tests/hard_coded/aditi_private_builtin.m:
	Remove an unnecessary import to avoid a warning.

tools/makebatch:
	Add an option --save-stage2-on-error, that saves the stage2 directory
	if a bootcheck fails.

scripts/ml.in:
	Make ml more robust in the face of garbage files.
2004-07-07 07:11:22 +00:00

225 lines
7.2 KiB
C

/*
** Copyright (C) 1997, 2000-2001, 2004 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
#include "mercury_imp.h"
#include "mercury_regs.h"
#include <stdio.h>
MR_Word *MR_sol_hp_var = NULL;
MR_Word *MR_min_hp_rec_var = NULL;
MR_Word *MR_min_sol_hp_rec_var = NULL;
MR_Word *MR_global_hp_var = NULL;
MR_Word MR_real_r_reg_map[MR_MAX_REAL_R_REG] = MR_REAL_R_REG_MAP_BODY;
unsigned long MR_num_uses[MR_MAX_REAL_R_REG + MR_NUM_SPECIAL_REG];
#ifdef MR_MEASURE_REGISTER_USAGE
#define MR_COUNT_FORMAT "\t%lu\n"
void
MR_print_register_usage_counts(void)
{
int i;
printf("register usage counts:\n");
for (i = 1; i <= MR_MAX_REAL_R_REG; i++) {
printf("r%d", i);
printf(MR_COUNT_FORMAT, MR_num_uses[MR_R_SLOT(i)]);
}
printf("MR_succip");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_SI_SLOT]);
printf("MR_hp");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_HP_SLOT]);
printf("MR_sp");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_SP_SLOT]);
printf("MR_curfr");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_CF_SLOT]);
printf("MR_maxfr");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_MF_SLOT]);
printf("MR_trail_ptr");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_TRAIL_PTR_SLOT]);
printf("MR_ticket_counter");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_TICKET_COUNTER_SLOT]);
printf("MR_ticket_high_water");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_TICKET_HIGH_WATER_SLOT]);
printf("MR_sol_hp");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_SOL_HP_SLOT]);
printf("MR_min_hp_rec");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_MIN_HP_REC_SLOT]);
printf("MR_min_sol_hp_rec");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_MIN_SOL_HP_REC_SLOT]);
printf("MR_global_hp");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_GLOBAL_HP_SLOT]);
printf("MR_gen_next");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_GEN_NEXT_SLOT]);
printf("MR_gen_stack");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_GEN_STACK_SLOT]);
printf("MR_cut_next");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_CUT_NEXT_SLOT]);
printf("MR_cut_stack");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_CUT_STACK_SLOT]);
printf("MR_pneg_next");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_PNEG_NEXT_SLOT]);
printf("MR_pneg_stack");
printf(MR_COUNT_FORMAT, MR_num_uses[MR_PNEG_STACK_SLOT]);
}
#endif /* MR_MEASURE_REGISTER_USAGE */
#ifdef MR_VERIFY_FAKE_REGISTERS
#define MR_VERIFY_FORMAT "\t%d\n"
void
MR_verify_fake_registers(void)
{
int i;
printf("register slots:\n");
for (i = 1; i <= MR_MAX_REAL_R_REG; i++) {
printf("r%d", i);
printf(MR_VERIFY_FORMAT, MR_R_SLOT(i));
}
printf("r%d", MR_MAX_REAL_R_REG + 1);
printf(MR_VERIFY_FORMAT, MR_MAX_REAL_R_REG + MR_NUM_SPECIAL_REG);
printf("MR_succip");
printf(MR_VERIFY_FORMAT, MR_SI_SLOT);
printf("MR_hp");
printf(MR_VERIFY_FORMAT, MR_HP_SLOT);
printf("MR_sp");
printf(MR_VERIFY_FORMAT, MR_SP_SLOT);
printf("MR_curfr");
printf(MR_VERIFY_FORMAT, MR_CF_SLOT);
printf("MR_maxfr");
printf(MR_VERIFY_FORMAT, MR_MF_SLOT);
printf("MR_trail_ptr");
printf(MR_VERIFY_FORMAT, MR_TRAIL_PTR_SLOT);
printf("MR_ticket_counter");
printf(MR_VERIFY_FORMAT, MR_TICKET_COUNTER_SLOT);
printf("MR_ticket_high_water");
printf(MR_VERIFY_FORMAT, MR_TICKET_HIGH_WATER_SLOT);
printf("MR_sol_hp");
printf(MR_VERIFY_FORMAT, MR_SOL_HP_SLOT);
printf("MR_min_hp_rec");
printf(MR_VERIFY_FORMAT, MR_MIN_HP_REC_SLOT);
printf("MR_min_sol_hp_rec");
printf(MR_VERIFY_FORMAT, MR_MIN_SOL_HP_REC_SLOT);
printf("MR_global_hp");
printf(MR_VERIFY_FORMAT, MR_GLOBAL_HP_SLOT);
printf("MR_gen_next");
printf(MR_VERIFY_FORMAT, MR_GEN_NEXT_SLOT);
printf("MR_gen_stack");
printf(MR_VERIFY_FORMAT, MR_GEN_STACK_SLOT);
printf("MR_cut_next");
printf(MR_VERIFY_FORMAT, MR_CUT_NEXT_SLOT);
printf("MR_cut_stack");
printf(MR_VERIFY_FORMAT, MR_CUT_STACK_SLOT);
printf("MR_pneg_next");
printf(MR_VERIFY_FORMAT, MR_PNEG_NEXT_SLOT);
printf("MR_pneg_stack");
printf(MR_VERIFY_FORMAT, MR_PNEG_STACK_SLOT);
}
#endif /* MR_VERIFY_FAKE_REGISTERS */
MR_Word
MR_get_reg(int num)
{
MR_restore_transient_registers();
switch (num) {
case 1: return MR_r1;
case 2: return MR_r2;
case 3: return MR_r3;
case 4: return MR_r4;
case 5: return MR_r5;
case 6: return MR_r6;
case 7: return MR_r7;
case 8: return MR_r8;
case 9: return MR_r9;
case 10: return MR_r10;
case 11: return MR_r11;
case 12: return MR_r12;
case 13: return MR_r13;
case 14: return MR_r14;
case 15: return MR_r15;
case 16: return MR_r16;
case 17: return MR_r17;
case 18: return MR_r18;
case 19: return MR_r19;
case 20: return MR_r20;
case 21: return MR_r21;
case 22: return MR_r22;
case 23: return MR_r23;
case 24: return MR_r24;
case 25: return MR_r25;
case 26: return MR_r26;
case 27: return MR_r27;
case 28: return MR_r28;
case 29: return MR_r29;
case 30: return MR_r30;
case 31: return MR_r31;
case 32: return MR_r32;
}
/* NOTREACHED */
fprintf(stderr, "register %d out of range in get_reg\n", num);
abort();
return 0;
}
MR_Word
MR_set_reg(int num, MR_Word val)
{
MR_restore_transient_registers();
switch (num) {
case 1: MR_r1 = val; MR_save_transient_registers(); return val;
case 2: MR_r2 = val; MR_save_transient_registers(); return val;
case 3: MR_r3 = val; MR_save_transient_registers(); return val;
case 4: MR_r4 = val; MR_save_transient_registers(); return val;
case 5: MR_r5 = val; MR_save_transient_registers(); return val;
case 6: MR_r6 = val; MR_save_transient_registers(); return val;
case 7: MR_r7 = val; MR_save_transient_registers(); return val;
case 8: MR_r8 = val; MR_save_transient_registers(); return val;
case 9: MR_r9 = val; MR_save_transient_registers(); return val;
case 10: MR_r10 = val; MR_save_transient_registers(); return val;
case 11: MR_r11 = val; MR_save_transient_registers(); return val;
case 12: MR_r12 = val; MR_save_transient_registers(); return val;
case 13: MR_r13 = val; MR_save_transient_registers(); return val;
case 14: MR_r14 = val; MR_save_transient_registers(); return val;
case 15: MR_r15 = val; MR_save_transient_registers(); return val;
case 16: MR_r16 = val; MR_save_transient_registers(); return val;
case 17: MR_r17 = val; MR_save_transient_registers(); return val;
case 18: MR_r18 = val; MR_save_transient_registers(); return val;
case 19: MR_r19 = val; MR_save_transient_registers(); return val;
case 20: MR_r20 = val; MR_save_transient_registers(); return val;
case 21: MR_r21 = val; MR_save_transient_registers(); return val;
case 22: MR_r22 = val; MR_save_transient_registers(); return val;
case 23: MR_r23 = val; MR_save_transient_registers(); return val;
case 24: MR_r24 = val; MR_save_transient_registers(); return val;
case 25: MR_r25 = val; MR_save_transient_registers(); return val;
case 26: MR_r26 = val; MR_save_transient_registers(); return val;
case 27: MR_r27 = val; MR_save_transient_registers(); return val;
case 28: MR_r28 = val; MR_save_transient_registers(); return val;
case 29: MR_r29 = val; MR_save_transient_registers(); return val;
case 30: MR_r30 = val; MR_save_transient_registers(); return val;
case 31: MR_r31 = val; MR_save_transient_registers(); return val;
case 32: MR_r32 = val; MR_save_transient_registers(); return val;
}
/* NOTREACHED */
fprintf(stderr, "register %d out of range in set_reg\n", num);
abort();
return 0;
}