Files
mercury/compiler/analysis.framework.m
Julien Fischer 0d7d158f97 Add or update copyright notices.
compiler/*.m:
    As above.
2024-12-14 21:30:57 +11:00

226 lines
7.2 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2003-2004, 2006-2011 The University of Melbourne.
% Copyright (C) 2024 The Mercury team.
% 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.
%---------------------------------------------------------------------------%
%
% File: analysis.m.
% Main authors: stayl, wangp.
%
% An inter-module analysis framework, as described in
%
% Nicholas Nethercote. The Analysis Framework of HAL,
% Chapter 7: Inter-module Analysis, Master's Thesis,
% University of Melbourne, September 2001, revised April 2002.
% <http://njn.valgrind.org/pubs/masters2001.ps>.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module analysis.framework.
:- interface.
:- import_module hlds.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.file_names.
:- import_module parse_tree.prog_data.
:- import_module io.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module term.
:- import_module unit.
%---------------------------------------------------------------------------%
% The intention is that eventually any compiler can use this library
% via .NET by defining an instance of this type class.
:- typeclass compiler(Compiler) where [
func compiler_name(Compiler) = string,
% Describe the analyses which can be performed by a compiler.
%
pred analyses(Compiler, analysis_name, analysis_type),
mode analyses(in, in, out) is semidet,
mode analyses(in, out, out) is multi,
% module_name_to_read_file_name(Compiler, Globals, Ext,
% ModuleName, MaybeFileName, !IO)
%
pred module_name_to_read_file_name(Compiler::in, globals::in,
ext::in(ext_analysis), module_name::in, maybe_error(string)::out,
io::di, io::uo) is det,
% module_name_to_write_file_name(Compiler, Globals, Ext,
% ModuleName, FileName, !IO)
%
pred module_name_to_write_file_name(Compiler::in, globals::in,
ext::in(ext_analysis), module_name::in, string::out,
io::di, io::uo) is det
].
:- type analysis_name == string.
:- type analysis_type
---> some [FuncInfo, Call, Answer]
analysis_type(
unit(Call),
unit(Answer)
) => analysis(FuncInfo, Call, Answer).
%---------------------%
% An analysis is defined by a type describing call patterns
% and a type defining answer patterns. If the analysis needs to store
% more information about the function being analysed (e.g. arity),
% it should be stored as part of the type for call patterns.
%
:- typeclass analysis(FuncInfo, Call, Answer)
<= (call_pattern(FuncInfo, Call),
answer_pattern(FuncInfo, Answer))
where
[
func analysis_name(Call::unused, Answer::unused) =
(analysis_name::out) is det,
% The version number should be changed when the Call or Answer types
% are changed, so that results which use the old types can be discarded.
%
func analysis_version_number(Call::unused, Answer::unused) =
(int::out) is det,
func preferred_fixpoint_type(Call::unused, Answer::unused) =
(fixpoint_type::out) is det,
func bottom(FuncInfo::in, Call::unused) = (Answer::out) is det,
func top(FuncInfo::in, Call::unused) = (Answer::out) is det,
pred get_func_info(module_info::in, module_name::in, func_id::in,
Call::unused, Answer::unused, FuncInfo::out) is det
].
:- type fixpoint_type
---> least_fixpoint
% Start at `bottom'.
% Must run to completion.
; greatest_fixpoint.
% Start at `top'.
% Can stop at any time.
% This will need to encode language specific details like whether
% it is a predicate or a function, and the arity and mode number.
:- type func_id
---> func_id(
fid_pf :: pred_or_func,
fid_name :: string,
fid_arity :: pred_form_arity,
fid_mode :: proc_id
).
%---------------------%
:- typeclass call_pattern(FuncInfo, Call)
<= (partial_order(FuncInfo, Call),
to_term(Call))
where [].
:- typeclass answer_pattern(FuncInfo, Answer)
<= (partial_order(FuncInfo, Answer),
to_term(Answer))
where [].
%---------------------%
% An analysis result is a call pattern paired with an answer.
% The result has a status associated with it.
%
:- type some_analysis_result
---> some [FuncInfo, Call, Answer]
some_analysis_result(
some_ar_call :: Call,
some_ar_answer :: Answer,
some_ar_status :: analysis_status
)
=> analysis(FuncInfo, Call, Answer).
:- type analysis_result(Call, Answer)
---> analysis_result(
ar_call :: Call,
ar_answer :: Answer,
ar_status :: analysis_status
).
% The status of a module or a specific analysis result.
%
% NOTE: the lub operation below depends on the function symbols
% being in this exact order.
%
:- type analysis_status
---> invalid
; suboptimal
; optimal.
%---------------------%
:- type analysis_map(T) == map(module_name, module_analysis_map(T)).
:- type module_analysis_map(T) == map(analysis_name, func_analysis_map(T)).
:- type func_analysis_map(T) == map(func_id, list(T)).
%---------------------%
:- typeclass partial_order(FuncInfo, T) <= (T -> FuncInfo) where
[
pred more_precise_than(FuncInfo::in, T::in, T::in) is semidet,
pred equivalent(FuncInfo::in, T::in, T::in) is semidet
].
%---------------------%
:- typeclass to_term(S) where [
func to_term(S) = term,
pred from_term(term::in, S::out) is semidet
].
%---------------------------------------------------------------------------%
% Least upper bound of two analysis_status values.
%
:- func lub(analysis_status, analysis_status) = analysis_status.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
lub(StatusA, StatusB) = Status :-
compare(Cmp, StatusA, StatusB),
(
Cmp = (=),
Status = StatusA
;
Cmp = (<),
Status = StatusA
;
Cmp = (>),
Status = StatusB
).
%---------------------------------------------------------------------------%
:- end_module analysis.framework.
%---------------------------------------------------------------------------%