mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 23:35:25 +00:00
Estimated hours taken: 40 (+ unknown time by Zoltan)
Add support for memory profiling.
(A significant part of this change is actuallly Zoltan's work. Zoltan
did the changes to the compiler and a first go at the changes to the
runtime and library. I rewrote much of Zoltan's changes to the runtime
and library, added support for the new options/grades, added code to
interface with mprof, did the changes to the profiler, and wrote the
documentation.)
[TODO: add test cases.]
NEWS:
Mention support for memory profiling.
runtime/mercury_heap_profile.h:
runtime/mercury_heap_profile.c:
New files. These contain code to record heap profiling information.
runtime/mercury_heap.h:
Add new macros incr_hp_msg(), tag_incr_hp_msg(),
incr_hp_atomic_msg(), and tag_incr_hp_atomic_msg().
These are like the non-`msg' versions, except that if
PROFILE_MEMORY is defined, they also call MR_record_allocation()
from mercury_heap_profile.h to record heap profiling information.
Also, fix up the indentation in lots of places.
runtime/mercury_prof.h:
runtime/mercury_prof.c:
Added code to dump out memory profiling information to files
`Prof.MemoryWords' and `Prof.MemoryCells' (for use by mprof).
Change the format of the `Prof.Counts' file so that the
first line says what it is counting, the units, and a scale
factor. Prof.MemoryWords and Prof.MemoryCells can thus have
exactly the same format as Prof.Counts.
Also cleaned up the interface to mercury_prof.c a bit, and did
various other minor cleanups -- indentation changes, changes to
use MR_ prefixes, additional comments, etc.
runtime/mercury_prof_mem.h:
runtime/mercury_prof_mem.c:
Rename prof_malloc() as MR_prof_malloc().
Rename prof_make() as MR_PROF_NEW() and add MR_PROF_NEW_ARRAY().
runtime/mercury_wrapper.h:
Minor modifications to reflect the new interface to mercury_prof.c.
runtime/mercury_wrapper.c:
runtime/mercury_label.c:
Rename the old `-p' (primary cache size) option as `-C'.
Add a new `-p' option to disable profiling.
runtime/Mmakefile:
Add mercury_heap_profile.[ch].
Put the list of files in alphabetical order.
Delete some obsolete stuff for supporting `.mod' files.
Mention that libmer_dll.h and libmer_globals.h are
produced by Makefile.DLLs.
runtime/mercury_imp.h:
Mention that libmer_dll.h is produced by Makefile.DLLs.
runtime/mercury_dummy.c:
Change a comment to refer to libmer_dll.h rather than
libmer_globals.h.
compiler/llds.m:
Add a new field to `create' and `incr_hp' instructions
holding the name of the type, for heap profiling.
compiler/unify_gen.m:
Initialize the new field of `create' instructions with
the appropriate type name.
compiler/llds_out.m:
Output incr_hp_msg() / tag_incr_hp_msg() instead of
incr_hp() / tag_incr_hp().
compiler/*.m:
Minor changes to most files in the compiler back-end to
accomodate the new field in `incr_hp' and `create' instructions.
library/io.m:
Add `io__report_full_memory_stats'.
library/benchmarking.m:
Add `report_full_memory_stats'. This uses the information saved
by runtime/mercury_heap_profile.{c,h} to print out a report
of memory usage by procedures and by types.
Also modify `report_stats' to print out some of that information.
compiler/mercury_compile.m:
If `--statistics' is enabled, call io__report_full_memory_stats
at the end of main/2. This will print out full memory statistics,
if the compiler was compiled with memory profiling enabled.
compiler/options.m:
compiler/handle_options.m:
runtime/mercury_grade.h:
scripts/ml.in:
scripts/mgnuc.in:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
Add new option `--memory-profiling' and new grade `.memprof'.
Add `--time-profiling' as a new synonym for `--profiling'.
Also add `--profile-memory' for more fine-grained control:
`--memory-profiling' implies both `--profile-memory' and
`--profile-calls'.
scripts/mprof_merge_runs:
Update to handle the new format of Prof.Counts and to
also merge Prof.MemoryWords and Prof.MemoryCells.
profiler/options.m:
profiler/mercury_profile.m:
Add new options `--profile memory-words' (`-m'),
`--profile memory-cells' (`-M') and `--profile time' (`-t').
Thes options make the profiler select a different count file,
Prof.MemoryWords or Prof.MemoryCells instead of Prof.Counts.
specific to time profiling.
profiler/read.m:
profiler/process_file.m:
profiler/prof_info.m:
profiler/generate_output.m:
Update to handle the new format of the counts file.
When reading the counts file, look at the first line of
the file to determine what is being profiled.
profiler/globals.m:
Add a new global variable `what_to_profile' that records
what is being profiled.
profiler/output.m:
Change the headings to reflect what is being profiled.
doc/user_guide.texi:
Document memory profiling.
Document new options.
doc/user_guide.texi:
compiler/options.m:
Comment out the documentation for `.proftime'/`--profile-time',
since doing time and call profiling seperately doesn't work,
because the code addresses change when you recompile with a
different grade. Ditto for `.profmem'/`--profile-memory'.
Also comment out the documentation for
`.profcalls'/`--profile-calls', since it is redundant --
`.memprof' produces the same information and more.
configure.in:
Build a `.memprof' grade. (Hmm, should we do this only
if `--enable-all-grades' is specified?)
Don't ever build a `.profcalls' grade.
409 lines
15 KiB
Mathematica
409 lines
15 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997 University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This module generates the LLDS code that defines global constants to
|
|
% hold the `stack_layout' structures of the stack frames defined by the
|
|
% current module.
|
|
%
|
|
% The tables generated have a number of `create' rvals within them,
|
|
% these are removed by llds_common.m to create static structures.
|
|
%
|
|
% Author: trd.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Data Stucture: stack_layouts
|
|
%
|
|
% For each procedure,
|
|
% mercury_data__stack_layout__mercury__<proc_label>
|
|
% containing:
|
|
% code address (Code *) - address of entry
|
|
% number of stack slots (Integer)
|
|
% code_model (Integer) actually, type MR_Code_Model
|
|
% 0 = DET, 1 = NONDET
|
|
% succip stack location (Integer) actually, type MR_Live_Lval
|
|
% (the location will be set to -1
|
|
% if there is no succip available).
|
|
%
|
|
% For each continuation label in a procedure
|
|
% mercury_data__stack_layout__mercury__<proc_label>_i<label number>
|
|
% containing:
|
|
% code address (Code *) - address of label
|
|
% procedure info (Word *) - pointer to procedure stack layout
|
|
% number of live vars (Integer)
|
|
% live data locations and (Word *) - pointer to vector of
|
|
% types MR_Live_Lval and MR_Live_Type pairs
|
|
% type parameters (Word *) - pointer to vector of
|
|
% MR_Live_Lval
|
|
%
|
|
% If the number of live vars is 0, there could be two explanations. The
|
|
% continuation label might actually have no live data, or (more likely)
|
|
% it isn't a continuation label at all.
|
|
%
|
|
% If you need to know the live variables at non-continuation labels,
|
|
% this code will not be sufficient. In particular, it is expected that
|
|
% information about live variables at entry and exit points will be
|
|
% added.
|
|
%
|
|
% Note: That number of type parameters is stored as it is not needed --
|
|
% the type parameter vector will simply be indexed by the type parameter
|
|
% number stored within pseudo-typeinfos.
|
|
%
|
|
% XXX: Presently, type parameter vectors are not created, and
|
|
% inst information is ignored.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module stack_layout.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_module.
|
|
|
|
:- pred stack_layout__generate_llds(module_info, module_info, list(c_module)).
|
|
:- mode stack_layout__generate_llds(in, out, out) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module llds, globals, options, continuation_info, llds_out.
|
|
:- import_module base_type_layout.
|
|
:- import_module assoc_list, bool, string, int, list, map, std_util, require.
|
|
:- import_module set.
|
|
|
|
:- type stack_layout_info --->
|
|
stack_layout_info(
|
|
string, % module name
|
|
int, % next available cell number
|
|
list(c_module) % generated data
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Initialize the StackLayoutInfo, and begin processing.
|
|
stack_layout__generate_llds(ModuleInfo0, ModuleInfo, CModules) :-
|
|
module_info_get_continuation_info(ModuleInfo0, ContinuationInfo),
|
|
continuation_info__get_all_proc_layouts(ProcLayoutList,
|
|
ContinuationInfo, _),
|
|
|
|
module_info_name(ModuleInfo0, ModuleName),
|
|
module_info_get_cell_count(ModuleInfo0, CellCount),
|
|
|
|
LayoutInfo0 = stack_layout_info(ModuleName, CellCount, []),
|
|
list__foldl(stack_layout__construct_layouts, ProcLayoutList,
|
|
LayoutInfo0, LayoutInfo),
|
|
|
|
stack_layout__get_cmodules(CModules, LayoutInfo, _),
|
|
stack_layout__get_cell_number(FinalCellCount, LayoutInfo, _),
|
|
module_info_set_cell_count(ModuleInfo0, FinalCellCount, ModuleInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct the layouts for a single procedure.
|
|
|
|
:- pred stack_layout__construct_layouts(proc_layout_info,
|
|
stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_layouts(in, in, out) is det.
|
|
|
|
stack_layout__construct_layouts(ProcLayoutInfo) -->
|
|
|
|
{ ProcLayoutInfo = proc_layout_info(ProcLabel, StackSlots, CodeModel,
|
|
SuccipLoc, InternalMap) },
|
|
|
|
{ map__to_assoc_list(InternalMap, Internals) },
|
|
|
|
stack_layout__construct_proc_layout(ProcLabel, StackSlots,
|
|
CodeModel, SuccipLoc),
|
|
list__foldl(stack_layout__construct_internal_layout(ProcLabel),
|
|
Internals).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct the layout describing a single procedure.
|
|
|
|
:- pred stack_layout__construct_proc_layout(proc_label, int, code_model,
|
|
maybe(int), stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_proc_layout(in, in, in, in, in, out) is det.
|
|
stack_layout__construct_proc_layout(ProcLabel, StackSlots, CodeModel,
|
|
SuccipLoc) -->
|
|
{
|
|
SuccipLoc = yes(Location0)
|
|
->
|
|
Location = Location0
|
|
;
|
|
% Use a dummy location of -1 if there is
|
|
% no succip on the stack. The runtime system
|
|
% might be able to work around this, depending
|
|
% upon what it is using the stack layouts for.
|
|
Location = -1
|
|
},
|
|
{
|
|
CodeModel = model_det,
|
|
SuccipLval = stackvar(Location)
|
|
;
|
|
CodeModel = model_semi,
|
|
SuccipLval = stackvar(Location)
|
|
;
|
|
CodeModel = model_non,
|
|
SuccipLval = framevar(Location)
|
|
},
|
|
{ Label = local(ProcLabel) },
|
|
{ stack_layout__represent_lval(SuccipLval, SuccipRval) },
|
|
{ StackSlotsRval = const(int_const(StackSlots)) },
|
|
{ CodeAddrRval = const(code_addr_const(label(Label))) },
|
|
stack_layout__represent_code_model(CodeModel, CodeModelRval),
|
|
{ MaybeRvals = [yes(CodeAddrRval), yes(StackSlotsRval),
|
|
yes(CodeModelRval), yes(SuccipRval)] },
|
|
stack_layout__get_module_name(ModuleName),
|
|
|
|
{ CModule = c_data(ModuleName, stack_layout(Label), yes,
|
|
MaybeRvals, []) },
|
|
stack_layout__add_cmodule(CModule).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct the layout describing a single continuation label.
|
|
|
|
:- pred stack_layout__construct_internal_layout(proc_label,
|
|
pair(label, internal_layout_info),
|
|
stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_internal_layout(in, in, in, out) is det.
|
|
stack_layout__construct_internal_layout(ProcLabel, Label - Internal) -->
|
|
{ Internal = internal_layout_info(ContinuationLabelInfo) },
|
|
{
|
|
ContinuationLabelInfo = yes(continuation_label_info(
|
|
LiveLvalSet0, _TVars))
|
|
->
|
|
LiveLvalSet = LiveLvalSet0
|
|
;
|
|
% We record no live values here. This might not be
|
|
% true, however this label is not being used as a
|
|
% continuation, so it shouldn't be relied upon.
|
|
|
|
set__init(LiveLvalSet)
|
|
},
|
|
|
|
% XXX Should also output TVars.
|
|
|
|
{ set__to_sorted_list(LiveLvalSet, LiveLvals) },
|
|
|
|
% generate the required rvals
|
|
{ CodeAddrRval = const(label_entry(Label)) },
|
|
|
|
stack_layout__get_module_name(ModuleName),
|
|
{ EntryAddrRval = const(data_addr_const(data_addr(ModuleName,
|
|
stack_layout(local(ProcLabel))))) },
|
|
{ list__length(LiveLvals, Length) },
|
|
{ LengthRval = const(int_const(Length)) },
|
|
stack_layout__construct_liveval_pairs(LiveLvals, LiveValRval),
|
|
|
|
{ MaybeRvals = [yes(CodeAddrRval), yes(EntryAddrRval),
|
|
yes(LengthRval), yes(LiveValRval)] },
|
|
|
|
{ CModule = c_data(ModuleName, stack_layout(Label), yes,
|
|
MaybeRvals, []) },
|
|
stack_layout__add_cmodule(CModule).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct a vector of (lval, live_value_type) pairs.
|
|
|
|
:- pred stack_layout__construct_liveval_pairs(assoc_list(lval, live_value_type),
|
|
rval, stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_liveval_pairs(in, out, in, out) is det.
|
|
|
|
stack_layout__construct_liveval_pairs(LiveLvals, Rval) -->
|
|
list__map_foldl(stack_layout__construct_liveval_pair, LiveLvals,
|
|
RvalsList),
|
|
{ list__condense(RvalsList, Rvals) },
|
|
stack_layout__get_next_cell_number(CNum),
|
|
{ Rval = create(0, Rvals, no, CNum, "stack_layout_pair") }.
|
|
|
|
% Construct a pair of (lval, live_value_type) representations.
|
|
|
|
:- pred stack_layout__construct_liveval_pair(pair(lval, live_value_type),
|
|
list(maybe(rval)), stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_liveval_pair(in, out, in, out) is det.
|
|
|
|
stack_layout__construct_liveval_pair(Lval - LiveValueType, Rvals) -->
|
|
{ stack_layout__represent_lval(Lval, Rval0) },
|
|
stack_layout__represent_live_value_type(LiveValueType, Rval1),
|
|
{ Rvals = [yes(Rval0), yes(Rval1)] }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The constants here should be kept in sync with constants in
|
|
% the runtime system:
|
|
% mercury_accurate_gc.h - contains macros to access these
|
|
% constants.
|
|
|
|
% Construct a representation of a live_value_type.
|
|
%
|
|
% Low integers for special values, a pointer for other values.
|
|
% (Remember to keep the low integers below the max varint value in
|
|
% runtime/type_info.h).
|
|
|
|
:- pred stack_layout__represent_live_value_type(live_value_type, rval,
|
|
stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__represent_live_value_type(in, out, in, out) is det.
|
|
|
|
stack_layout__represent_live_value_type(succip, Rval) -->
|
|
{ Rval = const(int_const(0)) }.
|
|
stack_layout__represent_live_value_type(hp, Rval) -->
|
|
{ Rval = const(int_const(1)) }.
|
|
stack_layout__represent_live_value_type(curfr, Rval) -->
|
|
{ Rval = const(int_const(2)) }.
|
|
stack_layout__represent_live_value_type(maxfr, Rval) -->
|
|
{ Rval = const(int_const(3)) }.
|
|
stack_layout__represent_live_value_type(redoip, Rval) -->
|
|
{ Rval = const(int_const(4)) }.
|
|
stack_layout__represent_live_value_type(unwanted, Rval) -->
|
|
{ Rval = const(int_const(5)) }.
|
|
stack_layout__represent_live_value_type(var(Type, _Inst), Rval) -->
|
|
stack_layout__get_cell_number(CNum0),
|
|
{ base_type_layout__construct_pseudo_type_info(Type, Rval0, CNum0,
|
|
CNum) },
|
|
stack_layout__set_cell_number(CNum),
|
|
% XXX hack - don't yet write out insts
|
|
{ Rval1 = const(int_const(-1)) },
|
|
stack_layout__get_next_cell_number(CNum2),
|
|
{ Rval = create(0, [yes(Rval0), yes(Rval1)], no, CNum2,
|
|
"stack_layout_pair") }.
|
|
|
|
% Construct a representation of an lval.
|
|
|
|
:- pred stack_layout__represent_lval(lval, rval).
|
|
:- mode stack_layout__represent_lval(in, out) is det.
|
|
|
|
stack_layout__represent_lval(reg(r, Num), Rval) :-
|
|
stack_layout__make_tagged_rval(0, Num, Rval).
|
|
stack_layout__represent_lval(reg(f, Num), Rval) :-
|
|
stack_layout__make_tagged_rval(1, Num, Rval).
|
|
|
|
stack_layout__represent_lval(stackvar(Num), Rval) :-
|
|
stack_layout__make_tagged_rval(2, Num, Rval).
|
|
stack_layout__represent_lval(framevar(Num), Rval) :-
|
|
stack_layout__make_tagged_rval(3, Num, Rval).
|
|
|
|
stack_layout__represent_lval(succip, Rval) :-
|
|
stack_layout__make_tagged_rval(4, 0, Rval).
|
|
stack_layout__represent_lval(maxfr, Rval) :-
|
|
stack_layout__make_tagged_rval(5, 0, Rval).
|
|
stack_layout__represent_lval(curfr, Rval) :-
|
|
stack_layout__make_tagged_rval(6, 0, Rval).
|
|
stack_layout__represent_lval(hp, Rval) :-
|
|
stack_layout__make_tagged_rval(7, 0, Rval).
|
|
stack_layout__represent_lval(sp, Rval) :-
|
|
stack_layout__make_tagged_rval(8, 0, Rval).
|
|
|
|
stack_layout__represent_lval(temp(_, _), _) :-
|
|
error("stack_layout: continuation live value stored in temp register").
|
|
|
|
stack_layout__represent_lval(succip(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(redoip(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(succfr(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(prevfr(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
|
|
stack_layout__represent_lval(field(_, _, _), _) :-
|
|
error("stack_layout: continuation live value stored in field").
|
|
stack_layout__represent_lval(mem_ref(_), _) :-
|
|
error("stack_layout: continuation live value stored in mem_ref").
|
|
stack_layout__represent_lval(lvar(_), _) :-
|
|
error("stack_layout: continuation live value stored in lvar").
|
|
|
|
% Some things in this module are encoded using a low tag.
|
|
% This is not done using the normal compiler mkword, but by
|
|
% doing the bit shifting here.
|
|
%
|
|
% This allows us to use more than the usual 2 or 3 bits, but
|
|
% we have to use low tags and cannot tag pointers this way.
|
|
|
|
:- pred stack_layout__make_tagged_rval(int::in, int::in, rval::out) is det.
|
|
|
|
stack_layout__make_tagged_rval(Tag, Value, Rval) :-
|
|
stack_layout__make_tagged_word(Tag, Value, TaggedValue),
|
|
Rval = const(int_const(TaggedValue)).
|
|
|
|
:- pred stack_layout__make_tagged_word(int::in, int::in, int::out) is det.
|
|
|
|
stack_layout__make_tagged_word(Tag, Value, TaggedValue) :-
|
|
stack_layout__tag_bits(Bits),
|
|
TaggedValue = (Value << Bits) + Tag.
|
|
|
|
% Construct a represntation of the code model.
|
|
|
|
:- pred stack_layout__represent_code_model(code_model, rval, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__represent_code_model(in, out, in, out) is det.
|
|
stack_layout__represent_code_model(CodeModel, Rval) -->
|
|
(
|
|
{ CodeModel = model_det },
|
|
{ Rval = const(int_const(0)) }
|
|
;
|
|
{ CodeModel = model_semi },
|
|
{ Rval = const(int_const(0)) }
|
|
;
|
|
{ CodeModel = model_non },
|
|
{ Rval = const(int_const(1)) }
|
|
).
|
|
|
|
:- pred stack_layout__code_model(code_model::in, int::out) is det.
|
|
stack_layout__code_model(model_det, 0).
|
|
stack_layout__code_model(model_semi, 0).
|
|
stack_layout__code_model(model_non, 1).
|
|
|
|
:- pred stack_layout__tag_bits(int::out) is det.
|
|
stack_layout__tag_bits(8).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Access to the stack_layout data structure.
|
|
|
|
:- pred stack_layout__get_module_name(string, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__get_module_name(out, in, out) is det.
|
|
stack_layout__get_module_name(ModuleName, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(ModuleName, _, _).
|
|
|
|
:- pred stack_layout__get_next_cell_number(int, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__get_next_cell_number(out, in, out) is det.
|
|
stack_layout__get_next_cell_number(CNum0, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, CNum0, C),
|
|
CNum is CNum0 + 1,
|
|
LayoutInfo = stack_layout_info(A, CNum, C).
|
|
|
|
:- pred stack_layout__get_cell_number(int, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__get_cell_number(out, in, out) is det.
|
|
stack_layout__get_cell_number(CNum, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, CNum, _).
|
|
|
|
:- pred stack_layout__get_cmodules(list(c_module), stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__get_cmodules(out, in, out) is det.
|
|
stack_layout__get_cmodules(CModules, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, CModules).
|
|
|
|
:- pred stack_layout__add_cmodule(c_module, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__add_cmodule(in, in, out) is det.
|
|
stack_layout__add_cmodule(CModule, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, B, CModules0),
|
|
CModules = [CModule | CModules0],
|
|
LayoutInfo = stack_layout_info(A, B, CModules).
|
|
|
|
:- pred stack_layout__set_cell_number(int, stack_layout_info,
|
|
stack_layout_info).
|
|
:- mode stack_layout__set_cell_number(in, in, out) is det.
|
|
stack_layout__set_cell_number(CNum, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, _, C),
|
|
LayoutInfo = stack_layout_info(A, CNum, C).
|
|
|