%---------------------------------------------------------------------------% % vim: ft=mercury ts=4 sw=4 et %---------------------------------------------------------------------------% % Copyright (C) 1994-2012 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: code_info.m. % Main authors: conway, zs. % % This file defines the code_info type and various operations on it. % The code_info structure is the persistent part of the 'state' % of the code generator. The other part of the code generator state, % the location-dependent part, is in code_loc_dep.m. % % This file is organized into three submodules: % % - the code_info structure and its access predicates % - simple wrappers around access predicates % - managing stack slots % %---------------------------------------------------------------------------% :- module ll_backend.code_info. :- interface. :- import_module hlds. :- import_module hlds.code_model. :- import_module hlds.hlds_data. :- import_module hlds.hlds_goal. :- import_module hlds.hlds_llds. :- import_module hlds.hlds_module. :- import_module hlds.hlds_pred. :- import_module libs. :- import_module libs.globals. :- import_module libs.optimization_options. :- import_module libs.trace_params. :- import_module ll_backend.continuation_info. :- import_module ll_backend.global_data. :- import_module ll_backend.layout. :- import_module ll_backend.llds. :- import_module ll_backend.trace_gen. :- import_module mdbcomp. :- import_module mdbcomp.goal_path. :- import_module mdbcomp.prim_data. :- import_module parse_tree. :- import_module parse_tree.prog_data. :- import_module parse_tree.set_of_var. :- import_module parse_tree.var_table. :- import_module bool. :- import_module counter. :- import_module io. :- import_module list. :- import_module map. :- import_module maybe. :- import_module set. :- import_module set_tree234. :- import_module term. %----------------------------------------------------------------------------% %----------------------------------------------------------------------------% :- implementation. :- import_module backend_libs. :- import_module backend_libs.proc_label. :- import_module hlds.hlds_proc_util. :- import_module hlds.type_util. :- import_module libs.options. :- import_module ll_backend.code_util. :- import_module parse_tree.prog_type. :- import_module cord. :- import_module int. :- import_module pair. :- import_module require. :- import_module string. :- import_module uint8. %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% % Submodule for the code_info type and its access predicates. % % This submodule has the following components: % % declarations for exported access predicates % declarations for non-exported access predicates % the definition of the type and the init predicate % the definition of the get access predicates % the definition of the set access predicates % % Please keep the order of mention of the various fields % consistent in each of these five components. :- interface. :- type code_info. % Create a new code_info structure. Also return info about the non-fixed % stack slots used for tracing purposes. % :- pred code_info_init(module_info::in, pred_id::in, proc_id::in, pred_info::in, proc_info::in, var_table::in, bool::in, static_cell_info::in, const_struct_map::in, io.text_output_stream::in, maybe(containing_goal_map)::in, list(string)::in, int::in, trace_slot_info::out, code_info::out) is det. :- pred get_module_info(code_info::in, module_info::out) is det. :- pred get_globals(code_info::in, globals::out) is det. :- pred get_exprn_opts(code_info::in, exprn_opts::out) is det. :- pred get_eff_trace_level(code_info::in, eff_trace_level::out) is det. :- pred get_pred_id(code_info::in, pred_id::out) is det. :- pred get_proc_id(code_info::in, proc_id::out) is det. :- pred get_pred_info(code_info::in, pred_info::out) is det. :- pred get_proc_info(code_info::in, proc_info::out) is det. :- pred get_proc_label(code_info::in, proc_label::out) is det. :- pred get_var_table(code_info::in, var_table::out) is det. :- pred get_var_slot_count(code_info::in, int::out) is det. :- pred get_maybe_trace_info(code_info::in, maybe(trace_info)::out) is det. :- pred get_opt_no_return_calls(code_info::in, bool::out) is det. :- pred get_emit_trail_ops(code_info::in, add_trail_ops::out) is det. :- pred get_opt_trail_ops(code_info::in, bool::out) is det. :- pred get_emit_region_ops(code_info::in, add_region_ops::out) is det. :- pred get_opt_region_ops(code_info::in, bool::out) is det. :- pred get_auto_comments(code_info::in, bool::out) is det. :- pred get_lcmc_null(code_info::in, maybe_opt_lcmc_null::out) is det. :- pred get_profile_memory(code_info::in, bool::out) is det. :- pred get_may_use_atomic_alloc(code_info::in, may_use_atomic_alloc::out) is det. :- pred get_num_ptag_bits(code_info::in, uint8::out) is det. :- pred get_gc_method(code_info::in, gc_method::out) is det. :- pred get_maybe_containing_goal_map(code_info::in, maybe(containing_goal_map)::out) is det. :- pred get_const_struct_map(code_info::in, const_struct_map::out) is det. % get_progress_stream is not exported. :- pred get_label_counter(code_info::in, counter::out) is det. :- pred get_succip_used(code_info::in, bool::out) is det. :- pred get_layout_info(code_info::in, proc_label_layout_info::out) is det. :- pred get_proc_trace_events(code_info::in, bool::out) is det. :- pred get_max_regs_in_use_at_trace(code_info::in, int::out, int::out) is det. :- pred get_created_temp_frame(code_info::in, bool::out) is det. :- pred get_max_temp_slot_count(code_info::in, int::out) is det. :- pred get_temp_content_map(code_info::in, map(lval, slot_contents)::out) is det. :- pred get_persistent_temps(code_info::in, set(lval)::out) is det. % get_closure_seq_counter is not exported. :- pred get_closure_layouts(code_info::in, list(closure_proc_id_data)::out) is det. :- pred get_static_cell_info(code_info::in, static_cell_info::out) is det. :- pred get_alloc_sites(code_info::in, set_tree234(alloc_site_info)::out) is det. :- pred get_used_env_vars(code_info::in, set(string)::out) is det. :- pred get_out_of_line_code(code_info::in, llds_code::out) is det. % set_maybe_trace_info is not exported. % set_label_counter is not exported. % set_succip_used is not exported. % set_layout_info is not exported. :- pred set_proc_trace_events(bool::in, code_info::in, code_info::out) is det. :- pred set_max_regs_in_use_at_trace(int::in, int::in, code_info::in, code_info::out) is det. :- pred set_max_temp_slot_count(int::in, code_info::in, code_info::out) is det. :- pred set_temp_content_map(map(lval, slot_contents)::in, code_info::in, code_info::out) is det. :- pred set_persistent_temps(set(lval)::in, code_info::in, code_info::out) is det. % set_closure_seq_counter is not exported. % set_closure_layouts is not exported. :- pred set_created_temp_frame(bool::in, code_info::in, code_info::out) is det. :- pred set_static_cell_info(static_cell_info::in, code_info::in, code_info::out) is det. :- pred set_alloc_sites(set_tree234(alloc_site_info)::in, code_info::in, code_info::out) is det. :- pred set_used_env_vars(set(string)::in, code_info::in, code_info::out) is det. %---------------------------------------------------------------------------% :- implementation. :- func init_exprn_opts(globals) = exprn_opts. :- pred init_maybe_trace_info(globals::in, proc_info::in, eff_trace_level::in, trace_slot_info::out, code_info::in, code_info::out) is det. :- pred get_progress_stream(code_info::in, io.text_output_stream::out) is det. :- pred get_closure_seq_counter(code_info::in, counter::out) is det. :- pred set_maybe_trace_info(maybe(trace_info)::in, code_info::in, code_info::out) is det. :- pred set_label_counter(counter::in, code_info::in, code_info::out) is det. :- pred set_succip_used(bool::in, code_info::in, code_info::out) is det. :- pred set_layout_info(proc_label_layout_info::in, code_info::in, code_info::out) is det. :- pred set_closure_seq_counter(counter::in, code_info::in, code_info::out) is det. :- pred set_closure_layouts(list(closure_proc_id_data)::in, code_info::in, code_info::out) is det. %---------------------------------------------------------------------------% % The code_info structure has two groups of fields. % % Some fields are static; they are set when the code_info structure % is initialized, and never changed afterwards. % % The other fields record persistent information that does not depend % on a code location. Updates to these fields must remain effective % even when the code generator resets its location-dependent state. :- type code_info ---> code_info( code_info_static :: code_info_static, code_info_persistent :: code_info_persistent ). :- type code_info_static ---> code_info_static( % The module_info structure - you just never know % when you might need it. cis_module_info :: module_info, % For the code generation options. cis_globals :: globals, cis_exprn_opts :: exprn_opts, cis_eff_trace_level :: eff_trace_level, % The id of the current predicate. cis_pred_id :: pred_id, % The id of the current procedure. cis_proc_id :: proc_id, % The pred_info for the predicate containing this procedure. cis_pred_info :: pred_info, % The proc_info for this procedure. cis_proc_info :: proc_info, % The proc_label for this procedure. cis_proc_label :: proc_label, % The variables in this procedure. cis_var_table :: var_table, % The number of stack slots allocated. for storing variables. % (Some extra stack slots are used for saving and restoring % registers.) cis_var_slot_count :: int, % Information about which stack slots the call sequence number % and depth are stored in, provided tracing is switched on. cis_maybe_trace_info :: maybe(trace_info), % Should we optimize calls that cannot return? cis_opt_no_return_calls :: bool, % Should we emit trail operations? cis_emit_trail_ops :: add_trail_ops, % Should we try to avoid generating trail operations? cis_opt_trail_ops :: bool, % Should we emit region operations? cis_emit_region_ops :: add_region_ops, % Should we try to avoid generating region operations? cis_opt_region_ops :: bool, % The setting of --auto-comments. cis_auto_comments :: bool, % The settings of --optimize-constructor-last-call-null, % --profile-memory, and --use-atomic-cells. cis_lcmc_null :: maybe_opt_lcmc_null, cis_profile_memory :: bool, cis_may_use_atomic_alloc :: may_use_atomic_alloc, % The number of primary tags bits we are using. cis_num_ptag_bits :: uint8, % The GC method. cis_gc_method :: gc_method, cis_containing_goal_map :: maybe(containing_goal_map), % Maps the number of an entry in the module's const_struct_db % to its rval. cis_const_struct_map :: const_struct_map, % The stream to write any debugging output to. cis_progress_stream :: io.text_output_stream ). :- type code_info_persistent ---> code_info_persistent( % Counter for the local labels used by this procedure. cip_label_num_src :: counter, % Do we need to store succip? cip_store_succip :: bool, % Information on which values are live and where at which % labels, for tracing and/or accurate gc. cip_label_layout_info :: proc_label_layout_info, % Did the procedure have any trace events? cip_proc_trace_events :: bool, % At each call to MR_trace, we compute the highest rN and fN % registers that contain useful values. These slot contain the % maximum of these highest values. Therefore at all calls to % MR_trace in the procedure, we need only save the registers % whose numbers are equal to or smaller than this field. % This slot contains -1 if tracing is not enabled. cip_max_reg_r_used :: int, cip_max_reg_f_used :: int, % The maximum number of extra temporary stackslots that % have been used during the procedure. cip_stackslot_max :: int, % The temporary locations that have ever been used on the % stack, and what they contain. Once we have used a stack slot % to store e.g. a ticket, we never reuse that slot to hold % something else, e.g. a saved hp. This policy prevents us % from making such conflicting choices in parallel branches, % which would make it impossible to describe to gc what the % slot contains after the end of the branched control % structure. cip_temp_content_map :: map(lval, slot_contents), % Stack slot locations that should not be released even when % the code generator resets its location-dependent state. cip_persistent_temps :: set(lval), cip_closure_layout_seq :: counter, % Closure layout structures generated by this procedure. cip_closure_layouts :: list(closure_proc_id_data), % True iff the procedure has created one or more temporary % nondet frames. cip_created_temp_frame :: bool, cip_static_cell_info :: static_cell_info, cip_alloc_sites :: set_tree234(alloc_site_info), cip_used_env_vars :: set(string), % A counter and table for allocating and maintaining slots % where string IDs will be placed at runtime for threadscope % profiling. The actual string IDs are allocated at runtime % and their IDs are placed in an array slot which can be % referred to statically. cip_ts_string_table_size :: int, cip_ts_rev_string_table :: list(string), % Code that is part of this procedure, but that can be placed % after the procedure without a cache penalty. For example, % code that is spawned off by loop control is placed here. cip_out_of_line_code :: llds_code ). %---------------------------------------------------------------------------% code_info_init(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo, VarTable, SaveSuccip, StaticCellInfo, ConstStructMap, ProgressStream, MaybeContainingGoalMap, TSRevStringTable, TSStringTableSize, TraceSlotInfo, CodeInfo) :- % argument ModuleInfo module_info_get_globals(ModuleInfo, Globals), ExprnOpts = init_exprn_opts(Globals), % argument PredId % argument ProcId % argument PredInfo % argument ProcInfo ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId), proc_info_get_stack_slots(ProcInfo, StackSlots), max_var_slot(StackSlots, VarSlotMax), globals.get_trace_level(Globals, TraceLevel), EffTraceLevel = eff_trace_level_for_proc(ModuleInfo, PredInfo, ProcInfo, TraceLevel), trace_reserved_slots(Globals, ProcInfo, EffTraceLevel, FixedSlots, _), int.max(VarSlotMax, FixedSlots, SlotMax), MaybeTraceInfo = no, globals.lookup_bool_option(Globals, opt_no_return_calls, OptNoReturnCalls), globals.lookup_bool_option(Globals, use_trail, UseTrail), globals.lookup_bool_option(Globals, disable_trail_ops, DisableTrailOps), ( if UseTrail = yes, DisableTrailOps = no then EmitTrailOps = add_trail_ops else EmitTrailOps = do_not_add_trail_ops ), globals.lookup_bool_option(Globals, optimize_trail_usage, OptTrailOps), globals.get_opt_tuple(Globals, OptTuple), UseRegions = OptTuple ^ ot_analyse_regions, ( UseRegions = analyse_regions, EmitRegionOps = add_region_ops ; UseRegions = do_not_analyse_regions, EmitRegionOps = do_not_add_region_ops ), globals.lookup_bool_option(Globals, optimize_region_ops, OptRegionOps), globals.lookup_bool_option(Globals, auto_comments, AutoComments), LCMCNull = OptTuple ^ ot_opt_lcmc_null, globals.lookup_bool_option(Globals, profile_memory, ProfileMemory), UseAtomicCells = OptTuple ^ ot_use_atomic_cells, ( UseAtomicCells = do_not_use_atomic_cells, InitMayUseAtomic = may_not_use_atomic_alloc ; UseAtomicCells = use_atomic_cells, InitMayUseAtomic = may_use_atomic_alloc ), globals.lookup_int_option(Globals, num_ptag_bits, NumPtagBitsInt), NumPtagBits = uint8.det_from_int(NumPtagBitsInt), globals.get_gc_method(Globals, GCMethod), % argument MaybeContainingGoalMap % argument ConstStructMap CodeInfoStatic0 = code_info_static( ModuleInfo, Globals, ExprnOpts, EffTraceLevel, PredId, ProcId, PredInfo, ProcInfo, ProcLabel, VarTable, SlotMax, MaybeTraceInfo, OptNoReturnCalls, EmitTrailOps, OptTrailOps, EmitRegionOps, OptRegionOps, AutoComments, LCMCNull, ProfileMemory, InitMayUseAtomic, NumPtagBits, GCMethod, MaybeContainingGoalMap, ConstStructMap, ProgressStream ), LabelNumCounter0 = counter.init(1), % argument SaveSuccip map.init(LayoutMap), ProcTraceEvents = no, MaxRegRUsed = -1, MaxRegFUsed = -1, MaxTempSlotCount = 0, map.init(TempContentMap), set.init(PersistentTemps), ClosureLayoutSeqNumCounter0 = counter.init(1), ClosureLayouts = [], CreatedTempFrame = no, % argument StaticCellInfo AllocSitesMap0 = set_tree234.init, set.init(UsedEnvVars), OutOfLineCode = cord.init, CodeInfoPersistent0 = code_info_persistent( LabelNumCounter0, SaveSuccip, LayoutMap, ProcTraceEvents, MaxRegRUsed, MaxRegFUsed, MaxTempSlotCount, TempContentMap, PersistentTemps, ClosureLayoutSeqNumCounter0, ClosureLayouts, CreatedTempFrame, StaticCellInfo, AllocSitesMap0, UsedEnvVars, TSStringTableSize, TSRevStringTable, OutOfLineCode ), CodeInfo0 = code_info(CodeInfoStatic0, CodeInfoPersistent0), init_maybe_trace_info(Globals, ProcInfo, EffTraceLevel, TraceSlotInfo, CodeInfo0, CodeInfo). init_exprn_opts(Globals) = ExprnOpts :- globals.lookup_bool_option(Globals, gcc_non_local_gotos, OptNLG), ( OptNLG = yes, NLG = have_non_local_gotos ; OptNLG = no, NLG = do_not_have_non_local_gotos ), globals.lookup_bool_option(Globals, asm_labels, OptASM), ( OptASM = yes, ASM = have_asm_labels ; OptASM = no, ASM = do_not_have_asm_labels ), globals.get_opt_tuple(Globals, OptTuple), OptSGCell = OptTuple ^ ot_use_static_ground_cells, ( OptSGCell = use_static_ground_cells, SGCell = have_static_ground_cells ; OptSGCell = do_not_use_static_ground_cells, SGCell = do_not_have_static_ground_cells ), globals.lookup_bool_option(Globals, unboxed_float, OptUBF), ( OptUBF = yes, UBF = have_unboxed_floats ; OptUBF = no, UBF = do_not_have_unboxed_floats ), globals.lookup_bool_option(Globals, use_float_registers, OptFloatRegs), ( OptFloatRegs = yes, UseFloatRegs = use_float_registers ; OptFloatRegs = no, UseFloatRegs = do_not_use_float_registers ), double_width_floats_on_det_stack(Globals, FloatDwords), ( FloatDwords = yes, DetStackFloatWidth = double_width ; FloatDwords = no, DetStackFloatWidth = single_width ), globals.lookup_bool_option(Globals, unboxed_int64s, OptUBI64s), ( OptUBI64s = yes, UBI64s = have_unboxed_int64s ; OptUBI64s = no, UBI64s = do_not_have_unboxed_int64s ), OptSGFloat = OptTuple ^ ot_use_static_ground_floats, ( OptSGFloat = use_static_ground_floats, SGFloat = have_static_ground_floats ; OptSGFloat = do_not_use_static_ground_floats, SGFloat = do_not_have_static_ground_floats ), OptSGInt64s = OptTuple ^ ot_use_static_ground_int64s, ( OptSGInt64s = use_static_ground_int64s, SGInt64s = have_static_ground_int64s ; OptSGInt64s = do_not_use_static_ground_int64s, SGInt64s = do_not_have_static_ground_int64s ), OptStaticCodeAddr = OptTuple ^ ot_use_static_code_addresses, ( OptStaticCodeAddr = use_static_code_addresses, StaticCodeAddrs = have_static_code_addresses ; OptStaticCodeAddr = do_not_use_static_code_addresses, StaticCodeAddrs = do_not_have_static_code_addresses ), ExprnOpts = exprn_opts(NLG, ASM, UBF, UseFloatRegs, DetStackFloatWidth, UBI64s, SGCell, SGFloat, SGInt64s, StaticCodeAddrs). init_maybe_trace_info(Globals, ProcInfo, EffTraceLevel, TraceSlotInfo, !CI) :- TraceEnabled = is_exec_trace_enabled_at_eff_trace_level(EffTraceLevel), ( TraceEnabled = exec_trace_is_enabled, proc_info_get_has_tail_rec_call(ProcInfo, HasTailRecCall), HasTailRecCall = has_tail_rec_call(HasSelfTailRecCall, _HasMutualTailRecCall), ( HasSelfTailRecCall = has_self_tail_rec_call, get_next_label(TailRecLabel, !CI), MaybeTailRecLabel = yes(TailRecLabel) ; HasSelfTailRecCall = has_no_self_tail_rec_call, MaybeTailRecLabel = no ), trace_setup(Globals, ProcInfo, EffTraceLevel, MaybeTailRecLabel, TraceSlotInfo, TraceInfo, !CI), set_maybe_trace_info(yes(TraceInfo), !CI) ; TraceEnabled = exec_trace_is_not_enabled, TraceSlotInfo = trace_slot_info(no, no, no, no, no, no) ). %---------------------------------------------------------------------------% get_module_info(CI, X) :- X = CI ^ code_info_static ^ cis_module_info. get_globals(CI, X) :- X = CI ^ code_info_static ^ cis_globals. get_exprn_opts(CI, X) :- X = CI ^ code_info_static ^ cis_exprn_opts. get_eff_trace_level(CI, X) :- X = CI ^ code_info_static ^ cis_eff_trace_level. get_pred_id(CI, X) :- X = CI ^ code_info_static ^ cis_pred_id. get_proc_id(CI, X) :- X = CI ^ code_info_static ^ cis_proc_id. get_pred_info(CI, X) :- X = CI ^ code_info_static ^ cis_pred_info. get_proc_info(CI, X) :- X = CI ^ code_info_static ^ cis_proc_info. get_proc_label(CI, X) :- X = CI ^ code_info_static ^ cis_proc_label. get_var_table(CI, X) :- X = CI ^ code_info_static ^ cis_var_table. get_var_slot_count(CI, X) :- X = CI ^ code_info_static ^ cis_var_slot_count. get_maybe_trace_info(CI, X) :- X = CI ^ code_info_static ^ cis_maybe_trace_info. get_opt_no_return_calls(CI, X) :- X = CI ^ code_info_static ^ cis_opt_no_return_calls. get_emit_trail_ops(CI, X) :- X = CI ^ code_info_static ^ cis_emit_trail_ops. get_opt_trail_ops(CI, X) :- X = CI ^ code_info_static ^ cis_opt_trail_ops. get_emit_region_ops(CI, X) :- X = CI ^ code_info_static ^ cis_emit_region_ops. get_opt_region_ops(CI, X) :- X = CI ^ code_info_static ^ cis_opt_region_ops. get_auto_comments(CI, X) :- X = CI ^ code_info_static ^ cis_auto_comments. get_lcmc_null(CI, X) :- X = CI ^ code_info_static ^ cis_lcmc_null. get_profile_memory(CI, X) :- X = CI ^ code_info_static ^ cis_profile_memory. get_may_use_atomic_alloc(CI, X) :- X = CI ^ code_info_static ^ cis_may_use_atomic_alloc. get_num_ptag_bits(CI, X) :- X = CI ^ code_info_static ^ cis_num_ptag_bits. get_gc_method(CI, X) :- X = CI ^ code_info_static ^ cis_gc_method. get_maybe_containing_goal_map(CI, X) :- X = CI ^ code_info_static ^ cis_containing_goal_map. get_const_struct_map(CI, X) :- X = CI ^ code_info_static ^ cis_const_struct_map. get_progress_stream(CI, X) :- X = CI ^ code_info_static ^ cis_progress_stream. get_label_counter(CI, X) :- X = CI ^ code_info_persistent ^ cip_label_num_src. get_succip_used(CI, X) :- X = CI ^ code_info_persistent ^ cip_store_succip. get_layout_info(CI, X) :- X = CI ^ code_info_persistent ^ cip_label_layout_info. get_proc_trace_events(CI, X) :- X = CI ^ code_info_persistent ^ cip_proc_trace_events. get_max_regs_in_use_at_trace(CI, MaxRegR, MaxRegF) :- MaxRegR = CI ^ code_info_persistent ^ cip_max_reg_r_used, MaxRegF = CI ^ code_info_persistent ^ cip_max_reg_f_used. get_created_temp_frame(CI, X) :- X = CI ^ code_info_persistent ^ cip_created_temp_frame. get_max_temp_slot_count(CI, X) :- X = CI ^ code_info_persistent ^ cip_stackslot_max. get_temp_content_map(CI, X) :- X = CI ^ code_info_persistent ^ cip_temp_content_map. get_persistent_temps(CI, X) :- X = CI ^ code_info_persistent ^ cip_persistent_temps. get_closure_seq_counter(CI, X) :- X = CI ^ code_info_persistent ^ cip_closure_layout_seq. get_closure_layouts(CI, X) :- X = CI ^ code_info_persistent ^ cip_closure_layouts. get_static_cell_info(CI, X) :- X = CI ^ code_info_persistent ^ cip_static_cell_info. get_alloc_sites(CI, X) :- X = CI ^ code_info_persistent ^ cip_alloc_sites. get_used_env_vars(CI, X) :- X = CI ^ code_info_persistent ^ cip_used_env_vars. get_out_of_line_code(CI, X) :- X = CI ^ code_info_persistent ^ cip_out_of_line_code. set_maybe_trace_info(X, !CI) :- !CI ^ code_info_static ^ cis_maybe_trace_info := X. set_label_counter(X, !CI) :- !CI ^ code_info_persistent ^ cip_label_num_src := X. set_succip_used(X, !CI) :- !CI ^ code_info_persistent ^ cip_store_succip := X. set_layout_info(X, !CI) :- !CI ^ code_info_persistent ^ cip_label_layout_info := X. set_proc_trace_events(X, !CI) :- !CI ^ code_info_persistent ^ cip_proc_trace_events := X. set_max_regs_in_use_at_trace(MR, MF, !CI) :- !CI ^ code_info_persistent ^ cip_max_reg_r_used := MR, !CI ^ code_info_persistent ^ cip_max_reg_f_used := MF. set_max_temp_slot_count(X, !CI) :- !CI ^ code_info_persistent ^ cip_stackslot_max := X. set_temp_content_map(X, !CI) :- !CI ^ code_info_persistent ^ cip_temp_content_map := X. set_persistent_temps(X, !CI) :- !CI ^ code_info_persistent ^ cip_persistent_temps := X. set_closure_seq_counter(X, !CI) :- !CI ^ code_info_persistent ^ cip_closure_layout_seq := X. set_closure_layouts(X, !CI) :- !CI ^ code_info_persistent ^ cip_closure_layouts := X. set_created_temp_frame(X, !CI) :- !CI ^ code_info_persistent ^ cip_created_temp_frame := X. set_static_cell_info(X, !CI) :- !CI ^ code_info_persistent ^ cip_static_cell_info := X. set_alloc_sites(X, !CI) :- !CI ^ code_info_persistent ^ cip_alloc_sites := X. set_used_env_vars(X, !CI) :- !CI ^ code_info_persistent ^ cip_used_env_vars := X. :- pred max_var_slot(stack_slots::in, int::out) is det. max_var_slot(StackSlots, SlotCount) :- map.values(StackSlots, StackSlotList), max_var_slot_loop(StackSlotList, 0, SlotCount). :- pred max_var_slot_loop(list(stack_slot)::in, int::in, int::out) is det. max_var_slot_loop([], !Max). max_var_slot_loop([Slot | Slots], !Max) :- ( Slot = det_slot(N, Width) ; Slot = parent_det_slot(N, Width) ; Slot = nondet_slot(N), Width = single_width ), ( Width = single_width, int.max(N, !Max) ; Width = double_width, int.max(N + 1, !Max) ), max_var_slot_loop(Slots, !Max). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% % Submodule for simple wrappers around access predicates. :- interface. % Get the hlds mapping from variables to stack slots. % :- pred get_stack_slots(code_info::in, stack_slots::out) is det. % Find out whether the body of the current procedure should use % typeinfo liveness. % :- func body_typeinfo_liveness(code_info) = bool. % Find out the type of the given variable. % :- func variable_type(code_info, prog_var) = mer_type. % Compute the principal type constructor of the given type, and return % the definition of this type constructor, if it has one (some type % constructors are built in, and some are hidden behind abstraction % barriers). % :- pred search_type_defn(code_info::in, mer_type::in, hlds_type_defn::out) is semidet. % Compute the principal type constructor of the given type, and return % the definition of this type constructor. Abort if it doesn't have a % definition (e.g. because it is a builtin). % :- func lookup_type_defn(code_info, mer_type) = hlds_type_defn. :- func lookup_cheaper_tag_test(code_info, mer_type) = maybe_cheaper_tag_test. :- func filter_region_vars(code_info, set_of_progvar) = set_of_progvar. % Get the code model of the current procedure. % :- func get_proc_model(code_info) = code_model. % Get the list of the head variables of the current procedure. % :- func get_headvars(code_info) = list(prog_var). % Get the call argument information for the current procedure % :- func get_arginfo(code_info) = list(arg_info). % Get the call argument info for a given mode of a given predicate % :- func get_pred_proc_arginfo(code_info, pred_id, proc_id) = list(arg_info). :- type for_call_or_closure ---> for_immediate_call ; for_closure. % Create a code address which holds the address of the specified procedure. % The fourth argument should be `for_immediate_call' if the caller % will use the returned address only to construct calls from the % current procedure, and `for_closure' if the returned address is % to be put into a closure. (These are the only circumstances in which % this predicate is called.) % :- func make_proc_entry_label(code_info, module_info, pred_id, proc_id, for_call_or_closure) = code_addr. % Generate the next local label in sequence. % :- pred get_next_label(label::out, code_info::in, code_info::out) is det. % Note that the succip slot is used, and thus cannot be optimized away. % :- pred succip_is_used(code_info::in, code_info::out) is det. :- pred add_trace_layout_for_label(label::in, term.context::in, trace_port::in, bool::in, forward_goal_path::in, maybe(user_event_info)::in, layout_label_info::in, code_info::in, code_info::out) is det. :- pred get_next_closure_seq_no(int::out, code_info::in, code_info::out) is det. :- pred add_resume_layout_for_label(label::in, layout_label_info::in, code_info::in, code_info::out) is det. :- pred add_closure_layout(closure_proc_id_data::in, code_info::in, code_info::out) is det. :- pred add_threadscope_string(string::in, int::out, code_info::in, code_info::out) is det. :- pred get_threadscope_rev_string_table(code_info::in, list(string)::out, int::out) is det. :- pred add_scalar_static_cell(list(typed_rval)::in, data_id::out, code_info::in, code_info::out) is det. :- pred add_scalar_static_cell_natural_types(list(rval)::in, data_id::out, code_info::in, code_info::out) is det. :- pred add_vector_static_cell(list(llds_type)::in, list(list(rval))::in, data_id::out, code_info::in, code_info::out) is det. :- pred maybe_add_alloc_site_info(prog_context::in, string::in, int::in, maybe(alloc_site_id)::out, code_info::in, code_info::out) is det. :- pred add_alloc_site_info(prog_context::in, string::in, int::in, alloc_site_id::out, code_info::in, code_info::out) is det. % Should we add trail ops to the code we generate for the goal with the % given goal_info. This will be 'no' unless we are in a trailing grade. % :- func should_add_trail_ops(code_info, hlds_goal_info) = add_trail_ops. % Should we add region ops to the code we generate for the goal with the % given goal_info. This will be 'no' unless we are in a rbmm grade. % :- func should_add_region_ops(code_info, hlds_goal_info) = add_region_ops. :- pred get_containing_goal_map(code_info::in, containing_goal_map::out) is det. :- pred add_out_of_line_code(llds_code::in, code_info::in, code_info::out) is det. % Should we trace the operation of the code generator? % :- pred should_trace_code_gen(code_info::in, maybe(io.text_output_stream)::out) is det. %---------------------------------------------------------------------------% :- implementation. get_stack_slots(CI, StackSlots) :- get_proc_info(CI, ProcInfo), proc_info_get_stack_slots(ProcInfo, StackSlots). body_typeinfo_liveness(CI) = TypeInfoLiveness :- get_module_info(CI, ModuleInfo), get_pred_id(CI, PredId), module_info_pred_info(ModuleInfo, PredId, PredInfo), get_globals(CI, Globals), body_should_use_typeinfo_liveness(PredInfo, Globals, TypeInfoLiveness). variable_type(CI, Var) = Type :- get_var_table(CI, VarTable), lookup_var_entry(VarTable, Var, Entry), Type = Entry ^ vte_type. search_type_defn(CI, Type, TypeDefn) :- get_module_info(CI, ModuleInfo), type_to_ctor_det(Type, TypeCtor), module_info_get_type_table(ModuleInfo, TypeTable), search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn). lookup_type_defn(CI, Type) = TypeDefn :- ( if search_type_defn(CI, Type, TypeDefnPrime) then TypeDefn = TypeDefnPrime else unexpected($pred, "type ctor has no definition") ). lookup_cheaper_tag_test(CI, Type) = CheaperTagTest :- ( if search_type_defn(CI, Type, TypeDefn), get_type_defn_body(TypeDefn, TypeBody), TypeBody = hlds_du_type(type_body_du(_, _, _, _, MaybeRepn, _)), MaybeRepn = yes(Repn) then CheaperTagTest = Repn ^ dur_cheaper_tag_test else CheaperTagTest = no_cheaper_tag_test ). filter_region_vars(CI, ForwardLiveVarsBeforeGoal) = RegionVars :- get_var_table(CI, VarTable), RegionVars = set_of_var.filter(is_region_var(VarTable), ForwardLiveVarsBeforeGoal). %---------------------------------------------------------------------------% get_proc_model(CI) = CodeModel :- get_proc_info(CI, ProcInfo), CodeModel = proc_info_interface_code_model(ProcInfo). get_headvars(CI) = HeadVars :- get_module_info(CI, ModuleInfo), get_pred_id(CI, PredId), get_proc_id(CI, ProcId), module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo), proc_info_get_headvars(ProcInfo, HeadVars). get_arginfo(CI) = ArgInfo :- get_pred_id(CI, PredId), get_proc_id(CI, ProcId), ArgInfo = get_pred_proc_arginfo(CI, PredId, ProcId). get_pred_proc_arginfo(CI, PredId, ProcId) = ArgInfo :- get_module_info(CI, ModuleInfo), module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo), proc_info_arg_info(ProcInfo, ArgInfo). %---------------------------------------------------------------------------% make_proc_entry_label(CI, ModuleInfo, PredId, ProcId, CallOrClosure) = CodeAddr :- ( CallOrClosure = for_closure, ForFromWhere = for_from_everywhere ; CallOrClosure = for_immediate_call, get_globals(CI, Globals), globals.get_opt_tuple(Globals, OptTuple), UseJustOneCFunc = OptTuple ^ ot_use_just_one_c_func, get_pred_id(CI, CurPredId), get_proc_id(CI, CurProcId), ForFromWhere = for_from_proc(UseJustOneCFunc, CurPredId, CurProcId) ), CodeAddr = make_entry_label(ModuleInfo, PredId, ProcId, ForFromWhere). get_next_label(Label, !CI) :- get_proc_label(!.CI, ProcLabel), get_label_counter(!.CI, C0), counter.allocate(N, C0, C), set_label_counter(C, !CI), Label = internal_label(N, ProcLabel). succip_is_used(!CI) :- set_succip_used(yes, !CI). add_trace_layout_for_label(Label, Context, Port, IsHidden, GoalPath, MaybeSolverEventInfo, Layout, !CI) :- get_layout_info(!.CI, Internals0), Exec = yes(trace_port_layout_info(Context, Port, IsHidden, GoalPath, MaybeSolverEventInfo, Layout)), ( Label = internal_label(LabelNum, _) ; Label = entry_label(_, _), unexpected($pred, "entry") ), ( if map.search(Internals0, LabelNum, Internal0) then Internal0 = internal_layout_info(Exec0, Resume, Return), ( Exec0 = no ; Exec0 = yes(_), unexpected($pred, "already known label") ), Internal = internal_layout_info(Exec, Resume, Return), map.det_update(LabelNum, Internal, Internals0, Internals) else Internal = internal_layout_info(Exec, no, no), map.det_insert(LabelNum, Internal, Internals0, Internals) ), set_layout_info(Internals, !CI). get_next_closure_seq_no(SeqNo, !CI) :- get_closure_seq_counter(!.CI, C0), counter.allocate(SeqNo, C0, C), set_closure_seq_counter(C, !CI). add_resume_layout_for_label(Label, LayoutInfo, !CI) :- get_layout_info(!.CI, Internals0), Resume = yes(LayoutInfo), ( Label = internal_label(LabelNum, _) ; Label = entry_label(_, _), unexpected($pred, "entry") ), ( if map.search(Internals0, LabelNum, Internal0) then Internal0 = internal_layout_info(Exec, Resume0, Return), ( Resume0 = no ; Resume0 = yes(_), unexpected($pred, "already known label") ), Internal = internal_layout_info(Exec, Resume, Return), map.det_update(LabelNum, Internal, Internals0, Internals) else Internal = internal_layout_info(no, Resume, no), map.det_insert(LabelNum, Internal, Internals0, Internals) ), set_layout_info(Internals, !CI). add_closure_layout(ClosureLayout, !CI) :- get_closure_layouts(!.CI, ClosureLayouts), set_closure_layouts([ClosureLayout | ClosureLayouts], !CI). add_threadscope_string(String, SlotNum, !CI) :- Persistent0 = !.CI ^ code_info_persistent, Size0 = Persistent0 ^ cip_ts_string_table_size, RevTable0 = Persistent0 ^ cip_ts_rev_string_table, SlotNum = Size0, Size = Size0 + 1, RevTable = [String | RevTable0], Persistent1 = Persistent0 ^ cip_ts_string_table_size := Size, Persistent = Persistent1 ^ cip_ts_rev_string_table := RevTable, !CI ^ code_info_persistent := Persistent. get_threadscope_rev_string_table(CI, RevTable, TableSize) :- RevTable = CI ^ code_info_persistent ^ cip_ts_rev_string_table, TableSize = CI ^ code_info_persistent ^ cip_ts_string_table_size. add_scalar_static_cell(RvalsTypes, DataAddr, !CI) :- get_static_cell_info(!.CI, StaticCellInfo0), global_data.add_scalar_static_cell(RvalsTypes, DataAddr, StaticCellInfo0, StaticCellInfo), set_static_cell_info(StaticCellInfo, !CI). add_scalar_static_cell_natural_types(Rvals, DataAddr, !CI) :- get_static_cell_info(!.CI, StaticCellInfo0), global_data.add_scalar_static_cell_natural_types(Rvals, DataAddr, StaticCellInfo0, StaticCellInfo), set_static_cell_info(StaticCellInfo, !CI). add_vector_static_cell(Types, Vector, DataAddr, !CI) :- get_static_cell_info(!.CI, StaticCellInfo0), global_data.add_vector_static_cell(Types, Vector, DataAddr, StaticCellInfo0, StaticCellInfo), set_static_cell_info(StaticCellInfo, !CI). maybe_add_alloc_site_info(Context, VarTypeMsg, Size, MaybeAllocId, !CI) :- get_profile_memory(!.CI, ProfileMemory), ( ProfileMemory = yes, add_alloc_site_info(Context, VarTypeMsg, Size, AllocId, !CI), MaybeAllocId = yes(AllocId) ; ProfileMemory = no, MaybeAllocId = no ). add_alloc_site_info(Context, VarTypeMsg, Size, AllocId, !CI) :- get_proc_label(!.CI, ProcLabel), AllocSite = alloc_site_info(ProcLabel, Context, VarTypeMsg, Size), AllocId = alloc_site_id(AllocSite), get_alloc_sites(!.CI, AllocSites0), set_tree234.insert(AllocSite, AllocSites0, AllocSites), set_alloc_sites(AllocSites, !CI). %---------------------------------------------------------------------------% should_add_trail_ops(CodeInfo, _GoalInfo) = AddTrailOps :- % XXX We will eventually need to make use of GoalInfo here. get_emit_trail_ops(CodeInfo, AddTrailOps). should_add_region_ops(CodeInfo, _GoalInfo) = AddRegionOps :- % XXX We will eventually need to make use of GoalInfo here. get_emit_region_ops(CodeInfo, AddRegionOps). %---------------------------------------------------------------------------% get_containing_goal_map(CI, ContainingGoalMap) :- get_maybe_containing_goal_map(CI, MaybeContainingGoalMap), ( MaybeContainingGoalMap = yes(ContainingGoalMap) ; MaybeContainingGoalMap = no, unexpected($pred, "no map") ). add_out_of_line_code(NewCode, !CI) :- Code0 = !.CI ^ code_info_persistent ^ cip_out_of_line_code, Code = Code0 ++ NewCode, !CI ^ code_info_persistent ^ cip_out_of_line_code := Code. %---------------------------------------------------------------------------% should_trace_code_gen(CI, ShouldDebug) :- get_pred_id(CI, PredId), pred_id_to_int(PredId, PredIdInt), get_module_info(CI, ModuleInfo), module_info_get_globals(ModuleInfo, Globals), globals.lookup_int_option(Globals, debug_code_gen_pred_id, DebugPredIdInt), ( if PredIdInt = DebugPredIdInt then get_progress_stream(CI, ProgressStream), ShouldDebug = yes(ProgressStream) else ShouldDebug = no ). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% % Submodule for managing stack slots. :- interface. % Return the lval of the stack slot in which the given variable is stored. % Aborts if the variable does not have a stack slot an assigned to it. % :- pred get_variable_slot(code_info::in, prog_var::in, lval::out) is det. % Returns the total stackslot count, but not including space for % succip, and without padding for alignment. This total can change in the % future if this call is followed by further allocations of temp slots. % :- pred get_total_stackslot_count(code_info::in, int::out) is det. % If necessary, round up a det stack frame allocation so that the stack % pointer remains on an even word boundary. % :- func round_det_stack_frame_size(code_info, int) = int. %---------------------------------------------------------------------------% :- implementation. get_variable_slot(CI, Var, Slot) :- get_stack_slots(CI, StackSlots), ( if map.search(StackSlots, Var, SlotLocn) then Slot = stack_slot_to_lval(SlotLocn) else get_var_table(CI, VarTable), lookup_var_entry(VarTable, Var, Entry), Name = var_entry_name(Var, Entry), term.var_to_int(Var, VarNum), string.format("variable `%s' (%d) not found", [s(Name), i(VarNum)], Msg), unexpected($pred, Msg) ). get_total_stackslot_count(CI, NumSlots) :- get_var_slot_count(CI, SlotsForVars), get_max_temp_slot_count(CI, SlotsForTemps), NumSlots = SlotsForVars + SlotsForTemps. round_det_stack_frame_size(CI, NumSlots) = NumSlotsRoundup :- ( if odd(NumSlots), get_exprn_opts(CI, ExprnOpts), get_det_stack_float_width(ExprnOpts) = double_width then NumSlotsRoundup = NumSlots + 1 else NumSlotsRoundup = NumSlots ). %---------------------------------------------------------------------------% :- end_module ll_backend.code_info. %---------------------------------------------------------------------------%