[m-rev.] for review: inter-module analysis framework
Simon Taylor
stayl at cs.mu.OZ.AU
Fri Aug 9 02:50:31 AEST 2002
Estimated hours taken: 80
Branches: main
A first implementation of the inter-module analysis framwork.
Currently only unused argument analysis is supported.
TODO:
- support other analyses, e.g. termination, type specialization
- dependency tracking and invalidation after source modifications
- garbage collection of unused versions
- least fixpoint analyses
analysis/Mmakefile:
analysis/mer_analysis.m:
analysis/analysis.m:
analysis/analysis.file.m:
The analysis library.
Mmake.workspace:
Mmakefile:
compiler/Mmakefile:
tools/bootcheck:
Link the analysis library into mercury_compile.
compiler/hlds_module.m:
Store analysis information in the module_info.
compiler/options.m:
doc/user_guide.texi:
Add an option `--intermodule-analysis'.
compiler/mercury_compile.m:
Call the analysis library to write the gathered
information at the end of a compilation.
compiler/unused_args.m:
Call the analysis library to retrieve information
about imported procedures. This replaces code which
used the `.opt' files.
Change the names created for unused arguments procedures
to include the arguments removed, rather than a sequence
number. I think Zoltan is working on a change to name
mangling, so I haven't updated the demangler.
compiler/prog_util.m:
Generate the new predicate names for unused_args.m.
library/std_util.m:
Add a polymorphic version of unit, which is useful
for binding type variables.
compiler/modules.m:
scripts/Mmake.vars.in:
Clean up files created by the analysis framework
in `mmake realclean'.
util/mdemangle.c:
profiler/demangle.m:
Document the change in the name mangling of procedures with
unused arguments.
configure.in:
Check for state variables and fixes for some typeclass bugs.
tests/warnings/Mmakefile:
tests/warnings/unused_args_analysis.{m,exp}:
Test case.
Index: Mmake.workspace
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmake.workspace,v
retrieving revision 1.8
diff -u -u -r1.8 Mmake.workspace
--- Mmake.workspace 7 Aug 2002 13:11:47 -0000 1.8
+++ Mmake.workspace 8 Aug 2002 06:30:19 -0000
@@ -53,6 +53,7 @@
BOEHM_GC_DIR = $(WORKSPACE)/boehm_gc
COMPILER_DIR = $(WORKSPACE)/compiler
UTIL_DIR = $(WORKSPACE)/util
+ANALYSIS_DIR = $(WORKSPACE)/analysis
# The names of the various libraries.
# The archives and shared object objects have a "lib" prefix and a ".a" or
@@ -67,6 +68,7 @@
STD_LIB_NAME = mer_std
TRACE_LIB_NAME = mer_trace
BROWSER_LIB_NAME = mer_browser
+ANALYSIS_LIB_NAME = mer_analysis
# This specifies the path to the so_locations file (or its equivalent),
# which is used by the linker to help it to map different shared objects
Index: Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmakefile,v
retrieving revision 1.82
diff -u -u -r1.82 Mmakefile
--- Mmakefile 26 Jun 2002 06:59:03 -0000 1.82
+++ Mmakefile 22 Jul 2002 07:24:58 -0000
@@ -30,6 +30,7 @@
library \
trace \
browser \
+ analysis \
compiler \
doc \
profiler \
@@ -53,7 +54,8 @@
# `mmake depend' forces them to be remade to ensure that they are up-to-date.
.PHONY: dep
-dep: dep_library dep_browser dep_compiler dep_profiler dep_deep_profiler
+dep: dep_library dep_browser dep_analysis dep_compiler \
+ dep_profiler dep_deep_profiler
.PHONY: dep_library
dep_library: library/$(deps_subdir)mer_std.dep
@@ -67,6 +69,12 @@
browser/$(deps_subdir)mer_browser.dep:
+cd browser && $(SUBDIR_MMAKE) depend
+.PHONY: dep_analysis
+dep_analysis: analysis/$(deps_subdir)mer_analysis.dep
+
+analysis/$(deps_subdir)mer_analysis.dep:
+ +cd analysis && $(SUBDIR_MMAKE) depend
+
.PHONY: dep_compiler
dep_compiler: compiler/$(deps_subdir)top_level.dep
@@ -99,6 +107,7 @@
depend:
+cd library && $(SUBDIR_MMAKE) depend
+cd browser && $(SUBDIR_MMAKE) depend
+ +cd analysis && $(SUBDIR_MMAKE) depend
+cd compiler && $(SUBDIR_MMAKE) depend
+cd profiler && $(SUBDIR_MMAKE) depend
+cd deep_profiler && $(SUBDIR_MMAKE) depend
@@ -153,16 +162,22 @@
browser: dep_browser scripts util boehm_gc runtime library
+cd browser && $(SUBDIR_MMAKE)
+.PHONY: analysis
+analysis: dep_analysis scripts util boehm_gc runtime library browser trace
+ +cd analysis && $(SUBDIR_MMAKE)
+
.PHONY: runtime
trace: scripts boehm_gc runtime library browser
+cd trace && $(SUBDIR_MMAKE)
.PHONY: compiler
-compiler: dep_compiler scripts util boehm_gc runtime library browser trace
+compiler: dep_compiler scripts util boehm_gc runtime library \
+ browser trace analysis
+cd compiler && $(SUBDIR_MMAKE)
.PHONY: libmmc
-libmmc: dep_compiler scripts util boehm_gc runtime library browser trace
+libmmc: dep_compiler scripts util boehm_gc runtime library \
+ browser trace analysis
+cd compiler && $(SUBDIR_MMAKE) libmmc
.PHONY: doc
@@ -181,7 +196,8 @@
#-----------------------------------------------------------------------------#
.PHONY: tags
-tags: tags_compiler tags_library tags_browser tags_profiler tags_deep_profiler
+tags: tags_compiler tags_library tags_browser tags_analysis \
+ tags_profiler tags_deep_profiler
.PHONY: tags_compiler
tags_compiler:
@@ -195,6 +211,10 @@
tags_browser:
+cd browser && $(SUBDIR_MMAKE) tags
+.PHONY: tags_analysis
+tags_analysis:
+ +cd analysis && $(SUBDIR_MMAKE) tags
+
.PHONY: tags_profiler
tags_profiler:
+cd profiler && $(SUBDIR_MMAKE) tags
@@ -208,7 +228,8 @@
# Remove from each of the listed directories mmc-generated files that don't
# belong there.
cleanint:
- for dir in browser compiler deep_profiler library profiler; do \
+ for dir in analysis browser compiler deep_profiler library profiler; \
+ do \
echo Looking for inappropriate files in the $$dir directory: ; \
( cd $$dir && ../tools/cleanint > .cleanint ) ; \
if test -s $$dir/.cleanint ; then \
@@ -261,6 +282,8 @@
+cd browser && $(SUBDIR_MMAKE) depend
+cd browser && $(SUBDIR_MMAKE) all-ints cs $(BROWSER_LIB_NAME).init tags
+cd trace && $(SUBDIR_MMAKE) cs
+ +cd analysis && $(SUBDIR_MMAKE) depend
+ +cd analysis && $(SUBDIR_MMAKE) cs tags
+cd compiler && $(SUBDIR_MMAKE) depend
+cd compiler && $(SUBDIR_MMAKE) cs tags
+cd profiler && $(SUBDIR_MMAKE) depend
@@ -527,6 +550,9 @@
touch browser/*.optdate
chmod +w browser/*.dep
touch browser/*.dep
+ touch analysis/*.date*
+ chmod +w analysis/*.dep
+ touch analysis/*.dep
touch compiler/*.date*
chmod +w compiler/*.dep
touch compiler/*.dep
Index: configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.314
diff -u -u -r1.314 configure.in
--- configure.in 7 Aug 2002 23:36:49 -0000 1.314
+++ configure.in 8 Aug 2002 16:13:23 -0000
@@ -104,12 +104,12 @@
:- import_module int.
- main -->
- { return_rtti_version(Version) },
- ( { Version >= 6 } ->
- print("Hello, world\n")
+ main(!IO) :-
+ return_rtti_version(Version),
+ ( Version >= 6 ->
+ print("Hello, world\n", !IO)
;
- print("Nope.\n")
+ print("Nope.\n", !IO)
).
:- pred return_rtti_version(int::out) is det.
@@ -123,7 +123,7 @@
# Test for the `--bug-intermod-2002-06-13' option.
echo $BOOTSTRAP_MC conftest >&AC_FD_CC 2>&1 &&
$BOOTSTRAP_MC \
- --bug-intermod-2002-06-13 \
+ --bug-foreign_import-2002-08-06 \
--halt-at-warn $link_static_opt conftest \
</dev/null >&AC_FD_CC 2>&1 &&
test "`./conftest 2>&1 | tr -d '\015'`" = "Hello, world"
Index: analysis/Mmakefile
===================================================================
RCS file: analysis/Mmakefile
diff -N analysis/Mmakefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ analysis/Mmakefile 2 Aug 2002 05:43:57 -0000
@@ -0,0 +1,113 @@
+#-----------------------------------------------------------------------------#
+# Copyright (C) 2002 The 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.
+#-----------------------------------------------------------------------------#
+# analysis/Mmakefile - this is the Mmakefile for building the Mercury
+# inter-module analysis library.
+
+MERCURY_DIR=..
+LINK_STDLIB_ONLY=yes
+include $(MERCURY_DIR)/Mmake.common
+
+# Module-specific options should go in Mercury.options so they
+# can be found by `mmc --make'.
+include Mercury.options
+
+MAIN_TARGET=library
+MERCURY_MAIN_MODULES=$(ANALYSIS_LIB_NAME)
+
+#-----------------------------------------------------------------------------#
+
+# Specify which compilers to use to compile the library.
+# Don't change these without good reason - if you want to
+# do a temporary change, change ../Mmake.params.
+
+MLFLAGS += -R$(FINAL_INSTALL_MERC_LIB_DIR) \
+ -R$(FINAL_INSTALL_MERC_GC_LIB_DIR)
+
+MTAGS = $(SCRIPTS_DIR)/mtags
+
+LN = ln
+
+#-----------------------------------------------------------------------------#
+
+# Stuff for Windows DLLS using gnu-win32
+
+ifeq ($(USE_DLLS),yes)
+
+DLL_CFLAGS = -Dlib$(ANALYSIS_LIB_NAME)_DEFINE_DLL
+
+include $(MERCURY_DIR)/Makefile.DLLs
+
+else
+
+DLL_CFLAGS =
+DLL_DEF_LIB =
+
+endif
+
+#-----------------------------------------------------------------------------#
+
+# targets
+
+.PHONY: all
+all : library
+
+DEPENDS = $(ANALYSIS_LIB_NAME).depend
+.PHONY: depend
+depend : $(DEPENDS)
+
+.PHONY: check
+check : $(ANALYSIS_LIB_NAME).check
+
+.PHONY: all-ints
+all-ints: ints int3s
+
+.PHONY: ints
+ints : $(ANALYSIS_LIB_NAME).ints
+
+.PHONY: int3s
+int3s : $(ANALYSIS_LIB_NAME).int3s
+
+#-----------------------------------------------------------------------------#
+
+tags : $(MTAGS) $($(ANALYSIS_LIB_NAME).ms)
+ $(MTAGS) $($(ANALYSIS_LIB_NAME).ms) ../library/*.m
+
+$(ANALYSIS_LIB_NAME).stats : $(COMPILER_DIR)/source_stats.awk \
+ $($(ANALYSIS_LIB_NAME).ms)
+ awk -f $(COMPILER_DIR)/source_stats.awk \
+ `vpath_find $($(ANALYSIS_LIB_NAME).ms)` > $@
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: dates
+dates :
+ touch $($(ANALYSIS_LIB_NAME).dates)
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: os cs ss
+ifeq ($(MMAKE_USE_MMC_MAKE),no)
+os: $($(ANALYSIS_LIB_NAME).os)
+cs: $($(ANALYSIS_LIB_NAME).cs)
+ss: $($(ANALYSIS_LIB_NAME).ss)
+else
+os: $(ANALYSIS_LIB_NAME).os
+cs: $(ANALYSIS_LIB_NAME).cs
+ss: $(ANALYSIS_LIB_NAME).ss
+endif
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: library
+library: lib$(ANALYSIS_LIB_NAME)
+
+#-----------------------------------------------------------------------------#
+
+# Installation targets
+
+.PHONY: install
+install:
+
Index: analysis/analysis.file.m
===================================================================
RCS file: analysis/analysis.file.m
diff -N analysis/analysis.file.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ analysis/analysis.file.m 7 Aug 2002 15:31:37 -0000
@@ -0,0 +1,327 @@
+%-----------------------------------------------------------------------------%
+% An analysis file contains analysis results for a single module.
+:- module analysis__file.
+
+:- interface.
+
+:- pred read_module_analysis_results(analysis_info::in,
+ module_id::in, module_analysis_map(analysis_result)::out,
+ io__state::di, io__state::uo) is det.
+
+:- pred write_module_analysis_results(analysis_info::in,
+ module_id::in, module_analysis_map(analysis_result)::in,
+ io__state::di, io__state::uo) is det.
+
+:- pred read_module_analysis_requests(analysis_info::in,
+ module_id::in, module_analysis_map(analysis_request)::out,
+ io__state::di, io__state::uo) is det.
+
+:- pred write_module_analysis_requests(analysis_info::in,
+ module_id::in, module_analysis_map(analysis_request)::in,
+ io__state::di, io__state::uo) is det.
+
+:- pred empty_request_file(analysis_info::in, module_id::in,
+ io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+% The format of an analysis file is:
+%
+% version_number.
+% analysis_name(func_id, call_pattern, answer_pattern).
+%-----------------------------------------------------------------------------%
+:- import_module bool, exception, parser, term, term_io, varset.
+
+:- type invalid_analysis_file ---> invalid_analysis_file.
+
+:- func version_number = int.
+version_number = 1.
+
+read_module_analysis_results(Info, ModuleId, ModuleResults, !IO) :-
+ read_analysis_file(Info ^ compiler, ModuleId, ".analysis",
+ parse_result_entry(Info ^ compiler),
+ map__init, ModuleResults, !IO).
+
+:- pred parse_result_entry(Compiler::in)
+ `with_type` parse_entry(module_analysis_map(analysis_result))
+ `with_inst` parse_entry <= compiler(Compiler).
+
+parse_result_entry(Compiler, Term, Results0, Results) :-
+ (
+ Term = term__functor(term__atom(AnalysisName),
+ [FuncIdTerm, CallPatternTerm,
+ AnswerPatternTerm], _),
+ FuncIdTerm =
+ term__functor(term__string(FuncId), [], _),
+ CallPatternTerm = term__functor(
+ term__string(CallPatternString), [], _),
+ AnswerPatternTerm = term__functor(
+ term__string(AnswerPatternString), [], _),
+ analysis_type(_ `with_type` unit(FuncInfo),
+ _ `with_type` unit(Call),
+ _ `with_type` unit(Answer)) =
+ analyses(Compiler, AnalysisName),
+
+ CallPattern = from_string(CallPatternString)
+ `with_type` Call,
+ AnswerPattern = from_string(AnswerPatternString)
+ `with_type` Answer
+ ->
+ Result = 'new analysis_result'(unit1 `with_type` unit(FuncInfo),
+ CallPattern, AnswerPattern),
+ (
+ AnalysisResults0 = map__search(Results0,
+ AnalysisName)
+ ->
+ AnalysisResults1 = AnalysisResults0
+ ;
+ AnalysisResults1 = map__init
+ ),
+ (
+ FuncResults0 = map__search(AnalysisResults1,
+ FuncId)
+ ->
+ FuncResults = [Result | FuncResults0]
+ ;
+ FuncResults = [Result]
+ ),
+ Results = map__set(Results0, AnalysisName,
+ map__set(AnalysisResults1,
+ FuncId, FuncResults))
+ ;
+ throw(invalid_analysis_file)
+ ).
+
+read_module_analysis_requests(Info, ModuleId, ModuleRequests, !IO) :-
+ read_analysis_file(Info ^ compiler, ModuleId, ".request",
+ parse_request_entry(Info ^ compiler),
+ map__init, ModuleRequests, !IO).
+
+:- pred parse_request_entry(Compiler::in)
+ `with_type` parse_entry(module_analysis_map(analysis_request))
+ `with_inst` parse_entry <= compiler(Compiler).
+
+parse_request_entry(Compiler, Term, Results0, Results) :-
+ (
+ Term = term__functor(term__atom(AnalysisName),
+ [FuncIdTerm, CallPatternTerm], _),
+ FuncIdTerm =
+ term__functor(term__string(FuncId), [], _),
+ CallPatternTerm = term__functor(
+ term__string(CallPatternString), [], _),
+ analysis_type(_ `with_type` unit(FuncInfo),
+ _ `with_type` unit(Call), _) =
+ analyses(Compiler, AnalysisName),
+
+ CallPattern = from_string(CallPatternString)
+ `with_type` Call
+ ->
+ Result = 'new analysis_request'(
+ unit1 `with_type` unit(FuncInfo),
+ CallPattern),
+ (
+ AnalysisResults0 = map__search(Results0,
+ AnalysisName)
+ ->
+ AnalysisResults1 = AnalysisResults0
+ ;
+ AnalysisResults1 = map__init
+ ),
+ (
+ FuncResults0 = map__search(AnalysisResults1,
+ FuncId)
+ ->
+ FuncResults = [Result | FuncResults0]
+ ;
+ FuncResults = [Result]
+ ),
+ Results = map__set(Results0, AnalysisName,
+ map__set(AnalysisResults1,
+ FuncId, FuncResults))
+ ;
+ throw(invalid_analysis_file)
+ ).
+
+:- type parse_entry(T) == pred(term, T, T).
+:- inst parse_entry == (pred(in, in, out) is det).
+
+:- pred read_analysis_file(Compiler::in, module_id::in, string::in,
+ parse_entry(T)::in(parse_entry), T::in, T::out,
+ io__state::di, io__state::uo) is det <= compiler(Compiler).
+
+read_analysis_file(Compiler, ModuleId, Suffix, ParseEntry,
+ ModuleResults0, ModuleResults, !IO) :-
+ module_id_to_file_name(Compiler, ModuleId,
+ Suffix, AnalysisFileName, !IO),
+ io__open_input(AnalysisFileName, OpenResult, !IO),
+ (
+ OpenResult = ok(Stream),
+ io__set_input_stream(Stream, OldStream, !IO),
+ promise_only_solution_io(
+ (pred(R::out, di, uo) is cc_multi -->
+ try_io((pred(Results1::out, di, uo) is det -->
+ read_analysis_file_2(ParseEntry,
+ ModuleResults0, Results1)
+ ), R)
+ ), Result, !IO),
+ (
+ Result = succeeded(ModuleResults)
+ ;
+ Result = failed,
+ ModuleResults = ModuleResults0
+ ;
+ Result = exception(_),
+ % XXX Report error.
+ ModuleResults = ModuleResults0
+ ),
+ io__set_input_stream(OldStream, _, !IO),
+ io__close_input(Stream, !IO)
+ ;
+ OpenResult = error(_),
+ ModuleResults = ModuleResults0
+ ).
+
+:- pred read_analysis_file_2(parse_entry(T)::in(parse_entry),
+ T::in, T::out, io__state::di, io__state::uo) is det.
+
+read_analysis_file_2(ParseEntry, Results0, Results, !IO) :-
+ parser__read_term(TermResult `with_type` read_term, !IO),
+ (
+ TermResult = term(_, term__functor(
+ term__integer(version_number), [], _))
+ ->
+ true
+ ;
+ throw(invalid_analysis_file)
+ ),
+ read_analysis_file_3(ParseEntry, Results0, Results, !IO).
+
+:- pred read_analysis_file_3(parse_entry(T)::in(parse_entry),
+ T::in, T::out, io__state::di, io__state::uo) is det.
+
+read_analysis_file_3(ParseEntry, Results0, Results, !IO) :-
+ parser__read_term(TermResult, !IO),
+ (
+ TermResult = term(_, Term) `with_type` read_term,
+ ParseEntry(Term, Results0, Results)
+ ;
+ TermResult = eof,
+ Results = Results0
+ ;
+ TermResult = error(_, _),
+ throw(invalid_analysis_file)
+ ).
+
+write_module_analysis_results(Info, ModuleId, ModuleResults, !IO) :-
+ write_analysis_file(Info ^ compiler, ModuleId, ".analysis",
+ write_result_entry, ModuleResults, !IO).
+
+write_module_analysis_requests(Info, ModuleId, ModuleRequests, !IO) :-
+ module_id_to_file_name(Info ^ compiler, ModuleId, ".request",
+ AnalysisFileName, !IO),
+ io__open_input(AnalysisFileName, InputResult, !IO),
+ ( InputResult = ok(InputStream) ->
+ io__set_input_stream(InputStream, OldInputStream, !IO),
+ parser__read_term(VersionResult `with_type` read_term, !IO),
+ io__set_input_stream(OldInputStream, _, !IO),
+ io__close_input(InputStream, !IO),
+ (
+ VersionResult = term(_, term__functor(
+ term__integer(version_number), [], _))
+ ->
+ io__open_append(AnalysisFileName, AppendResult, !IO),
+ ( AppendResult = ok(AppendStream) ->
+ io__set_output_stream(AppendStream,
+ OldOutputStream, !IO),
+ write_analysis_entries(write_request_entry,
+ ModuleRequests, !IO),
+ io__set_output_stream(OldOutputStream, _, !IO),
+ io__close_output(AppendStream, !IO),
+ Appended = yes
+ ;
+ Appended = no
+ )
+ ;
+ Appended = no
+ )
+ ;
+ Appended = no
+ ),
+ ( Appended = no ->
+ write_analysis_file(Info ^ compiler, ModuleId, ".request",
+ write_request_entry, ModuleRequests, !IO)
+ ;
+ true
+ ).
+
+:- pred write_result_entry `with_type` write_entry(analysis_result)
+ `with_inst` write_entry.
+
+write_result_entry(AnalysisName, FuncId,
+ analysis_result(_, Call, Answer), !IO) :-
+ term_io__write_term_nl(varset__init `with_type` varset,
+ functor(atom(AnalysisName), [
+ functor(string(FuncId), [], context_init),
+ functor(string(to_string(Call)), [], context_init),
+ functor(string(to_string(Answer)), [], context_init)
+ ], context_init), !IO).
+
+:- pred write_request_entry `with_type` write_entry(analysis_request)
+ `with_inst` write_entry.
+
+write_request_entry(AnalysisName, FuncId, analysis_request(_, Call), !IO) :-
+ term_io__write_term_nl(varset__init `with_type` varset,
+ functor(atom(AnalysisName), [
+ functor(string(FuncId), [], context_init),
+ functor(string(to_string(Call)), [], context_init)
+ ], context_init), !IO).
+
+:- type write_entry(T) == pred(analysis_name, func_id, T, io__state, io__state).
+:- inst write_entry == (pred(in, in, in, di, uo) is det).
+
+:- pred write_analysis_file(Compiler::in, module_id::in, string::in,
+ write_entry(T)::in(write_entry), module_analysis_map(T)::in,
+ io__state::di, io__state::uo) is det <= compiler(Compiler).
+
+write_analysis_file(Compiler, ModuleId, Suffix,
+ WriteEntry, ModuleResults, !IO) :-
+ module_id_to_file_name(Compiler, ModuleId,
+ Suffix, AnalysisFileName, !IO),
+ io__open_output(AnalysisFileName, OpenResult, !IO),
+ (
+ OpenResult = ok(Stream),
+ io__set_output_stream(Stream, OldOutput, !IO),
+ io__write_int(version_number, !IO),
+ io__write_string(".\n", !IO),
+ write_analysis_entries(WriteEntry, ModuleResults, !IO),
+ io__set_output_stream(OldOutput, _, !IO),
+ io__close_output(Stream, !IO)
+ ;
+ OpenResult = error(Msg),
+ io__write_string("Error opening ", !IO),
+ io__write_string(AnalysisFileName, !IO),
+ io__write_string(" for output: ", !IO),
+ io__write_string(io__error_message(Msg), !IO),
+ io__nl(!IO)
+ ).
+
+:- pred write_analysis_entries(write_entry(T)::in(write_entry),
+ module_analysis_map(T)::in, io__state::di, io__state::uo) is det.
+
+write_analysis_entries(WriteEntry, ModuleResults, !IO) :-
+ map__foldl(
+ (pred(AnalysisName::in, FuncResults::in, di, uo) is det -->
+ map__foldl(
+ (pred(FuncId::in, FuncResultList::in, di, uo) is det -->
+ list__foldl(
+ (pred(FuncResult::in, di, uo) is det -->
+ WriteEntry(AnalysisName, FuncId, FuncResult)
+ ), FuncResultList)
+ ), FuncResults)
+ ), ModuleResults, !IO).
+
+empty_request_file(Info, ModuleId, !IO) :-
+ module_id_to_file_name(Info ^ compiler, ModuleId, ".request",
+ RequestFileName, !IO),
+ io__remove_file(RequestFileName, _, !IO).
+
Index: analysis/analysis.m
===================================================================
RCS file: analysis/analysis.m
diff -N analysis/analysis.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ analysis/analysis.m 7 Aug 2002 15:31:12 -0000
@@ -0,0 +1,312 @@
+:- module analysis.
+
+:- interface.
+
+:- import_module assoc_list, io, list, std_util.
+
+ % The intention is that eventually any compiler can
+ % use this library via .NET by defining an instance
+ % of this class.
+:- typeclass compiler(Compiler) where [
+ func compiler_name(Compiler) = string,
+
+ % Describe the analyses which can be performed by a compiler.
+ func analyses(Compiler, analysis_name) = analysis_type is semidet,
+
+ % module_id_to_file_name(Compiler, ModuleId, Ext, FileName)
+ pred module_id_to_file_name(Compiler::in, module_id::in,
+ string::in, string::out, io__state::di, io__state::uo) is det
+].
+
+:- type module_id == string.
+
+:- type analysis_name == string.
+
+:- type analysis_type
+ ---> some [FuncInfo, Call, Answer]
+ analysis_type(unit(FuncInfo), unit(Call), unit(Answer))
+ => analysis(FuncInfo, Call, Answer).
+
+ % An analysis is defined by a type describing call patterns,
+ % a type defining answer patterns and a type giving information
+ % about the function being analysed (e.g. arity) which should
+ % be provided by the caller.
+:- typeclass analysis(FuncInfo, Call, Answer) <=
+ (call_pattern(FuncInfo, Call),
+ answer_pattern(FuncInfo, Answer))
+ where
+[
+ func analysis_name(FuncInfo::unused, Call::unused, Answer::unused) =
+ (analysis_name::out) is det,
+
+ func preferred_fixpoint_type(FuncInfo::in,
+ Call::unused, Answer::unused) =
+ (fixpoint_type::out) is det
+].
+
+:- type fixpoint_type
+ --->
+ % Start at `bottom'.
+ % Must run to completion.
+ least_fixpoint
+ ;
+ % Start at `top'.
+ % Can stop at any time.
+ greatest_fixpoint
+ .
+
+:- typeclass call_pattern(FuncInfo, Call)
+ <= (partial_order(FuncInfo, Call), to_string(Call)) where [].
+
+:- typeclass answer_pattern(FuncInfo, Answer)
+ <= (partial_order(FuncInfo, Answer), to_string(Answer)) where [
+ func bottom(FuncInfo) = Answer,
+ func top(FuncInfo) = Answer
+].
+
+:- typeclass partial_order(FuncInfo, Call) where [
+ pred more_precise_than(FuncInfo::in,
+ Call::in, Call::in) is semidet,
+ pred equivalent(FuncInfo::in,
+ Call::in, Call::in) is semidet
+].
+
+:- typeclass to_string(S) where [
+ func to_string(S) = string,
+ func from_string(string) = S is semidet
+].
+
+:- type any_call ---> any_call.
+:- instance call_pattern(unit, any_call).
+:- instance partial_order(unit, any_call).
+:- instance to_string(any_call).
+
+ % 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 == string.
+
+ % Holds information used while analysing a module.
+:- type analysis_info.
+
+:- func init_analysis_info(Compiler) = analysis_info <= compiler(Compiler).
+
+ % Look up all results for a given function.
+:- pred lookup_results(module_id::in, func_id::in, FuncInfo::in,
+ assoc_list(Call, Answer)::out, analysis_info::in, analysis_info::out,
+ io__state::di, io__state::uo) is det
+ <= analysis(FuncInfo, Call, Answer).
+
+ % Look up the best result matching a given call.
+:- pred lookup_best_result(module_id::in, func_id::in, FuncInfo::in,
+ Call::in, maybe(pair(Call, Answer))::out, analysis_info::in,
+ analysis_info::out, io__state::di, io__state::uo) is det
+ <= analysis(FuncInfo, Call, Answer).
+
+ % Record an analysis result for a (usually local) function.
+:- pred record_result(module_id::in, func_id::in, FuncInfo::in, Call::in,
+ Answer::in, analysis_info::in, analysis_info::out) is det
+ <= analysis(FuncInfo, Call, Answer).
+
+ % Lookup all the requests for a given (usually local) function.
+:- pred lookup_requests(analysis_name::in, module_id::in, func_id::in,
+ FuncInfo::in, list(Call)::out, analysis_info::in, analysis_info::out,
+ io__state::di, io__state::uo) is det <= call_pattern(FuncInfo, Call).
+
+ % Record a request for a local function.
+:- pred record_request(analysis_name::in, module_id::in, func_id::in,
+ FuncInfo::in, Call::in, analysis_info::in, analysis_info::out) is det
+ <= call_pattern(FuncInfo, Call).
+
+ % Should be called after all analysis is completed to write the
+ % requests and results for the current compilation to the
+ % analysis files.
+:- pred write_analysis_files(module_id::in, analysis_info::in,
+ io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- include_module analysis__file.
+:- import_module analysis__file.
+
+:- import_module map, require, set.
+
+:- type analysis_info
+ ---> some [Compiler] analysis_info(
+ compiler :: Compiler,
+ analysis_requests :: analysis_map(analysis_request),
+ analysis_results :: analysis_map(analysis_result)
+ ) => compiler(Compiler).
+
+:- type analysis_result
+ ---> some [FuncInfo, Call, Answer] analysis_result(unit(FuncInfo),
+ Call, Answer) => analysis(FuncInfo, Call, Answer).
+
+:- type analysis_request
+ ---> some [FuncInfo, Call] analysis_request(unit(FuncInfo), Call)
+ => call_pattern(FuncInfo, Call).
+
+:- type analysis_hash == int.
+
+:- type analysis_map(T) == map(module_id, 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)).
+
+:- instance call_pattern(unit, any_call) where [].
+:- instance partial_order(unit, any_call) where [
+ more_precise_than(_, _, _) :- semidet_fail,
+ equivalent(_, _, _) :- semidet_succeed
+].
+:- instance to_string(any_call) where [
+ to_string(any_call) = "",
+ from_string("") = any_call
+].
+
+init_analysis_info(Compiler) =
+ 'new analysis_info'(Compiler, map__init, map__init).
+
+lookup_results(ModuleId, FuncId, _FuncInfo, ResultList, !Info, !IO) :-
+ %io__write_string("looking up results for ", !IO),
+ %io__write_string(FuncId, !IO),
+ %io__nl(!IO),
+ ( map__search(!.Info ^ analysis_results, ModuleId, ModuleResults0) ->
+ ModuleResults = ModuleResults0
+ ;
+ read_module_analysis_results(!.Info, ModuleId,
+ ModuleResults, !IO),
+ !:Info = !.Info ^ analysis_results
+ ^ elem(ModuleId) := ModuleResults
+ ),
+ AnalysisName = analysis_name(_ `with_type` FuncInfo,
+ _ `with_type` Call, _ `with_type` Answer),
+ (
+ Results = ModuleResults ^ elem(AnalysisName) ^ elem(FuncId)
+ ->
+ ResultList = list__map(
+ (func(Result) = ResultCall - ResultAnswer :-
+ Result = analysis_result(_,
+ ResultCall0, ResultAnswer0),
+ det_univ_to_type(univ(ResultCall0), ResultCall),
+ det_univ_to_type(univ(ResultAnswer0), ResultAnswer)
+ ), Results)
+ ;
+ ResultList = []
+ ).
+
+lookup_best_result(ModuleId, FuncId, FuncInfo, Call,
+ MaybeBestResult, !Info, !IO) :-
+ %io__write_string("looking up best result for ", !IO),
+ %io__write_string(FuncId, !IO),
+ %io__nl(!IO),
+ lookup_results(ModuleId, FuncId, FuncInfo, ResultList, !Info, !IO),
+ MatchingResults = list__filter(
+ (pred((ResultCall - _)::in) is semidet :-
+ ( more_precise_than(FuncInfo, Call, ResultCall)
+ ; equivalent(FuncInfo, Call, ResultCall)
+ )
+ ), ResultList),
+ (
+ MatchingResults = [],
+ MaybeBestResult = no
+ ;
+ MatchingResults = [FirstResult | MatchingResults1],
+ MaybeBestResult = yes(list__foldl(
+ (func(ThisResult, BestResult) =
+ (
+ more_precise_than(FuncInfo,
+ snd(ThisResult), snd(BestResult))
+ ->
+ ThisResult
+ ;
+ BestResult
+ )
+ ), MatchingResults1, FirstResult))
+ ).
+
+record_result(ModuleId, FuncId, FuncInfo, CallPattern, AnswerPattern, !Info) :-
+ ( ModuleResults0 = map__search(!.Info ^ analysis_results, ModuleId) ->
+ ModuleResults1 = ModuleResults0
+ ;
+ ModuleResults1 = map__init
+ ),
+ AnalysisName = analysis_name(FuncInfo, CallPattern, AnswerPattern),
+ ( AnalysisResults0 = map__search(ModuleResults1, AnalysisName) ->
+ AnalysisResults1 = AnalysisResults0
+ ;
+ AnalysisResults1 = map__init
+ ),
+ ( FuncResults0 = map__search(AnalysisResults1, FuncId) ->
+ FuncResults1 = FuncResults0
+ ;
+ FuncResults1 = []
+ ),
+ !:Info = !.Info ^ analysis_results :=
+ map__set(!.Info ^ analysis_results, ModuleId,
+ map__set(ModuleResults1, AnalysisName,
+ map__set(AnalysisResults1, FuncId,
+ ['new analysis_result'(unit1 `with_type` unit(FuncInfo),
+ CallPattern, AnswerPattern) | FuncResults1]))).
+
+lookup_requests(AnalysisName, ModuleId, FuncId, _FuncInfo,
+ CallPatterns, !Info, !IO) :-
+ ( map__search(!.Info ^ analysis_requests, ModuleId, ModuleRequests0) ->
+ ModuleRequests = ModuleRequests0
+ ;
+ read_module_analysis_requests(!.Info,
+ ModuleId, ModuleRequests, !IO),
+ !:Info = !.Info ^ analysis_requests
+ ^ elem(ModuleId) := ModuleRequests
+ ),
+ ( CallPatterns0 = ModuleRequests ^ elem(AnalysisName) ^ elem(FuncId) ->
+ CallPatterns = list__filter_map(
+ (func(Call0) = Call is semidet :-
+ univ(Call) = univ(Call0)
+ ), CallPatterns0)
+ ;
+ CallPatterns = []
+ ).
+
+record_request(AnalysisName, ModuleId, FuncId, _FuncInfo,
+ CallPattern, !Info) :-
+ ( ModuleResults0 = map__search(!.Info ^ analysis_requests, ModuleId) ->
+ ModuleResults1 = ModuleResults0
+ ;
+ ModuleResults1 = map__init
+ ),
+ ( AnalysisResults0 = map__search(ModuleResults1, AnalysisName) ->
+ AnalysisResults1 = AnalysisResults0
+ ;
+ AnalysisResults1 = map__init
+ ),
+ ( FuncResults0 = map__search(AnalysisResults1, FuncId) ->
+ FuncResults1 = FuncResults0
+ ;
+ FuncResults1 = []
+ ),
+ !:Info = !.Info ^ analysis_requests :=
+ map__set(!.Info ^ analysis_requests, ModuleId,
+ map__set(ModuleResults1, AnalysisName,
+ map__set(AnalysisResults1, FuncId,
+ ['new analysis_request'(unit1 `with_type` unit(FuncInfo),
+ CallPattern) | FuncResults1]))).
+
+write_analysis_files(ModuleId, Info, !IO) :-
+
+ %
+ % Write the results for the current module.
+ %
+ ( ModuleResults0 = map__search(Info ^ analysis_results, ModuleId) ->
+ ModuleResults = ModuleResults0
+ ;
+ ModuleResults = map__init
+ ),
+ write_module_analysis_results(Info, ModuleId, ModuleResults, !IO),
+
+ %
+ % Write the requests for the imported modules.
+ %
+ map__foldl(write_module_analysis_requests(Info),
+ Info ^ analysis_requests, !IO),
+
+ empty_request_file(Info, ModuleId, !IO).
+
Index: analysis/mer_analysis.m
===================================================================
RCS file: analysis/mer_analysis.m
diff -N analysis/mer_analysis.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ analysis/mer_analysis.m 1 Aug 2002 10:24:36 -0000
@@ -0,0 +1,3 @@
+:- module mer_analysis.
+
+:- import_module analysis.
Index: compiler/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mmakefile,v
retrieving revision 1.60
diff -u -u -r1.60 Mmakefile
--- compiler/Mmakefile 8 Aug 2002 07:22:36 -0000 1.60
+++ compiler/Mmakefile 8 Aug 2002 16:25:19 -0000
@@ -22,7 +22,7 @@
MERCURY_MAIN_MODULES = top_level mlds_to_gcc
-VPATH=$(LIBRARY_DIR) $(BROWSER_DIR)
+VPATH=$(LIBRARY_DIR) $(BROWSER_DIR) $(ANALYSIS_DIR)
#-----------------------------------------------------------------------------#
@@ -40,10 +40,13 @@
GCC_BACKEND_LIBS =
endif
-MCFLAGS += -I $(BROWSER_DIR)
-MLOBJS := ../main.$O $(MLOBJS)
+MCFLAGS += -I $(BROWSER_DIR) -I $(ANALYSIS_DIR) \
+ --c-include-directory $(ANALYSIS_DIR)
+CFLAGS += -I $(ANALYSIS_DIR)
+MLOBJS := ../main.$O ../analysis/lib$(ANALYSIS_LIB_NAME).$A $(MLOBJS)
ALL_MLLIBS = $(MLLIBS) $(EXTRA_MLLIBS) $(GCC_BACKEND_LIBS)
MLFLAGS += --no-main --shared
+C2INITARGS += $(ANALYSIS_DIR)/$(ANALYSIS_LIB_NAME).init
#
# Work-around for a fixed limit: on alpha-dec-osf3.2, if we compile with
@@ -215,6 +218,7 @@
$(MC_PROG): $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
$(MC_PROG): $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
$(MC_PROG): $(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A
+$(MC_PROG): $(ANALYSIS_DIR)/lib$(ANALYSIS_LIB_NAME).$A
# Should also depend on $(BOEHM_GC_DIR)/libgc(_prof).$A, but only
# if in .gc(.prof) grade; GNU make does not support dynamic dependencies,
# so just leave it out.
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.76
diff -u -u -r1.76 hlds_module.m
--- compiler/hlds_module.m 1 Aug 2002 11:52:17 -0000 1.76
+++ compiler/hlds_module.m 8 Aug 2002 06:30:22 -0000
@@ -26,12 +26,15 @@
:- import_module hlds__hlds_pred, hlds__hlds_data, check_hlds__unify_proc.
:- import_module hlds__special_pred.
:- import_module libs__globals, backend_libs__foreign.
+:- import_module analysis.
:- import_module relation, map, std_util, list, set, multi_map, counter.
:- implementation.
:- import_module hlds__hlds_out, parse_tree__prog_out, parse_tree__prog_util.
:- import_module check_hlds__typecheck, parse_tree__modules.
+:- import_module transform_hlds__mmc_analysis.
+
:- import_module bool, require, int, string.
%-----------------------------------------------------------------------------%
@@ -373,6 +376,13 @@
no_tag_type_table, module_info).
:- mode module_info_set_no_tag_types(in, in, out) is det.
+:- pred module_info_analysis_info(module_info, analysis_info).
+:- mode module_info_analysis_info(in, out) is det.
+
+:- pred module_info_set_analysis_info(module_info,
+ analysis_info, module_info).
+:- mode module_info_set_analysis_info(in, in, out) is det.
+
%-----------------------------------------------------------------------------%
:- pred module_info_preds(module_info, pred_table).
@@ -573,12 +583,16 @@
type_spec_info :: type_spec_info,
% data used for user-guided type
% specialization.
- no_tag_type_table :: no_tag_type_table
+ no_tag_type_table :: no_tag_type_table,
% Information about no tag
% types. This information is
% also in the type_table,
% but lookups in this table
% will be much faster.
+
+ analysis_info :: analysis_info
+ % Information for the inter-module
+ % analysis framework.
).
% A predicate which creates an empty module
@@ -619,7 +633,7 @@
ModuleSubInfo = module_sub(Name, Globals, no, [], [], [], no, 0, 0, [],
[], StratPreds, UnusedArgInfo, 0, ImportedModules,
IndirectlyImportedModules, no_aditi_compilation,
- TypeSpecInfo, NoTagTypes),
+ TypeSpecInfo, NoTagTypes, init_analysis_info(mmc)),
ModuleInfo = module(ModuleSubInfo, PredicateTable, Requests,
UnifyPredMap, QualifierInfo, Types, Insts, Modes, Ctors,
ClassTable, SuperClassTable, InstanceTable, AssertionTable,
@@ -701,6 +715,7 @@
MI ^ sub_info ^ do_aditi_compilation).
module_info_type_spec_info(MI, MI ^ sub_info ^ type_spec_info).
module_info_no_tag_types(MI, MI ^ sub_info ^ no_tag_type_table).
+module_info_analysis_info(MI, MI ^ sub_info ^ analysis_info).
%-----------------------------------------------------------------------------%
@@ -749,6 +764,8 @@
MI ^ sub_info ^ type_spec_info := NewVal).
module_info_set_no_tag_types(MI, NewVal,
MI ^ sub_info ^ no_tag_type_table := NewVal).
+module_info_set_analysis_info(MI, NewVal,
+ MI ^ sub_info ^ analysis_info := NewVal).
%-----------------------------------------------------------------------------%
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.265
diff -u -u -r1.265 mercury_compile.m
--- compiler/mercury_compile.m 7 Aug 2002 13:11:52 -0000 1.265
+++ compiler/mercury_compile.m 8 Aug 2002 06:30:23 -0000
@@ -108,6 +108,10 @@
:- import_module libs__timestamp.
:- import_module make, make__options_file, backend_libs__compile_target_code.
+ % inter-module analysis framework
+:- import_module analysis.
+:- import_module transform_hlds__mmc_analysis.
+
% library modules
:- import_module int, list, map, set, std_util, require, string, bool, dir.
:- import_module library, getopt, set_bbbtree, term, varset, assoc_list.
@@ -1124,6 +1128,18 @@
% magic sets can report errors.
{ module_info_num_errors(HLDS50, NumErrors) },
( { NumErrors = 0 } ->
+
+ globals__io_lookup_bool_option(intermodule_analysis,
+ IntermodAnalysis),
+ ( { IntermodAnalysis = yes } ->
+ { module_info_analysis_info(HLDS50, AnalysisInfo) },
+ analysis__write_analysis_files(
+ module_name_to_module_id(ModuleName),
+ AnalysisInfo)
+ ;
+ []
+ ),
+
mercury_compile__maybe_generate_rl_bytecode(HLDS50,
Verbose, MaybeRLFile),
( { Target = c ; Target = asm } ->
@@ -1138,6 +1154,7 @@
;
[]
),
+
( { AditiOnly = yes } ->
{ HLDS = HLDS50 }
; { Target = il } ->
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.245
diff -u -u -r1.245 modules.m
--- compiler/modules.m 7 Aug 2002 14:40:39 -0000 1.245
+++ compiler/modules.m 8 Aug 2002 06:30:24 -0000
@@ -3992,6 +3992,18 @@
io__write_string(DepStream, "\n"),
io__write_string(DepStream, MakeVarName),
+ io__write_string(DepStream, ".analysiss = "),
+ write_compact_dependencies_list(Modules, "$(analysiss_subdir)",
+ ".analysis", Basis, DepStream),
+ io__write_string(DepStream, "\n"),
+
+ io__write_string(DepStream, MakeVarName),
+ io__write_string(DepStream, ".requests = "),
+ write_compact_dependencies_list(Modules, "$(requests_subdir)",
+ ".request", Basis, DepStream),
+ io__write_string(DepStream, "\n"),
+
+ io__write_string(DepStream, MakeVarName),
io__write_string(DepStream, ".schemas = "),
write_compact_dependencies_list(Modules, "", ".base_schema",
Basis, DepStream),
@@ -4466,6 +4478,8 @@
"\t-echo $(", MakeVarName, ".int3s) | xargs rm -f\n",
"\t-echo $(", MakeVarName, ".opts) | xargs rm -f\n",
"\t-echo $(", MakeVarName, ".trans_opts) | xargs rm -f\n",
+ "\t-echo $(", MakeVarName, ".analysiss) | xargs rm -f\n",
+ "\t-echo $(", MakeVarName, ".requests) | xargs rm -f\n",
"\t-echo $(", MakeVarName, ".ds) | xargs rm -f\n",
"\t-echo $(", MakeVarName, ".module_deps) | xargs rm -f\n",
"\t-echo $(", MakeVarName, ".all_mhs) | xargs rm -f\n",
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.382
diff -u -u -r1.382 options.m
--- compiler/options.m 8 Aug 2002 06:25:45 -0000 1.382
+++ compiler/options.m 8 Aug 2002 06:30:24 -0000
@@ -366,6 +366,7 @@
; opt_level
; opt_space % default is to optimize time
; intermodule_optimization
+ ; intermodule_analysis
; read_opt_files_transitively
; use_opt_files
; use_trans_opt_files
@@ -879,6 +880,7 @@
opt_level - int_special,
opt_space - special,
intermodule_optimization - bool(no),
+ intermodule_analysis - bool(no),
read_opt_files_transitively - bool(yes),
use_opt_files - bool(no),
use_trans_opt_files - bool(no),
@@ -1434,6 +1436,7 @@
long_option("optimise-space", opt_space).
long_option("intermodule-optimization", intermodule_optimization).
long_option("intermodule-optimisation", intermodule_optimization).
+long_option("intermodule-analysis", intermodule_analysis).
long_option("read-opt-files-transitively", read_opt_files_transitively).
long_option("use-opt-files", use_opt_files).
long_option("use-trans-opt-files", use_trans_opt_files).
@@ -3065,6 +3068,10 @@
"\t`.trans_opt' files which are already built,",
"\te.g. those for the standard library, but do",
"\tnot build any others.",
+ "--intermodule-analysis",
+ "\tPerform analyses such as termination analysis and",
+ "\tunused argument elimination across module boundaries.",
+ "\tThis option is not yet fully implemented.",
"--split-c-files",
"\tGenerate each C function in its own C file,",
"\tso that the linker will optimize away unused code.",
Index: compiler/prog_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_util.m,v
retrieving revision 1.57
diff -u -u -r1.57 prog_util.m
--- compiler/prog_util.m 9 Jul 2002 01:29:42 -0000 1.57
+++ compiler/prog_util.m 30 Jul 2002 08:23:47 -0000
@@ -166,6 +166,7 @@
:- type new_pred_id
---> counter(int, int) % Line number, Counter
; type_subst(tvarset, type_subst)
+ ; unused_args(list(int))
.
%-----------------------------------------------------------------------------%
@@ -472,6 +473,9 @@
SubstStr)
)),
list_to_string(SubstToString, TypeSubst, PredIdStr)
+ ;
+ NewPredId = unused_args(Args),
+ list_to_string(int_to_string, Args, PredIdStr)
),
string__format("%s__%s__%s__%s",
Index: compiler/transform_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/transform_hlds.m,v
retrieving revision 1.2
diff -u -u -r1.2 transform_hlds.m
--- compiler/transform_hlds.m 8 May 2002 18:21:53 -0000 1.2
+++ compiler/transform_hlds.m 26 Jul 2002 13:55:24 -0000
@@ -33,7 +33,7 @@
:- include_module higher_order.
:- include_module inlining.
:- include_module deforest.
- :- include_module pd_cost, pd_debug, pd_info, pd_term.
+ :- include_module constraint, pd_cost, pd_debug, pd_info, pd_term.
:- include_module pd_util.
:- include_module delay_construct.
:- include_module unused_args.
@@ -43,8 +43,10 @@
:- include_module dead_proc_elim.
:- include_module const_prop.
+:- include_module mmc_analysis.
+
% XXX The following modules are all currently unused.
-:- include_module constraint, transform.
+:- include_module transform.
:- include_module lco.
%-----------------------------------------------------------------------------%
Index: compiler/unused_args.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unused_args.m,v
retrieving revision 1.77
diff -u -u -r1.77 unused_args.m
--- compiler/unused_args.m 28 Mar 2002 03:43:47 -0000 1.77
+++ compiler/unused_args.m 7 Aug 2002 15:34:02 -0000
@@ -44,16 +44,28 @@
:- interface.
:- import_module hlds__hlds_module.
+:- import_module analysis.
:- import_module io.
:- pred unused_args__process_module(module_info::in, module_info::out,
io__state::di, io__state::uo) is det.
+ % Instances used by mmc_analysis.m.
+:- type unused_args_answer.
+:- type unused_args_func_info.
+:- instance analysis(unused_args_func_info, any_call, unused_args_answer).
+:- instance partial_order(unused_args_func_info, any_call).
+:- instance call_pattern(unused_args_func_info, any_call).
+:- instance partial_order(unused_args_func_info, unused_args_answer).
+:- instance answer_pattern(unused_args_func_info, unused_args_answer).
+:- instance to_string(unused_args_answer).
+
%-------------------------------------------------------------------------------
:- implementation.
:- import_module parse_tree__mercury_to_mercury, parse_tree__modules.
:- import_module parse_tree__prog_data, parse_tree__prog_out.
+:- import_module parse_tree__prog_util.
:- import_module hlds__hlds_pred, hlds__hlds_goal, hlds__hlds_data.
:- import_module hlds__hlds_out, hlds__instmap, hlds__make_hlds.
:- import_module hlds__quantification, hlds__special_pred.
@@ -61,6 +73,7 @@
:- import_module hlds__goal_util.
:- import_module check_hlds__type_util, check_hlds__mode_util.
:- import_module check_hlds__inst_match, check_hlds__polymorphism.
+:- import_module transform_hlds__mmc_analysis.
:- import_module ll_backend__code_util.
:- import_module libs__options, libs__globals.
@@ -87,24 +100,75 @@
warning_info(prog_context, string, int, list(int)).
% context, pred name, arity, list of args to warn
+%-----------------------------------------------------------------------------%
+ % Types and instances used by mmc_analysis.m.
+
+ % The list of unused arguments is in sorted order.
+:- type unused_args_answer ---> unused_args(list(int)).
+
+:- instance analysis(unused_args_func_info, any_call,
+ unused_args_answer) where [
+ analysis_name(_, _, _) = "unused_args",
+ preferred_fixpoint_type(_, _, _) = least_fixpoint
+].
+
+:- type unused_args_func_info ---> unused_args_func_info(arity).
+
+:- instance call_pattern(unused_args_func_info, any_call) where [].
+:- instance partial_order(unused_args_func_info, any_call) where [
+ (more_precise_than(_, _, _) :- semidet_fail),
+ (equivalent(_, _, _) :- semidet_succeed)
+].
+
+:- instance answer_pattern(unused_args_func_info, unused_args_answer) where [
+ bottom(unused_args_func_info(Arity)) = unused_args(1 `..` Arity),
+ top(_) = unused_args([])
+].
+:- instance partial_order(unused_args_func_info, unused_args_answer) where [
+ (more_precise_than(_, unused_args(Args1), unused_args(Args2)) :-
+ set__subset(sorted_list_to_set(Args2),
+ sorted_list_to_set(Args1))
+ ),
+ equivalent(_, Args, Args)
+].
+
+:- instance to_string(unused_args_answer) where [
+ to_string(unused_args(Args)) =
+ string__join_list(" ", list__map(int_to_string, Args)),
+ (from_string(String) = unused_args(Args) :-
+ {Digits, Args0} = string__foldl(
+ (func(Char, {Digits0, Ints0}) =
+ ( char__is_digit(Char) ->
+ {[Char | Digits0], Ints0}
+ ;
+ {[], [string__det_to_int(
+ string__from_rev_char_list(Digits0)) | Ints0]}
+ )
+ ), String, {[], []}),
+ Args = list__reverse([string__det_to_int(
+ string__from_rev_char_list(Digits)) | Args0])
+ )
+].
-unused_args__process_module(ModuleInfo0, ModuleInfo) -->
+%-----------------------------------------------------------------------------%
+
+unused_args__process_module(!ModuleInfo) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
- { init_var_usage(ModuleInfo0, VarUsage0, PredProcs, OptProcs) },
+ init_var_usage(VarUsage0, PredProcs, ProcCallInfo0, !ModuleInfo),
%maybe_write_string(VeryVerbose, "% Finished initialisation.\n"),
{ unused_args_pass(PredProcs, VarUsage0, VarUsage) },
%maybe_write_string(VeryVerbose, "% Finished analysis.\n"),
{ map__init(UnusedArgInfo0) },
- { get_unused_arg_info(ModuleInfo0, PredProcs, VarUsage,
+ { get_unused_arg_info(!.ModuleInfo, PredProcs, VarUsage,
UnusedArgInfo0, UnusedArgInfo) },
{ map__keys(UnusedArgInfo, PredProcsToFix) },
globals__io_lookup_bool_option(make_optimization_interface, MakeOpt),
( { MakeOpt = yes } ->
- { module_info_name(ModuleInfo0, ModuleName) },
+ { module_info_name(!.ModuleInfo, ModuleName) },
module_name_to_file_name(ModuleName, ".opt.tmp", no,
OptFileName),
io__open_append(OptFileName, OptFileRes),
@@ -123,7 +187,7 @@
globals__io_lookup_bool_option(warn_unused_args, DoWarn),
( { DoWarn = yes ; MakeOpt = yes } ->
{ set__init(WarnedPredIds0) },
- output_warnings_and_pragmas(ModuleInfo0, UnusedArgInfo,
+ output_warnings_and_pragmas(!.ModuleInfo, UnusedArgInfo,
MaybeOptFile, DoWarn, PredProcsToFix, WarnedPredIds0)
;
[]
@@ -137,29 +201,22 @@
(
{ DoFixup = yes }
->
- { map__init(ProcCallInfo0) },
- { create_new_preds(PredProcsToFix, UnusedArgInfo,
- ProcCallInfo0, ProcCallInfo1,
- ModuleInfo0, ModuleInfo1) },
- { make_imported_unused_args_pred_infos(OptProcs,
- ProcCallInfo1, ProcCallInfo,
- ModuleInfo1, ModuleInfo2) },
+ list__foldl3(create_new_pred(UnusedArgInfo), PredProcsToFix,
+ ProcCallInfo0, ProcCallInfo, !ModuleInfo),
% maybe_write_string(VeryVerbose, "% Finished new preds.\n"),
- fixup_unused_args(VarUsage, PredProcs, ProcCallInfo,
- ModuleInfo2, ModuleInfo3, VeryVerbose),
+ fixup_unused_args(VarUsage, PredProcs,
+ ProcCallInfo, !ModuleInfo, VeryVerbose),
% maybe_write_string(VeryVerbose, "% Fixed up goals.\n"),
{ map__is_empty(ProcCallInfo) ->
- ModuleInfo = ModuleInfo3
+ true
;
% The dependencies have changed, so the dependency
% graph needs rebuilding.
- module_info_clobber_dependency_info(ModuleInfo3,
- ModuleInfo)
+ module_info_clobber_dependency_info(!ModuleInfo)
}
;
- { ModuleInfo = ModuleInfo0 }
+ []
).
-
%-------------------------------------------------------------------------------
% Initialisation section
@@ -170,96 +227,110 @@
% iteration over.
% OptPredProcList is a list of procedures for which we got
% unused argument information from .opt files.
-:- pred init_var_usage(module_info::in, var_usage::out,
- pred_proc_list::out, pred_proc_list::out) is det.
+:- pred init_var_usage(var_usage::out, pred_proc_list::out,
+ proc_call_info::out, module_info::in, module_info::out,
+ io__state::di, io__state::uo) is det.
-init_var_usage(ModuleInfo, VarUsage, PredProcList, OptPredProcList) :-
+init_var_usage(VarUsage, PredProcList, ProcCallInfo, !ModuleInfo, !IO) :-
+ map__init(ProcCallInfo0),
map__init(VarUsage0),
- module_info_predids(ModuleInfo, PredIds),
- module_info_preds(ModuleInfo, PredTable),
- module_info_unused_arg_info(ModuleInfo, UnusedArgInfo),
- setup_local_var_usage(ModuleInfo, PredTable, PredIds, UnusedArgInfo,
- VarUsage0, VarUsage, [], PredProcList, [], OptPredProcList).
-
-
+ module_info_predids(!.ModuleInfo, PredIds),
+ module_info_unused_arg_info(!.ModuleInfo, UnusedArgInfo),
+ setup_local_var_usage(PredIds, UnusedArgInfo,
+ VarUsage0, VarUsage, [], PredProcList,
+ ProcCallInfo0, ProcCallInfo, !ModuleInfo, !IO).
% setup args for the whole module.
-:- pred setup_local_var_usage(module_info::in, pred_table::in,
- list(pred_id)::in, unused_arg_info::in, var_usage::in,
- var_usage::out, pred_proc_list::in, pred_proc_list::out,
- pred_proc_list::in, pred_proc_list::out) is det.
-
-setup_local_var_usage(_, _, [], _, VarUsage, VarUsage,
- PredProcs, PredProcs, OptProcs, OptProcs).
-setup_local_var_usage(ModuleInfo, PredTable, [PredId | PredIds], UnusedArgInfo,
- VarUsage0, VarUsage, PredProcList0, PredProcList,
- OptProcList0, OptProcList) :-
- map__lookup(PredTable, PredId, PredInfo),
+:- pred setup_local_var_usage(list(pred_id)::in, unused_arg_info::in,
+ var_usage::in, var_usage::out, pred_proc_list::in, pred_proc_list::out,
+ proc_call_info::in, proc_call_info::out, module_info::in,
+ module_info::out, io__state::di, io__state::uo) is det.
+
+setup_local_var_usage([], _, !VarUsage, !PredProcs,
+ !OptProcs, !ModuleInfo, !IO).
+setup_local_var_usage([PredId | PredIds], UnusedArgInfo,
+ !VarUsage, !PredProcList, !OptProcs, !ModuleInfo, !IO) :-
+ module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
% The builtins use all their arguments.
( code_util__predinfo_is_builtin(PredInfo) ->
- VarUsage1 = VarUsage0,
- setup_local_var_usage(ModuleInfo, PredTable, PredIds,
- UnusedArgInfo, VarUsage1, VarUsage, PredProcList0,
- PredProcList, OptProcList0, OptProcList)
+ setup_local_var_usage(PredIds, UnusedArgInfo, !VarUsage,
+ !PredProcList, !OptProcs, !ModuleInfo, !IO)
;
pred_info_procids(PredInfo, ProcIds),
- setup_pred_args(ModuleInfo, PredId, ProcIds, UnusedArgInfo,
- VarUsage0, VarUsage1, PredProcList0, PredProcList1,
- OptProcList0, OptProcList1),
- setup_local_var_usage(ModuleInfo, PredTable, PredIds,
- UnusedArgInfo, VarUsage1, VarUsage, PredProcList1,
- PredProcList, OptProcList1, OptProcList)
+ setup_pred_args(PredId, ProcIds, UnusedArgInfo, !VarUsage,
+ !PredProcList, !OptProcs, !ModuleInfo, !IO),
+ setup_local_var_usage(PredIds, UnusedArgInfo, !VarUsage,
+ !PredProcList, !OptProcs, !ModuleInfo, !IO)
).
-
% setup args for a predicate
-:- pred setup_pred_args(module_info::in, pred_id::in, list(proc_id)::in,
- unused_arg_info::in, var_usage::in, var_usage::out,
- pred_proc_list::in, pred_proc_list::out,
- pred_proc_list::in, pred_proc_list::out) is det.
-
-setup_pred_args(_, _, [], _, VarUsage, VarUsage,
- PredProcs, PredProcs, OptProcs, OptProcs).
-setup_pred_args(ModuleInfo, PredId, [ProcId | Rest], UnusedArgInfo, VarUsage0,
- VarUsage, PredProcs0, PredProcs, OptProcs0, OptProcs) :-
- module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
+:- pred setup_pred_args(pred_id::in, list(proc_id)::in, unused_arg_info::in,
+ var_usage::in, var_usage::out, pred_proc_list::in, pred_proc_list::out,
+ proc_call_info::in, proc_call_info::out, module_info::in,
+ module_info::out, io__state::di, io__state::uo) is det.
+
+setup_pred_args(_, [], _, !VarUsage, !PredProcs, !OptProcs, !ModuleInfo, !IO).
+setup_pred_args(PredId, [ProcId | Rest], UnusedArgInfo, !VarUsage,
+ !PredProcs, !OptProcs, !ModuleInfo, !IO) :-
+ module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
PredInfo, ProcInfo),
map__init(VarDep0),
- Proc = proc(PredId, ProcId),
+ globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
(
- % Get the unused argument info from the .opt files.
- % Don't use the .opt file info when we have the clauses
- % (opt_imported preds) since we may be able to do better with
- % the information in this module.
+ % Don't use the intermodule analysis info when we have the
+ % clauses (opt_imported preds) since we may be able to do
+ % better with the information in this module.
+ Intermod = yes,
pred_info_is_imported(PredInfo)
->
- ( map__search(UnusedArgInfo, Proc, UnusedArgs) ->
+ pred_info_module(PredInfo, PredModule),
+ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
+ pred_info_name(PredInfo, PredName),
+ pred_info_arity(PredInfo, PredArity),
+ FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
+ PredName, PredArity, ProcId),
+ module_info_analysis_info(!.ModuleInfo, AnalysisInfo0),
+ lookup_best_result(module_name_to_module_id(PredModule),
+ FuncId, unused_args_func_info(PredArity),
+ any_call, MaybeBestResult,
+ AnalysisInfo0, AnalysisInfo, !IO),
+ module_info_set_analysis_info(!.ModuleInfo,
+ AnalysisInfo, !:ModuleInfo),
+ ( MaybeBestResult = yes(_ - unused_args(UnusedArgs)) ->
proc_info_headvars(ProcInfo, HeadVars),
list__map(list__index1_det(HeadVars),
- UnusedArgs, UnusedVars),
+ UnusedArgs, UnusedVars),
initialise_vardep(VarDep0, UnusedVars, VarDep),
- map__set(VarUsage0, proc(PredId, ProcId),
- VarDep, VarUsage1),
- OptProcs1 = [proc(PredId, ProcId) | OptProcs0]
+ !:VarUsage = map__set(!.VarUsage,
+ proc(PredId, ProcId), VarDep),
+ globals__io_lookup_bool_option(optimize_unused_args,
+ Optimize, !IO),
+ ( Optimize = yes ->
+ make_imported_unused_args_pred_info(
+ proc(PredId, ProcId), UnusedArgs,
+ !OptProcs, !ModuleInfo)
+ ;
+ true
+ )
;
- VarUsage1 = VarUsage0,
- OptProcs1 = OptProcs0
- ),
- PredProcs1 = PredProcs0
+ true
+ )
;
- pred_info_is_pseudo_imported(PredInfo),
- hlds_pred__in_in_unification_proc_id(ProcId)
+ (
+ pred_info_is_imported(PredInfo)
+ ;
+ pred_info_is_pseudo_imported(PredInfo),
+ hlds_pred__in_in_unification_proc_id(ProcId)
+ )
->
- PredProcs1 = PredProcs0,
- OptProcs1 = OptProcs0,
- VarUsage1 = VarUsage0
+ true
;
proc_info_vartypes(ProcInfo, VarTypes),
map__keys(VarTypes, Vars),
initialise_vardep(VarDep0, Vars, VarDep1),
- setup_output_args(ModuleInfo, ProcInfo, VarDep1, VarDep2),
+ setup_output_args(!.ModuleInfo, ProcInfo, VarDep1, VarDep2),
- module_info_globals(ModuleInfo, Globals),
+ module_info_globals(!.ModuleInfo, Globals),
proc_interface_should_use_typeinfo_liveness(PredInfo, ProcId,
Globals, TypeInfoLiveness),
( TypeInfoLiveness = yes ->
@@ -272,14 +343,15 @@
),
proc_info_goal(ProcInfo, Goal - _),
- Info = traverse_info(ModuleInfo, VarTypes),
+ Info = traverse_info(!.ModuleInfo, VarTypes),
traverse_goal(Info, Goal, VarDep3, VarDep),
- map__set(VarUsage0, proc(PredId, ProcId), VarDep, VarUsage1),
- PredProcs1 = [proc(PredId, ProcId) | PredProcs0],
- OptProcs1 = OptProcs0
+ !:VarUsage = map__set(!.VarUsage,
+ proc(PredId, ProcId), VarDep),
+
+ !:PredProcs = [proc(PredId, ProcId) | !.PredProcs]
),
- setup_pred_args(ModuleInfo, PredId, Rest, UnusedArgInfo, VarUsage1,
- VarUsage, PredProcs1, PredProcs, OptProcs1, OptProcs).
+ setup_pred_args(PredId, Rest, UnusedArgInfo,
+ !VarUsage, !PredProcs, !OptProcs, !ModuleInfo, !IO).
:- pred initialise_vardep(var_dep::in, list(prog_var)::in, var_dep::out) is det.
@@ -732,11 +804,7 @@
UnusedArgInfo0, UnusedArgInfo) :-
PredProc = proc(PredId, ProcId),
map__lookup(VarUsage, PredProc, LocalVarUsage),
-
- module_info_preds(ModuleInfo, Preds),
- map__lookup(Preds, PredId, PredInfo),
- pred_info_procedures(PredInfo, Procs),
- map__lookup(Procs, ProcId, ProcInfo),
+ module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_headvars(ProcInfo, HeadVars),
get_unused_arg_nos(LocalVarUsage, HeadVars, 1, UnusedArgs),
map__det_insert(UnusedArgInfo0, PredProc, UnusedArgs, UnusedArgInfo1),
@@ -765,40 +833,74 @@
% interface.
% The other is that the next proc_id for a predicate is
% chosen based on the length of the list of proc_ids.
-:- pred create_new_preds(pred_proc_list::in, unused_arg_info::in,
+:- pred create_new_pred(unused_arg_info::in, pred_proc_id::in,
proc_call_info::in, proc_call_info::out,
- module_info::in, module_info::out) is det.
-
-create_new_preds([], _UnusedArgInfo, ProcCallInfo, ProcCallInfo, Mod, Mod).
-create_new_preds([PredProc | PredProcs], UnusedArgInfo,
- ProcCallInfo0, ProcCallInfo, ModuleInfo0, ModuleInfo) :-
- create_new_pred(PredProc, UnusedArgInfo, ProcCallInfo0, ProcCallInfo1,
- ModuleInfo0, ModuleInfo1),
- create_new_preds(PredProcs, UnusedArgInfo, ProcCallInfo1, ProcCallInfo,
- ModuleInfo1, ModuleInfo).
+ module_info::in, module_info::out,
+ io__state::di, io__state::uo) is det.
-:- pred create_new_pred(pred_proc_id::in, unused_arg_info::in,
- proc_call_info::in, proc_call_info::out,
- module_info::in, module_info::out) is det.
-
-create_new_pred(proc(PredId, ProcId), UnusedArgInfo,
- ProcCallInfo0, ProcCallInfo, ModuleInfo0, ModuleInfo) :-
+create_new_pred(UnusedArgInfo, proc(PredId, ProcId),
+ !ProcCallInfo, !ModuleInfo, !IO) :-
map__lookup(UnusedArgInfo, proc(PredId, ProcId), UnusedArgs),
- module_info_pred_proc_info(ModuleInfo0, PredId, ProcId, PredInfo0,
- OldProc0),
+ module_info_pred_proc_info(!.ModuleInfo,
+ PredId, ProcId, OrigPredInfo, OrigProcInfo),
(
UnusedArgs = []
->
- ModuleInfo = ModuleInfo0,
- ProcCallInfo = ProcCallInfo0
+ true
;
- need_extra_proc(ModuleInfo0, UnusedArgs, proc(PredId, ProcId),
- IntermodUnusedArgs, InMap),
- pred_info_import_status(PredInfo0, Status0),
+ pred_info_module(OrigPredInfo, PredModule),
+ pred_info_name(OrigPredInfo, PredName),
+
+ globals__io_lookup_bool_option(intermodule_analysis,
+ Intermod, !IO),
+ ( Intermod = yes ->
+ module_info_analysis_info(!.ModuleInfo, AnalysisInfo0),
+ pred_info_get_is_pred_or_func(OrigPredInfo,
+ PredOrFunc),
+ pred_info_arity(OrigPredInfo, PredArity),
+ ModuleId = module_name_to_module_id(PredModule),
+ FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
+ PredName, PredArity, ProcId),
+ FuncInfo = unused_args_func_info(PredArity),
+
+ lookup_results(ModuleId, FuncId, FuncInfo,
+ IntermodResults0, AnalysisInfo0, AnalysisInfo1,
+ !IO),
+ IntermodResults1 = list__map(
+ (func(any_call - unused_args(ResArgs)) = ResArgs),
+ IntermodResults0),
+ ( list__member(UnusedArgs, IntermodResults1) ->
+ AnalysisInfo = AnalysisInfo1
+ ;
+ analysis__record_result(ModuleId,
+ FuncId, FuncInfo, any_call,
+ unused_args(UnusedArgs),
+ AnalysisInfo1, AnalysisInfo)
+ ),
+ module_info_set_analysis_info(!.ModuleInfo,
+ AnalysisInfo, !:ModuleInfo),
+
+ %
+ % XXX Mark versions which have more unused arguments
+ % than what we have computed here as invalid
+ % in the AnalysisInfo, so that modules which use
+ % those versions can be recompiled.
+ %
+ IntermodResults = list__filter(
+ (pred(VersionUnusedArgs::in) is semidet :-
+ set__subset(
+ sorted_list_to_set(VersionUnusedArgs),
+ sorted_list_to_set(UnusedArgs))
+ ), IntermodResults1)
+ ;
+ IntermodResults0 = [],
+ IntermodResults = []
+ ),
+ pred_info_import_status(OrigPredInfo, Status0),
(
Status0 = opt_imported,
- InMap = yes,
- IntermodUnusedArgs = no
+ IntermodResults0 = [_|_],
+ IntermodResults = []
->
% If this predicate is from a .opt file, and
% no more arguments have been removed than in the
@@ -807,129 +909,91 @@
% it if no other optimization is performed on it.
Status = opt_imported
;
- Status0 = exported,
- InMap = yes
+ status_is_exported(Status0, yes)
->
- % This specialized version of the predicate was
- % declared in the .opt file for this module so
+ % This specialized version of the predicate will be
+ % declared in the analysis file for this module so
% it must be exported.
- Status = exported
+ Status = Status0
;
Status = local
),
- ( IntermodUnusedArgs = no ->
- NameSuffix = "__ua"
- ;
- % This predicate was declared in a .opt file,
- % but more arguments were removed than was declared
- % in the .opt file, so a different name is required.
- NameSuffix = "__uab"
- ),
- make_new_pred_info(ModuleInfo0, PredInfo0, UnusedArgs,
- NameSuffix, Status, proc(PredId, ProcId), NewPredInfo0),
+ make_new_pred_info(!.ModuleInfo, OrigPredInfo, UnusedArgs,
+ Status, proc(PredId, ProcId), NewPredInfo0),
+ pred_info_name(NewPredInfo0, NewPredName),
pred_info_procedures(NewPredInfo0, NewProcs0),
- next_mode_id(NewProcs0, no, NewProcId),
% Assign the old procedure to a new predicate, which
% will be fixed up in fixup_unused_args.
- map__set(NewProcs0, NewProcId, OldProc0, NewProcs),
+ map__set(NewProcs0, ProcId, OrigProcInfo, NewProcs),
pred_info_set_procedures(NewPredInfo0, NewProcs, NewPredInfo),
% add the new proc to the pred table
- module_info_get_predicate_table(ModuleInfo0, PredTable0),
- predicate_table_insert(PredTable0, NewPredInfo, NewPredId,
- PredTable1),
- pred_info_module(NewPredInfo, PredModule),
- pred_info_name(NewPredInfo, PredName),
- PredSymName = qualified(PredModule, PredName),
- % add the new proc to the proc_call_info map
- map__det_insert(ProcCallInfo0, proc(PredId, ProcId),
- call_info(NewPredId, NewProcId, PredSymName, UnusedArgs),
- ProcCallInfo),
- (
- Status0 = exported,
- IntermodUnusedArgs = yes(UnusedArgs2)
- ->
- % Add an exported predicate with the number of removed
- % arguments promised in the .opt file which just calls
- % the new predicate.
- make_new_pred_info(ModuleInfo0, PredInfo0,
- UnusedArgs2, "__ua", exported,
- proc(PredId, ProcId), ExtraPredInfo0),
- create_call_goal(UnusedArgs, NewPredId, NewProcId,
- PredModule, PredName, OldProc0, ExtraProc0),
- proc_info_headvars(OldProc0, HeadVars0),
- remove_listof_elements(HeadVars0, 1, UnusedArgs2,
- IntermodHeadVars),
- proc_info_set_headvars(ExtraProc0, IntermodHeadVars,
- ExtraProc1),
- proc_info_argmodes(OldProc0, ArgModes0),
- remove_listof_elements(ArgModes0, 1, UnusedArgs2,
- IntermodArgModes),
- proc_info_set_argmodes(ExtraProc1, IntermodArgModes,
- ExtraProc),
- pred_info_procedures(ExtraPredInfo0, ExtraProcs0),
- next_mode_id(ExtraProcs0, no, ExtraProcId),
- map__set(ExtraProcs0, ExtraProcId,
- ExtraProc, ExtraProcs),
- pred_info_set_procedures(ExtraPredInfo0, ExtraProcs,
- ExtraPredInfo),
- predicate_table_insert(PredTable1, ExtraPredInfo,
- _, PredTable2)
- ;
- PredTable2 = PredTable1
- ),
+ module_info_get_predicate_table(!.ModuleInfo, PredTable0),
+ predicate_table_insert(PredTable0,
+ NewPredInfo, NewPredId, PredTable),
+ module_info_set_predicate_table(!.ModuleInfo,
+ PredTable, !:ModuleInfo),
- predicate_table_get_preds(PredTable2, Preds0),
- pred_info_procedures(PredInfo0, Procs0),
- create_call_goal(UnusedArgs, NewPredId, NewProcId,
- PredModule, PredName, OldProc0, OldProc),
- map__set(Procs0, ProcId, OldProc, Procs),
- pred_info_set_procedures(PredInfo0, Procs, PredInfo),
- map__det_update(Preds0, PredId, PredInfo, Preds1),
- predicate_table_set_preds(PredTable2, Preds1, PredTable),
- module_info_set_predicate_table(ModuleInfo0, PredTable,
- ModuleInfo)
- ).
-
- % Check that if this procedure has a pragma unused_args declaration
- % in the .opt file, the number of removed arguments matches with what
- % has just been computed. If not, it means that more arguments were
- % found to be unused given the information from .opt files, so we need
- % to create an interface predicate with the promised number of
- % arguments removed which calls the fully optimized version.
-:- pred need_extra_proc(module_info::in, list(int)::in, pred_proc_id::in,
- maybe(list(int))::out, bool::out) is det.
-
-need_extra_proc(ModuleInfo, UnusedArgs, PredProcId,
- MaybeIntermodUnusedArgs, InMap) :-
- module_info_unused_arg_info(ModuleInfo, IntermodUnusedArgInfo),
- (
- map__search(IntermodUnusedArgInfo,
- PredProcId, IntermodUnusedArgs)
- ->
- InMap = yes,
- ( IntermodUnusedArgs = UnusedArgs ->
- MaybeIntermodUnusedArgs = no
- ;
- MaybeIntermodUnusedArgs = yes(IntermodUnusedArgs)
- )
- ;
- InMap = no,
- MaybeIntermodUnusedArgs = no
+ % add the new proc to the proc_call_info map
+ PredSymName = qualified(PredModule, NewPredName),
+ map__det_insert(!.ProcCallInfo, proc(PredId, ProcId),
+ call_info(NewPredId, ProcId, PredSymName, UnusedArgs),
+ !:ProcCallInfo),
+
+ % add a forwarding predicate with the
+ % original interface.
+ create_call_goal(UnusedArgs, NewPredId, ProcId, PredModule,
+ NewPredName, OrigProcInfo, ForwardingProcInfo),
+ module_info_set_pred_proc_info(!.ModuleInfo,
+ PredId, ProcId, OrigPredInfo,
+ ForwardingProcInfo, !:ModuleInfo),
+
+ % add forwarding predicates for results
+ % produced in previous compilations.
+ list__foldl(
+ make_intermod_proc(PredId, NewPredId, ProcId,
+ NewPredName, OrigPredInfo, OrigProcInfo,
+ UnusedArgs),
+ IntermodResults, !ModuleInfo)
).
+:- pred make_intermod_proc(pred_id::in, pred_id::in, proc_id::in, string::in,
+ pred_info::in, proc_info::in, list(int)::in, list(int)::in,
+ module_info::in, module_info::out) is det.
+
+make_intermod_proc(PredId, NewPredId, ProcId, NewPredName,
+ OrigPredInfo, OrigProcInfo, UnusedArgs,
+ UnusedArgs2, !ModuleInfo) :-
+ % Add an exported predicate with the number of removed
+ % arguments promised in the analysis file which just calls
+ % the new predicate.
+ make_new_pred_info(!.ModuleInfo, OrigPredInfo, UnusedArgs2,
+ exported, proc(PredId, ProcId), ExtraPredInfo0),
+ pred_info_module(OrigPredInfo, PredModule),
+ create_call_goal(UnusedArgs, NewPredId, ProcId,
+ PredModule, NewPredName, OrigProcInfo, ExtraProc0),
+ proc_info_headvars(OrigProcInfo, HeadVars0),
+ remove_listof_elements(HeadVars0, 1, UnusedArgs2, IntermodHeadVars),
+ proc_info_set_headvars(ExtraProc0, IntermodHeadVars, ExtraProc1),
+ proc_info_argmodes(OrigProcInfo, ArgModes0),
+ remove_listof_elements(ArgModes0, 1, UnusedArgs2, IntermodArgModes),
+ proc_info_set_argmodes(ExtraProc1, IntermodArgModes, ExtraProc),
+ pred_info_procedures(ExtraPredInfo0, ExtraProcs0),
+ map__set(ExtraProcs0, ProcId, ExtraProc, ExtraProcs),
+ pred_info_set_procedures(ExtraPredInfo0, ExtraProcs, ExtraPredInfo),
+ module_info_get_predicate_table(!.ModuleInfo, PredTable0),
+ predicate_table_insert(PredTable0, ExtraPredInfo, _, PredTable),
+ module_info_set_predicate_table(!.ModuleInfo, PredTable, !:ModuleInfo).
+
:- pred make_new_pred_info(module_info::in, pred_info::in, list(int)::in,
- string::in, import_status::in, pred_proc_id::in,
- pred_info::out) is det.
+ import_status::in, pred_proc_id::in, pred_info::out) is det.
-make_new_pred_info(ModuleInfo, PredInfo0, UnusedArgs, NameSuffix, Status,
- proc(_PredId, ProcId), PredInfo) :-
+make_new_pred_info(ModuleInfo, PredInfo0, UnusedArgs, Status,
+ proc(_PredId, _ProcId), PredInfo) :-
pred_info_module(PredInfo0, PredModule),
pred_info_name(PredInfo0, Name0),
pred_info_get_is_pred_or_func(PredInfo0, PredOrFunc),
- proc_id_to_int(ProcId, ProcInt),
- string__int_to_string(ProcInt, Id),
pred_info_arg_types(PredInfo0, Tvars, ExistQVars, ArgTypes0),
% create a unique new pred name using the old proc_id
(
@@ -961,7 +1025,8 @@
;
Name1 = Name0
),
- string__append_list([Name1, NameSuffix, Id], Name),
+ make_pred_name(PredModule, "UnusedArgs", yes(PredOrFunc),
+ Name1, unused_args(UnusedArgs), Name),
pred_info_arity(PredInfo0, Arity),
pred_info_typevarset(PredInfo0, TypeVars),
remove_listof_elements(ArgTypes0, 1, UnusedArgs, ArgTypes),
@@ -972,9 +1037,7 @@
pred_info_get_class_context(PredInfo0, ClassContext),
pred_info_get_aditi_owner(PredInfo0, Owner),
map__init(EmptyProofs),
- % *** This will need to be fixed when the condition
- % field of the pred_info becomes used.
- pred_info_init(PredModule, qualified(PredModule, Name), Arity, Tvars,
+ pred_info_init(PredModule, Name, Arity, Tvars,
ExistQVars, ArgTypes, true, Context, ClausesInfo, Status,
Markers, GoalType, PredOrFunc, ClassContext, EmptyProofs,
Owner, PredInfo1),
@@ -1018,23 +1081,18 @@
% Create a pred_info for an imported pred with a pragma unused_args
% in the .opt file.
-:- pred make_imported_unused_args_pred_infos(pred_proc_list::in,
+:- pred make_imported_unused_args_pred_info(pred_proc_id::in, list(int)::in,
proc_call_info::in, proc_call_info::out,
module_info::in, module_info::out) is det.
-make_imported_unused_args_pred_infos([], ProcCallInfo, ProcCallInfo,
- ModuleInfo, ModuleInfo).
-make_imported_unused_args_pred_infos([OptProc | OptProcs],
+make_imported_unused_args_pred_info(OptProc, UnusedArgs,
ProcCallInfo0, ProcCallInfo, ModuleInfo0, ModuleInfo) :-
- module_info_unused_arg_info(ModuleInfo0, UnusedArgInfo),
- map__lookup(UnusedArgInfo, OptProc, UnusedArgs),
OptProc = proc(PredId, ProcId),
module_info_pred_proc_info(ModuleInfo0,
PredId, ProcId, PredInfo0, ProcInfo0),
make_new_pred_info(ModuleInfo0, PredInfo0, UnusedArgs,
- "__ua", imported(interface), OptProc, NewPredInfo0),
+ imported(interface), OptProc, NewPredInfo0),
pred_info_procedures(NewPredInfo0, NewProcs0),
- next_mode_id(NewProcs0, no, NewProcId),
% Assign the old procedure to a new predicate.
proc_info_headvars(ProcInfo0, HeadVars0),
@@ -1043,23 +1101,20 @@
proc_info_argmodes(ProcInfo1, ArgModes0),
remove_listof_elements(ArgModes0, 1, UnusedArgs, ArgModes),
proc_info_set_argmodes(ProcInfo0, ArgModes, ProcInfo),
- map__set(NewProcs0, NewProcId, ProcInfo, NewProcs),
+ map__set(NewProcs0, ProcId, ProcInfo, NewProcs),
pred_info_set_procedures(NewPredInfo0, NewProcs, NewPredInfo),
% Add the new proc to the pred table.
module_info_get_predicate_table(ModuleInfo0, PredTable0),
predicate_table_insert(PredTable0, NewPredInfo, NewPredId, PredTable1),
- module_info_set_predicate_table(ModuleInfo0, PredTable1, ModuleInfo1),
+ module_info_set_predicate_table(ModuleInfo0, PredTable1, ModuleInfo),
pred_info_module(NewPredInfo, PredModule),
pred_info_name(NewPredInfo, PredName),
PredSymName = qualified(PredModule, PredName),
% Add the new proc to the proc_call_info map.
map__det_insert(ProcCallInfo0, proc(PredId, ProcId),
- call_info(NewPredId, NewProcId, PredSymName, UnusedArgs),
- ProcCallInfo1),
- make_imported_unused_args_pred_infos(OptProcs, ProcCallInfo1,
- ProcCallInfo, ModuleInfo1, ModuleInfo).
-
+ call_info(NewPredId, ProcId, PredSymName, UnusedArgs),
+ ProcCallInfo).
:- pred remove_listof_elements(list(T)::in, int::in, list(int)::in,
list(T)::out) is det.
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.320
diff -u -u -r1.320 user_guide.texi
--- doc/user_guide.texi 8 Aug 2002 06:25:48 -0000 1.320
+++ doc/user_guide.texi 8 Aug 2002 16:23:46 -0000
@@ -5064,6 +5064,12 @@
already built, e.g.@: those for the standard library, but do not build any
others.
+ at item --intermodule-analysis
+ at findex --intermodule-analysis
+Perform analyses such as termination analysis and
+unused argument elimination across module boundaries.
+This option is not yet fully implemented.
+
@sp 1
@item --split-c-files
@findex --split-c-files
Index: library/std_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.272
diff -u -u -r1.272 std_util.m
--- library/std_util.m 21 Jun 2002 13:26:50 -0000 1.272
+++ library/std_util.m 7 Aug 2002 15:04:10 -0000
@@ -135,6 +135,8 @@
:- type unit ---> unit.
+:- type unit(T) ---> unit1.
+
%-----------------------------------------------------------------------------%
% The "pair" type. Useful for many purposes.
Index: profiler/demangle.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/demangle.m,v
retrieving revision 1.15
diff -u -u -r1.15 demangle.m
--- profiler/demangle.m 25 Sep 2001 09:37:07 -0000 1.15
+++ profiler/demangle.m 8 Aug 2002 15:30:46 -0000
@@ -157,6 +157,8 @@
% Process the mangling introduced by unused_args.m.
% This involves stripping off the `__ua<m>' or `__uab<m>' added to
% the end of the predicate/function name, where m is the mode number.
+ % XXX This is out-of-date. The compiler now generates names
+ % such as UnusedArgs__p__[1].
%
(
remove_trailing_int(UA_ModeNum),
Index: scripts/Mmake.vars.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/Mmake.vars.in,v
retrieving revision 1.77
diff -u -u -r1.77 Mmake.vars.in
--- scripts/Mmake.vars.in 7 Aug 2002 13:12:09 -0000 1.77
+++ scripts/Mmake.vars.in 8 Aug 2002 06:21:49 -0000
@@ -548,6 +549,8 @@
int3s_subdir=$(SUBDIR)int3s/
opts_subdir=$(SUBDIR)opts/
trans_opts_subdir=$(SUBDIR)trans_opts/
+analysiss_subdir=$(SUBDIR)analysiss/
+requests_subdir=$(SUBDIR)requests/
date0s_subdir=$(SUBDIR)date0s/
dates_subdir=$(SUBDIR)dates/
date3s_subdir=$(SUBDIR)date3s/
@@ -588,6 +591,8 @@
int3s_subdir=
opts_subdir=
trans_opts_subdir=
+analysiss_subdir=
+requests_subdir=
date0s_subdir=
dates_subdir=
date3s_subdir=
Index: tests/warnings/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/warnings/Mmakefile,v
retrieving revision 1.21
diff -u -u -r1.21 Mmakefile
--- tests/warnings/Mmakefile 1 Aug 2002 00:41:40 -0000 1.21
+++ tests/warnings/Mmakefile 8 Aug 2002 10:57:46 -0000
@@ -23,6 +23,7 @@
simple_code \
singleton_test \
state_vars_test \
+ unused_args_analysis \
unused_args_test \
unused_import
@@ -44,6 +45,9 @@
--trace-optimized
MCFLAGS-duplicate_call = --warn-duplicate-calls
+MCFLAGS-unused_args_analysis = --intermodule-analysis \
+ --optimize-unused-args --warn-unused-args
+MCFLAGS-unused_args_analysis2 = --intermodule-analysis --optimize-unused-args
MCFLAGS-unused_args_test = --warn-unused-args
MCFLAGS-unused_import = --warn-interface-imports
MCFLAGS-inference_test = --infer-all
@@ -52,6 +56,11 @@
# some of the infinite recursion warnings don't show up at
# lower optimization levels.
MCFLAGS-infinite_recursion = --excess-assign --common-struct
+
+ # Build the `.analysis' file for unused_args_analysis2
+ # before building unused_args_analysis.c.
+$(cs_subdir)unused_args_analysis.c: $(cs_subdir)unused_args_analysis2.c
+unused_args_analysis.err: $(cs_subdir)unused_args_analysis2.c
#-----------------------------------------------------------------------------#
Index: tests/warnings/unused_args_analysis.exp
===================================================================
RCS file: tests/warnings/unused_args_analysis.exp
diff -N tests/warnings/unused_args_analysis.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/warnings/unused_args_analysis.exp 8 Aug 2002 10:57:53 -0000
@@ -0,0 +1,2 @@
+unused_args_analysis.m:005: In predicate `unused_args_analysis:p/2':
+unused_args_analysis.m:005: warning: argument 1 is unused.
Index: tests/warnings/unused_args_analysis.m
===================================================================
RCS file: tests/warnings/unused_args_analysis.m
diff -N tests/warnings/unused_args_analysis.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/warnings/unused_args_analysis.m 1 Aug 2002 15:53:47 -0000
@@ -0,0 +1,11 @@
+:- module unused_args_analysis.
+
+:- interface.
+
+:- pred p(int::in, int::out) is det.
+
+:- implementation.
+
+:- import_module unused_args_analysis2.
+
+p(X, Y) :- p2(X, Y).
Index: tools/bootcheck
===================================================================
RCS file: /home/mercury1/repository/mercury/tools/bootcheck,v
retrieving revision 1.132
diff -u -u -r1.132 bootcheck
--- tools/bootcheck 7 Aug 2002 03:16:38 -0000 1.132
+++ tools/bootcheck 8 Aug 2002 06:34:01 -0000
@@ -477,6 +477,13 @@
cp $root/browser/Mmake* $root/browser/Mercury.options .
$LN_S $root/browser/$BROWSER_LIB_NAME.init .
cd $root/stage2
+ mkdir analysis
+ cd analysis
+ $LN_S $root/analysis/*.m .
+ cp $root/analysis/Mmake* $root/analysis/Mercury.options .
+ $LN_S $root/analysis/$ANALYSIS_LIB_NAME.init .
+
+ cd $root/stage2
if $copy_runtime
then
# Remove symbolic link to the stage 1 runtime
@@ -596,7 +603,8 @@
fi
if (cd stage2 && $MMAKE $mmake_opts dep_library dep_browser \
- dep_compiler dep_profiler dep_deep_profiler)
+ dep_analysis dep_compiler dep_profiler \
+ dep_deep_profiler)
then
echo "building of stage 2 dependencies successful"
else
@@ -628,6 +636,14 @@
exit 1
fi
+ if (cd stage2 && $MMAKE $mmake_opts $jfactor analysis)
+ then
+ echo "building of stage 2 analysis successful"
+ else
+ echo "building of stage 2 analysis not successful"
+ exit 1
+ fi
+
if (cd stage2/compiler && $MMAKE $mmake_opts $jfactor mercury_compile)
then
echo "building of stage 2 compiler successful"
@@ -718,6 +734,12 @@
cp $root/browser/Mmake* $root/browser/Mercury.options .
$LN_S $root/browser/$BROWSER_LIB_NAME.init .
cd $root/stage3
+ mkdir analysis
+ cd analysis
+ $LN_S $root/analysis/*.m .
+ cp $root/analysis/Mmake* $root/analysis/Mercury.options .
+ $LN_S $root/analysis/$ANALYSIS_LIB_NAME.init .
+ cd $root/stage3
$LN_S $root/boehm_gc .
$LN_S $root/bindist .
$LN_S $root/doc .
@@ -757,7 +779,7 @@
fi
if (cd stage3 && $MMAKE $mmake_opts dep_library dep_browser \
- dep_compiler)
+ dep_analysis dep_compiler)
then
echo "building of stage 3 dependencies successful"
else
@@ -815,6 +837,26 @@
fi
fi
+ if (cd stage3/analysis &&
+ $MMAKE $mmake_opts $jfactor all-ints &&
+ $MMAKE $mmake_opts $jfactor ${target_ext}s)
+ then
+ echo "building of stage 3 analysis successful"
+ else
+ echo "building of stage 3 analysis initially not successful"
+ df .
+ # try again, in case the failure cause was transient
+ if (cd stage3/analysis &&
+ $MMAKE $mmake_opts $jfactor all-ints &&
+ $MMAKE $mmake_opts $jfactor ${target_ext}s)
+ then
+ echo "building of stage 3 analysis successful"
+ else
+ echo "building of stage 3 analysis not successful"
+ exit 1
+ fi
+ fi
+
if (cd stage3/compiler && $MMAKE $mmake_opts $jfactor ${target_ext}s)
then
echo "building of stage 3 compiler successful"
@@ -846,7 +888,7 @@
exec > "$outfile" # redirect stdout to $outfile
fi
- for dir in library browser compiler; do
+ for dir in library browser analysis compiler; do
# `mmake cs' in the compiler directory doesn't build
# `top_level_init.c', so we only compare the `.c'
# files present in the stage3 directory.
Index: util/mdemangle.c
===================================================================
RCS file: /home/mercury1/repository/mercury/util/mdemangle.c,v
retrieving revision 1.45
diff -u -u -r1.45 mdemangle.c
--- util/mdemangle.c 23 Jul 2002 19:39:00 -0000 1.45
+++ util/mdemangle.c 8 Aug 2002 15:35:52 -0000
@@ -162,8 +162,13 @@
static const char func[] = "func__";
static const char porf[] = "pred_or_func__";
+ /*
+ ** XXX This is out-of-date. The compiler now generates names
+ ** such as UnusedArgs__p__[1].
+ */
static const char ua_suffix[] = "__ua"; /* added by unused_args.m */
static const char ua_suffix2[] = "__uab"; /* added by unused_args.m */
+
static const char ho_suffix[] = "__ho"; /* added by higher_order.m */
static const char mercury_data[] = "mercury_data_";
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list