Files
mercury/compiler/llds_out.m
Zoltan Somogyi 9e31ef9baa Split llds into two parts. llds.m defines the data types, while llds_out.m
Estimated hours taken: 1.5

Split llds into two parts. llds.m defines the data types, while llds_out.m
has the predicates for printing the code.

Removed the call_closure instruction. Instead, we use calls to the
system-defined addresses do_call_{det,semidet,nondet}_closure. This is
how call_closure was implemented already. The advantage of the new
implementation is that it allows jump optimization of what used to be
call_closures, without new code in jumpopt.
1996-04-24 08:59:06 +00:00

2261 lines
70 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995 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.
%-----------------------------------------------------------------------------%
% LLDS - The Low-Level Data Structure.
% This module defines the routines for printing out LLDS,
% the Low Level Data Structure.
% Main authors: conway, fjh, zs.
%-----------------------------------------------------------------------------%
:- module llds_out.
:- interface.
:- import_module llds, tree, shapes, export.
:- import_module io, bool, string, int, float, list, set, term, std_util.
:- import_module library. % for the version number.
% Given a 'c_file' structure, open the appropriate .mod file
% and output the code into that file.
:- pred output_c_file(c_file, io__state, io__state).
:- mode output_c_file(in, di, uo) is det.
% Convert an lval to a string description of that lval.
:- pred llds_out__lval_to_string(lval, string).
:- mode llds_out__lval_to_string(in, out) is semidet.
:- pred llds_out__binary_op_to_string(binary_op, string).
:- mode llds_out__binary_op_to_string(in, out) is det.
% Output an instruction (used for debugging).
:- pred output_instruction(instr, io__state, io__state).
:- mode output_instruction(in, di, uo) is det.
% Output a label (used by garbage collection).
:- pred output_label(label, io__state, io__state).
:- mode output_label(in, di, uo) is det.
% Output a proc label (used for building static call graph for prof).
:- pred output_proc_label(proc_label, io__state, io__state).
:- mode output_proc_label(in, di, uo) is det.
% Get a proc label string (used by procs which are exported to C).
:- pred get_proc_label(proc_label, string).
:- mode get_proc_label(in, out) is det.
% Mangle an arbitrary name into a C identifier
:- pred llds_out__name_mangle(string, string).
:- mode llds_out__name_mangle(in, out) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module char, require, globals, options.
:- import_module exprn_aux, prog_out.
%-----------------------------------------------------------------------------%
output_c_file(C_File) -->
globals__io_lookup_bool_option(split_c_files, SplitFiles),
( { SplitFiles = yes } ->
{ C_File = c_file(BaseName, C_HeaderInfo, Modules) },
{ string__append(BaseName, ".dir", ObjDirName) },
make_directory(ObjDirName),
output_c_file_init(BaseName, Modules),
output_c_file_list(Modules, 1, BaseName, C_HeaderInfo)
;
output_single_c_file(C_File, no)
).
:- pred make_directory(string, io__state, io__state).
:- mode make_directory(in, di, uo) is det.
make_directory(DirName) -->
{ string__format("[ -d %s ] || mkdir -p %s", [s(DirName), s(DirName)],
Command) },
io__call_system(Command, _Result).
:- pred output_c_file_list(list(c_module), int, string, list(c_header_code),
io__state, io__state).
:- mode output_c_file_list(in, in, in, in, di, uo) is det.
output_c_file_list([], _, _, _) --> [].
output_c_file_list([Module|Modules], Num, BaseName, C_HeaderLines) -->
output_single_c_file(c_file(BaseName, C_HeaderLines, [Module]),
yes(Num)),
{ Num1 is Num + 1 },
output_c_file_list(Modules, Num1, BaseName, C_HeaderLines).
:- pred output_c_file_init(string, list(c_module), io__state, io__state).
:- mode output_c_file_init(in, in, di, uo) is det.
output_c_file_init(BaseName, Modules) -->
{ string__format("%s.dir/%s_%03d", [s(BaseName), s(BaseName), i(0)],
NewName) },
{ string__append(NewName, ".c", FileName) },
io__tell(FileName, Result),
(
{ Result = ok }
->
{ library__version(Version) },
io__write_strings(
["/*\n** Automatically generated from `", BaseName,
".m' by the\n** Mercury compiler, version ", Version,
". Do not edit.\n*/\n"]),
io__write_string("/*\n"),
io__write_string("INIT "),
output_init_name(BaseName),
io__write_string("\n"),
io__write_string("ENDINIT\n"),
io__write_string("*/\n\n"),
io__write_string("#include ""imp.h""\n"),
output_c_module_init_list(BaseName, Modules),
io__told
;
io__progname_base("llds.m", ProgName),
io__write_string("\n"),
io__write_string(ProgName),
io__write_string(": can't open `"),
io__write_string(FileName),
io__write_string("' for output\n"),
io__set_exit_status(1)
).
:- pred output_single_c_file(c_file, maybe(int), io__state, io__state).
:- mode output_single_c_file(in, in, di, uo) is det.
output_single_c_file(c_file(BaseName, C_HeaderLines, Modules), SplitFiles)
-->
( { SplitFiles = yes(Num) } ->
{ string__format("%s.dir/%s_%03d.c", [s(BaseName), s(BaseName),
i(Num)], FileName) }
;
{ string__append(BaseName, ".c", FileName) }
),
io__tell(FileName, Result),
(
{ Result = ok }
->
{ library__version(Version) },
io__write_strings(
["/*\n** Automatically generated from `", BaseName,
".m' by the\n** Mercury compiler, version ", Version,
". Do not edit.\n*/\n"]),
( { SplitFiles = yes(_) } ->
[]
;
io__write_string("/*\n"),
io__write_string("INIT "),
output_init_name(BaseName),
io__write_string("\n"),
io__write_string("ENDINIT\n"),
io__write_string("*/\n\n")
),
io__write_string("#include ""imp.h""\n"),
output_c_header_include_lines(C_HeaderLines),
output_c_module_list(Modules, BaseName),
io__write_string("\n"),
( { SplitFiles = yes(_) } ->
[]
;
output_c_module_init_list(BaseName, Modules)
),
io__told
;
io__progname_base("llds.m", ProgName),
io__write_string("\n"),
io__write_string(ProgName),
io__write_string(": can't open `"),
io__write_string(FileName),
io__write_string("' for output\n"),
io__set_exit_status(1)
).
:- pred output_c_module_init_list(string, list(c_module), io__state, io__state).
:- mode output_c_module_init_list(in, in, di, uo) is det.
output_c_module_init_list(BaseName, Modules) -->
io__write_string("#if (defined(USE_GCC_NONLOCAL_GOTOS) && "),
io__write_string("!defined(USE_ASM_LABELS)) \\\n\t|| "),
io__write_string("defined(PROFILE_CALLS) || defined(DEBUG_GOTOS) \\\n"),
io__write_string("\t|| defined(DEBUG_LABELS) || !defined(SPEED)\n\n"),
io__write_string("static void "),
output_bunch_name(BaseName, 0),
io__write_string("(void)\n"),
io__write_string("{\n"),
output_c_module_init_list_2(Modules, BaseName, 0, 40, 0, InitFuncs),
io__write_string("}\n\n#endif\n\n"),
io__write_string("void "),
output_init_name(BaseName),
io__write_string("(void); /* suppress gcc warning */\n"),
io__write_string("void "),
output_init_name(BaseName),
io__write_string("(void)\n"),
io__write_string("{\n"),
io__write_string("#if (defined(USE_GCC_NONLOCAL_GOTOS) && "),
io__write_string("!defined(USE_ASM_LABELS)) \\\n\t|| "),
io__write_string("defined(PROFILE_CALLS) || defined(DEBUG_GOTOS) \\\n"),
io__write_string("\t|| defined(DEBUG_LABELS) || !defined(SPEED)\n\n"),
output_c_module_init_list_3(0, BaseName, InitFuncs),
io__write_string("#endif\n}\n").
:- pred output_c_module_init_list_2(list(c_module), string, int, int, int, int,
io__state, io__state).
:- mode output_c_module_init_list_2(in, in, in, in, in, out, di, uo) is det.
output_c_module_init_list_2([], _, _, _, InitFunc, InitFunc) --> [].
output_c_module_init_list_2([c_export(_) | Ms], A, B, C, D, E) -->
output_c_module_init_list_2(Ms, A, B, C, D, E).
output_c_module_init_list_2([c_code(_, _) | Ms], A, B, C, D, E) -->
output_c_module_init_list_2(Ms, A, B, C, D, E).
output_c_module_init_list_2([c_module(ModuleName, _) | Ms], BaseName,
Calls0, MaxCalls, InitFunc0, InitFunc) -->
( { Calls0 > MaxCalls } ->
io__write_string("}\n\n"),
{ InitFunc1 is InitFunc0 + 1 },
io__write_string("static void "),
output_bunch_name(BaseName, InitFunc1),
io__write_string("(void)\n"),
io__write_string("{\n"),
{ Calls1 = 1 }
;
{ InitFunc1 = InitFunc0 },
{ Calls1 is Calls0 + 1 }
),
globals__io_lookup_bool_option(split_c_files, SplitFiles),
( { SplitFiles = yes } ->
io__write_string("\t{ extern ModuleFunc "),
output_module_name(ModuleName),
io__write_string(";\n"),
io__write_string("\t "),
output_module_name(ModuleName),
io__write_string("(); }\n")
;
io__write_string("\t"),
output_module_name(ModuleName),
io__write_string("();\n")
),
output_c_module_init_list_2(Ms, BaseName,
Calls1, MaxCalls, InitFunc1, InitFunc).
:- pred output_c_module_init_list_3(int, string, int, io__state, io__state).
:- mode output_c_module_init_list_3(in, in, in, di, uo) is det.
output_c_module_init_list_3(InitFunc0, BaseName, MaxInitFunc) -->
( { InitFunc0 > MaxInitFunc } ->
[]
;
io__write_string("\t"),
output_bunch_name(BaseName, InitFunc0),
io__write_string("();\n"),
{ InitFunc1 is InitFunc0 + 1},
output_c_module_init_list_3(InitFunc1, BaseName, MaxInitFunc)
).
:- pred output_init_name(string, io__state, io__state).
:- mode output_init_name(in, di, uo) is det.
output_init_name(BaseName0) -->
io__write_string("mercury__"),
{ llds_out__name_mangle(BaseName0, BaseName) },
io__write_string(BaseName),
io__write_string("__init").
:- pred output_bunch_name(string, int, io__state, io__state).
:- mode output_bunch_name(in, in, di, uo) is det.
output_bunch_name(BaseName0, Number) -->
io__write_string("mercury__"),
{ llds_out__name_mangle(BaseName0, BaseName) },
io__write_string(BaseName),
io__write_string("_bunch_"),
io__write_int(Number).
:- pred output_module_name(string, io__state, io__state).
:- mode output_module_name(in, di, uo) is det.
output_module_name(ModuleName0) -->
io__write_string("mercury__"),
{ llds_out__name_mangle(ModuleName0, ModuleName) },
io__write_string(ModuleName).
:- pred output_c_module_list(list(c_module), string, io__state, io__state).
:- mode output_c_module_list(in, in, di, uo) is det.
output_c_module_list([], _) --> [].
output_c_module_list([M|Ms], BaseName) -->
output_c_module(M, BaseName),
output_c_module_list(Ms, BaseName).
:- pred output_c_module(c_module, string, io__state, io__state).
:- mode output_c_module(in, in, di, uo) is det.
output_c_module(c_code(C_Code, Context), _) -->
globals__io_lookup_bool_option(auto_comments, PrintComments),
( { PrintComments = yes } ->
io__write_string("/* "),
prog_out__write_context(Context),
io__write_string(" pragma(c_code) */\n")
;
[]
),
io__write_string(C_Code),
io__write_string("\n").
output_c_module(c_module(ModuleName, Procedures), _) -->
{ gather_labels(Procedures, Labels) },
io__write_string("\n"),
output_c_label_decl_list(Labels),
io__write_string("\n"),
io__write_string("BEGIN_MODULE("),
output_module_name(ModuleName),
io__write_string(")\n"),
output_c_label_init_list(Labels),
io__write_string("BEGIN_CODE\n"),
io__write_string("\n"),
globals__io_lookup_bool_option(auto_comments, PrintComments),
globals__io_lookup_bool_option(emit_c_loops, EmitCLoops),
output_c_procedure_list(Procedures, PrintComments, EmitCLoops),
io__write_string("END_MODULE\n").
output_c_module(c_export(PragmaExports), BaseName) -->
(
{ PragmaExports = [_|_] }
->
globals__io_lookup_bool_option(split_c_files, SplitFiles),
( { SplitFiles = yes } ->
io__write_strings(
["#include ""../", BaseName, ".h""\n"])
;
io__write_strings(["#include """, BaseName, ".h""\n"])
),
output_exported_c_functions(PragmaExports)
;
% Don't spit out a #include if there are no pragma(export,...)s
[]
).
% output_c_header_include_lines reverses the list of c header lines
% and passes them to output_c_header_include_lines_2 which outputs them.
% The list must be reversed since they are inserted in reverse order
:- pred output_c_header_include_lines(list(c_header_code),
io__state, io__state).
:- mode output_c_header_include_lines(in, di, uo) is det.
output_c_header_include_lines(Headers) -->
{ list__reverse(Headers, RevHeaders) },
output_c_header_include_lines_2(RevHeaders).
:- pred output_c_header_include_lines_2(list(c_header_code),
io__state, io__state).
:- mode output_c_header_include_lines_2(in, di, uo) is det.
output_c_header_include_lines_2([]) -->
[].
output_c_header_include_lines_2([Code - Context|Hs]) -->
globals__io_lookup_bool_option(auto_comments, PrintComments),
( { PrintComments = yes } ->
io__write_string("/* "),
prog_out__write_context(Context),
io__write_string(" pragma(c_code) */\n")
;
[]
),
io__write_string(Code),
io__write_string("\n"),
output_c_header_include_lines_2(Hs).
:- pred output_exported_c_functions(list(string), io__state, io__state).
:- mode output_exported_c_functions(in, di, uo) is det.
output_exported_c_functions([]) --> [].
output_exported_c_functions([F|Fs]) -->
io__write_string(F),
output_exported_c_functions(Fs).
:- pred output_c_label_decl_list(list(label), io__state, io__state).
:- mode output_c_label_decl_list(in, di, uo) is det.
output_c_label_decl_list(Labels) -->
globals__io_lookup_int_option(procs_per_c_function, ProcsPerFunc),
output_c_label_decl_list_2(Labels, ProcsPerFunc).
:- pred output_c_label_decl_list_2(list(label), int, io__state, io__state).
:- mode output_c_label_decl_list_2(in, in, di, uo) is det.
output_c_label_decl_list_2([], _) --> [].
output_c_label_decl_list_2([Label | Labels], ProcsPerFunc) -->
output_c_label_decl(Label, ProcsPerFunc),
output_c_label_decl_list_2(Labels, ProcsPerFunc).
:- pred output_c_label_decl(label, int, io__state, io__state).
:- mode output_c_label_decl(in, in, di, uo) is det.
output_c_label_decl(Label, ProcsPerFunc) -->
(
{ Label = exported(_) },
io__write_string("Define_extern_entry(")
;
{ Label = local(_) },
% if we are splitting procs between functions, then
% every procedure could be referred to by a procedure
% in a different function, so make them static, not local
% similarly if we're splitting between files make them extern
( { ProcsPerFunc = 0 } ->
io__write_string("Declare_local(")
;
globals__io_lookup_bool_option(split_c_files,
SplitFiles),
( { SplitFiles = no } ->
io__write_string("Declare_static(")
;
io__write_string("Define_extern_entry(")
)
)
;
{ Label = local(_, _) },
io__write_string("Declare_label(")
),
output_label(Label),
io__write_string(");\n").
:- pred output_c_label_init_list(list(label), io__state, io__state).
:- mode output_c_label_init_list(in, di, uo) is det.
output_c_label_init_list(Labels) -->
globals__io_lookup_int_option(procs_per_c_function, ProcsPerFunc),
output_c_label_init_list_2(Labels, ProcsPerFunc).
:- pred output_c_label_init_list_2(list(label), int, io__state, io__state).
:- mode output_c_label_init_list_2(in, in, di, uo) is det.
output_c_label_init_list_2([], _) --> [].
output_c_label_init_list_2([Label | Labels], ProcsPerFunc) -->
output_c_label_init(Label, ProcsPerFunc),
output_c_label_init_list_2(Labels, ProcsPerFunc).
:- pred output_c_label_init(label, int, io__state, io__state).
:- mode output_c_label_init(in, in, di, uo) is det.
output_c_label_init(Label, ProcPerFunc) -->
(
{ Label = exported(_) },
io__write_string("\tinit_entry("),
output_label(Label),
io__write_string(");\n")
;
{ Label = local(_) },
( { ProcPerFunc = 0 } ->
io__write_string("\tinit_local("),
output_label(Label),
io__write_string(");\n")
;
io__write_string("\tinit_entry("),
output_label(Label),
io__write_string(");\n")
)
;
{ Label = local(_, _) },
io__write_string("\tinit_label("),
output_label(Label),
io__write_string(");\n")
).
% The following code is very straightforward and
% unremarkable. The only thing of note is that is
% uses the logical io library, and that it uses DCGs
% to avoid having to explicitly shuffle the state-of-the-world
% arguments around all the time, as discussed in my hons thesis. -fjh.
:- pred output_c_procedure_list(list(c_procedure), bool, bool,
io__state, io__state).
:- mode output_c_procedure_list(in, in, in, di, uo) is det.
output_c_procedure_list([], _, _) --> [].
output_c_procedure_list([Proc | Procs], PrintComments, EmitCLoops) -->
output_c_procedure(Proc, PrintComments, EmitCLoops),
output_c_procedure_list(Procs, PrintComments, EmitCLoops).
:- pred output_c_procedure(c_procedure, bool, bool, io__state, io__state).
:- mode output_c_procedure(in, in, in, di, uo) is det.
output_c_procedure(Proc, PrintComments, EmitCLoops) -->
{ Proc = c_procedure(Name, Arity, ModeNum0, Instrs) },
( { PrintComments = yes } ->
io__write_string("\n/*-------------------------------------"),
io__write_string("------------------------------------*/\n")
;
[]
),
io__write_string("/* code for predicate '"),
% Now that we have unused_args.m mangling predicate names,
% we should probably demangle them here.
io__write_string(Name),
io__write_string("'/"),
io__write_int(Arity),
io__write_string(" in mode "),
{ ModeNum is ModeNum0 mod 10000 }, % strip off the priority
io__write_int(ModeNum),
io__write_string(" */\n"),
{ llds_out__find_caller_label(Instrs, CallerLabel) },
{ set__init(ContLabelSet0) },
{ llds_out__find_cont_labels(Instrs, ContLabelSet0, ContLabelSet) },
{ set__init(WhileSet0) },
( { EmitCLoops = yes } ->
{ llds_out__find_while_labels(Instrs, WhileSet0, WhileSet) }
;
{ WhileSet = WhileSet0 }
),
output_instruction_list(Instrs, PrintComments,
CallerLabel - ContLabelSet, WhileSet).
:- pred llds_out__find_caller_label(list(instruction), label).
:- mode llds_out__find_caller_label(in, out) is det.
llds_out__find_caller_label([], _) :-
error("cannot find caller label").
llds_out__find_caller_label([Instr0 - _ | Instrs], CallerLabel) :-
( Instr0 = label(Label) ->
( ( Label = local(_) ; Label = exported(_) ) ->
CallerLabel = Label
;
error("caller label is internal label")
)
;
llds_out__find_caller_label(Instrs, CallerLabel)
).
% Locate all the labels which are the continutation labels for calls
% or nondet disjunctions, and store them in ContLabelSet.
:- pred llds_out__find_cont_labels(list(instruction), set(label), set(label)).
:- mode llds_out__find_cont_labels(in, in, out) is det.
llds_out__find_cont_labels([], ContLabelSet, ContLabelSet).
llds_out__find_cont_labels([Instr - _ | Instrs], ContLabelSet0, ContLabelSet)
:-
(
(
Instr = call(_, label(ContLabel), _, _)
;
Instr = mkframe(_Comment2, _SlotCount, label(ContLabel))
;
Instr = modframe(label(ContLabel))
;
Instr = assign(redoip(lval(maxfr)),
const(address_const(label(ContLabel))))
)
->
set__insert(ContLabelSet0, ContLabel, ContLabelSet1)
;
Instr = block(_, Block)
->
llds_out__find_cont_labels(Block, ContLabelSet0, ContLabelSet1)
;
ContLabelSet1 = ContLabelSet0
),
llds_out__find_cont_labels(Instrs, ContLabelSet1, ContLabelSet).
% Locate all the labels which can be profitably turned into
% labels starting while loops. The idea is to do this transform:
%
% L1: L1:
% while (1) {
% ... ...
% if (...) goto L1 if (...) continue
% ... => ...
% if (...) goto L? if (...) goto L?
% ... ...
% if (...) goto L1 if (...) continue
% ... ...
% break;
% }
% L2: L2:
%
% The second of these is better if we don't have fast jumps.
:- pred llds_out__find_while_labels(list(instruction), set(label), set(label)).
:- mode llds_out__find_while_labels(in, in, out) is det.
llds_out__find_while_labels([], WhileSet, WhileSet).
llds_out__find_while_labels([Instr0 - _ | Instrs0], WhileSet0, WhileSet) :-
(
Instr0 = label(Label),
llds_out__is_while_label(Label, Instrs0, Instrs1, 0, UseCount),
UseCount > 0
->
set__insert(WhileSet0, Label, WhileSet1),
llds_out__find_while_labels(Instrs1, WhileSet1, WhileSet)
;
llds_out__find_while_labels(Instrs0, WhileSet0, WhileSet)
).
:- pred llds_out__is_while_label(label, list(instruction), list(instruction),
int, int).
:- mode llds_out__is_while_label(in, in, out, in, out) is det.
llds_out__is_while_label(_, [], [], Count, Count).
llds_out__is_while_label(Label, [Instr0 - Comment0 | Instrs0], Instrs,
Count0, Count) :-
( Instr0 = label(_) ->
Count = Count0,
Instrs = [Instr0 - Comment0 | Instrs0]
; Instr0 = goto(label(Label)) ->
Count1 is Count0 + 1,
llds_out__is_while_label(Label, Instrs0, Instrs, Count1, Count)
; Instr0 = if_val(_, label(Label)) ->
Count1 is Count0 + 1,
llds_out__is_while_label(Label, Instrs0, Instrs, Count1, Count)
;
llds_out__is_while_label(Label, Instrs0, Instrs, Count0, Count)
).
:- pred output_instruction_list(list(instruction), bool,
pair(label, set(label)), set(label), io__state, io__state).
:- mode output_instruction_list(in, in, in, in, di, uo) is det.
output_instruction_list([], _, _, _) --> [].
output_instruction_list([Instr0 - Comment0 | Instrs], PrintComments,
ProfInfo, WhileSet) -->
output_instruction_and_comment(Instr0, Comment0, PrintComments,
ProfInfo),
( { Instr0 = label(Label), set__member(Label, WhileSet) } ->
io__write_string("\twhile (1) {\n"),
output_instruction_list_while(Instrs, Label, PrintComments,
ProfInfo, WhileSet)
;
output_instruction_list(Instrs, PrintComments,
ProfInfo, WhileSet)
).
:- pred output_instruction_list_while(list(instruction), label,
bool, pair(label, set(label)), set(label), io__state, io__state).
:- mode output_instruction_list_while(in, in, in, in, in, di, uo) is det.
output_instruction_list_while([], _, _, _, _) -->
io__write_string("\tbreak; } /* end while */\n").
output_instruction_list_while([Instr0 - Comment0 | Instrs], Label,
PrintComments, ProfInfo, WhileSet) -->
( { Instr0 = label(_) } ->
io__write_string("\tbreak; } /* end while */\n"),
output_instruction_list([Instr0 - Comment0 | Instrs],
PrintComments, ProfInfo, WhileSet)
; { Instr0 = goto(label(Label)) } ->
io__write_string("\t/* continue */ } /* end while */\n"),
output_instruction_list(Instrs,
PrintComments, ProfInfo, WhileSet)
; { Instr0 = if_val(Rval, label(Label)) } ->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_rval_decls(Rval, DeclSet0, DeclSet1),
output_code_addr_decls(label(Label), DeclSet1, _),
io__write_string("if ("),
output_rval(Rval),
io__write_string(")\n\t\tcontinue; }\n"),
( { PrintComments = yes, Comment0 \= "" } ->
io__write_string("\t\t/* "),
io__write_string(Comment0),
io__write_string(" */\n")
;
[]
),
output_instruction_list_while(Instrs, Label, PrintComments,
ProfInfo, WhileSet)
;
output_instruction_and_comment(Instr0, Comment0, PrintComments,
ProfInfo),
output_instruction_list_while(Instrs, Label, PrintComments,
ProfInfo, WhileSet)
).
:- pred output_instruction_and_comment(instr, string, bool,
pair(label, set(label)), io__state, io__state).
:- mode output_instruction_and_comment(in, in, in, in, di, uo) is det.
output_instruction_and_comment(Instr, Comment, PrintComments, ProfInfo) -->
(
{ PrintComments = no },
( { Instr = comment(_) ; Instr = livevals(_) } ->
[]
;
output_instruction(Instr, ProfInfo),
io__write_string("\n")
)
;
{ PrintComments = yes },
output_instruction(Instr, ProfInfo),
io__write_string("\n"),
( { Comment = "" } ->
[]
;
io__write_string("\t\t/* "),
io__write_string(Comment),
io__write_string(" */\n")
)
).
% The three-argument output_instruction is only for debugging.
output_instruction(Instr) -->
{ set__init(ContLabelSet) },
{ ProfInfo = local(proc("DEBUG", "DEBUG", 0, 0)) - ContLabelSet },
output_instruction(Instr, ProfInfo).
:- pred output_instruction(instr, pair(label, set(label)),
io__state, io__state).
:- mode output_instruction(in, in, di, uo) is det.
output_instruction(comment(Comment), _) -->
io__write_strings(["/* ", Comment, " */"]).
output_instruction(livevals(LiveVals), _) -->
io__write_string("/*\n * Live lvalues:\n"),
{ set__to_sorted_list(LiveVals, LiveValsList) },
output_livevals(LiveValsList),
io__write_string(" */").
output_instruction(block(N, Instrs), ProfInfo) -->
io__write_string("\t{ Word "),
output_temp_decls(N),
io__write_string(";\n"),
globals__io_lookup_bool_option(auto_comments, PrintComments),
{ set__init(WhileSet0) },
output_instruction_list(Instrs, PrintComments, ProfInfo, WhileSet0),
io__write_string("\t}\n").
output_instruction(assign(Lval, Rval), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_lval_decls(Lval, DeclSet0, DeclSet1),
output_rval_decls(Rval, DeclSet1, _),
output_lval(Lval),
io__write_string(" = "),
output_rval(Rval),
io__write_string("; }").
output_instruction(call(Target, ContLabel, LiveVals, _), ProfInfo) -->
{ ProfInfo = CallerLabel - _ },
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_code_addr_decls(Target, DeclSet0, DeclSet1),
output_code_addr_decls(ContLabel, DeclSet1, _),
output_call(Target, ContLabel, CallerLabel),
io__write_string(" }\n"),
output_gc_livevals(LiveVals).
output_instruction(c_code(C_Code_String), _) -->
io__write_string("\t"),
io__write_string(C_Code_String).
output_instruction(mkframe(Str, Num, FailureContinuation), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_code_addr_decls(FailureContinuation, DeclSet0, _),
io__write_string("mkframe("""),
io__write_string(Str),
io__write_string(""", "),
io__write_int(Num),
io__write_string(", "),
output_code_addr(FailureContinuation),
io__write_string("); }").
output_instruction(modframe(FailureContinuation), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_code_addr_decls(FailureContinuation, DeclSet0, _),
io__write_string("modframe("),
output_code_addr(FailureContinuation),
io__write_string("); }").
output_instruction(label(Label), ProfInfo) -->
output_label_defn(Label),
maybe_output_update_prof_counter(Label, ProfInfo).
output_instruction(goto(CodeAddr), ProfInfo) -->
{ ProfInfo = CallerLabel - _ },
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_code_addr_decls(CodeAddr, DeclSet0, _),
output_goto(CodeAddr, CallerLabel),
io__write_string(" }").
output_instruction(computed_goto(Rval, Labels), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_rval_decls(Rval, DeclSet0, _),
io__write_string("COMPUTED_GOTO("),
output_rval(Rval),
io__write_string(",\n\t\t"),
output_label_list(Labels),
io__write_string("); }").
output_instruction(if_val(Rval, Target), ProfInfo) -->
{ ProfInfo = CallerLabel - _ },
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_rval_decls(Rval, DeclSet0, DeclSet1),
output_code_addr_decls(Target, DeclSet1, _),
io__write_string("if ("),
output_rval(Rval),
io__write_string(")\n\t\t"),
output_goto(Target, CallerLabel),
io__write_string(" }").
output_instruction(incr_hp(Lval, MaybeTag, Rval), _) -->
(
{ MaybeTag = no },
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_lval_decls(Lval, DeclSet0, DeclSet1),
output_rval_decls(Rval, DeclSet1, _),
io__write_string("incr_hp("),
output_lval(Lval),
io__write_string(", "),
output_rval(Rval),
io__write_string("); }")
;
{ MaybeTag = yes(Tag) },
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_lval_decls(Lval, DeclSet0, DeclSet1),
output_rval_decls(Rval, DeclSet1, _),
io__write_string("tag_incr_hp("),
output_lval(Lval),
io__write_string(", "),
output_tag(Tag),
io__write_string(", "),
output_rval(Rval),
io__write_string("); }")
).
output_instruction(mark_hp(Lval), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_lval_decls(Lval, DeclSet0, _),
io__write_string("mark_hp("),
output_lval(Lval),
io__write_string("); }").
output_instruction(restore_hp(Rval), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_rval_decls(Rval, DeclSet0, _),
io__write_string("restore_hp("),
output_rval(Rval),
io__write_string("); }").
output_instruction(store_ticket(Lval), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_lval_decls(Lval, DeclSet0, _),
io__write_string("store_ticket("),
output_lval(Lval),
io__write_string("); }").
output_instruction(restore_ticket(Rval), _) -->
io__write_string("\t{ "),
{ set__init(DeclSet0) },
output_rval_decls(Rval, DeclSet0, _),
io__write_string("restore_ticket("),
output_rval(Rval),
io__write_string("); }").
output_instruction(discard_ticket, _) -->
io__write_string("\t"),
io__write_string("discard_ticket();").
output_instruction(incr_sp(N), _) -->
io__write_string("\t"),
io__write_string("incr_sp("),
io__write_int(N),
io__write_string(");").
output_instruction(decr_sp(N), _) -->
io__write_string("\t"),
io__write_string("decr_sp("),
io__write_int(N),
io__write_string(");").
% The code we produce for pragma(c_code, ...) is in the form
% {
% <declaration of one local variable for each one in the proc>
% <assignment of the input regs to the corresponding locals>
% <the C code itself>
% <assignment to the output regs of the corresponding locals>
% }
%
output_instruction(pragma_c(Decls, Inputs, C_Code, Outputs), _) -->
io__write_string("\t{\n"),
output_pragma_decls(Decls),
output_pragma_inputs(Inputs),
io__write_string("\t\t"),
io__write_string(C_Code),
io__write_string("\n"),
output_pragma_outputs(Outputs),
io__write_string("\n\t}\n").
% Output the local variable declarations at the top of the
% pragma_c_code code.
:- pred output_pragma_decls(list(pragma_c_decl), io__state, io__state).
:- mode output_pragma_decls(in, di, uo) is det.
output_pragma_decls([]) --> [].
output_pragma_decls([D|Decls]) -->
{ D = pragma_c_decl(Type, VarName) },
% Apart from special cases, the local variables are Words
{ export__term_to_type_string(Type, VarType) },
io__write_string("\t\t"),
io__write_string(VarType),
io__write_string("\t"),
io__write_string(VarName),
io__write_string(";\n"),
output_pragma_decls(Decls).
% Output the input variable assignments at the top of the
% pragma_c_code code.
:- pred output_pragma_inputs(list(pragma_c_input), io__state, io__state).
:- mode output_pragma_inputs(in, di, uo) is det.
output_pragma_inputs([]) --> [].
output_pragma_inputs([I|Inputs]) -->
{ I = pragma_c_input(VarName, Type, Rval) },
io__write_string("\t\t"),
io__write_string(VarName),
io__write_string(" = "),
(
{ Type = term__functor(term__atom("string"), [], _) }
->
io__write_string("(String) "),
output_rval(Rval)
;
{ Type = term__functor(term__atom("float"), [], _) }
->
io__write_string("word_to_float("),
output_rval(Rval),
io__write_string(")")
;
output_rval(Rval)
),
io__write_string(";\n"),
output_pragma_inputs(Inputs).
% Output the output variable assignments at the bottom of the
% pragma_c_code
:- pred output_pragma_outputs(list(pragma_c_output), io__state, io__state).
:- mode output_pragma_outputs(in, di, uo) is det.
output_pragma_outputs([]) --> [].
output_pragma_outputs([O|Outputs]) -->
{ O = pragma_c_output(Lval, Type, VarName) },
io__write_string("\t\t"),
output_lval(Lval),
io__write_string(" = "),
(
{ Type = term__functor(term__atom("string"), [], _) }
->
io__write_string("(Word) "),
io__write_string(VarName)
;
{ Type = term__functor(term__atom("float"), [], _) }
->
io__write_string("float_to_word("),
io__write_string(VarName),
io__write_string(")")
;
io__write_string(VarName)
),
io__write_string(";\n"),
output_pragma_outputs(Outputs).
:- pred output_livevals(list(lval), io__state, io__state).
:- mode output_livevals(in, di, uo) is det.
output_livevals([]) --> [].
output_livevals([Lval|Lvals]) -->
io__write_string(" *\t"),
output_lval(Lval),
io__write_string("\n"),
output_livevals(Lvals).
:- pred output_gc_livevals(list(liveinfo), io__state, io__state).
:- mode output_gc_livevals(in, di, uo) is det.
output_gc_livevals(LiveVals) -->
globals__io_lookup_bool_option(auto_comments, PrintAutoComments),
( { PrintAutoComments = yes } ->
io__write_string("/*\n"),
io__write_string(" * Garbage collection livevals info\n"),
output_gc_livevals_2(LiveVals),
io__write_string(" */")
;
[]
).
:- pred output_gc_livevals_2(list(liveinfo), io__state, io__state).
:- mode output_gc_livevals_2(in, di, uo) is det.
output_gc_livevals_2([]) --> [].
output_gc_livevals_2([live_lvalue(Lval, Shape)|Lvals]) -->
io__write_string(" *\t"),
output_lval(Lval),
io__write_string("\t"),
shapes__write_shape_num(Shape),
io__write_string("\n"),
output_gc_livevals_2(Lvals).
:- pred output_temp_decls(int, io__state, io__state).
:- mode output_temp_decls(in, di, uo) is det.
output_temp_decls(N) -->
output_temp_decls_2(1, N).
:- pred output_temp_decls_2(int, int, io__state, io__state).
:- mode output_temp_decls_2(in, in, di, uo) is det.
output_temp_decls_2(Next, Max) -->
( { Next =< Max } ->
( { Next > 1 } ->
io__write_string(", ")
;
[]
),
io__write_string("temp"),
io__write_int(Next),
{ Next1 is Next + 1 },
output_temp_decls_2(Next1, Max)
;
[]
).
% Every time we emit a declaration for a symbol, we insert it into the
% set of symbols we've already declared. That way, we avoid generating
% the same symbol twice, which would cause an error in the C code.
:- type decl_set == set(decl_id).
:- type decl_id ---> create_label(int) ; float_label(string).
:- pred output_rval_decls(rval, decl_set, decl_set, io__state, io__state).
:- mode output_rval_decls(in, in, out, di, uo) is det.
output_rval_decls(lval(Lval), DeclSet0, DeclSet) -->
output_lval_decls(Lval, DeclSet0, DeclSet).
output_rval_decls(var(_), _, _) -->
{ error("output_rval_decls: unexpected var") }.
output_rval_decls(mkword(_, Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_rval_decls(const(Const), DeclSet0, DeclSet) -->
( { Const = address_const(CodeAddress) } ->
output_code_addr_decls(CodeAddress, DeclSet0, DeclSet)
; { Const = float_const(FloatVal) } ->
%
% If floats are boxed, and the static ground terms
% option is enabled, then for each float constant
% which we might want to box we declare a static const
% variable holding that constant.
%
globals__io_lookup_bool_option(unboxed_float, UnboxedFloat),
globals__io_lookup_bool_option(static_ground_terms,
StaticGroundTerms),
( { UnboxedFloat = no, StaticGroundTerms = yes } ->
{ string__float_to_string(FloatVal, FloatString) },
{ FloatLabel = float_label(FloatString) },
( { set__member(FloatLabel, DeclSet0) } ->
{ DeclSet = DeclSet0 }
;
{ set__insert(DeclSet0, FloatLabel, DeclSet) },
{ llds_out__float_const_name(FloatString,
FloatName) },
io__write_strings([
"static const Float ", FloatName,
" = ", FloatString, ";\n\t "
])
)
;
{ DeclSet = DeclSet0 }
)
;
{ DeclSet = DeclSet0 }
).
output_rval_decls(unop(_, Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_rval_decls(binop(_, Rval1, Rval2), DeclSet0, DeclSet) -->
output_rval_decls(Rval1, DeclSet0, DeclSet1),
output_rval_decls(Rval2, DeclSet1, DeclSet).
%
% Originally we used to output static constants as
%
% static const Word mercury_const_...[] = { ... };
%
% However, if the initializer contains any code addresses,
% this causes problems with gcc when using shared libraries,
% because the constant will need to be dynamically linked,
% but gcc notices that it is of type `Word' which is not a pointer
% type and hence assumes that it will not need relocation,
% and places it in the `rdata' section. This causes minor
% problems with Solaris: if you use gcc 2.7 and link with `gcc -shared',
% you get a link error; the work-around is to link with `gcc -G'.
% It also causes major problems with Irix 5: the relocation is not
% done, resulting in a core dump at runtime. It also causes
% major problems on AIX RS/6000 systems: a link error or core dump.
%
% The gcc maintainers said that this was a bug in our code, since it
% converted a pointer to an integer, which is ANSI/ISO C says is
% implementation-defined. Hmmph.
%
% So now we output it as
%
% static const Word * mercury_const_...[] = { (Word *)... };
%
% if the constant refers to any code addresses or data addresses.
% This includes string literals, and references to other constants,
% including boxed float consts.
%
% We output the original format if possible, since we want it
% to go in rdata if it can, because rdata is shared.
%
output_rval_decls(create(_Tag, ArgVals, Label), DeclSet0, DeclSet) -->
{ CreateLabel = create_label(Label) },
( { set__member(CreateLabel, DeclSet0) } ->
{ DeclSet = DeclSet0 }
;
{ set__insert(DeclSet0, CreateLabel, DeclSet1) },
output_cons_arg_decls(ArgVals, DeclSet1, DeclSet),
(
% must we use use `Word *'?
{
% yes if the constant refers to any code addresses
exprn_aux__maybe_rval_list_code_addrs(ArgVals,
CodeAddrs),
CodeAddrs \= []
;
% yes if the constant contains any string constants
% or any float constants
% or any sub-creates
exprn_aux__args_contain_rval(ArgVals, Rval),
( Rval = const(string_const(_))
; Rval = const(float_const(_))
; Rval = create(_, _, Label1),
% every create contains a create - itself.
% We don't want to count that one,
% so we check that the labels are different:
Label1 \= Label
)
}
->
io__write_string("static const Word * mercury_const_"),
io__write_int(Label),
io__write_string("[] = {\n\t\t"),
output_cons_args(ArgVals, yes),
io__write_string("};\n\t ")
;
io__write_string("static const Word mercury_const_"),
io__write_int(Label),
io__write_string("[] = {\n\t\t"),
output_cons_args(ArgVals, no),
io__write_string("};\n\t ")
)
).
:- pred llds_out__float_const_name(string::in, string::out) is det.
llds_out__float_const_name(FloatName0, FloatName) :-
%
% The name of the variable is based on the
% value of the float const, with "pt" instead
% of ".", and "neg" instead of "-".
% We call llds_name_mangle too, just to be sure.
%
string__replace_all(FloatName0, ".", "pt", FloatName1),
string__replace_all(FloatName1, "-", "neg", FloatName2),
llds_out__name_mangle(FloatName2, FloatName3),
string__append("mercury_float_const_", FloatName3, FloatName).
:- pred output_cons_arg_decls(list(maybe(rval)), decl_set, decl_set,
io__state, io__state).
:- mode output_cons_arg_decls(in, in, out, di, uo) is det.
output_cons_arg_decls([], DeclSet, DeclSet) --> [].
output_cons_arg_decls([Arg | Args], DeclSet0, DeclSet) -->
( { Arg = yes(Rval) } ->
output_rval_decls(Rval, DeclSet0, DeclSet1)
;
{ DeclSet1 = DeclSet0 }
),
output_cons_arg_decls(Args, DeclSet1, DeclSet).
:- pred output_cons_args(list(maybe(rval)), bool, io__state, io__state).
:- mode output_cons_args(in, in, di, uo) is det.
% output_cons_args(Args, CastToPointer):
% output the arguments;
% if CastToPointer is yes, then cast them all to `(Word *)'.
output_cons_args([], _) --> [].
output_cons_args([Arg | Args], CastToPointer) -->
( { Arg = yes(Rval) } ->
( { CastToPointer = yes } ->
io__write_string("(Word *) ")
;
[]
),
output_rval(Rval)
;
% `Arg = no' means the argument is uninitialized,
% but that would mean the term isn't ground
{ error("output_cons_args: missing argument") }
),
( { Args \= [] } ->
io__write_string(",\n\t\t"),
output_cons_args(Args, CastToPointer)
;
io__write_string("\n\t ")
).
:- pred output_lval_decls(lval, decl_set, decl_set, io__state, io__state).
:- mode output_lval_decls(in, in, out, di, uo) is det.
output_lval_decls(field(_, Rval, FieldNum), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet1),
output_rval_decls(FieldNum, DeclSet1, DeclSet).
output_lval_decls(reg(_), DeclSet, DeclSet) --> [].
output_lval_decls(stackvar(_), DeclSet, DeclSet) --> [].
output_lval_decls(framevar(_), DeclSet, DeclSet) --> [].
output_lval_decls(succip, DeclSet, DeclSet) --> [].
output_lval_decls(maxfr, DeclSet, DeclSet) --> [].
output_lval_decls(curfr, DeclSet, DeclSet) --> [].
output_lval_decls(succfr(Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_lval_decls(prevfr(Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_lval_decls(redoip(Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_lval_decls(succip(Rval), DeclSet0, DeclSet) -->
output_rval_decls(Rval, DeclSet0, DeclSet).
output_lval_decls(hp, DeclSet, DeclSet) --> [].
output_lval_decls(sp, DeclSet, DeclSet) --> [].
output_lval_decls(lvar(_), DeclSet, DeclSet) --> [].
output_lval_decls(temp(_), DeclSet, DeclSet) --> [].
:- pred output_code_addr_decls(code_addr, decl_set, decl_set,
io__state, io__state).
:- mode output_code_addr_decls(in, in, out, di, uo) is det.
output_code_addr_decls(label(_), DeclSet, DeclSet) --> [].
output_code_addr_decls(imported(ProcLabel), DeclSet, DeclSet) -->
io__write_string("Declare_entry("),
output_proc_label(ProcLabel),
io__write_string(");\n\t ").
output_code_addr_decls(succip, DeclSet, DeclSet) --> [].
output_code_addr_decls(do_succeed(_), DeclSet, DeclSet) --> [].
output_code_addr_decls(do_redo, DeclSet, DeclSet) -->
globals__io_lookup_bool_option(use_macro_for_redo_fail, UseMacro),
(
{ UseMacro = yes }
;
{ UseMacro = no },
io__write_string("Declare_entry("),
io__write_string("do_redo"),
io__write_string(");\n\t ")
).
output_code_addr_decls(do_fail, DeclSet, DeclSet) -->
globals__io_lookup_bool_option(use_macro_for_redo_fail, UseMacro),
(
{ UseMacro = yes }
;
{ UseMacro = no },
io__write_string("Declare_entry("),
io__write_string("do_fail"),
io__write_string(");\n\t ")
).
output_code_addr_decls(do_det_closure, DeclSet, DeclSet) -->
io__write_string("Declare_entry(do_call_det_closure);\n\t ").
output_code_addr_decls(do_semidet_closure, DeclSet, DeclSet) -->
io__write_string("Declare_entry(do_call_semidet_closure);\n\t ").
output_code_addr_decls(do_nondet_closure, DeclSet, DeclSet) -->
io__write_string("Declare_entry(do_call_nondet_closure);\n\t ").
:- pred maybe_output_update_prof_counter(label, pair(label, set(label)),
io__state, io__state).
:- mode maybe_output_update_prof_counter(in, in, di, uo) is det.
maybe_output_update_prof_counter(Label, CallerLabel - ContLabelSet) -->
(
{ set__member(Label, ContLabelSet) }
->
io__write_string("\n\tupdate_prof_current_proc(LABEL("),
output_label(CallerLabel),
io__write_string("));")
;
[]
).
:- pred output_goto(code_addr, label, io__state, io__state).
:- mode output_goto(in, in, di, uo) is det.
% Note that we do some optimization here:
% instead of always outputting `GOTO(<label>)', we
% output different things for each different kind of label.
output_goto(label(Label), CallerLabel) -->
(
{ Label = local(_) ; Label = exported(_) }
->
io__write_string("localtailcall("),
output_label(Label),
io__write_string(",\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");")
;
{ Label = local(_, _) }
->
io__write_string("GOTO_LABEL("),
output_label(Label),
io__write_string(");")
;
% just in case - this will always work,
% but shouldn't be needed
io__write_string("GOTO(LABEL("),
output_label(Label),
io__write_string("));")
).
output_goto(imported(ProcLabel), CallerLabel) -->
io__write_string("tailcall(ENTRY("),
output_proc_label(ProcLabel),
io__write_string("),\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");").
output_goto(succip, _) -->
io__write_string("proceed();").
output_goto(do_succeed(Last), _) -->
(
{ Last = no },
io__write_string("succeed();")
;
{ Last = yes },
io__write_string("succeed_discard();")
).
output_goto(do_redo, _) -->
globals__io_lookup_bool_option(use_macro_for_redo_fail, UseMacro),
(
{ UseMacro = yes },
io__write_string("redo();")
;
{ UseMacro = no },
io__write_string("GOTO(ENTRY(do_redo));")
).
output_goto(do_fail, _) -->
globals__io_lookup_bool_option(use_macro_for_redo_fail, UseMacro),
(
{ UseMacro = yes },
io__write_string("fail();")
;
{ UseMacro = no },
io__write_string("GOTO(ENTRY(do_fail));")
).
output_goto(do_det_closure, CallerLabel) -->
io__write_string("tailcall(ENTRY(do_call_det_closure),\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");").
output_goto(do_semidet_closure, CallerLabel) -->
io__write_string("tailcall(ENTRY(do_call_semidet_closure),\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");").
output_goto(do_nondet_closure, CallerLabel) -->
io__write_string("tailcall(ENTRY(do_call_nondet_closure),\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");").
% Note that we also do some optimization here by
% outputting `localcall' rather than `call' for
% calls to local labels, or `call_localret' for
% calls which return to local labels (i.e. most of them).
:- pred output_call(code_addr, code_addr, label, io__state, io__state).
:- mode output_call(in, in, in, di, uo) is det.
output_call(Target, Continuation, CallerLabel) -->
( { Target = label(Label) } ->
io__write_string("localcall("),
output_label(Label),
io__write_string(",\n\t\t"),
output_code_addr(Continuation)
; { Continuation = label(ContLabel) } ->
io__write_string("call_localret("),
output_code_addr(Target),
io__write_string(",\n\t\t"),
output_label(ContLabel)
;
io__write_string("call("),
output_code_addr(Target),
io__write_string(",\n\t\t"),
output_code_addr(Continuation)
),
io__write_string(",\n\t\t"),
output_label_as_code_addr(CallerLabel),
io__write_string(");").
% :- pred output_call_closure(code_model, code_addr, label, io__state, io__state).
% :- mode output_call_closure(in, in, in, di, uo) is det.
%
% output_call_closure(CodeModel, Continuation, CallerLabel) -->
% (
% { CodeModel = model_det },
% io__write_string("call_det_closure(")
% ;
% { CodeModel = model_semi },
% io__write_string("call_semidet_closure(")
% ;
% { CodeModel = model_non },
% io__write_string("call_nondet_closure(")
% ),
% output_code_addr(Continuation),
% io__write_string(","),
% output_label_as_code_addr(CallerLabel),
% io__write_string(");").
:- pred output_code_addr(code_addr, io__state, io__state).
:- mode output_code_addr(in, di, uo) is det.
output_code_addr(label(Label)) -->
output_label_as_code_addr(Label).
output_code_addr(imported(ProcLabel)) -->
io__write_string("ENTRY("),
output_proc_label(ProcLabel),
io__write_string(")").
output_code_addr(succip) -->
io__write_string("succip").
output_code_addr(do_succeed(Last)) -->
(
{ Last = no },
io__write_string("ENTRY(do_succeed)")
;
{ Last = yes },
io__write_string("ENTRY(do_last_succeed)")
).
output_code_addr(do_redo) -->
io__write_string("ENTRY(do_redo)").
output_code_addr(do_fail) -->
io__write_string("ENTRY(do_fail)").
output_code_addr(do_det_closure) -->
io__write_string("ENTRY(do_call_det_closure)").
output_code_addr(do_semidet_closure) -->
io__write_string("ENTRY(do_call_semidet_closure)").
output_code_addr(do_nondet_closure) -->
io__write_string("ENTRY(do_call_nondet_closure)").
:- pred output_label_as_code_addr(label, io__state, io__state).
:- mode output_label_as_code_addr(in, di, uo) is det.
output_label_as_code_addr(Label) -->
io__write_string("LABEL("),
output_label(Label),
io__write_string(")").
:- pred output_label_list(list(label), io__state, io__state).
:- mode output_label_list(in, di, uo) is det.
output_label_list([]) --> [].
output_label_list([Label | Labels]) -->
io__write_string("LABEL("),
output_label(Label),
io__write_string(")"),
output_label_list_2(Labels).
:- pred output_label_list_2(list(label), io__state, io__state).
:- mode output_label_list_2(in, di, uo) is det.
output_label_list_2([]) --> [].
output_label_list_2([Label | Labels]) -->
io__write_string(" AND\n\t\t"),
io__write_string("LABEL("),
output_label(Label),
io__write_string(")"),
output_label_list_2(Labels).
:- pred output_label_defn(label, io__state, io__state).
:- mode output_label_defn(in, di, uo) is det.
output_label_defn(exported(ProcLabel)) -->
io__write_string("Define_entry("),
output_proc_label(ProcLabel),
io__write_string(");").
output_label_defn(local(ProcLabel)) -->
globals__io_lookup_int_option(procs_per_c_function, ProcsPerFunc),
% if we are splitting procs between functions, then
% every procedure could be referred to by a procedure
% in a different function, so make them static, not local
% similarly if we're splitting between files make them extern
( { ProcsPerFunc = 0 } ->
io__write_string("Define_local("),
output_proc_label(ProcLabel),
io__write_string("_l);") % l for "local".
;
globals__io_lookup_bool_option(split_c_files, SplitFiles),
( { SplitFiles = no } ->
io__write_string("Define_static("),
output_proc_label(ProcLabel),
io__write_string(");")
;
io__write_string("Define_entry("),
output_proc_label(ProcLabel),
io__write_string(");")
)
).
output_label_defn(local(ProcLabel, Num)) -->
io__write_string("Define_label("),
output_proc_label(ProcLabel),
io__write_string("_i"), % i for "internal" (not Intel ;-)
io__write_int(Num),
io__write_string(");").
% Note that the suffixes _l etc. used to be interpreted by mod2c,
% which generated different code depending on the suffix.
output_label(exported(ProcLabel)) -->
output_proc_label(ProcLabel).
output_label(local(ProcLabel)) -->
output_proc_label(ProcLabel),
globals__io_lookup_int_option(procs_per_c_function, ProcsPerFunc),
( { ProcsPerFunc = 0 } ->
io__write_string("_l") % l for "local".
;
% if we are splitting procs between functions, then
% every procedure could be referred to by a procedure
% in a different function, so don't make them local
[]
).
output_label(local(ProcLabel, Num)) -->
output_proc_label(ProcLabel),
io__write_string("_i"), % i for "internal" (not Intel ;-)
io__write_int(Num).
output_proc_label(ProcLabel) -->
{ get_proc_label(ProcLabel, ProcLabelString) },
io__write_string(ProcLabelString).
get_proc_label(proc(Module, Pred, Arity, ModeNum0),ProcLabelString) :-
get_label_name(Module, Pred, Arity, LabelName),
string__int_to_string(Arity, ArityString),
ModeNum is ModeNum0 mod 10000, % strip off the priority
string__int_to_string(ModeNum, ModeNumString),
string__append_list([LabelName, "_", ArityString, "_", ModeNumString],
ProcLabelString).
get_proc_label(special_proc(Module, PredName, TypeName0, TypeArity,
ModeNum0), ProcLabelString) :-
get_label_name(Module, PredName, TypeArity, LabelName),
llds_out__name_mangle(TypeName0, TypeName),
string__int_to_string(TypeArity, TypeArityString),
ModeNum is ModeNum0 mod 10000, % strip off the priority
string__int_to_string(ModeNum, ModeNumString),
string__append_list( [LabelName, "_", TypeName,
"_", TypeArityString, "_", ModeNumString],
ProcLabelString).
% llds_out__output_label_name/5 writes a name to standard out. Depending
% on the name of the label module and arity, the module name may also
% be written as a qualifier.
:- pred llds_out__output_label_name(string, string, int, io__state, io__state).
:- mode llds_out__output_label_name(in, in, in, di, uo) is det.
llds_out__output_label_name(Module, Name, Arity) -->
{ get_label_name(Module, Name, Arity, LabelName) },
io__write_string(LabelName).
:- pred get_label_name(string, string, int, string).
:- mode get_label_name(in, in, in, out) is det.
get_label_name(Module0, Name0, Arity, LabelName) :-
get_label_prefix(Prefix),
(
(
Module0 = "mercury_builtin"
;
Name0 = "main",
Arity = 2
;
string__append("__", _, Name0)
)
% The conditions above define which labels are printed without
% module qualification. XXX Changes to runtime/* are necessary
% to allow `mercury_builtin' labels to be qualified/
% overloaded.
->
llds_out__name_mangle(Name0, Name),
string__append(Prefix, Name, LabelName)
;
string__append(Module0, "__", UnderscoresModule),
( string__append(UnderscoresModule, Name1, Name0) ->
Name2 = Name1
;
Name2 = Name0
),
llds_out__name_mangle(Module0, Module),
llds_out__name_mangle(Name2, Name),
string__append_list([Prefix, Module, "__", Name], LabelName)
).
% To ensure that Mercury labels don't clash with C symbols, we
% prefix them with `mercury__'.
:- pred get_label_prefix(string).
:- mode get_label_prefix(out) is det.
get_label_prefix("mercury__").
:- pred output_reg(reg, io__state, io__state).
:- mode output_reg(in, di, uo) is det.
output_reg(r(N)) -->
( { N > 32 } ->
io__write_string("r("),
io__write_int(N),
io__write_string(")")
;
io__write_string("r"),
io__write_int(N)
).
output_reg(f(_)) -->
{ error("Floating point registers not implemented") }.
:- pred output_tag(tag, io__state, io__state).
:- mode output_tag(in, di, uo) is det.
output_tag(Tag) -->
io__write_string("mktag("),
io__write_int(Tag),
io__write_string(")").
% output an rval, as type `Integer', `Word', or `Unsigned'
% (normally as `Integer', so that arithmetic operators use signed arithmetic.)
:- pred output_rval(rval, io__state, io__state).
:- mode output_rval(in, di, uo) is det.
output_rval(const(Const)) -->
output_rval_const(Const).
output_rval(unop(UnaryOp, Exprn)) -->
output_unary_op(UnaryOp),
io__write_string("("),
output_rval(Exprn),
io__write_string(")").
output_rval(binop(Op, X, Y)) -->
(
{ Op = array_index }
->
io__write_string("((Integer *)"),
output_rval(X),
io__write_string(")["),
output_rval(Y),
io__write_string("]")
;
{ llds_out__string_op(Op, OpStr) }
->
io__write_string("(strcmp((char *)"),
output_rval(X),
io__write_string(", (char *)"),
output_rval(Y),
io__write_string(")"),
io__write_string(" "),
io__write_string(OpStr),
io__write_string("0)")
;
{ llds_out__float_compare_op(Op, OpStr) }
->
io__write_string("("),
output_rval_as_float(X),
io__write_string(" "),
io__write_string(OpStr),
io__write_string(" "),
output_rval_as_float(Y),
io__write_string(")")
;
{ llds_out__float_op(Op, OpStr) }
->
io__write_string("float_to_word("),
output_rval_as_float(X),
io__write_string(" "),
io__write_string(OpStr),
io__write_string(" "),
output_rval_as_float(Y),
io__write_string(")")
;
{ Op = (+) },
{ Y = const(int_const(C)) },
{ C < 0 }
->
{ NewOp = (-) },
{ NewC is 0 - C },
{ NewY = const(int_const(NewC)) },
io__write_string("("),
output_rval(X),
io__write_string(" "),
output_binary_op(NewOp),
io__write_string(" "),
output_rval(NewY),
io__write_string(")")
;
io__write_string("("),
output_rval(X),
io__write_string(" "),
output_binary_op(Op),
io__write_string(" "),
output_rval(Y),
io__write_string(")")
).
output_rval(mkword(Tag, Exprn)) -->
io__write_string("(Integer) mkword("),
output_tag(Tag),
io__write_string(", "),
output_rval(Exprn),
io__write_string(")").
output_rval(lval(Lval)) -->
output_rval_lval(Lval).
output_rval(create(Tag, _Args, LabelNum)) -->
% emit a reference to the static constant which we
% declared in output_rval_decls.
io__write_string("mkword(mktag("),
io__write_int(Tag),
io__write_string("), "),
io__write_string("mercury_const_"),
io__write_int(LabelNum),
io__write_string(")").
output_rval(var(_)) -->
{ error("Cannot output a var(_) expression in code") }.
% output an rval, converted to type `Float' (the Mercury floating point type).
:- pred output_rval_as_float(rval, io__state, io__state).
:- mode output_rval_as_float(in, di, uo) is det.
output_rval_as_float(Rval) -->
( { Rval = const(float_const(FloatVal)) } ->
io__write_float(FloatVal)
; { Rval = binop(Op, X, Y) }, { llds_out__float_op(Op, OpStr) } ->
io__write_string("("),
output_rval_as_float(X),
io__write_string(" "),
io__write_string(OpStr),
io__write_string(" "),
output_rval_as_float(Y),
io__write_string(")")
;
io__write_string("word_to_float("),
output_rval(Rval),
io__write_string(")")
).
:- pred output_unary_op(unary_op, io__state, io__state).
:- mode output_unary_op(in, di, uo) is det.
output_unary_op(mktag) -->
io__write_string("mktag").
output_unary_op(tag) -->
io__write_string("tag").
output_unary_op(unmktag) -->
io__write_string("unmktag").
output_unary_op(mkbody) -->
io__write_string("mkbody").
output_unary_op(body) -->
io__write_string("body").
output_unary_op(unmkbody) -->
io__write_string("unmkbody").
output_unary_op(hash_string) -->
io__write_string("hash_string").
output_unary_op(bitwise_complement) -->
io__write_string("~").
output_unary_op(not) -->
io__write_string("!").
output_unary_op(cast_to_unsigned) -->
io__write_string("(unsigned)").
:- pred llds_out__string_op(binary_op, string).
:- mode llds_out__string_op(in, out) is semidet.
llds_out__string_op(str_eq, "==").
llds_out__string_op(str_ne, "!=").
llds_out__string_op(str_le, "<=").
llds_out__string_op(str_ge, ">=").
llds_out__string_op(str_lt, "<").
llds_out__string_op(str_gt, ">").
:- pred llds_out__float_op(binary_op, string).
:- mode llds_out__float_op(in, out) is semidet.
llds_out__float_op(float_plus, "+").
llds_out__float_op(float_minus, "-").
llds_out__float_op(float_times, "*").
llds_out__float_op(float_divide, "/").
:- pred llds_out__float_compare_op(binary_op, string).
:- mode llds_out__float_compare_op(in, out) is semidet.
llds_out__float_compare_op(float_eq, "==").
llds_out__float_compare_op(float_ne, "!=").
llds_out__float_compare_op(float_le, "<=").
llds_out__float_compare_op(float_ge, ">=").
llds_out__float_compare_op(float_lt, "<").
llds_out__float_compare_op(float_gt, ">").
:- pred output_rval_const(rval_const, io__state, io__state).
:- mode output_rval_const(in, di, uo) is det.
output_rval_const(int_const(N)) -->
io__write_int(N).
output_rval_const(float_const(Float)) -->
globals__io_lookup_bool_option(unboxed_float, UnboxFloat),
globals__io_lookup_bool_option(static_ground_terms, StaticGroundTerms),
( { UnboxFloat = no, StaticGroundTerms = yes } ->
%
% for boxed floats, if --static-ground-terms is enabled,
% we just refer to the static const which we declared earlier
%
{ string__float_to_string(Float, FloatString) },
{ llds_out__float_const_name(FloatString, FloatName) },
io__write_string("(Word)(&"),
io__write_string(FloatName),
io__write_string(")")
;
io__write_string("float_const("),
io__write_float(Float),
io__write_string(")")
).
output_rval_const(string_const(String)) -->
io__write_string("string_const("""),
output_c_quoted_string(String),
{ string__length(String, StringLength) },
io__write_string(""", "),
io__write_int(StringLength),
io__write_string(")").
output_rval_const(true) -->
io__write_string("TRUE").
output_rval_const(false) -->
io__write_string("FALSE").
output_rval_const(address_const(CodeAddress)) -->
io__write_string("(Integer) "),
output_code_addr(CodeAddress).
:- pred output_lval(lval, io__state, io__state).
:- mode output_lval(in, di, uo) is det.
output_lval(reg(R)) -->
output_reg(R).
output_lval(stackvar(N)) -->
{ (N < 0) ->
error("stack var out of range")
;
true
},
io__write_string("detstackvar("),
io__write_int(N),
io__write_string(")").
output_lval(framevar(N)) -->
{ (N < 0) ->
error("frame var out of range")
;
true
},
io__write_string("framevar("),
io__write_int(N),
io__write_string(")").
output_lval(succip) -->
io__write_string("LVALUE_CAST(Word,succip)").
output_lval(sp) -->
io__write_string("LVALUE_CAST(Word,sp)").
output_lval(hp) -->
io__write_string("LVALUE_CAST(Word,hp)").
output_lval(maxfr) -->
io__write_string("LVALUE_CAST(Word,maxfr)").
output_lval(curfr) -->
io__write_string("LVALUE_CAST(Word,curfr)").
output_lval(succfr(Rval)) -->
io__write_string("LVALUE_CAST(Word,bt_succfr("),
output_rval(Rval),
io__write_string("))").
output_lval(prevfr(Rval)) -->
io__write_string("LVALUE_CAST(Word,bt_prevfr("),
output_rval(Rval),
io__write_string("))").
output_lval(redoip(Rval)) -->
io__write_string("LVALUE_CAST(Word,bt_redoip("),
output_rval(Rval),
io__write_string("))").
output_lval(succip(Rval)) -->
io__write_string("LVALUE_CAST(Word,bt_succip("),
output_rval(Rval),
io__write_string("))").
output_lval(field(Tag, Rval, FieldNum)) -->
io__write_string("field("),
output_tag(Tag),
io__write_string(", "),
output_rval(Rval),
io__write_string(", "),
output_rval(FieldNum),
io__write_string(")").
output_lval(lvar(_)) -->
{ error("Illegal to output an lvar") }.
output_lval(temp(N)) -->
io__write_string("temp"),
io__write_int(N).
% output_rval_lval is the same as output_lval,
% except that the result is cast to (Integer).
:- pred output_rval_lval(lval, io__state, io__state).
:- mode output_rval_lval(in, di, uo) is det.
output_rval_lval(reg(R)) -->
io__write_string("(Integer) "),
output_reg(R).
output_rval_lval(stackvar(N)) -->
{ (N < 0) ->
error("stack var out of range")
;
true
},
io__write_string("(Integer) detstackvar("),
io__write_int(N),
io__write_string(")").
output_rval_lval(framevar(N)) -->
{ (N < 0) ->
error("nondet stack var out of range")
;
true
},
io__write_string("(Integer) framevar("),
io__write_int(N),
io__write_string(")").
output_rval_lval(succip) -->
io__write_string("(Integer) succip").
output_rval_lval(sp) -->
io__write_string("(Integer) sp").
output_rval_lval(hp) -->
io__write_string("(Integer) hp").
output_rval_lval(maxfr) -->
io__write_string("(Integer) maxfr").
output_rval_lval(curfr) -->
io__write_string("(Integer) curfr").
output_rval_lval(succfr(Rval)) -->
io__write_string("(Integer) bt_succfr("),
output_rval(Rval),
io__write_string(")").
output_rval_lval(prevfr(Rval)) -->
io__write_string("(Integer) bt_prevfr("),
output_rval(Rval),
io__write_string(")").
output_rval_lval(redoip(Rval)) -->
io__write_string("(Integer) bt_redoip("),
output_rval(Rval),
io__write_string(")").
output_rval_lval(succip(Rval)) -->
io__write_string("(Integer) bt_succip("),
output_rval(Rval),
io__write_string(")").
output_rval_lval(field(Tag, Rval, FieldNum)) -->
io__write_string("(Integer) field("),
output_tag(Tag),
io__write_string(", "),
output_rval(Rval),
io__write_string(", "),
output_rval(FieldNum),
io__write_string(")").
output_rval_lval(lvar(_)) -->
{ error("Illegal to output an lvar") }.
output_rval_lval(temp(N)) -->
io__write_string("(Integer) temp"),
io__write_int(N).
%-----------------------------------------------------------------------------%
:- pred output_c_quoted_string(string, io__state, io__state).
:- mode output_c_quoted_string(in, di, uo) is det.
output_c_quoted_string(S0) -->
( { string__first_char(S0, Char, S1) } ->
( { quote_c_char(Char, QuoteChar) } ->
io__write_char('\\'),
io__write_char(QuoteChar)
;
io__write_char(Char)
),
output_c_quoted_string(S1)
;
[]
).
:- pred quote_c_char(character, character).
:- mode quote_c_char(in, out) is semidet.
quote_c_char('"', '"').
quote_c_char('\\', '\\').
quote_c_char('\n', 'n').
quote_c_char('\t', 't').
quote_c_char('\b', 'b').
%-----------------------------------------------------------------------------%
:- pred output_binary_op(binary_op, io__state, io__state).
:- mode output_binary_op(in, di, uo) is det.
output_binary_op(Op) -->
{ llds_out__binary_op_to_string(Op, String) },
io__write_string(String).
llds_out__binary_op_to_string(+, "+").
llds_out__binary_op_to_string(-, "-").
llds_out__binary_op_to_string(*, "*").
llds_out__binary_op_to_string(/, "/").
llds_out__binary_op_to_string(<<, "<<").
llds_out__binary_op_to_string(>>, ">>").
llds_out__binary_op_to_string(&, "&").
llds_out__binary_op_to_string('|', "|").
llds_out__binary_op_to_string(^, "^").
llds_out__binary_op_to_string(mod, "%").
llds_out__binary_op_to_string(eq, "==").
llds_out__binary_op_to_string(ne, "!=").
llds_out__binary_op_to_string(and, "&&").
llds_out__binary_op_to_string(or, "||").
llds_out__binary_op_to_string(<, "<").
llds_out__binary_op_to_string(>, ">").
llds_out__binary_op_to_string(<=, "<=").
llds_out__binary_op_to_string(>=, ">=").
% The following is just for debugging purposes -
% string operators are not output as `str_eq', etc.
llds_out__binary_op_to_string(array_index, "array_index").
llds_out__binary_op_to_string(str_eq, "str_eq").
llds_out__binary_op_to_string(str_ne, "str_ne").
llds_out__binary_op_to_string(str_lt, "str_lt").
llds_out__binary_op_to_string(str_gt, "str_gt").
llds_out__binary_op_to_string(str_le, "str_le").
llds_out__binary_op_to_string(str_ge, "str_ge").
llds_out__binary_op_to_string(float_eq, "float_eq").
llds_out__binary_op_to_string(float_ne, "float_ne").
llds_out__binary_op_to_string(float_lt, "float_lt").
llds_out__binary_op_to_string(float_gt, "float_gt").
llds_out__binary_op_to_string(float_le, "float_le").
llds_out__binary_op_to_string(float_ge, "float_ge").
llds_out__binary_op_to_string(float_plus, "float_plus").
llds_out__binary_op_to_string(float_minus, "float_minus").
llds_out__binary_op_to_string(float_times, "float_times").
llds_out__binary_op_to_string(float_divide, "float_divide").
%-----------------------------------------------------------------------------%
:- pred clause_num_to_string(int::in, string::out) is det.
clause_num_to_string(N, Str) :-
( clause_num_to_string_2(N, Str0) ->
Str = Str0
;
error("clause_num_to_string failed")
).
:- pred clause_num_to_string_2(int::in, string::out) is semidet.
clause_num_to_string_2(N, Str) :-
(
N < 26
->
int_to_letter(N, Str)
;
N_Low is N mod 26,
N_High is N // 26,
int_to_letter(N_Low, L),
clause_num_to_string(N_High, S),
string__append(S, L, Str)
).
:- pred int_to_letter(int, string).
:- mode int_to_letter(in, out) is semidet.
% This code is boring, but portable - it works even for EBCDIC ;-)
int_to_letter(0, "a").
int_to_letter(1, "b").
int_to_letter(2, "c").
int_to_letter(3, "d").
int_to_letter(4, "e").
int_to_letter(5, "f").
int_to_letter(6, "g").
int_to_letter(7, "h").
int_to_letter(8, "i").
int_to_letter(9, "j").
int_to_letter(10, "k").
int_to_letter(11, "l").
int_to_letter(12, "m").
int_to_letter(13, "n").
int_to_letter(14, "o").
int_to_letter(15, "p").
int_to_letter(16, "q").
int_to_letter(17, "r").
int_to_letter(18, "s").
int_to_letter(19, "t").
int_to_letter(20, "u").
int_to_letter(21, "v").
int_to_letter(22, "w").
int_to_letter(23, "x").
int_to_letter(24, "y").
int_to_letter(25, "z").
llds_out__lval_to_string(framevar(N), Description) :-
string__int_to_string(N, N_String),
string__append("framevar(", N_String, Tmp),
string__append(Tmp, ")", Description).
llds_out__lval_to_string(stackvar(N), Description) :-
string__int_to_string(N, N_String),
string__append("stackvar(", N_String, Tmp),
string__append(Tmp, ")", Description).
llds_out__lval_to_string(reg(Reg), Description) :-
llds_out__reg_to_string(Reg, Reg_String),
string__append("reg(", Reg_String, Tmp),
string__append(Tmp, ")", Description).
:- pred llds_out__reg_to_string(reg, string).
:- mode llds_out__reg_to_string(in, out) is det.
llds_out__reg_to_string(r(N), Description) :-
string__int_to_string(N, N_String),
string__append("r(", N_String, Tmp),
string__append(Tmp, ")", Description).
llds_out__reg_to_string(f(N), Description) :-
string__int_to_string(N, N_String),
string__append("f(", N_String, Tmp),
string__append(Tmp, ")", Description).
%-----------------------------------------------------------------------------%
% Convert a Mercury predicate name into something that can form
% part of a C identifier. This predicate is necessary because
% quoted names such as 'name with embedded spaces' are valid
% predicate names in Mercury.
llds_out__name_mangle(Name, MangledName) :-
(
string__is_alnum_or_underscore(Name)
->
% any names that start with `f_' are changed so that
% they start with `f__', so that we can use names starting
% with `f_' (followed by anything except an underscore)
% without fear of name collisions
(
string__append("f_", Suffix, Name)
->
string__append("f__", Suffix, MangledName)
;
MangledName = Name
)
;
llds_out__convert_to_valid_c_identifier(Name, MangledName)
).
:- pred llds_out__convert_to_valid_c_identifier(string, string).
:- mode llds_out__convert_to_valid_c_identifier(in, out) is det.
llds_out__convert_to_valid_c_identifier(String, Name) :-
(
llds_out__name_conversion_table(String, Name0)
->
Name = Name0
;
llds_out__convert_to_valid_c_identifier_2(String, Name0),
string__append("f", Name0, Name)
).
% A table used to convert Mercury functors into
% C identifiers. Feel free to add any new translations you want.
% The C identifiers should start with "f_",
% to avoid introducing name clashes.
% If the functor name is not found in the table, then
% we use a fall-back method which produces ugly names.
:- pred llds_out__name_conversion_table(string, string).
:- mode llds_out__name_conversion_table(in, out) is semidet.
llds_out__name_conversion_table("\\=", "f_not_equal").
llds_out__name_conversion_table(">=", "f_greater_or_equal").
llds_out__name_conversion_table("=<", "f_less_or_equal").
llds_out__name_conversion_table("=", "f_equal").
llds_out__name_conversion_table("<", "f_less_than").
llds_out__name_conversion_table(">", "f_greater_than").
llds_out__name_conversion_table("-", "f_minus").
llds_out__name_conversion_table("+", "f_plus").
llds_out__name_conversion_table("*", "f_times").
llds_out__name_conversion_table("/", "f_slash").
llds_out__name_conversion_table(",", "f_comma").
llds_out__name_conversion_table(";", "f_semicolon").
llds_out__name_conversion_table("!", "f_cut").
% This is the fall-back method.
% Given a string, produce a C identifier
% for that string by concatenating the decimal
% expansions of the character codes in the string,
% separated by underlines.
% The C identifier will start with "f_"; this predicate
% constructs everything except the initial "f".
%
% For example, given the input "\n\t" we return "_10_8".
:- pred llds_out__convert_to_valid_c_identifier_2(string, string).
:- mode llds_out__convert_to_valid_c_identifier_2(in, out) is det.
llds_out__convert_to_valid_c_identifier_2(String, Name) :-
(
string__first_char(String, Char, Rest)
->
char__to_int(Char, Code),
string__int_to_string(Code, CodeString),
string__append("_", CodeString, ThisCharString),
llds_out__convert_to_valid_c_identifier_2(Rest, Name0),
string__append(ThisCharString, Name0, Name)
;
% String is the empty string
Name = String
).
%-----------------------------------------------------------------------------%
:- pred gather_labels(list(c_procedure), list(label)).
:- mode gather_labels(in, out) is det.
gather_labels(Procs, Labels) :-
gather_labels_2(Procs, [], Labels1),
list__reverse(Labels1, Labels).
:- pred gather_labels_2(list(c_procedure), list(label), list(label)).
:- mode gather_labels_2(in, in, out) is det.
gather_labels_2([], Labels, Labels).
gather_labels_2([c_procedure(_, _, _, Instrs) | Procs], Labels0, Labels) :-
gather_labels_from_instrs(Instrs, Labels0, Labels1),
gather_labels_2(Procs, Labels1, Labels).
:- pred gather_labels_from_instrs(list(instruction), list(label), list(label)).
:- mode gather_labels_from_instrs(in, in, out) is det.
gather_labels_from_instrs([], Labels, Labels).
gather_labels_from_instrs([Instr | Instrs], Labels0, Labels) :-
( Instr = label(Label) - _ ->
Labels1 = [Label | Labels0]
;
Labels1 = Labels0
),
gather_labels_from_instrs(Instrs, Labels1, Labels).
%-----------------------------------------------------------------------------%