Files
mercury/compiler/name_mangle.m
Zoltan Somogyi 08365979d0 Move pred_name.m to the HLDS package.
This is so that it can become the home of the type currently named
pred_origin in hlds_pred.m, which (after being given new name) will become
a structured representation of predicate names.

The only thing that kept pred_name.m in the parse_tree package was the fact
that parse_pragma.m, which has no access to the hlds package, called it
to create the name of a type-specialized predicate when parsing
type_spec pragmas. The main part of this diff, apart from the trivial
updates to import hlds.pred_name instead parse_tree.pred_name, deals
with this issue.

The problem is how to ensure that the compiler invocations that create
type-specialized predicates (invocations that compile the module containing
the type_spec pragma that calls for this) and the invocations that create
the calls to those predicates (invocations that mostly compile other modules)
agree on the name of the name of the type-specialized predicate.

The old approach was this.

    When reading in (say) mod1.m which contains a type_spec pragma,
    we construct the name of the type-specialized predicate from

    - the name of the module (mod1),
    - the name of the predicate to be specialized, and
    - the type substitution in the pragma.

    We then record this name in the pragma.

    If the compiler invocation generates code, we use this name in the
    predicate definition. If the compiler invocation creates a .int file,
    we record the name in the third argument of the type_spec pragma.
    This third argument is NOT allowed to exist in .m files.

    Other compiler invocations that read in mod1.int when compiling
    another module, e.g. mod2.m, use the specialized name in the third argument
    of the type_spec pragma as the name to use in calls.

In this approach, the single-source-of-truth about the name of the
type-specialized predicate is the name constructed when parsing mod1.m,
which is conveyed to compiler invocations on other modules through
the third argument of the type_spec pragma.

The new approach is this:

    When reading in (say) mod1.m which contains a type_spec pragma,
    we give guaranteed-to-be-unique names to all the anonymous variables
    in the type_spec pragma. We also record in the type_spec pragma
    the name of the module whose (source or interface) file we read
    the pragma from. The name of the predicate to be specialized
    was of course already in the pragma.

    If the compiler invocation generates code, we construct the name
    of the type-specialized version of the predicate when we add the
    all-tvars-are-named type_spec pragma to the HLDS. If the compiler
    invocation creates a .int file, we write out the all-tvars-are-named
    version of the type_spec pragma. The pragma also contains the predicate
    name to be specialized. It does not contain the name of the module,
    but we will write out type_spec pragmas from module_x.m *only* to
    module_x.int, never to any other .int file, so any readers of
    the type_spec pragma from mod1.int will also know the name of the
    module that the pragma came from.

    Other compiler invocations that read in mod1.int when compiling
    another module, e.g. mod2.m, therefore get exactly the same

    - module name,
    - the name of the predicate to be specialized, and
    - the type substitution in the pragma

    as the compiler invocations on mod1.m. The module name are the
    predicate name are never changed by being written out and then
    read back in, and *due to the explicit names given to any formerly
    anonymous variables*, the type substitution is changed by this either.
    This means that the compiler invocations on mod1.m and mod2.m
    give the same parameters to the same function, and therefore they are
    guaranteed to get the same string as the name of the type-specialized
    version of the predicate.

In this approach, the single-source-of-truth about the name of the
type-specialized predicate is the function constructing that name
and its inputs.

compiler/hlds.m:
compiler/parse_tree.m:
compiler/pred_name.m:
    Move pred_name.m from the parse_tree package to the hlds package.

compiler/prog_item.m:
    Change the representation of type_spec pragmas to

    - delete the name of the specialized predicate, and replace it with
    - the name of the module the pragma was read in from.

compiler/parse_pragma.m:
    Delete the code for parsing the third argument of type_spec pragmas.
    Allow them to exist for a short transition period, but ignore them.
    (If we read in files containing them, the result will be a link error
    if the type substitution contains anonymous variables. In that case,
    a rebuild of the program with all modules compiled using the *same
    compiler version* will work.)

    Give guaranteed-to-be-unique names to all anonymous type variable
    in the type substitution part of the type_spec pragma we construct.

compiler/add_pragma_type_spec.m:
    Construct the name of the type-specialized predicate as the type_spec
    pragma is added to the HLDS.

compiler/parse_tree_out_pragma.m:
    Never write out a type_spec par_loop_control with a third argument.

    Delete the var_name_print argument of the predicate that writes out
    type_spec pragmas. Instead, *always* use print_name_only.

compiler/options.m:
    Add a way of testing whether the installed compiler has this change.

compiler/accumulator.m:
compiler/add_pragma_tabling.m:
compiler/add_special_pred.m:
compiler/base_typeclass_info.m:
compiler/check_typeclass.m:
compiler/dep_par_conj.m:
compiler/distance_granularity.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/intermod.m:
compiler/lambda.m:
compiler/layout_out.m:
compiler/lco.m:
compiler/loop_inv.m:
compiler/make_hlds_passes.m:
compiler/name_mangle.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/par_loop_control.m:
compiler/parse_tree_out.m:
compiler/pd_info.m:
compiler/prog_rep.m:
compiler/ssdebug.m:
compiler/stm_expand.m:
compiler/structure_reuse.versions.m:
compiler/table_gen.m:
compiler/tupling.m:
compiler/untupling.m:
compiler/unused_args.m:
2022-07-20 21:33:09 +10:00

256 lines
9.4 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2003-2008 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.
%-----------------------------------------------------------------------------%
%
% File: name_mangle.m.
%
% This module defines routines for generating and/or outputting identifiers
% for modules, predicates/functions, and procedures in forms that are
% syntactically acceptable in all our target languages, meaning C, Java
% and MSIL.
%
% NOTE: some parts of the name mangling routines are defined in
% prog_foreign.m because they are required by the frontend of the compiler,
% for generating makefile fragments etc.
%
% Warning: any changes to the name mangling algorithms implemented in this
% module may also require changes to profiler/demangle.m, util/mdemangle.c and
% compiler/prog_foreign.m.
%
%-----------------------------------------------------------------------------%
:- module backend_libs.name_mangle.
:- interface.
:- import_module backend_libs.rtti.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
%-----------------------------------------------------------------------------%
:- type maybe_add_label_prefix
---> do_not_add_label_prefix
; add_label_prefix.
% Get a proc label string (used by procs which are exported to C).
% The boolean controls whether label_prefix is added to the string.
%
:- func proc_label_to_c_string(maybe_add_label_prefix, proc_label) = string.
% Succeed iff the given name or sym_name doesn't need mangling.
%
:- pred name_doesnt_need_mangling(string::in) is semidet.
:- pred sym_name_doesnt_need_mangling(sym_name::in) is semidet.
% Create a name for base_typeclass_info.
%
:- func make_base_typeclass_info_name(tc_name, string) = string.
:- func make_base_typeclass_info_name_with_data_prefix(tc_name, string)
= string.
% To ensure that Mercury labels don't clash with C symbols, we
% prefix them with the string returned by this function.
%
:- func mercury_label_prefix = string.
% To ensure that the names of global variables generated by the Mercury
% compiler don't clash with C symbols, we prefix them with the string
% returned by this function.
%
:- func mercury_var_prefix = string.
% All the C data structures we generate which are either fully static
% or static after initialization should have one of these prefixes,
% to ensure that Mercury global variables don't clash with C symbols.
%
:- func mercury_data_prefix = string.
:- func mercury_scalar_common_array_prefix = string.
:- func mercury_vector_common_array_prefix = string.
% All the C types we generate should have this prefix to ensure
% that they don't clash with C symbols.
%
:- func mercury_common_type_prefix = string.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.
:- import_module hlds.pred_name.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_foreign.
:- import_module int.
:- import_module list.
:- import_module string.
%-----------------------------------------------------------------------------%
proc_label_to_c_string(AddPrefix, ProcLabel) = ProcLabelString :-
(
ProcLabel = ordinary_proc_label(DefiningModule, PredOrFunc, PredModule,
PredName, Arity, ModeNum),
LabelName = make_pred_or_func_name(DefiningModule, PredOrFunc,
PredModule, PredName, Arity, AddPrefix),
(
PredOrFunc = pf_function,
OrigArity = Arity - 1
;
PredOrFunc = pf_predicate,
OrigArity = Arity
),
ProcLabelString = string.format("%s_%d_%d",
[s(LabelName), i(OrigArity), i(ModeNum)])
;
ProcLabel = special_proc_label(Module, SpecialPredId, TypeModule,
TypeName, TypeArity, ModeNum),
% For a special proc, output a label of the form:
% mercury____<PredName>___<TypeModule>__<TypeName>_<TypeArity>_<Mode>
% Figure out the LabelName.
DummyArity = -1, % not used by make_pred_or_func_name.
TypeCtor = type_ctor(qualified(TypeModule, TypeName), TypeArity),
PredName = uci_pred_name(SpecialPredId, TypeCtor),
LabelName = make_pred_or_func_name(unqualified(""), pf_predicate,
unqualified(""), PredName, DummyArity, AddPrefix),
% Mangle all the relevant names.
MangledModule = sym_name_mangle(Module),
MangledTypeModule = sym_name_mangle(TypeModule),
MangledTypeName = name_mangle(TypeName),
% Module-qualify the type name.
% To handle locally produced unification preds for imported types,
% we need to qualify it with both the module name of the
% type, and also (if it is different) the module name of the
% current module.
QualifiedMangledTypeName = qualify_name(MangledTypeModule,
MangledTypeName),
FullyQualifiedMangledTypeName = maybe_qualify_name(MangledModule,
QualifiedMangledTypeName),
% Join it all together.
ProcLabelString = string.format("%s_%s_%d_%d",
[s(LabelName), s(FullyQualifiedMangledTypeName),
i(TypeArity), i(ModeNum)])
).
% Make a name identifying a predicate or a function, given the
% defining module, predicate or function indicator, declaring module,
% predicate name, arity, and whether or not to add the
% mercury_label_prefix.
%
:- func make_pred_or_func_name(module_name, pred_or_func, module_name, string,
arity, maybe_add_label_prefix) = string.
make_pred_or_func_name(DefiningModule, PredOrFunc, DeclaringModule,
Name0, Arity, AddPrefix) = LabelName :-
% WARNING: any changes to the name mangling algorithm here may also
% require changes to profiler/demangle.m, util/mdemangle.c and
% compiler/prog_foreign.m.
DeclaringModuleName = sym_name_mangle(DeclaringModule),
DefiningModuleName = sym_name_mangle(DefiningModule),
( if dont_module_qualify_name(Name0, Arity) then
LabelName0 = Name0
else
LabelName0 = qualify_name(DeclaringModuleName, Name0)
),
% If this is a specialized version of a predicate defined
% in some other module, then it needs both module prefixes.
( if DefiningModule \= DeclaringModule then
LabelName1 = DefiningModuleName ++ "__" ++ LabelName0
else
LabelName1 = LabelName0
),
LabelName2 = name_mangle(LabelName1),
(
PredOrFunc = pf_function,
LabelName3 = "fn__" ++ LabelName2
;
PredOrFunc = pf_predicate,
LabelName3 = LabelName2
),
(
AddPrefix = add_label_prefix,
LabelName = mercury_label_prefix ++ LabelName3
;
AddPrefix = do_not_add_label_prefix,
LabelName = LabelName3
).
% Define the conditions for which labels are printed
% without module qualification.
%
:- pred dont_module_qualify_name(string::in, arity::in) is semidet.
dont_module_qualify_name(Name, Arity) :-
(
Name = "main",
Arity = 2
;
string.prefix(Name, "__")
).
name_doesnt_need_mangling(Name) :-
string.is_all_alnum_or_underscore(Name),
not string.append("f_", _Suffix, Name).
sym_name_doesnt_need_mangling(unqualified(Name)) :-
name_doesnt_need_mangling(Name).
sym_name_doesnt_need_mangling(qualified(ModuleName, PlainName)) :-
sym_name_doesnt_need_mangling(ModuleName),
name_doesnt_need_mangling(PlainName).
% Produces a string of the form Module__Name, unless Module__
% is already a prefix of Name.
%
:- func maybe_qualify_name(string, string) = string.
maybe_qualify_name(Module0, Name0) = Name :-
string.append(Module0, "__", UnderscoresModule),
( if string.append(UnderscoresModule, _, Name0) then
Name = Name0
else
string.append(UnderscoresModule, Name0, Name)
).
%-----------------------------------------------------------------------------%
make_base_typeclass_info_name(TCName, TypeNames) = Str :-
TCName = tc_name(ModuleName, ClassName, ClassArity),
ClassSym = qualified(ModuleName, ClassName),
MangledClassString = sym_name_mangle(ClassSym),
MangledTypeNames = name_mangle(TypeNames),
Str = string.format("base_typeclass_info_%s__arity%d__%s",
[s(MangledClassString), i(ClassArity), s(MangledTypeNames)]).
make_base_typeclass_info_name_with_data_prefix(TCName, TypeNames) = Str :-
Str = mercury_data_prefix ++
make_base_typeclass_info_name(TCName, TypeNames).
%-----------------------------------------------------------------------------%
mercury_label_prefix = "mercury__".
mercury_var_prefix = "mercury_var_".
mercury_data_prefix = "mercury_data_".
mercury_scalar_common_array_prefix = "mercury_common_".
mercury_vector_common_array_prefix = "mercury_vector_common_".
mercury_common_type_prefix = "mercury_type_".
%-----------------------------------------------------------------------------%
:- end_module backend_libs.name_mangle.
%-----------------------------------------------------------------------------%