%-----------------------------------------------------------------------------% % Copyright (C) 1998-1999 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. %-----------------------------------------------------------------------------% % % Module: transform_llds % % Main authors: petdr % % This module does source to source transformations of the llds data % structure. This is sometimes necessary to avoid limits in some % compilers. % % This module currently transforms computed gotos into a binary search % down to smaller computed gotos. This avoids a limitation in the lcc % compiler. % %-----------------------------------------------------------------------------% :- module transform_llds. :- interface. :- import_module llds. :- pred transform_llds(c_file, c_file, io__state, io__state). :- mode transform_llds(in, out, di, uo) is det. %-----------------------------------------------------------------------------% :- implementation. :- import_module builtin_ops, globals, options, opt_util, prog_data. :- import_module bool, int, list, require, std_util. transform_llds(LLDS0, LLDS) --> globals__io_lookup_int_option(max_jump_table_size, Size), ( { Size = 0 } -> { LLDS = LLDS0 } ; transform_c_file(LLDS0, LLDS) ). %-----------------------------------------------------------------------------% :- pred transform_c_file(c_file, c_file, io__state, io__state). :- mode transform_c_file(in, out, di, uo) is det. transform_c_file(c_file(ModuleName, HeaderInfo, A, B, C, D, Modules0), c_file(ModuleName, HeaderInfo, A, B, C, D, Modules)) --> transform_c_module_list(Modules0, Modules). %-----------------------------------------------------------------------------% :- pred transform_c_module_list(list(comp_gen_c_module), list(comp_gen_c_module), io__state, io__state). :- mode transform_c_module_list(in, out, di, uo) is det. transform_c_module_list([], []) --> []. transform_c_module_list([M0 | M0s], [M | Ms]) --> transform_c_module(M0, M), transform_c_module_list(M0s, Ms). %-----------------------------------------------------------------------------% :- pred transform_c_module(comp_gen_c_module, comp_gen_c_module, io__state, io__state). :- mode transform_c_module(in, out, di, uo) is det. transform_c_module(comp_gen_c_module(Name, Procedures0), comp_gen_c_module(Name, Procedures)) --> transform_c_procedure_list(Procedures0, Procedures). %-----------------------------------------------------------------------------% :- pred transform_c_procedure_list(list(c_procedure), list(c_procedure), io__state, io__state). :- mode transform_c_procedure_list(in, out, di, uo) is det. transform_c_procedure_list([], []) --> []. transform_c_procedure_list([P0 | P0s], [P | Ps]) --> transform_c_procedure(P0, P), transform_c_procedure_list(P0s, Ps). %-----------------------------------------------------------------------------% :- pred transform_c_procedure(c_procedure, c_procedure, io__state, io__state). :- mode transform_c_procedure(in, out, di, uo) is det. transform_c_procedure(c_procedure(Name, Arity, PredProcId, Instructions0), c_procedure(Name, Arity, PredProcId, Instructions)) --> transform_instructions(Instructions0, Instructions). %-----------------------------------------------------------------------------% :- pred transform_instructions(list(instruction), list(instruction), io__state, io__state). :- mode transform_instructions(in, out, di, uo) is det. transform_instructions(Instrs0, Instrs) --> { opt_util__get_prologue(Instrs0, ProcLabel, _, _, _) }, { max_label_int(Instrs0, 0, N) }, transform_instructions_2(Instrs0, ProcLabel, N, Instrs). :- pred transform_instructions_2(list(instruction), proc_label, int, list(instruction), io__state, io__state). :- mode transform_instructions_2(in, in, in, out, di, uo) is det. transform_instructions_2([], _, _, []) --> []. transform_instructions_2([Instr0 | Instrs0], ProcLabel, N0, Instrs) --> transform_instruction(Instr0, ProcLabel, N0, InstrsA, N), transform_instructions_2(Instrs0, ProcLabel, N, InstrsB), { list__append(InstrsA, InstrsB, Instrs) }. %-----------------------------------------------------------------------------% :- pred transform_instruction(instruction, proc_label, int, list(instruction), int, io__state, io__state). :- mode transform_instruction(in, in, in, out, out, di, uo) is det. transform_instruction(Instr0, ProcLabel, N0, Instrs, N) --> globals__io_lookup_int_option(max_jump_table_size, Size), ( { Instr0 = computed_goto(_Rval, Labels) - _}, { list__length(Labels, L) }, { L > Size } -> split_computed_goto(Instr0, Size, L, ProcLabel, N0, Instrs, N) ; { Instrs = [Instr0] }, { N = N0 } ). %-----------------------------------------------------------------------------% % % split_computed_goto(I, S, L, P, N0, Is, N) % % If instruction, I, is a computed_goto whose jump_table size is % greater then S, then split the table in half and insert the % instructions, Is, to do a binary search down to a jump_table % whose size is sufficiently small. % :- pred split_computed_goto(instruction, int, int, proc_label, int, list(instruction), int, io__state, io__state). :- mode split_computed_goto(in, in, in, in, in, out, out, di, uo) is det. split_computed_goto(Instr0, MaxSize, Length, ProcLabel, N0, Instrs, N) --> ( { Length =< MaxSize } -> { Instrs = [Instr0] }, { N = N0 } ; { Instr0 = computed_goto(Rval, Labels) - _Comment } -> { N1 is N0 + 1}, { N2 is N1 + 1}, { Mid = Length // 2 }, ( { list__split_list(Mid, Labels, Start0, End0) } -> { Start = Start0, End = End0 } ; { error("split_computed_goto: list__split_list") } ), { Index = binop((-), Rval, const(int_const(Mid))) }, { Test = binop((>=), Rval, const(int_const(Mid))) }, { ElseAddr = label(local(ProcLabel, N1)) }, { ElseLabel = label(local(ProcLabel, N1)) - ""}, { IfInstr = if_val(Test, ElseAddr ) - "Binary search"}, { ThenInstr = computed_goto(Rval, Start) - "Then section" }, { ElseInstr = computed_goto(Index, End) - "Else section" }, split_computed_goto(ThenInstr, MaxSize, Mid, ProcLabel, N2, ThenInstrs, N3), split_computed_goto(ElseInstr, MaxSize, Length - Mid, ProcLabel, N3, ElseInstrs, N), { list__append(ThenInstrs, [ElseLabel | ElseInstrs], InstrsA) }, { Instrs = [IfInstr | InstrsA] } ; { error("split_computed_goto") } ). %-----------------------------------------------------------------------------% % % max_label_int(Is, M0, M) % % Find the highest integer, M, used in local labels from the list of % intructions, Is, where M0 is the highest integer found so far. % :- pred max_label_int(list(instruction), int, int). :- mode max_label_int(in, in, out) is det. max_label_int([], N, N). max_label_int([Instr - _Comment | Instrs], N0, N) :- ( Instr = label(local(_, Num)), Num > N0 -> max_label_int(Instrs, Num, N) ; max_label_int(Instrs, N0, N) ). %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%