[m-rev.] for review: [CTGC] user annotated sharing, second version

Nancy Mazur Nancy.Mazur at cs.kuleuven.ac.be
Mon Jul 3 19:19:05 AEST 2006


Hi Julien, 

here is the full change for providing user annotated sharing, including some
documentation, and the necessary changes to equiv_types.m and
recompilation.*.m. 

I would like to be able to commit this, as the library modules need some
user annotations at some point in time. 

Nancy

===================================================================


Estimated hours taken: 32
Branches: main

Add the possibility of annotating foreign code with sharing information. 
The sharing information is part of the foreign_proc pragmas, and must be
of the following format: 
	no_sharing 		% meaning that the procedure does not 
				% create any sharing.
	unknown_sharing		% meaning that the procedure creates any
				% possible sharing;
	sharing(MaybeTypeInformation, SharingList)	
				% meaning that the procedure creates at most
				% the listed sharing.
where
MaybeTypes = 
	yes(Types)
	no
where Types corresponds to the type-signature of the foreign proc (i.e. they
must be unifiable). The types are only needed when the typeselectors used in
specifying the sharing make use of type variables.

and

SharingList = list of SharingPair

and

SharingPair = cel(Var1, Typeselectors1) - cel(Var2, Typeselectors2)

where
	Var1, Var2 correspond to head variables from the foreign proc; 
	Typeselectors1, Typeselectors2 correspond to a list of typeselectors,
	i.e., a list of types possibly in terms of the types given in 
	MaybeTypes.

Example: 

:- pred array.init_2(int::in, T::in, array(T)::array_uo) is det.

:- pragma foreign_proc("C",
    array.init_2(Size::in, Item::in, Array::array_uo),
    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
    sharing(yes(int, T, array(T)), [cel(Item,[]) - cel(Array,[T])])],
"
    ML_alloc_marray(Array, Size + 1, MR_PROC_LABEL);
    ML_init_marray(Array, Size, Item);
").

The meaning: a call init_2(Size, Item, Array) may create
sharing between Item, and any terms of Array with the type T (i.e. the elements
of the array). 

compiler/add_pragma.m:
compiler/prog_ctgc.m:
compiler/prog_io_pragma.m:
	Parsing/Renaming routines for the user annotated sharing.

compiler/ctgc.util.m:
	BUGFIX. The definition of "get_type_substitution" was actually doing
	the wrong thing, as it was creating a substitution with which to
	rename two type-lists "away" from each other... while the analysis
	needs the substitution resulting from unifying the type-lists.

compiler/module_qual.m:
	Module qualify the types that are part of the sharing declaration.

compiler/prog_data.m:
	Types for recording user annotated sharing.
	Change the definition of the public representation for 
	structure sharing.

compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.indirect.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
	Use foreign_proc sharing information when computing the overall
	sharing.

compiler/equiv_type.m:
compiler/recompilation.m:
compiler/recompilation.usage.m:
	Expand equivalence types.
	I left an XXX comment in recompilation.usage.m, as I don't know what
	exactly should be found at that place in the case of such a 
	sharing foreign_proc declaration.

doc/reference_manual.texi:
	Document the sharing foreign_proc pragmas. (Commented out). 
	Add entries for documenting structure sharing analysis, and
	compile-time garbage collection. (Commented out).


Index: compiler/add_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/add_pragma.m,v
retrieving revision 1.35
diff -u -d -r1.35 add_pragma.m
--- compiler/add_pragma.m	15 Jun 2006 19:36:57 -0000	1.35
+++ compiler/add_pragma.m	3 Jul 2006 08:58:50 -0000
@@ -1574,9 +1574,9 @@
                 pred_info_get_arg_types(!.PredInfo, ArgTypes),
                 pred_info_get_purity(!.PredInfo, Purity),
                 clauses_info_add_pragma_foreign_proc(Purity, Attributes,
-                    PredId, ProcId, ProgVarSet, PVars, ArgTypes, PragmaImpl,
-                    Context, PredOrFunc, PredName, Arity, Clauses0, Clauses,
-                    !ModuleInfo, !IO),
+                    PredId, ProcId, ProgVarSet, PVars, ArgTypes, 
+                    PragmaImpl, Context, PredOrFunc, PredName, Arity, 
+                    Clauses0, Clauses, !ModuleInfo, !IO),
                 pred_info_set_clauses_info(Clauses, !PredInfo),
                 pred_info_update_goal_type(pragmas, !PredInfo),
                 map.det_update(Preds0, PredId, !.PredInfo, Preds),
@@ -2362,14 +2362,14 @@
     %
 :- pred clauses_info_add_pragma_foreign_proc(purity::in,
     pragma_foreign_proc_attributes::in, pred_id::in, proc_id::in,
-    prog_varset::in, list(pragma_var)::in, list(mer_type)::in,
+    prog_varset::in, list(pragma_var)::in, list(mer_type)::in, 
     pragma_foreign_code_impl::in, prog_context::in, pred_or_func::in,
     sym_name::in, arity::in, clauses_info::in, clauses_info::out,
     module_info::in, module_info::out, io::di, io::uo) is det.
 
 clauses_info_add_pragma_foreign_proc(Purity, Attributes0, PredId, ProcId,
-        PVarSet, PVars, OrigArgTypes, PragmaImpl0, Context, PredOrFunc,
-        PredName, Arity, !ClausesInfo, !ModuleInfo, !IO) :-
+        PVarSet, PVars, OrigArgTypes, PragmaImpl0, Context, 
+        PredOrFunc, PredName, Arity, !ClausesInfo, !ModuleInfo, !IO) :-
 
     !.ClausesInfo = clauses_info(VarSet0, ExplicitVarTypes, TVarNameMap,
         InferredVarTypes, HeadVars, ClauseRep, RttiVarMaps,
@@ -2395,7 +2395,7 @@
     %
     foreign.extrude_pragma_implementation(BackendForeignLanguages,
         PVars, PredName, PredOrFunc, Context, !ModuleInfo,
-        Attributes0, Attributes, PragmaImpl0, PragmaImpl),
+        Attributes0, Attributes1, PragmaImpl0, PragmaImpl),
 
     %
     % Check for arguments occurring multiple times.
@@ -2437,6 +2437,9 @@
         % Put the purity in the goal_info in case this foreign code is inlined.
         add_goal_info_purity_feature(Purity, GoalInfo1, GoalInfo),
         make_foreign_args(HeadVars, ArgInfo, OrigArgTypes, ForeignArgs),
+        % Perform some renaming in any user annotated sharing information.
+        maybe_rename_user_annotated_sharing_information(Args0, HeadVars, 
+            OrigArgTypes, Attributes1, Attributes, !IO),
         HldsGoal0 = foreign_proc(Attributes, PredId, ProcId, ForeignArgs, [],
             PragmaImpl) - GoalInfo,
         map.init(EmptyVarTypes),
@@ -2465,6 +2468,31 @@
             HasForeignClauses)
     ).
 
+    % Rename any user annotated structure sharing information from the
+    % variables (incl. type variables) in terms of which that information
+    % is expressed, to the formal variables in terms of which the clause
+    % is expressed. 
+    %
+:- pred maybe_rename_user_annotated_sharing_information(list(prog_var)::in,
+    list(prog_var)::in, list(mer_type)::in, 
+    pragma_foreign_proc_attributes::in, pragma_foreign_proc_attributes::out, 
+    io::di, io::uo) is det.
+
+maybe_rename_user_annotated_sharing_information(ActualHeadVars, FormalHeadVars,
+        FormalTypes, !Attributes, !IO):-
+    globals.io_lookup_bool_option(structure_sharing_analysis, SharingAnalysis,
+        !IO),
+    (
+        SharingAnalysis = no
+    ;
+        SharingAnalysis = yes, 
+        rename_user_annotated_sharing(ActualHeadVars, FormalHeadVars,
+            FormalTypes, user_annotated_sharing(!.Attributes), 
+            FormalUserSharing),
+        set_user_annotated_sharing(FormalUserSharing, !Attributes)
+    ).
+    
+    
 :- func is_applicable_for_current_backend(backend,
     list(pragma_foreign_proc_extra_attribute)) = bool.
 
Index: compiler/ctgc.util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ctgc.util.m,v
retrieving revision 1.6
diff -u -d -r1.6 ctgc.util.m
--- compiler/ctgc.util.m	29 May 2006 13:04:32 -0000	1.6
+++ compiler/ctgc.util.m	3 Jul 2006 08:58:50 -0000
@@ -47,9 +47,8 @@
     % Same as above, but then in the context of the types of the called 
     % procedures. 
     %
-:- func get_type_substitution(module_info, pred_proc_id, list(mer_type),
-    tvarset) = tsubst.
-
+:- func get_type_substitution(module_info, pred_proc_id, 
+    list(mer_type), tvarset) = tsubst.
 
 %-----------------------------------------------------------------------------%
 
@@ -101,25 +100,14 @@
     proc_info_get_headvars(ProcInfo, FormalVars),
     map.from_corresponding_lists(FormalVars, ActualArgs, VariableRenaming).
 
-get_type_substitution(ModuleInfo, PPId, ActualTypes, ActualTVarset) = 
+get_type_substitution(ModuleInfo, PPId, ActualTypes, _TVarSet) = 
         TypeSubstitution :- 
     module_info_pred_proc_info(ModuleInfo, PPId, PredInfo, _ProcInfo),
 
     % types of the head variables.
-    pred_info_get_arg_types(PredInfo, FormalTVarset, _, FormalTypes),
-
-    % (this is a bit that was inspired by the code for
-    % arg_type_list_subsumes/6)
-    tvarset_merge_renaming(ActualTVarset, FormalTVarset,_TVarSet1, Renaming),
-    apply_variable_renaming_to_type_list(Renaming, FormalTypes,
-        RenFormalTypes),
+    pred_info_get_arg_types(PredInfo, FormalTypes),
 
-    ( type_list_subsumes(RenFormalTypes, ActualTypes, TypeSubstitution0) ->
-        TypeSubstitution = TypeSubstitution0
-    ;
-        unexpected(this_file, "Types are supposed to be unifiable.")
-    ).
-    
+    type_list_subsumes_det(FormalTypes, ActualTypes, TypeSubstitution).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/equiv_type.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/equiv_type.m,v
retrieving revision 1.62
diff -u -d -r1.62 equiv_type.m
--- compiler/equiv_type.m	20 Apr 2006 05:36:51 -0000	1.62
+++ compiler/equiv_type.m	3 Jul 2006 08:58:52 -0000
@@ -416,6 +416,36 @@
     ).
 
 replace_in_item(ModuleName,
+        pragma(Origin, foreign_proc(Attrs0, PName, PredOrFunc, 
+            ProcVars, ProcVarset, ProcInstVarset, ProcImpl)),
+        _Context, EqvMap, _EqvInstMap,
+        pragma(Origin, foreign_proc(Attrs, PName, PredOrFunc, 
+            ProcVars, ProcVarset, ProcInstVarset, ProcImpl)),
+        [], !Info) :-
+    some [!EquivTypeInfo] (
+        maybe_record_expanded_items(ModuleName, PName, !.Info, 
+            !:EquivTypeInfo),
+        UserSharing0 = user_annotated_sharing(Attrs0), 
+        (   
+            UserSharing0 = user_sharing(Sharing0, MaybeTypes0),
+            MaybeTypes0 = yes(user_type_info(Types0, TVarset0))
+        ->
+            replace_in_type_list(EqvMap, Types0, Types, _AnythingChanged, 
+                TVarset0, TVarset, !EquivTypeInfo),
+            replace_in_structure_sharing_domain(EqvMap, Sharing0, Sharing,
+                TVarset0, !EquivTypeInfo),
+            MaybeTypes = yes(user_type_info(Types, TVarset)),
+            UserSharing = user_sharing(Sharing, MaybeTypes),
+            set_user_annotated_sharing(UserSharing, Attrs0, Attrs)
+        ;
+            Attrs = Attrs0
+        ),
+        ItemId = item_id(foreign_proc_item, item_name(PName, 
+            list.length(ProcVars))),
+        finish_recording_expanded_items(ItemId, !.EquivTypeInfo, !Info)
+    ). 
+
+replace_in_item(ModuleName,
         mutable(MutName, Type0, InitValue, Inst0, Attrs, Varset),
         _Context, EqvMap, EqvInstMap,
         mutable(MutName, Type, InitValue, Inst, Attrs, Varset),
@@ -953,6 +983,48 @@
 replace_in_tm(EqvMap, type_and_mode(Type0, Mode),
         type_and_mode(Type, Mode), !VarSet, !Info) :-
     replace_in_type(EqvMap, Type0, Type, _, !VarSet, !Info).
+
+%-----------------------------------------------------------------------------%
+%
+:- pred replace_in_structure_sharing_domain(eqv_map::in, 
+    structure_sharing_domain::in, structure_sharing_domain::out, 
+    tvarset::in, equiv_type_info::in, equiv_type_info::out) is det.
+
+replace_in_structure_sharing_domain(_, X @ structure_sharing_bottom,
+    X, _TVarset, !EquivTypeInfo).
+replace_in_structure_sharing_domain(_, X @ structure_sharing_top(_), 
+    X, _TVarset, !EquivTypeInfo).
+replace_in_structure_sharing_domain(EqvMap, 
+        structure_sharing_real(SharingPairs0),
+        structure_sharing_real(SharingPairs), TVarset, !EquivTypeInfo) :- 
+    list.map_foldl(replace_in_structure_sharing_pair(EqvMap, TVarset), 
+        SharingPairs0, SharingPairs, !EquivTypeInfo).
+
+:- pred replace_in_structure_sharing_pair(eqv_map::in, tvarset::in, 
+    structure_sharing_pair::in, structure_sharing_pair::out,
+    equiv_type_info::in, equiv_type_info::out) is det.
+
+replace_in_structure_sharing_pair(EqvMap, TVarset, Data10 - Data20, 
+        Data1 - Data2, !EquivTypeInfo) :- 
+    replace_in_datastruct(EqvMap, TVarset, Data10, Data1, !EquivTypeInfo),
+    replace_in_datastruct(EqvMap, TVarset, Data20, Data2, !EquivTypeInfo).
+
+:- pred replace_in_datastruct(eqv_map::in, tvarset::in, datastruct::in,
+    datastruct::out, equiv_type_info::in, equiv_type_info::out) is det.
+
+replace_in_datastruct(EqvMap, TVarset, Data0, Data, !EquivTypeInfo) :- 
+    Sel0 = Data0 ^ sc_selector,
+    list.map_foldl(replace_in_unit_selector(EqvMap, TVarset), Sel0, Sel, 
+        !EquivTypeInfo), 
+    Data = Data0 ^ sc_selector := Sel.
+
+:- pred replace_in_unit_selector(eqv_map::in, tvarset::in, unit_selector::in,
+    unit_selector::out, equiv_type_info::in, equiv_type_info::out) is det.
+
+replace_in_unit_selector(_, _, X @ termsel(_, _), X, !EquivTypeInfo).
+replace_in_unit_selector(EqvMap, TVarset, typesel(Type0), typesel(Type),
+        !EquivTypeInfo) :-
+    replace_in_type(EqvMap, Type0, Type, _, TVarset, _, !EquivTypeInfo).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/module_qual.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/module_qual.m,v
retrieving revision 1.137
diff -u -d -r1.137 module_qual.m
--- compiler/module_qual.m	15 Jun 2006 19:37:04 -0000	1.137
+++ compiler/module_qual.m	3 Jul 2006 08:58:55 -0000
@@ -1060,10 +1060,17 @@
 qualify_pragma(X at foreign_decl(_, _, _), X, !Info, !IO).
 qualify_pragma(X at foreign_code(_, _), X, !Info, !IO).
 qualify_pragma(X at foreign_import_module(_, _), X, !Info, !IO).
-qualify_pragma(X, Y, !Info, !IO) :-
-    PragmaVars0 = X ^ proc_vars,
-    qualify_pragma_vars(PragmaVars0, PragmaVars, !Info, !IO),
-    Y = X ^ proc_vars := PragmaVars.
+qualify_pragma(foreign_proc(Attrs0, Name, PredOrFunc, Vars0, Varset, 
+        InstVarset, Impl), foreign_proc(Attrs, Name, PredOrFunc, Vars, Varset,
+        InstVarset, Impl), !Info, !IO) :-
+    qualify_pragma_vars(Vars0, Vars, !Info, !IO), 
+    UserSharing0 = user_annotated_sharing(Attrs0),
+    qualify_user_sharing(UserSharing0, UserSharing, !Info, !IO),
+    set_user_annotated_sharing(UserSharing, Attrs0, Attrs).  
+% qualify_pragma(X, Y, !Info, !IO) :-
+    % PragmaVars0 = X ^ proc_vars,
+    % qualify_pragma_vars(PragmaVars0, PragmaVars, !Info, !IO),
+    % Y = X ^ proc_vars := PragmaVars.
 qualify_pragma(tabled(EvalMethod, Name, Arity, PredOrFunc, MModes0, Attrs),
         tabled(EvalMethod, Name, Arity, PredOrFunc, MModes, Attrs),
         !Info, !IO) :-
@@ -1347,6 +1354,25 @@
 convert_simple_item_type(inst_id) = inst_item.
 convert_simple_item_type(class_id) = typeclass_item.
 
+:- pred qualify_user_sharing(user_annotated_sharing::in, 
+    user_annotated_sharing::out, mq_info::in, mq_info::out, 
+    io::di, io::uo) is det.
+
+qualify_user_sharing(!UserSharing, !Info, !IO) :-
+    (
+        !.UserSharing = no_user_annotated_sharing
+    ;
+        !.UserSharing = user_sharing(Sharing, MaybeTypes0),
+        (
+            MaybeTypes0 = yes(user_type_info(Types0, TVarset))
+        ->
+            qualify_type_list(Types0, Types, !Info, !IO),
+            MaybeTypes = yes(user_type_info(Types, TVarset)), 
+            !:UserSharing = user_sharing(Sharing, MaybeTypes)
+        ;
+            true
+        )
+    ).
 %-----------------------------------------------------------------------------%
 
 :- type id_type
Index: compiler/prog_ctgc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_ctgc.m,v
retrieving revision 1.10
diff -u -d -r1.10 prog_ctgc.m
--- compiler/prog_ctgc.m	15 Jun 2006 19:37:08 -0000	1.10
+++ compiler/prog_ctgc.m	3 Jul 2006 08:58:56 -0000
@@ -27,6 +27,7 @@
 :- import_module map.
 :- import_module maybe.
 :- import_module term.
+:- import_module varset.
 
 %-----------------------------------------------------------------------------%
 %
@@ -51,6 +52,9 @@
 
 :- func parse_structure_reuse_domain(term(T)) = structure_reuse_domain.
 
+:- pred parse_user_annotated_sharing(varset::in, term::in, 
+    user_annotated_sharing::out) is semidet.
+
 %-----------------------------------------------------------------------------%
 %
 % Printing routines
@@ -153,6 +157,10 @@
     tsubst::in, structure_sharing_domain::in,
     structure_sharing_domain::out) is det.
 
+:- pred rename_user_annotated_sharing(list(prog_var)::in, list(prog_var)::in,
+    list(mer_type)::in, user_annotated_sharing::in, 
+    user_annotated_sharing::out) is det.
+
 :- pred rename_structure_reuse_condition(map(prog_var, prog_var)::in, 
     tsubst::in, structure_reuse_condition::in, 
     structure_reuse_condition::out) is det.
@@ -175,11 +183,13 @@
 :- import_module parse_tree.prog_io.
 :- import_module parse_tree.prog_io_util.
 :- import_module parse_tree.prog_out.
+:- import_module parse_tree.prog_type.
 :- import_module parse_tree.prog_type_subst.
 :- import_module parse_tree.prog_util.
 
 :- import_module string.
 :- import_module pair.
+:- import_module set.
 :- import_module varset.
 
 %-----------------------------------------------------------------------------%
@@ -331,14 +341,15 @@
         Term = term.functor(term.atom(Cons), _, Context),
         (
             Cons = "[|]",
-            SharingAs0 = real(parse_structure_sharing(Term))
+            SharingAs0 = structure_sharing_real(parse_structure_sharing(Term))
         ;
             Cons = "bottom",
-            SharingAs0 = bottom
+            SharingAs0 = structure_sharing_bottom
         ;
             Cons = "top",
             context_to_string(Context, ContextMsg),
-            SharingAs0 = top(["imported top: " ++ ContextMsg ++ "."])
+            SharingAs0 = structure_sharing_top(["imported top: " 
+                ++ ContextMsg ++ "."])
         )
     ->
         SharingAs = SharingAs0
@@ -415,6 +426,88 @@
             "(term not a functor).")
     ).
 
+%-----------------------------------------------------------------------------%
+
+parse_user_annotated_sharing(Varset, Term, UserSharing) :- 
+    (
+        Term = term.functor(term.atom("no_sharing"), [], _), 
+        UserSharing = user_sharing(structure_sharing_bottom, no)
+    ;
+        Term = term.functor(term.atom("unknown_sharing"), [], Context),
+        context_to_string(Context, ContextString), 
+        Msg = "user declared top(" ++ ContextString ++ ")",
+        UserSharing = user_sharing(structure_sharing_top([Msg]), no)
+    ;
+        Term = term.functor(term.atom("sharing"), 
+            [TypesTerm, UserSharingTerm], _),
+        (
+            TypesTerm = term.functor(term.atom("yes"), ListTypeTerms, _),
+            parse_types(ListTypeTerms, ok(Types)), 
+            term.vars_list(ListTypeTerms, TypeVars),
+            varset.select(Varset, set.list_to_set(TypeVars), Varset0),
+            MaybeUserTypes = yes(user_type_info(Types, 
+                varset.coerce(Varset0)))
+        ;
+            TypesTerm = term.functor(term.atom("no"), _, _), 
+            MaybeUserTypes = no
+        ), 
+        parse_user_annotated_sharing_term(UserSharingTerm, Sharing), 
+        UserSharing = user_sharing(Sharing, MaybeUserTypes)
+    ).
+
+:- pred parse_user_annotated_sharing_term(term::in, 
+    structure_sharing_domain::out) is semidet.
+
+parse_user_annotated_sharing_term(SharingDomainUserTerm, SharingDomain) :-
+    get_list_term_arguments(SharingDomainUserTerm, SharingPairTerms),
+    (
+        SharingPairTerms = [],
+        SharingDomain = structure_sharing_bottom
+    ;
+        SharingPairTerms = [_|_],
+        list.map(parse_user_annotated_sharing_pair_term, SharingPairTerms,
+            SharingPairs),
+        SharingDomain = structure_sharing_real(SharingPairs)
+    ).
+     
+:- pred get_list_term_arguments(term::in, list(term)::out) is semidet.
+
+get_list_term_arguments(ListTerm, ArgumentTerms) :-
+    ListTerm = term.functor(term.atom(Cons), Args, _),
+    (
+        Cons = "[|]",
+        Args = [FirstTerm, RestTerm],
+        get_list_term_arguments(RestTerm, RestList),
+        ArgumentTerms = [FirstTerm | RestList]
+    ;
+        Cons = "[]",
+        ArgumentTerms = []
+    ).
+
+:- pred parse_user_annotated_sharing_pair_term(term::in, 
+    structure_sharing_pair::out) is semidet.
+
+parse_user_annotated_sharing_pair_term(Term, SharingPair) :-
+    Term = term.functor(term.atom("-"), [Left, Right], _),
+    parse_user_annotated_datastruct_term(Left, LeftData),
+    parse_user_annotated_datastruct_term(Right, RightData),
+    SharingPair = LeftData - RightData.
+        
+:- pred parse_user_annotated_datastruct_term(term::in, datastruct::out) 
+    is semidet.
+
+parse_user_annotated_datastruct_term(Term, Datastruct) :- 
+    Term = term.functor(term.atom("cel"), [VarTerm, TypesTerm], _),
+    VarTerm = term.variable(GenericVar),
+    term.coerce_var(GenericVar, ProgVar),
+    get_list_term_arguments(TypesTerm, TypeTermsList),
+    parse_types(TypeTermsList, ok(Types)),
+    list.map(mer_type_to_typesel, Types, Selector),
+    Datastruct = selected_cel(ProgVar, Selector).
+
+:- pred mer_type_to_typesel(mer_type::in, unit_selector::out) is det.
+
+mer_type_to_typesel(Type, typesel(Type)).
 
 %-----------------------------------------------------------------------------%
 %
@@ -518,7 +611,7 @@
         MaybeThreshold, Start, Separator, End, SharingAs, !IO) :-
     io.write_string(Start, !IO),
     (
-        SharingAs = top(Msgs),
+        SharingAs = structure_sharing_top(Msgs),
         (
             VerboseTop = no,
             io.write_string("top", !IO)
@@ -529,10 +622,10 @@
             io.write_string("])", !IO)
         )
     ;
-        SharingAs = bottom,
+        SharingAs = structure_sharing_bottom,
         io.write_string("bottom", !IO)
     ;
-        SharingAs = real(SharingPairs),
+        SharingAs = structure_sharing_real(SharingPairs),
         print_structure_sharing(ProgVarSet, TypeVarSet,
         MaybeThreshold, "[", Separator, "]", SharingPairs, !IO)
     ),
@@ -628,11 +721,48 @@
 rename_structure_sharing(Dict, TypeSubst, !List) :-
     list.map(rename_structure_sharing_pair(Dict, TypeSubst), !List).
 
-rename_structure_sharing_domain(_, _, bottom, bottom).
-rename_structure_sharing_domain(_, _, X @ top(_), X).
-rename_structure_sharing_domain(Dict, TypeSubst, real(!.List), real(!:List)):-
+rename_structure_sharing_domain(_, _, X @ structure_sharing_bottom, X).
+rename_structure_sharing_domain(_, _, X @ structure_sharing_top(_), X).
+rename_structure_sharing_domain(Dict, TypeSubst, 
+        structure_sharing_real(!.List), structure_sharing_real(!:List)):-
     rename_structure_sharing(Dict, TypeSubst, !List).
 
+%-----------------------------------------------------------------------------%
+
+rename_user_annotated_sharing(HeadVars, NewHeadVars, NewTypes, 
+        !UserSharing) :- 
+    (
+        !.UserSharing = no_user_annotated_sharing
+    ;
+        !.UserSharing = user_sharing(Sharing, MaybeTypes),
+        some [!SharingDomain] (
+            !:SharingDomain = Sharing, 
+            (
+                !.SharingDomain = structure_sharing_bottom
+            ;
+                !.SharingDomain = structure_sharing_top(_)
+            ;
+                !.SharingDomain = structure_sharing_real(SharingPairs),
+                map.from_corresponding_lists(HeadVars, NewHeadVars, 
+                    VarRenaming),
+                (
+                    MaybeTypes = yes(user_type_info(UserSharingTypes, 
+                        _UserSharingTVarSet))
+                ->
+                    type_list_subsumes_det(UserSharingTypes, NewTypes, 
+                        TypeSubst)
+                ;
+                    TypeSubst = map.init
+                ),
+                rename_structure_sharing(VarRenaming, TypeSubst, 
+                        SharingPairs, NewSharingPairs),
+                !:SharingDomain = structure_sharing_real(NewSharingPairs)
+            ),
+            !:UserSharing = user_sharing(!.SharingDomain, no)
+        )
+    ). 
+
+%-----------------------------------------------------------------------------%
 rename_structure_reuse_condition(Dict, TypeSubst, 
         structure_reuse_condition(DeadNodes, LiveNodes, Sharing), 
         structure_reuse_condition(RenDeadNodes, RenLiveNodes, RenSharing)) :- 
Index: compiler/prog_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.167
diff -u -d -r1.167 prog_data.m
--- compiler/prog_data.m	15 Jun 2006 19:37:08 -0000	1.167
+++ compiler/prog_data.m	3 Jul 2006 08:58:58 -0000
@@ -328,9 +328,9 @@
     % This is the public representation of the type "sharing_as". 
     %
 :- type structure_sharing_domain
-    --->    bottom
-    ;       real(structure_sharing)
-    ;       top(list(top_feedback)).
+    --->    structure_sharing_bottom
+    ;       structure_sharing_real(structure_sharing)
+    ;       structure_sharing_top(list(top_feedback)).
 
     % Public representation of structure sharing.
     %
@@ -364,6 +364,25 @@
     --->    termsel(cons_id, int)       % term selector
     ;       typesel(mer_type).          % type selector
 
+    % Type to represent the sharing information that is manually added
+    % to procedures implemented as foreign_procs.
+    %
+:- type user_annotated_sharing
+    --->    no_user_annotated_sharing
+    ;       user_sharing(
+                sharing     ::  structure_sharing_domain, 
+                maybe_types ::  maybe(user_sharing_type_information)
+            ).
+
+    % The user may have declared the sharing in terms of type variables. In
+    % that case, we record the types, and the type variable set.
+    %
+:- type user_sharing_type_information
+    --->    user_type_info(
+                types       ::  list(mer_type),
+                typevarset  ::  tvarset
+            ).
+
 %-----------------------------------------------------------------------------%
 %
 % Stuff for the `structure_reuse_info' pragma.
@@ -657,6 +676,8 @@
 :- func thread_safe(pragma_foreign_proc_attributes) = thread_safe.
 :- func purity(pragma_foreign_proc_attributes) = purity.
 :- func terminates(pragma_foreign_proc_attributes) = terminates.
+:- func user_annotated_sharing(pragma_foreign_proc_attributes) = 
+    user_annotated_sharing.
 :- func foreign_language(pragma_foreign_proc_attributes) = foreign_language.
 :- func tabled_for_io(pragma_foreign_proc_attributes) = tabled_for_io.
 :- func legacy_purity_behaviour(pragma_foreign_proc_attributes) = bool.
@@ -694,6 +715,10 @@
     pragma_foreign_proc_attributes::in,
     pragma_foreign_proc_attributes::out) is det.
 
+:- pred set_user_annotated_sharing(user_annotated_sharing::in, 
+    pragma_foreign_proc_attributes::in,
+    pragma_foreign_proc_attributes::out) is det.
+
 :- pred set_may_throw_exception(may_throw_exception::in,
     pragma_foreign_proc_attributes::in,
     pragma_foreign_proc_attributes::out) is det.
@@ -1463,6 +1488,7 @@
                 tabled_for_io           :: tabled_for_io,
                 purity                  :: purity,
                 terminates              :: terminates,
+                user_annotated_sharing  :: user_annotated_sharing,
                 may_throw_exception     :: may_throw_exception,
 
                 % There is some special case behaviour for pragma c_code
@@ -1479,8 +1505,9 @@
 default_attributes(Language) =
     attributes(Language, may_call_mercury, not_thread_safe,
         not_tabled_for_io, purity_impure, depends_on_mercury_calls,
-        default_exception_behaviour, no, no, may_modify_trail,
-        default_calls_mm_tabled, native_if_possible, []).
+        no_user_annotated_sharing, default_exception_behaviour, 
+        no, no, may_modify_trail, default_calls_mm_tabled, 
+        native_if_possible, []).
 
 set_may_call_mercury(MayCallMercury, Attrs0, Attrs) :-
     Attrs = Attrs0 ^ may_call_mercury := MayCallMercury.
@@ -1494,6 +1521,8 @@
     Attrs = Attrs0 ^ purity := Purity.
 set_terminates(Terminates, Attrs0, Attrs) :-
     Attrs = Attrs0 ^ terminates := Terminates.
+set_user_annotated_sharing(UserSharing, Attrs0, Attrs) :-
+    Attrs = Attrs0 ^ user_annotated_sharing := UserSharing.
 set_may_throw_exception(MayThrowException, Attrs0, Attrs) :-
     Attrs = Attrs0 ^ may_throw_exception := MayThrowException.
 set_legacy_purity_behaviour(Legacy, Attrs0, Attrs) :-
@@ -1512,7 +1541,7 @@
     % in the attribute list -- the foreign language specifier string
     % is at the start of the pragma.
     Attrs = attributes(_Lang, MayCallMercury, ThreadSafe, TabledForIO,
-        Purity, Terminates, Exceptions, _LegacyBehaviour,
+        Purity, Terminates, _UserSharing, Exceptions, _LegacyBehaviour,
         OrdinaryDespiteDetism, MayModifyTrail, MayCallMM_Tabled,
         BoxPolicy, ExtraAttributes),
     (
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.105
diff -u -d -r1.105 prog_io_pragma.m
--- compiler/prog_io_pragma.m	15 Jun 2006 19:37:10 -0000	1.105
+++ compiler/prog_io_pragma.m	3 Jul 2006 08:59:01 -0000
@@ -528,7 +528,7 @@
         PTerms6 = [PredAndVarsTerm, FlagsTerm, FieldsTerm,
             FirstTerm, LaterTerm, SharedTerm],
         parse_pragma_foreign_proc_attributes_term(ForeignLanguage, Pragma,
-            FlagsTerm, MaybeFlags),
+            VarSet, FlagsTerm, MaybeFlags),
         ( MaybeFlags = ok(Flags) ->
             (
                 parse_pragma_keyword("local_vars", FieldsTerm, Fields,
@@ -619,7 +619,7 @@
         PTerms3 = [PredAndVarsTerm, FlagsTerm, CodeTerm],
         ( CodeTerm = term.functor(term.string(Code), [], Context) ->
             parse_pragma_foreign_proc_attributes_term(ForeignLanguage,
-                Pragma, FlagsTerm, MaybeFlags),
+                Pragma, VarSet, FlagsTerm, MaybeFlags),
             (
                 MaybeFlags = ok(Flags),
                 parse_pragma_foreign_code(ModuleName, Flags,
@@ -628,7 +628,7 @@
             ;
                 MaybeFlags = error(FlagsErr, FlagsErrTerm),
                 parse_pragma_foreign_proc_attributes_term(
-                    ForeignLanguage, Pragma, PredAndVarsTerm,
+                    ForeignLanguage, Pragma, VarSet, PredAndVarsTerm,
                     MaybeFlags2),
                 (
                     MaybeFlags2 = ok(Flags),
@@ -713,7 +713,7 @@
         Result = error(string.append(InvalidDeclStr, ErrMsg0), ErrorTerm)
     ).
 
-parse_pragma_type(ModuleName, "import", PragmaTerms, ErrorTerm, _VarSet,
+parse_pragma_type(ModuleName, "import", PragmaTerms, ErrorTerm, VarSet,
         Result) :-
         % XXX we assume all imports are C
     ForeignLanguage = lang_c,
@@ -721,7 +721,7 @@
         (
             PragmaTerms = [PredAndModesTerm, FlagsTerm, FunctionTerm],
             parse_pragma_foreign_proc_attributes_term(ForeignLanguage,
-                "import", FlagsTerm, MaybeFlags),
+                "import", VarSet, FlagsTerm, MaybeFlags),
             (
                 MaybeFlags = error(FlagError, ErrorTerm),
                 FlagsResult = error("invalid second argument in "
@@ -1384,7 +1384,7 @@
     ;       thread_safe(thread_safe)
     ;       tabled_for_io(tabled_for_io)
     ;       purity(purity)
-    ;       aliasing
+    ;       user_annotated_sharing(user_annotated_sharing)
     ;       max_stack_size(int)
     ;       backend(backend)
     ;       terminates(terminates)
@@ -1395,11 +1395,11 @@
     ;       box_policy(box_policy).
 
 :- pred parse_pragma_foreign_proc_attributes_term(foreign_language::in,
-    string::in, term::in, maybe1(pragma_foreign_proc_attributes)::out)
-    is det.
+    string::in, varset::in, term::in, 
+    maybe1(pragma_foreign_proc_attributes)::out) is det.
 
-parse_pragma_foreign_proc_attributes_term(ForeignLanguage, Pragma, Term,
-        MaybeAttributes) :-
+parse_pragma_foreign_proc_attributes_term(ForeignLanguage, Pragma, Varset, 
+        Term, MaybeAttributes) :-
     Attributes0 = default_attributes(ForeignLanguage),
     ( ( Pragma = "c_code" ; Pragma = "import" ) ->
         set_legacy_purity_behaviour(yes, Attributes0, Attributes1),
@@ -1436,7 +1436,7 @@
         box_policy(native_if_possible) - box_policy(always_boxed)
     ],
     (
-        parse_pragma_foreign_proc_attributes_term0(Term, AttrList)
+        parse_pragma_foreign_proc_attributes_term0(Varset, Term, AttrList)
     ->
         (
             list.member(Conflict1 - Conflict2, ConflictingAttributes),
@@ -1486,10 +1486,8 @@
     set_may_call_mm_tabled(MayCallTabled, !Attrs).
 process_attribute(box_policy(BoxPolicy), !Attrs) :-
     set_box_policy(BoxPolicy, !Attrs).
-
-    % Aliasing is currently ignored in the main branch compiler.
-    %
-process_attribute(aliasing, Attrs, Attrs).
+process_attribute(user_annotated_sharing(UserSharing), !Attrs) :-
+    set_user_annotated_sharing(UserSharing, !Attrs).
 
     % Check whether all the required attributes have been set for
     % a particular language
@@ -1514,11 +1512,11 @@
     ).
 check_required_attributes(lang_java, Attrs, _Term) = ok(Attrs).
 
-:- pred parse_pragma_foreign_proc_attributes_term0(term::in,
+:- pred parse_pragma_foreign_proc_attributes_term0(varset::in, term::in, 
     list(collected_pragma_foreign_proc_attribute)::out) is semidet.
 
-parse_pragma_foreign_proc_attributes_term0(Term, Flags) :-
-    ( parse_single_pragma_foreign_proc_attribute(Term, Flag) ->
+parse_pragma_foreign_proc_attributes_term0(Varset, Term, Flags) :-
+    ( parse_single_pragma_foreign_proc_attribute(Varset, Term, Flag) ->
         Flags = [Flag]
     ;
         (
@@ -1526,24 +1524,25 @@
             Flags = []
         ;
             Term = term.functor(term.atom("[|]"), [Head, Tail], _),
-            parse_single_pragma_foreign_proc_attribute(Head, HeadFlag),
-            parse_pragma_foreign_proc_attributes_term0(Tail, TailFlags),
+            parse_single_pragma_foreign_proc_attribute(Varset, Head, HeadFlag),
+            parse_pragma_foreign_proc_attributes_term0(Varset, Tail, 
+                TailFlags),
             Flags = [HeadFlag | TailFlags]
         )
     ).
 
-:- pred parse_single_pragma_foreign_proc_attribute(term::in,
+:- pred parse_single_pragma_foreign_proc_attribute(varset::in, term::in, 
     collected_pragma_foreign_proc_attribute::out) is semidet.
 
-parse_single_pragma_foreign_proc_attribute(Term, Flag) :-
+parse_single_pragma_foreign_proc_attribute(Varset, Term, Flag) :-
     ( parse_may_call_mercury(Term, MayCallMercury) ->
         Flag = may_call_mercury(MayCallMercury)
     ; parse_threadsafe(Term, ThreadSafe) ->
         Flag = thread_safe(ThreadSafe)
     ; parse_tabled_for_io(Term, TabledForIo) ->
         Flag = tabled_for_io(TabledForIo)
-    ; parse_aliasing(Term) ->
-        Flag = aliasing
+    ; parse_user_annotated_sharing(Varset, Term, UserSharing) ->
+        Flag = user_annotated_sharing(UserSharing)
     ; parse_max_stack_size(Term, Size) ->
         Flag = max_stack_size(Size)
     ; parse_backend(Term, Backend) ->
@@ -1623,17 +1622,6 @@
         Str = "not_tabled_for_io",
         TabledForIo = not_tabled_for_io
     ).
-
-    % XXX For the moment we just ignore the following attributes.
-    % These attributes are used for aliasing on the reuse branch,
-    % and ignoring them allows the main branch compiler to compile
-    % the reuse branch.
-    %
-:- pred parse_aliasing(term::in) is semidet.
-
-parse_aliasing(term.functor(term.atom("no_aliasing"), [], _)).
-parse_aliasing(term.functor(term.atom("unknown_aliasing"), [], _)).
-parse_aliasing(term.functor(term.atom("alias"), [_Types, _Alias], _)).
 
 :- pred parse_max_stack_size(term::in, int::out) is semidet.
 
Index: compiler/recompilation.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/recompilation.m,v
retrieving revision 1.22
diff -u -d -r1.22 recompilation.m
--- compiler/recompilation.m	20 Apr 2006 05:37:01 -0000	1.22
+++ compiler/recompilation.m	3 Jul 2006 08:59:02 -0000
@@ -80,7 +80,8 @@
     ;       functor_item     % The RHS of a var-functor unification.
     ;       predicate_item
     ;       function_item
-    ;       mutable_item.
+    ;       mutable_item
+    ;       foreign_proc_item.
 
 :- inst simple_item
     --->    type_item
@@ -162,15 +163,16 @@
 
 :- type item_id_set(Map, Set, Cons)
     --->    item_id_set(
-                types       :: Map,
-                type_bodies :: Map,
-                modes       :: Map,
-                insts       :: Map,
-                typeclasses :: Map,
-                functors    :: Cons,
-                predicates  :: Set,
-                functions   :: Set,
-                mutables    :: Set
+                types           :: Map,
+                type_bodies     :: Map,
+                modes           :: Map,
+                insts           :: Map,
+                typeclasses     :: Map,
+                functors        :: Cons,
+                predicates      :: Set,
+                functions       :: Set,
+                mutables        :: Set,
+                foreign_procs   :: Set 
             ).
 
 :- type item_id_set(T) == item_id_set(T, T, T).
@@ -307,6 +309,7 @@
 string_to_item_type("function", function_item).
 string_to_item_type("functor", functor_item).
 string_to_item_type("mutable", mutable_item).
+string_to_item_type("foreign_proc", foreign_proc_item).
 
 type_ctor_to_item_name(type_ctor(SymName, Arity)) = item_name(SymName, Arity).
 inst_id_to_item_name(inst_id(SymName, Arity)) = item_name(SymName, Arity).
@@ -319,14 +322,14 @@
 %-----------------------------------------------------------------------------%
 
 init_item_id_set(Init) =
-    item_id_set(Init, Init, Init, Init, Init, Init, Init, Init, Init).
+    item_id_set(Init, Init, Init, Init, Init, Init, Init, Init, Init, Init).
 
 init_item_id_set(Simple, PorF, Cons) =
     item_id_set(Simple, Simple, Simple, Simple, Simple, Cons, PorF, PorF,
-        PorF).
+        PorF, PorF).
 
 init_used_items = item_id_set(map.init, map.init, map.init, map.init,
-    map.init, map.init, map.init, map.init, map.init).
+    map.init, map.init, map.init, map.init, map.init, map.init).
 
 extract_simple_item_set(Items, type_item) = Items ^ types.
 extract_simple_item_set(Items, type_body_item) = Items ^ type_bodies.
@@ -359,6 +362,7 @@
 extract_ids(Items, predicate_item) = Items ^ predicates.
 extract_ids(Items, function_item) = Items ^ functions.
 extract_ids(Items, mutable_item) = Items ^ mutables.
+extract_ids(Items, foreign_proc_item) = Items ^ foreign_procs.
 
 update_ids(Items, type_item, IdMap) = Items ^ types := IdMap.
 update_ids(Items, type_body_item, IdMap) = Items ^ type_bodies := IdMap.
@@ -369,6 +373,7 @@
 update_ids(Items, function_item, IdMap) = Items ^ functions := IdMap.
 update_ids(Items, functor_item, IdMap) = Items ^ functors := IdMap.
 update_ids(Items, mutable_item, IdMap) = Items ^ mutables := IdMap.
+update_ids(Items, foreign_proc_item, IdMap) = Items ^ foreign_procs := IdMap.
 
 map_ids(Func, Items0, Init) = Items :-
     Items1 = init_item_id_set(Init),
Index: compiler/recompilation.usage.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/recompilation.usage.m,v
retrieving revision 1.34
diff -u -d -r1.34 recompilation.usage.m
--- compiler/recompilation.usage.m	20 Apr 2006 05:37:01 -0000	1.34
+++ compiler/recompilation.usage.m	3 Jul 2006 08:59:04 -0000
@@ -549,14 +549,15 @@
     set.init(UsedClasses0),
 
     UsedItems = item_id_set(Types, TypeBodies, Modes, Insts, Classes,
-        _, _, _, _),
+        _, _, _, _, _),
     map.init(ResolvedCtors),
     map.init(ResolvedPreds),
     map.init(ResolvedFuncs),
     map.init(ResolvedMutables),
+    map.init(ResolvedForeignProcs),
     ResolvedUsedItems0 = item_id_set(Types, TypeBodies, Modes, Insts,
         Classes, ResolvedCtors, ResolvedPreds, ResolvedFuncs,
-        ResolvedMutables),
+        ResolvedMutables, ResolvedForeignProcs),
 
     Info0 = recompilation_usage_info(ModuleInfo, ItemsToProcess0,
         ImportedItems1, ModuleUsedClasses, Dependencies,
@@ -966,6 +967,8 @@
 find_items_used_by_item(functor_item, _, !Info) :-
     unexpected(this_file, "find_items_used_by_item: functor").
 find_items_used_by_item(mutable_item, _MutableItemId, !Info).
+    % XXX What should be done here??? 
+find_items_used_by_item(foreign_proc_item, _, !Info).
     %
     % Mutables are expanded into other item types which track the
     % types, insts, preds, and funcs used.
Index: compiler/structure_reuse.direct.detect_garbage.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/structure_reuse.direct.detect_garbage.m,v
retrieving revision 1.3
diff -u -d -r1.3 structure_reuse.direct.detect_garbage.m
--- compiler/structure_reuse.direct.detect_garbage.m	5 Jun 2006 05:23:27 -0000	1.3
+++ compiler/structure_reuse.direct.detect_garbage.m	3 Jul 2006 08:59:04 -0000
@@ -112,14 +112,11 @@
         !:SharingAs = sharing_as_least_upper_bound(ModuleInfo, ProcInfo,
             ThenSharingAs, ElseSharingAs)
     ;
-        GoalExpr = foreign_proc(_Attrs, _ForeignPredId, _ForeignProcId,
+        GoalExpr = foreign_proc(Attributes, ForeignPredId, ForeignProcId,
             _ForeignArgs, _, _),
-        % XXX User annotated structure sharing information is not yet
-        % supported.
         goal_info_get_context(GoalInfo, Context),
-        context_to_string(Context, ContextString),
-        !:SharingAs = sharing_as_top_sharing_accumulate(
-            "foreign_proc not handled yet (" ++ ContextString ++ ")",
+        !:SharingAs = add_foreign_proc_sharing(ModuleInfo, ProcInfo, 
+            proc(ForeignPredId, ForeignProcId), Attributes, Context, 
             !.SharingAs)
     ;
         GoalExpr = shorthand(_),
Index: compiler/structure_reuse.indirect.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
retrieving revision 1.3
diff -u -d -r1.3 structure_reuse.indirect.m
--- compiler/structure_reuse.indirect.m	15 Jun 2006 19:37:11 -0000	1.3
+++ compiler/structure_reuse.indirect.m	3 Jul 2006 08:59:05 -0000
@@ -262,6 +262,9 @@
     io::di, io::uo) is det.
 
 indirect_reuse_analyse_goal(BaseInfo, !Goal, !AnalysisInfo, !IO) :-
+    ModuleInfo = BaseInfo ^ module_info, 
+    ProcInfo = BaseInfo ^ proc_info, 
+    SharingTable = BaseInfo ^ sharing_table, 
     !.Goal = GoalExpr0 - GoalInfo0,
     (
         GoalExpr0 = conj(ConjType, Goals0),
@@ -273,9 +276,9 @@
         GoalExpr0 = call(CalleePredId, CalleeProcId, CalleeArgs, _, _, _),
         verify_indirect_reuse(BaseInfo, CalleePredId, CalleeProcId, 
             CalleeArgs, GoalInfo0, GoalInfo, !AnalysisInfo, !IO),
-        lookup_sharing_and_comb(BaseInfo ^ module_info, BaseInfo ^ proc_info,
-            BaseInfo ^ sharing_table, CalleePredId, CalleeProcId, 
-            CalleeArgs, !.AnalysisInfo ^ sharing_as, NewSharing),
+        lookup_sharing_and_comb(ModuleInfo, ProcInfo, SharingTable, 
+            CalleePredId, CalleeProcId, CalleeArgs, 
+            !.AnalysisInfo ^ sharing_as, NewSharing),
         !:AnalysisInfo = !.AnalysisInfo ^ sharing_as := NewSharing,
         GoalExpr = GoalExpr0,
         !:Goal = GoalExpr - GoalInfo
@@ -298,8 +301,8 @@
             true
         ), 
         !:AnalysisInfo = !.AnalysisInfo ^ sharing_as :=
-            add_unify_sharing(BaseInfo ^ module_info, BaseInfo ^ proc_info, 
-                Unification, GoalInfo0, !.AnalysisInfo ^ sharing_as)
+            add_unify_sharing(ModuleInfo, ProcInfo, Unification, 
+            GoalInfo0, !.AnalysisInfo ^ sharing_as)
     ;
         GoalExpr0 = disj(Goals0),
         list.map2_foldl2(
@@ -355,16 +358,13 @@
         GoalExpr = if_then_else(A, IfGoal, ThenGoal, ElseGoal),
         !:Goal = GoalExpr - GoalInfo0
     ;
-        GoalExpr0 = foreign_proc(_Attrs, _ForeignPredId, _ForeignProcId,
+        GoalExpr0 = foreign_proc(Attributes, ForeignPredId, ForeignProcId,
             _ForeignArgs, _, _),
-        % XXX User annotated structure sharing information is not yet
-        % supported.
         goal_info_get_context(GoalInfo0, Context),
-        context_to_string(Context, ContextString),
         !:AnalysisInfo = !.AnalysisInfo ^ sharing_as :=
-            sharing_as_top_sharing_accumulate(
-                "foreign_proc not handled yet (" ++ ContextString ++ ")",
-                !.AnalysisInfo ^ sharing_as)
+            add_foreign_proc_sharing(ModuleInfo, ProcInfo, 
+            proc(ForeignPredId, ForeignProcId), Attributes, Context, 
+            !.AnalysisInfo ^ sharing_as)
     ;
         GoalExpr0 = shorthand(_),
         unexpected(this_file, "indirect_reuse_analyse_goal: shorthand goal.")
Index: compiler/structure_sharing.analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/structure_sharing.analysis.m,v
retrieving revision 1.14
diff -u -d -r1.14 structure_sharing.analysis.m
--- compiler/structure_sharing.analysis.m	15 Jun 2006 19:37:12 -0000	1.14
+++ compiler/structure_sharing.analysis.m	3 Jul 2006 08:59:06 -0000
@@ -401,14 +401,11 @@
         !:SharingAs = sharing_as_least_upper_bound(ModuleInfo, ProcInfo,
             ThenSharingAs, ElseSharingAs)
     ;
-        GoalExpr = foreign_proc(_Attrs, _ForeignPredId, _ForeignProcId,
+        GoalExpr = foreign_proc(Attributes, ForeignPredId, ForeignProcId,
             _ForeignArgs, _, _),
-        % XXX User annotated structure sharing information is not yet
-        % supported.
         goal_info_get_context(GoalInfo, Context),
-        context_to_string(Context, ContextString),
-        !:SharingAs = sharing_as_top_sharing_accumulate(
-            "foreign_proc not handled yet (" ++ ContextString ++ ")",
+        !:SharingAs = add_foreign_proc_sharing(ModuleInfo, ProcInfo, 
+            proc(ForeignPredId, ForeignProcId), Attributes, Context, 
             !.SharingAs)
     ;
         GoalExpr = shorthand(_),
Index: compiler/structure_sharing.domain.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/structure_sharing.domain.m,v
retrieving revision 1.10
diff -u -d -r1.10 structure_sharing.domain.m
--- compiler/structure_sharing.domain.m	5 Jun 2006 05:23:27 -0000	1.10
+++ compiler/structure_sharing.domain.m	3 Jul 2006 08:59:09 -0000
@@ -149,10 +149,13 @@
 :- func add_unify_sharing(module_info, proc_info, unification, hlds_goal_info,
     sharing_as) = sharing_as.
 
-    % XXX Not yet implemented.
-% :- func add_foreign_code_sharing(module_info, pred_proc_id, goal_info
-    % pragma_foreign_proc_attributes, list(foreign_arg),
-    % sharing_as) = sharing_as.
+    % Add the sharing created by a call to some foreign code. This
+    % sharing corresponds to the sharing information with which the
+    % foreign code was manually annotated, or can be predicted to 
+    % "bottom", and in the worst case to "top". 
+    %
+:- func add_foreign_proc_sharing(module_info, proc_info, pred_proc_id, 
+    pragma_foreign_proc_attributes, prog_context, sharing_as) = sharing_as. 
 
     % Compare two sharing sets. A sharing set Set1 is subsumed by a sharing set
     % Set2 iff the total set of sharing represented by Set1 is a subset of the
@@ -587,6 +590,59 @@
     set.to_sorted_list(Deaths, DeathsList),
     sharing_as_project_with_type(outproject, DeathsList, Sharing0, Sharing).
 
+add_foreign_proc_sharing(ModuleInfo, ProcInfo, ForeignPPId, 
+        Attributes, GoalContext, OldSharing) = NewSharing :- 
+    ForeignSharing = sharing_as_for_foreign_proc(ModuleInfo, 
+        Attributes, ForeignPPId, GoalContext),
+    NewSharing = sharing_as_comb(ModuleInfo, ProcInfo, ForeignSharing, 
+        OldSharing).
+
+:- func sharing_as_for_foreign_proc(module_info, 
+    pragma_foreign_proc_attributes, pred_proc_id, prog_context) = sharing_as.
+
+sharing_as_for_foreign_proc(ModuleInfo, Attributes, ForeignPPId, 
+        ProgContext) = SharingAs :-
+    (
+        sharing_as_from_user_annotated_sharing(Attributes, SharingAs0)
+    ->
+        SharingAs = SharingAs0
+    ;
+        predict_called_pred_is_bottom(ModuleInfo, ForeignPPId)
+    ->
+        SharingAs = sharing_as_bottom
+    ;
+        context_to_string(ProgContext, ContextString), 
+        Msg = "foreign proc with unknown sharing (" 
+            ++ ContextString ++ ")",
+        SharingAs = sharing_as_top_sharing(Msg)
+    ).
+
+:- pred sharing_as_from_user_annotated_sharing(
+    pragma_foreign_proc_attributes::in, sharing_as::out) is semidet.
+
+sharing_as_from_user_annotated_sharing(Attributes, UserSharingAs) :- 
+    UserSharing = user_annotated_sharing(Attributes),
+    UserSharing = user_sharing(SharingDomain, _MaybeTypes), 
+    % Accept only the value "bottom" and "real" for the structure sharing.
+    % If the user has annotated the sharing with unknown sharing, we might
+    % try to predict bottom anyway.
+    some [!SharingAs] (
+        (
+            SharingDomain = structure_sharing_bottom,
+            !:SharingAs = sharing_as_bottom
+        ;
+            SharingDomain = structure_sharing_real(_SharingPairs),
+            !:SharingAs = from_structure_sharing_domain(SharingDomain)
+
+            % XXX 
+            % I have the feeling that renaming should not be needed at this
+            % place anymore, assuming that every foreign_proc call is
+            % correctly handled at the add_pragma stage? 
+        ), 
+        UserSharingAs = !.SharingAs
+    ).
+
+
 sharing_as_is_subsumed_by(ModuleInfo, ProcInfo, Sharing1, Sharing2) :-
     (
         Sharing2 = sharing_as_top(_)
@@ -676,27 +732,28 @@
 
 from_structure_sharing_domain(SharingDomain) = SharingAs :-
     (
-        SharingDomain = bottom,
+        SharingDomain = structure_sharing_bottom,
         SharingAs = sharing_as_bottom
     ;
-        SharingDomain = real(StructureSharing),
+        SharingDomain = structure_sharing_real(StructureSharing),
         SharingSet = from_sharing_pair_list(StructureSharing),
         wrap(SharingSet, SharingAs)
     ;
-        SharingDomain = top(Msgs),
+        SharingDomain = structure_sharing_top(Msgs),
         SharingAs = sharing_as_top(Msgs)
     ).
 
 to_structure_sharing_domain(SharingAs) = SharingDomain :-
     (
         SharingAs = sharing_as_bottom,
-        SharingDomain = bottom
+        SharingDomain = structure_sharing_bottom
     ;
         SharingAs = sharing_as_real_as(SharingSet),
-        SharingDomain = real(to_sharing_pair_list(SharingSet))
+        SharingDomain = structure_sharing_real(
+            to_sharing_pair_list(SharingSet))
     ;
         SharingAs = sharing_as_top(Msgs),
-        SharingDomain = top(Msgs)
+        SharingDomain = structure_sharing_top(Msgs)
     ).
 
 %-----------------------------------------------------------------------------%
cvs server: Diffing compiler/notes
cvs server: Diffing debian
cvs server: Diffing debian/patches
cvs server: Diffing deep
cvs server: Diffing deep_profiler
cvs server: Diffing deep_profiler/notes
cvs server: Diffing detail
cvs server: Diffing doc
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.355
diff -u -d -r1.355 reference_manual.texi
--- doc/reference_manual.texi	14 Jun 2006 08:14:50 -0000	1.355
+++ doc/reference_manual.texi	3 Jul 2006 08:59:21 -0000
@@ -6146,7 +6146,7 @@
 If they are actually pure or semipure, they must be explicitly
 promised as such by the user (either by using foreign language
 attributes specified below, or a promise_pure or promise_semipure pragma
-as specified in @ref{Impurity}.
+as specified in @ref{Impurity}).
 
 Additional restrictions on the foreign language interface code
 depend on the foreign language and compilation options.
@@ -6327,6 +6327,56 @@
 procedures that @samp{may_call_mercury}, in case none is specified, is
 @samp{may_call_mm_tabled}.
 
+ at c @item @samp{no_sharing/unknown_sharing/sharing(MaybeTypes, SharingList)}
+ at c This attribute declares whether or not the foreign procedure creates any
+ at c structure sharing @ref{Structure sharing analysis} between the output 
+ at c arguments
+ at c of the foreign procedure and its input arguments. Specifying that a foreign
+ at c procedure generates no sharing (attribute @samp{no_sharing}) is a promise
+ at c to the compiler that the procedure does not create any sharing
+ at c between its arguments. The attribute @samp{unknown_sharing} specifies 
+ at c that the
+ at c procedure may create any possible sharing between the arguments. 
+ at c Finally, using
+ at c @samp{sharing(MaybeTypes, SharingList)} it is possible to specify a list of
+ at c sharing arguments, declaring that the foreign procedure creates at most
+ at c the specified sharing between the arguments. @samp{MaybeTypes} takes 
+ at c the values
+ at c @samp{no/yes(Types)}, where @samp{Types} correspond to the types used in the
+ at c predicate declaration of this foreign procedure. 
+ at c @samp{SharingList} consists of a list
+ at c @samp{[SharingPairA, SharingPairB, ...]}, where each sharing pair 
+ at c is represented by a pair @samp{cel(Vari, Seli) - cel(Varj, Selj)}. 
+ at c @samp{Vari, Varj} must be variables that are part of the mode declaration
+ at c of the @samp{foreign_proc} definition. @samp{Seli, Selj} select
+ at c the subterms of the given arguments that actually share. Each selector 
+ at c @samp{Seli} is written as a list of types @samp{[Type1, Type2, ...]}
+ at c representing a path in the term structure of the given argument. An
+ at c empty list designates the complete term to which the argument corresponds.
+ at c The types can make use of type variables as long as @samp{MaybeTypes} is
+ at c set to @samp{yes(Types)}, and the type variables occur in any of the types
+ at c used in @samp{Types}.
+ at c 
+ at c @example
+ at c :- pred array.init_2(int::in, T::in, array(T)::array_uo) is det.
+ at c 
+ at c :- pragma foreign_proc("C",
+    @c array.init_2(Size::in, Item::in, Array::array_uo),
+    @c [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+    @c sharing(yes(int, T, array(T)), [cel(Item,[]) - cel(Array,[T])])],
+ at c "
+    @c ML_alloc_array(Array, Size + 1, MR_PROC_LABEL);
+    @c ML_init_array(Array, Size, Item);
+ at c ").
+ at c @end example
+ at c 
+ at c This sharing declaration promises that a call 
+ at c @code{init_2(Size, Item, Array)}, with types @code{int, T, array(T)}
+ at c may create sharing between any 
+ at c subterms of type @code{T} of the resulting array @code{Array} and the
+ at c term @code{Item}. Reformulated: the elements of @code{Array} may refer
+ at c to the same memory locations as @code{Item}.
+
 @end table
 
 @c -----------------------------------------------------------------------
@@ -9571,6 +9621,18 @@
 @c Note that neither the @samp{reserve_tag} pragma nor the @samp{--reserve-tag}
 @c compiler option will have any useful effect if the @samp{--high-level-data} 
 @c option is used (e.g. for the .NET or Java back-ends).
+
+ at c XXX TO DO!
+ at c @node Structure sharing analysis
+ at c @section Structure sharing analysis
+ at c 
+ at c The compiler includes a structure sharing analysis system. 
+
+ at c XXX TO DO!
+ at c @node Compile-time garbage collection
+ at c @section Compile-time garbage collection
+ at c
+ at c The compiler includes a compile-time garbage collection system (CTGC).
 
 @node Bibliography
 @chapter Bibliography

-- 
nancy.mazur at cs.kuleuven.ac.be ------------ Katholieke Universiteit Leuven -
tel: +32-16-327596 - fax: +32-16-327996 ------- Dept. of Computer Science -
--------------------------------------------------------------------------
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