aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/utils
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/utils')
-rwxr-xr-xerts/emulator/utils/beam_makeops118
-rwxr-xr-xerts/emulator/utils/count127
2 files changed, 225 insertions, 20 deletions
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index de19a2e35b..e7c57142c0 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -27,6 +27,7 @@ my $outdir = "."; # Directory for output files.
my $verbose = 0;
my $hot = 1;
my $num_file_opcodes = 0;
+my $wordsize = 32;
# This is shift counts and mask for the packer.
my $WHOLE_WORD = '';
@@ -36,12 +37,20 @@ my @pack_mask;
$pack_instr[2] = ['6', 'i'];
$pack_instr[3] = ['0', '0', 'i'];
+$pack_instr[4] = ['6', '6', '6', 'i']; # Only for 64 bit wordsize
$pack_shift[2] = ['0', 'BEAM_LOOSE_SHIFT'];
$pack_shift[3] = ['0', 'BEAM_TIGHT_SHIFT', '(2*BEAM_TIGHT_SHIFT)'];
+$pack_shift[4] = ['0', 'BEAM_LOOSE_SHIFT', # Only for 64 bit wordsize
+ '(2*BEAM_LOOSE_SHIFT)',
+ '(3*BEAM_LOOSE_SHIFT)'];
$pack_mask[2] = ['BEAM_LOOSE_MASK', $WHOLE_WORD];
$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK'];
+$pack_mask[4] = ['BEAM_LOOSE_MASK', # Only for 64 bit wordsize
+ 'BEAM_LOOSE_MASK',
+ 'BEAM_LOOSE_MASK',
+ $WHOLE_WORD];
# There are two types of instructions: generic and specific.
# The generic instructions are those generated by the Beam compiler.
@@ -80,6 +89,8 @@ my %cold_code;
my @unnumbered_generic;
my %unnumbered;
+my %is_transformed;
+
#
# Code transformations.
#
@@ -118,7 +129,8 @@ my %arg_size = ('r' => 0, # x(0) - x register zero
't' => 1, # untagged integer -- can be packed
'b' => 1, # pointer to bif
'A' => 1, # arity value
- 'P' => 1, # byte offset into tuple
+ 'P' => 1, # byte offset into tuple or stack
+ 'Q' => 1, # like 'P', but packable
'h' => 1, # character
'l' => 1, # float reg
'q' => 1, # literal term
@@ -157,6 +169,7 @@ my @tag_type;
$type_bit{'U'} = $type_bit{'u'};
$type_bit{'e'} = $type_bit{'u'};
$type_bit{'P'} = $type_bit{'u'};
+ $type_bit{'Q'} = $type_bit{'u'};
}
#
@@ -169,6 +182,7 @@ while (@ARGV && $ARGV[0] =~ /^-(.*)/) {
($target = \&emulator_output), next if /^emulator/;
($target = \&compiler_output), next if /^compiler/;
($outdir = shift), next if /^outdir/;
+ ($wordsize = shift), next if /^wordsize/;
($verbose = 1), next if /^v/;
die "$0: Bad option: -$_\n";
}
@@ -474,8 +488,9 @@ sub emulator_output {
$gen_transform_offset{$key} : -1;
my($spec_op) = $gen_to_spec{$key};
my($num_specific) = $num_specific{$key};
- defined $spec_op or $tr != -1 or
+ defined $spec_op or
$obsolete[$gen_opnum{$name,$arity}] or
+ $is_transformed{$name,$arity} or
error("instruction $key has no specific instruction");
$spec_op = -1 unless defined $spec_op;
&init_item($name, $arity, $spec_op, $num_specific, $tr, $min_window{$key});
@@ -498,12 +513,14 @@ sub emulator_output {
print "#define NUM_SPECIFIC_OPS ", scalar(@op_to_name), "\n";
print "\n";
print "#ifdef ARCH_64\n";
+ print "# define BEAM_WIDE_MASK 0xFFFFUL\n";
print "# define BEAM_LOOSE_MASK 0x1FFFUL\n";
print "#if HALFWORD_HEAP\n";
print "# define BEAM_TIGHT_MASK 0x1FFCUL\n";
print "#else\n";
print "# define BEAM_TIGHT_MASK 0x1FF8UL\n";
print "#endif\n";
+ print "# define BEAM_WIDE_SHIFT 32\n";
print "# define BEAM_LOOSE_SHIFT 16\n";
print "# define BEAM_TIGHT_SHIFT 16\n";
print "#else\n";
@@ -796,6 +813,7 @@ sub basic_generator {
'I' => 1,
't' => 1,
'P' => 1,
+ 'Q' => 1,
);
# Pick up the macro to use and its flags (if any).
@@ -916,7 +934,18 @@ sub basic_generator {
$var_decls .= "BeamInstr tmp_packed2;"
if $macro_code =~ /tmp_packed2/;
if ($flags =~ /-nonext/) {
- $code = "$macro_code\n";
+ $code = join("\n",
+ "{ $var_decls",
+ $macro_code,
+ "}");
+ } elsif ($flags =~ /-goto:(\S*)/) {
+ my $goto = $1;
+ $code = join("\n",
+ "{ $var_decls",
+ $macro_code,
+ "I += $size + 1;",
+ "goto $goto;",
+ "}");
} else {
$code = join("\n",
"{ $var_decls",
@@ -935,18 +964,31 @@ sub basic_generator {
sub do_pack {
my(@args) = @_;
- my($i);
my($packable_args) = 0;
+ my @is_packable; # Packability (boolean) for each argument.
+ my $wide_packing = 0;
#
# Count the number of packable arguments. If we encounter any 's' or 'd'
# arguments, packing is not possible.
#
- for ($i = 0; $i < @args; $i++) {
- if ($args[$i] =~ /[xyt]/) {
+ my $packable_types = "xytQ";
+ foreach my $arg (@args) {
+ if ($arg =~ /^[$packable_types]/) {
$packable_args++;
- } elsif ($args[$i] =~ /[sd]/) {
+ push @is_packable, 1;
+ } elsif ($arg =~ /^I/ and $wordsize == 64 and $packable_args < 2) {
+ $wide_packing = 1;
+ push @is_packable, 1;
+ if (++$packable_args == 2) {
+ # We can only pack two arguments. Turn off packing
+ # for the rest of the arguments.
+ $packable_types = "\xFF";
+ }
+ } elsif ($arg =~ /^[sd]/) {
return ('', '', @args);
+ } else {
+ push @is_packable, 0;
}
}
@@ -962,10 +1004,27 @@ sub do_pack {
# beginning).
my($up) = ''; # Pack commands (storing back while
# moving forward).
- my($args_per_word) = $packable_args < 4 ? $packable_args : 2;
- my(@shift) = @{$pack_shift[$args_per_word]};
- my(@mask) = @{$pack_mask[$args_per_word]};
- my(@pack_instr) = @{$pack_instr[$args_per_word]};
+ my $args_per_word;
+ if ($packable_args < 4 or $wordsize == 64) {
+ $args_per_word = $packable_args;
+ } else {
+ # 4 packable argument, 32 bit wordsize. Need 2 words.
+ $args_per_word = 2;
+ }
+
+ my @shift;
+ my @mask;
+ my @instr;
+
+ if ($wide_packing) {
+ @shift = ('0', 'BEAM_WIDE_SHIFT');
+ @mask = ('BEAM_WIDE_MASK', $WHOLE_WORD);
+ @instr = ('w', 'i');
+ } else {
+ @shift = @{$pack_shift[$args_per_word]};
+ @mask = @{$pack_mask[$args_per_word]};
+ @instr = @{$pack_instr[$args_per_word]};
+ }
#
# Now generate the packing instructions. One complication is that
@@ -979,10 +1038,10 @@ sub do_pack {
my($ap) = 0; # Argument number within word.
my($tmpnum) = 1; # Number of temporary variable.
my($expr) = '';
- for ($i = 0; $i < @args; $i++) {
+ for (my $i = 0; $i < @args; $i++) {
my($reg) = $args[$i];
my($this_size) = $arg_size{$reg};
- if ($reg =~ /[xyt]/) {
+ if ($is_packable[$i]) {
$this_size = 0;
$did_some_packing = 1;
@@ -993,7 +1052,7 @@ sub do_pack {
$this_size = 1;
}
- $down = "$pack_instr[$ap]$down";
+ $down = "$instr[$ap]$down";
my($unpack) = &make_unpack($tmpnum, $shift[$ap], $mask[$ap]);
$args[$i] = "pack:$this_size:$reg" . "b($unpack)";
@@ -1103,6 +1162,10 @@ sub compile_transform {
if ($obsolete[$gen_opnum{$name,$arity}]) {
error("obsolete function must not be used in transformations");
}
+
+ if ($src) {
+ $is_transformed{$name,$arity} = 1;
+ }
[$name,$arity,@ops];
}
@@ -1291,13 +1354,28 @@ sub tr_gen_from {
my($var, $type, $type_val, $cond, $val) = @$op;
if ($type ne '' && $type ne '*') {
- my($types) = '';
- my($type_mask) = 0;
- foreach (split('', $type)) {
- $types .= "$_ ";
- $type_mask |= $type_bit{$_};
+ #
+ # The is_bif, is_not_bif, and is_func instructions have
+ # their own built-in type test and don't need to
+ # be guarded with a type test instruction.
+ #
+ unless ($cond eq 'is_bif' or
+ $cond eq 'is_not_bif' or
+ $cond eq 'is_func') {
+ my($types) = '';
+ my($type_mask) = 0;
+ foreach (split('', $type)) {
+ $types .= "$_ ";
+ $type_mask |= $type_bit{$_};
+ }
+ if ($cond ne 'is_eq') {
+ push(@code, &make_op($types, 'is_type', $type_mask));
+ } else {
+ $cond = '';
+ push(@code, &make_op($types, 'is_type_eq',
+ $type_mask, $val));
+ }
}
- push(@code, &make_op($types, 'is_type', $type_mask));
}
if ($cond eq 'is_func') {
diff --git a/erts/emulator/utils/count b/erts/emulator/utils/count
new file mode 100755
index 0000000000..617f5c25e8
--- /dev/null
+++ b/erts/emulator/utils/count
@@ -0,0 +1,127 @@
+%% -*- erlang -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-mode(compile).
+
+main(_) ->
+ DisDir = "./dis",
+ ok = filelib:ensure_dir(filename:join(DisDir, "dummy")),
+ io:format("Dissambling to ~s\n", [DisDir]),
+ ok = file:set_cwd(DisDir),
+ Path = code:get_path() -- ["."],
+ Beams0 = [filelib:wildcard(filename:join(Dir, "*.beam")) ||
+ Dir <- Path],
+ Beams = lists:append(Beams0),
+ Mods0 = [list_to_atom(filename:rootname(filename:basename(F))) ||
+ F <- Beams],
+ Mods = lists:usort(Mods0),
+ start_sem(),
+ Ps = [begin
+ {_,Ref} = spawn_monitor(fun() -> count(M) end),
+ Ref
+ end || M <- Mods],
+ [put(list_to_atom(I), 0) || I <- erts_debug:instructions()],
+ Res = wait_for_all(Ps, 1),
+ OutFile = "count",
+ {ok,Out} = file:open(OutFile, [write]),
+ [io:format(Out, "~s ~p\n", [I,C]) || {I,C} <- Res],
+ ok = file:close(Out),
+ io:format("\nResult written to ~s\n",
+ [filename:join(DisDir, OutFile)]),
+ ok.
+
+wait_for_all([], _) ->
+ lists:reverse(lists:keysort(2, get()));
+wait_for_all([_|_]=Ps, I) ->
+ receive
+ {'DOWN',Ref,process,_,Result} ->
+ io:format("\r~p", [I]),
+ [increment(Key, Count) || {Key,Count} <- Result],
+ wait_for_all(Ps -- [Ref], I+1)
+ end.
+
+count(M) ->
+ down(),
+ erts_debug:df(M),
+ {ok,Fd} = file:open(atom_to_list(M) ++ ".dis", [read,raw]),
+ count_is(Fd),
+ ok = file:close(Fd),
+ exit(get()).
+
+count_is(Fd) ->
+ case file:read_line(Fd) of
+ {ok,Line} ->
+ count_instr(Line),
+ count_is(Fd);
+ eof ->
+ ok
+ end.
+
+count_instr([$\s|T]) ->
+ count_instr_1(T, []);
+count_instr([_|T]) ->
+ count_instr(T);
+count_instr([]) ->
+ %% Empty line.
+ ok.
+
+count_instr_1([$\s|_], Acc) ->
+ Instr = list_to_atom(lists:reverse(Acc)),
+ increment(Instr, 1);
+count_instr_1([H|T], Acc) ->
+ count_instr_1(T, [H|Acc]).
+
+increment(Key, Inc) ->
+ case get(Key) of
+ undefined ->
+ put(Key, Inc);
+ Count ->
+ put(Key, Count+Inc)
+ end.
+
+%%%
+%%% Counting sempahore to limit the number of processes that
+%%% can run concurrently.
+%%%
+
+down() ->
+ sem ! {down,self()},
+ receive
+ sem_taken -> ok
+ end.
+
+start_sem() ->
+ spawn(fun() ->
+ register(sem, self()),
+ process_flag(trap_exit, true),
+ do_sem(erlang:system_info(schedulers)+1) end).
+
+do_sem(0) ->
+ receive
+ {'EXIT',_,_} ->
+ do_sem(1)
+ end;
+do_sem(C) ->
+ receive
+ {down,Pid} ->
+ link(Pid),
+ Pid ! sem_taken,
+ do_sem(C-1)
+ end.