Files
mercury/compiler/basic_block.m
Zoltan Somogyi 7c5fe1e988 Record the number of instructions in each basic block.
Estimated hours taken: 1
Branches: main

compiler/basic_block.m:
	Record the number of instructions in each basic block.

compiler/use_local_vars.m:
	Do not perform this quadratic optimization on basic blocks
	on which it would take too long.

compiler/dupelim.m:
	Don't try to detect duplicates in big blocks; the attempt is expensive,
	and also very likely to fail. (Big blocks are unlikely to duplicated;
	the optimization was meant for redundant copies of the procedure
	epilogue.)

compiler/livemap.m:
	Put a limit on the number of iterations done by the fixpoint algorithm.
2011-05-25 08:04:27 +00:00

257 lines
10 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1997-2001,2003-2007, 2010-2011 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: basic_block.m.
% Main author: zs.
%
% This module defines a representation for basic blocks, sequences of
% instructions with one entry and one exit, and provides predicates that
% convert a list of instructions into a list of basic blocks and vice versa.
%
%-----------------------------------------------------------------------------%
:- module ll_backend.basic_block.
:- interface.
:- import_module ll_backend.llds.
:- import_module mdbcomp.prim_data.
:- import_module bool.
:- import_module counter.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module set.
%-----------------------------------------------------------------------------%
:- type block_map == map(label, block_info).
:- type block_info
---> block_info(
% The label starting the block.
bi_starting_label :: label,
% The instruction containing the label.
bi_label_instr :: instruction,
% The code of the block without the initial label.
bi_later_instrs :: list(instruction),
% The number of instructions in bi_later_instrs.
bi_num_later_instrs :: int,
% Does the previous block (if any) fall through to this block?
bi_fallen_into :: bool,
% The labels we can jump to (not falling through).
bi_jump_dests :: list(label),
% The label we fall through to (if there is one).
bi_fall_dest :: maybe(label)
).
% create_basic_blocks(ProcInstrs, Comments, ProcLabel, !C, NewLabels,
% LabelSeq, BlockMap):
%
% Given ProcInstrs, the instruction sequence of the procedure given by
% ProcLabel and whose label counter is currently !.C, create_basic_blocks
% will divide up ProcInstrs into a sequence of basic blocks, each
% identified by a label. The info on each basic block is returned in
% BlockMap, and the sequence of basic blocks is returned in LabelSeq.
% In the process, create_basic_blocks creates new labels for basic blocks
% that can be reached only by falling through. The set of these new labels
% is returned in NewLabels. Any initial comments are returned in Comments.
%
:- pred create_basic_blocks(list(instruction)::in, list(instruction)::out,
proc_label::in, counter::in, counter::out,
set(label)::out, list(label)::out, block_map::out) is det.
% extend_basic_blocks(!LabelSeq, !BlockMap, NewLabels):
%
% Given !.LabelSeq, a sequence of labels each referring to a basic block in
% !.BlockMap, and the set of labels NewLabels that are not the targets of
% gotos (e.g. because they were freshly created by create_basic_blocks),
% delete from !.LabelSeq each label in NewLabels, merging its basic block
% with the immediately previous basic block. As a result, each block in
% !:BlockMap is an extended basic block.
%
:- pred extend_basic_blocks(list(label)::in, list(label)::out,
block_map::in, block_map::out, set(label)::in) is det.
% flatten_basic_blocks(LabelSeq, BlockMap, Instrs, NumInstrs):
%
% Given LabelSeq, a sequence of labels each referring to a block in
% BlockMap, return the concatenation of the basic blocks referred to by
% the labels in LabelSeq.
%
:- pred flatten_basic_blocks(list(label)::in, block_map::in,
list(instruction)::out, int::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module ll_backend.opt_util.
:- import_module int.
:- import_module require.
%-----------------------------------------------------------------------------%
create_basic_blocks(Instrs0, Comments, ProcLabel, !C, NewLabels, LabelSeq,
BlockMap) :-
opt_util.get_prologue(Instrs0, LabelInstr, Comments, AfterLabelInstrs),
Instrs1 = [LabelInstr | AfterLabelInstrs],
build_block_map(Instrs1, LabelSeq, ProcLabel, no, map.init, BlockMap,
set.init, NewLabels, !C).
%-----------------------------------------------------------------------------%
% Build up the block map. As we go along, we add labels to the given
% instruction sequence so that every basic block has labels around it.
%
:- pred build_block_map(list(instruction)::in, list(label)::out,
proc_label::in, bool::in, block_map::in, block_map::out,
set(label)::in, set(label)::out, counter::in, counter::out) is det.
build_block_map([], [], _, _, !BlockMap, !NewLabels, !C).
build_block_map([OrigInstr0 | OrigInstrs0], LabelSeq, ProcLabel, FallInto,
!BlockMap, !NewLabels, !C) :-
( OrigInstr0 = llds_instr(label(OrigLabel), _) ->
Label = OrigLabel,
LabelInstr = OrigInstr0,
RestInstrs = OrigInstrs0
;
counter.allocate(N, !C),
Label = internal_label(N, ProcLabel),
set.insert(Label, !NewLabels),
LabelInstr = llds_instr(label(Label), ""),
RestInstrs = [OrigInstr0 | OrigInstrs0]
),
(
take_until_end_of_block(RestInstrs, [], RevBlockInstrs, Instrs1),
build_block_map(Instrs1, LabelSeq1, ProcLabel, NextFallInto, !BlockMap,
!NewLabels, !C),
(
RevBlockInstrs = [LastInstr | _],
reverse_and_count_list(RevBlockInstrs, [], BlockInstrs,
0, NumBlockInstrs),
LastInstr = llds_instr(LastUinstr, _),
opt_util.possible_targets(LastUinstr, SideLabels, _SideCodeAddrs),
opt_util.can_instr_fall_through(LastUinstr) = NextFallInto
;
RevBlockInstrs = [],
BlockInstrs = [],
NumBlockInstrs = 0,
SideLabels = [],
NextFallInto = yes
),
(
NextFallInto = yes,
get_fallthrough_from_seq(LabelSeq1, MaybeFallThrough)
;
NextFallInto = no,
MaybeFallThrough = no
),
BlockInfo = block_info(Label, LabelInstr, BlockInstrs, NumBlockInstrs,
FallInto, SideLabels, MaybeFallThrough),
map.det_insert(Label, BlockInfo, !BlockMap),
LabelSeq = [Label | LabelSeq1]
).
:- pred take_until_end_of_block(list(instruction)::in,
list(instruction)::in, list(instruction)::out,
list(instruction)::out) is det.
take_until_end_of_block([], !RevBlockInstrs, []).
take_until_end_of_block([Instr0 | Instrs0], !RevBlockInstrs, Rest) :-
Instr0 = llds_instr(Uinstr0, _Comment),
( Uinstr0 = label(_) ->
Rest = [Instr0 | Instrs0]
; opt_util.can_instr_branch_away(Uinstr0) = yes ->
!:RevBlockInstrs = [Instr0 | !.RevBlockInstrs],
Rest = Instrs0
;
!:RevBlockInstrs = [Instr0 | !.RevBlockInstrs],
take_until_end_of_block(Instrs0, !RevBlockInstrs, Rest)
).
:- pred reverse_and_count_list(list(T)::in, list(T)::in, list(T)::out,
int::in, int::out) is det.
reverse_and_count_list([], !List, !N).
reverse_and_count_list([X | Xs], !List, !N) :-
!:List = [X | !.List],
!:N = !.N + 1,
reverse_and_count_list(Xs, !List, !N).
:- pred get_fallthrough_from_seq(list(label)::in, maybe(label)::out) is det.
get_fallthrough_from_seq(LabelSeq, MaybeFallThrough) :-
(
LabelSeq = [NextLabel | _],
MaybeFallThrough = yes(NextLabel)
;
LabelSeq = [],
MaybeFallThrough = no
).
%-----------------------------------------------------------------------------%
extend_basic_blocks([], [], !BlockMap, _NewLabels).
extend_basic_blocks([Label | Labels], LabelSeq, !BlockMap, NewLabels) :-
(
Labels = [NextLabel | RestLabels],
set.member(NextLabel, NewLabels)
->
map.lookup(!.BlockMap, Label, BlockInfo),
map.lookup(!.BlockMap, NextLabel, NextBlockInfo),
BlockInfo = block_info(BlockLabel, BlockLabelInstr, BlockInstrs,
NumBlockInstrs, BlockFallInto, BlockSideLabels,
BlockMaybeFallThrough),
NextBlockInfo = block_info(NextBlockLabel, _, NextBlockInstrs,
NumNextBlockInstrs, NextBlockFallInto, NextBlockSideLabels,
NextBlockMaybeFallThrough),
expect(unify(BlockLabel, Label), $module, $pred,
"block label mismatch"),
expect(unify(NextBlockLabel, NextLabel), $module, $pred,
"next block label mismatch"),
expect(unify(BlockMaybeFallThrough, yes(NextLabel)), $module, $pred,
"fall through mismatch"),
expect(unify(NextBlockFallInto, yes), $module, $pred,
"fall into mismatch"),
NewBlockInfo = block_info(BlockLabel, BlockLabelInstr,
BlockInstrs ++ NextBlockInstrs,
NumBlockInstrs + NumNextBlockInstrs, BlockFallInto,
BlockSideLabels ++ NextBlockSideLabels, NextBlockMaybeFallThrough),
map.det_update(Label, NewBlockInfo, !BlockMap),
map.delete(NextLabel, !BlockMap),
extend_basic_blocks([Label | RestLabels], LabelSeq, !BlockMap,
NewLabels)
;
extend_basic_blocks(Labels, LabelSeqTail, !BlockMap, NewLabels),
LabelSeq = [Label | LabelSeqTail]
).
%-----------------------------------------------------------------------------%
flatten_basic_blocks([], _, [], 0).
flatten_basic_blocks([Label | Labels], BlockMap, Instrs, NumInstrs) :-
flatten_basic_blocks(Labels, BlockMap, RestInstrs, RestNumInstrs),
map.lookup(BlockMap, Label, BlockInfo),
BlockInfo = block_info(_, BlockLabelInstr, BlockInstrs, NumBlockInstrs,
_, _, _),
Instrs = [BlockLabelInstr | BlockInstrs] ++ RestInstrs,
NumInstrs = NumBlockInstrs + RestNumInstrs.
%-----------------------------------------------------------------------------%
:- end_module ll_backend.basic_block.
%-----------------------------------------------------------------------------%