%---------------------------------------------------------------------------% % 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. % . % %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% :- 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. %---------------------------------------------------------------------------%