[m-dev.] MLDS variable declarations

Peter Hawkins peter at hawkins.emu.id.au
Fri Sep 9 23:45:38 AEST 2005


Hi...

I'm hoping someone can help me understand this comment in ml_code_gen.m:
In this predicate:
    % Generate an MLDS definition for the specified procedure.
    %
:- pred ml_gen_proc_defn(module_info::in, pred_id::in, proc_id::in,
    mlds__entity_defn::out, mlds__defns::out) is det.

at line 1187 there is this comment:
        % This would generate all the local variables at the top of
        % the function:
        %   ml_gen_all_local_var_decls(Goal,
        %       VarSet, VarTypes, HeadVars, MLDS_LocalVars,
        %       Info1, Info2)
        % But instead we now generate them locally for each goal.
        % We just declare the `succeeded' var here, plus locals
        % for any output arguments that are returned by value
        % (e.g. if --nondet-copy-out is enabled, or for det function
        % return values).

Why are the local vars now generated for each goal rather than at the 
top of the procedure body? Would anyone care if I changed it back?

Motivation:
I'm thinking about how you could implement tracing in a high-level 
grade, and it occurs to me the biggest problem is producing a meaningful 
label layout structure. It's (relatively) easy to work out which MLDS 
variable contains a HLDS variable's value at a given point in time, but 
there's no easy way of working out the location of an arbitrary (say) C 
variable, because the C compiler might have placed it in a register or 
at a random part of the stack.
I can think of two ways to handle this:
1) Parse the .debug_info section of the generated object code, which 
contains information mapping C variables to their locations at given 
points in the program's execution. Not portable, and almost certainly 
not fun. This would involve writing per-operating system and 
per-architecture debug information parsing code, but much of this could 
possibly be stolen from gdb. And it's useless in languages other than C.
2) Move all of the variable declarations of a function into a specially 
defined struct/class/..., like so a procedure body is changed from:
void MR_CALL test__a_2_p_0(
  MR_Integer test__A1_3,
  MR_Integer * test__A2_4)
{
  {
    MR_bool test__succeeded;
    MR_Integer test__V_5_5;
    MR_Integer test__V_6_6 = (MR_Integer) 3;
    MR_Integer test__V_9_9;
...

into something like:
struct test__a_2_p_0_localvars {
/* Arguments */
  MR_Integer test__A1_3;
  MR_Integer * test__A2_4;

/* Local variables */
    MR_Integer test__V_5_5;
    MR_Integer test__V_6_6;
    MR_Integer test__V_9_9;
};

void MR_CALL test__a_2_p_0(
  MR_Integer test__A1_3,
  MR_Integer * test__A2_4)
{
  {
    MR_bool test__succeeded;
    struct test__a_2_p_0_localvars lv;
    lv.test__A1_3 = test__A1_3;
    lv.test__A2_4 = test__A2_4;
    lv.test__V_6_6 = (MR_Integer) 3;
...

It then becomes a easy task to fill out a layout structure by giving 
variable locations as offsets into the structure, and passing the base 
address of the structure to every call to MR_trace. This has the side 
effect of ensuring that variables can't be kept in registers, perhaps 
killing performance, but that's probably not an unendurable problem when 
debugging. I think you could make something similar work in Java or IL.

Stack traces can be handled by maintaining an auxiliary call stack of 
label layout structures for the debugger's use (push a layout just 
before making a call, pop it off again on return). Redo is basically the 
same as the 'commit' operation already supported by the MLDS backends.

=)
Peter
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list