📄 beam_makeops
字号:
print "# define BEAM_LOOSE_MASK 0xFFF\n"; print "# define BEAM_TIGHT_MASK 0xFFC\n"; print "# define BEAM_LOOSE_SHIFT 16\n"; print "# define BEAM_TIGHT_SHIFT 10\n"; print "#endif\n"; print "\n"; # # Definitions of tags. # my $letter; my $tag_num = 0; &comment('C', "The following operand types for generic instructions", "occur in beam files."); foreach $letter (split('', $compiler_types)) { print "#define TAG_$letter $tag_num\n"; $tag_num++; } print "\n"; &comment('C', "The following operand types are only used in the loader."); foreach $letter (split('', $loader_types)) { print "#define TAG_$letter $tag_num\n"; $tag_num++; } print "\n"; $i = 0; foreach (sort keys %match_engine_ops) { print "#define $_ $i\n"; $i++; } print "#define NUM_TOPS $i\n"; print "\n"; print "#define TE_MAX_VARS $te_max_vars\n"; print "\n"; print "extern char tag_to_letter[];\n"; print "extern Uint op_transform[];\n"; print "\n"; for ($i = 0; $i < @op_to_name; $i++) { print "#define op_$op_to_name[$i] $i\n"; } print "\n"; print "#define NUMBER_OF_OPCODES ",scalar(@op_to_name),"\n"; for ($i = 0; $i < @op_to_name; $i++) { print "#define op_count_$op_to_name[$i] ",$i+scalar(@op_to_name),"\n"; } print "\n"; print "#define DEFINE_OPCODES"; foreach (@op_to_name) { print " \\\n&&lb_$_,"; } print "\n\n"; print "#define DEFINE_COUNTING_OPCODES"; foreach (@op_to_name) { print " \\\n&&lb_count_$_,"; } print "\n\n"; print "#define DEFINE_COUNTING_LABELS"; for ($i = 0; $i < @op_to_name; $i++) { my($name) = $op_to_name[$i]; print " \\\nCountCase($name): opc[$i].count++; goto lb_$name;"; } print "\n\n"; for ($i = 0; $i < @gen_opname; $i++) { print "#define genop_$gen_opname[$i]_$gen_arity[$i] $i\n" if defined $gen_opname[$i]; } print "#endif\n"; # # Extension of transform engine. # $name = "$outdir/beam_tr_funcs.h"; open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n"; &comment('C'); &tr_gen_call(@call_table); $name = "$outdir/beam_pred_funcs.h"; open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n"; &comment('C'); &tr_gen_call(@pred_table); # # Implementation of operations for emulator. # $name = "$outdir/beam_hot.h"; open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n"; &comment('C'); &print_code(\%hot_code); $name = "$outdir/beam_cold.h"; open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n"; &comment('C'); &print_code(\%cold_code);}sub init_item { my($sep) = ""; print "{"; foreach (@_) { if (!defined $_) { print "${sep}NULL"; } elsif (/^\{/) { print "$sep$_"; } elsif (/^-?\d/) { print "$sep$_"; } else { print "$sep\"$_\""; } $sep = ", "; } print "},\n";}sub q { my($str) = @_; "\"$str\"";}sub print_code { my($ref) = @_; my(%sorted); my($key, $label); # Loop variables. foreach $key (keys %$ref) { my($sort_key); my($code) = ''; foreach $label (@{$ref->{$key}}) { $code .= "OpCase($label):\n"; $sort_key = $label; } foreach (split("\n", $key)) { $code .= " $_\n"; } $code .= "\n"; $sorted{$sort_key} = $code; } foreach (sort keys %sorted) { print $sorted{$_}; }}## Produce output needed by the compiler back-end (assembler).#sub compiler_output { my($module) = 'beam_opcodes'; my($name) = "${module}.erl"; my($i); open(STDOUT, ">$outdir/$name") || die "Failed to open $name for writing: $!\n"; print "-module($module).\n"; &comment('erlang'); print "-export([format_number/0]).\n"; print "-export([opcode/2,opname/1]).\n"; print "\n"; print "format_number() -> $BEAM_FORMAT_NUMBER.\n\n"; for ($i = 0; $i < @gen_opname; $i++) { next unless defined $gen_opname[$i]; print "opcode(", "e($gen_opname[$i]), ", $gen_arity[$i]) -> $i;\n"; } print "opcode(Name, Arity) -> erlang:fault(badarg, [Name,Arity]).\n\n"; for ($i = 0; $i < @gen_opname; $i++) { next unless defined $gen_opname[$i]; print "opname($i) -> {", "e($gen_opname[$i]), ",$gen_arity[$i]};\n"; } print "opname(Number) -> erlang:fault(badarg, [Number]).\n"; # # Generate .hrl file. # my($name) = "$outdir/${module}.hrl"; open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n"; &comment('erlang'); for ($i = 0; $i < @tag_type && $i < 8; $i++) { print "-define(tag_$tag_type[$i], $i).\n"; } print "\n";}## Check an operation for validity.#sub syntax_check { my($name, @args) = @_; my($i); &error("Bad opcode name '$name'") unless $name =~ /^[a-z][\w\d_]*$/; for ($i = 0; $i < @args; $i++) { &error("Argument " . ($i+1) . ": invalid type '$args[$i]'") unless defined $arg_size{$args[$i]}; }}sub error { my(@message) = @_; my($where) = $. ? "$ARGV($.): " : ""; die $where, @message, "\n";}sub comment { my($lang, @comments) = @_; my($prefix); if ($lang eq 'C') { print "/*\n"; $prefix = " * "; } elsif ($lang eq 'erlang') { $prefix = '%% '; } else { $prefix = '# '; } my(@prog) = split('/', $0); my($prog) = $prog[$#prog]; if (@comments) { my $line; foreach $line (@comments) { print "$prefix$line\n"; } } else { print "$prefix Warning: Do not edit this file. It was automatically\n"; print "$prefix generated by '$prog' on ", (scalar localtime), ".\n"; } if ($lang eq 'C') { print " */\n"; } print "\n";}## Basic implementation of instruction in emulator loop# (assuming no packing).#sub basic_generator { my($name, $hot, @args) = @_; my($size) = 0; my($macro) = ''; my($flags) = ''; my(@f); my(@f_types); my($fail_type); my($prefix) = ''; my($tmp_arg_num) = 1; my($pack_spec) = ''; my($var_decls) = ''; my($gen_dest_arg) = 'StoreSimpleDest'; my($i); # The following argument types should be included as macro arguments. my(%incl_arg) = ('c' => 1, 'i' => 1, 'a' => 1, 'A' => 1, 'N' => 1, 'U' => 1, 'I' => 1, 't' => 1, 'P' => 1, ); # Pick up the macro to use and its flags (if any). $macro = $macro{$name} if defined $macro{$name}; $flags = $macro_flags{$name} if defined $macro_flags{$name}; # # Add any arguments to be included as macro arguments (for instance, # 'p' is usually not an argument, except for calls). # while ($flags =~ /-arg_(\w)/g) { $incl_arg{$1} = 1; }; # # Pack arguments if requested. # if ($flags =~ /-pack/ && $hot) { ($prefix, $pack_spec, @args) = &do_pack(@args); } # # Calculate the size of the instruction and generate each argument for # the macro. # foreach (@args) { my($this_size) = $arg_size{$_}; SWITCH: { /^pack:(\d):(.*)/ and do { push(@f, $2); push(@f_types, 'packed'); $this_size = $1; last SWITCH; }; /r/ and do { push(@f, "r(0)"); push(@f_types, $_); last SWITCH }; /[xy]/ and do { push(@f, "$_" . "b(Arg($size))"); push(@f_types, $_); last SWITCH; }; /n/ and do { push(@f, "NIL"); push(@f_types, $_); last SWITCH }; /s/ and do { my($tmp) = "targ$tmp_arg_num"; $var_decls .= "Eterm $tmp; "; $tmp_arg_num++; push(@f, $tmp); push(@f_types, $_); $prefix .= "GetR($size, $tmp);\n"; last SWITCH; }; /d/ and do { $var_decls .= "Eterm dst; "; push(@f, "dst"); push(@f_types, $_); $prefix .= "dst = Arg($size);\n"; $gen_dest_arg = 'StoreResult'; last SWITCH; }; defined($incl_arg{$_}) and do { push(@f, "Arg($size)"); push(@f_types, $_); last SWITCH; }; /[fp]/ and do { $fail_type = $_; last SWITCH }; /[eLIFEbASjPowl]/ and do { last SWITCH; }; die "$name: The generator can't handle $_, at"; } $size += $this_size; } # # If requested, pass a pointer to the destination register. # The destination must be the last operand. # if ($flags =~ /-gen_dest/) { push(@f, $gen_dest_arg); } # # Add a fail action macro if requested. # $flags =~ /-fail_action/ and do { if (!defined $fail_type) { my($i); for ($i = 0; $i < @f_types; $i++) { local($_) = $f_types[$i]; /[rxycians]/ and do { push(@f, "Badmatch($f[$i])"); next }; } } elsif ($fail_type eq 'f') { push(@f, "ClauseFail()"); } else { my($i); for ($i = 0; $i < @f_types; $i++) { local($_) = $f_types[$i]; /[rxycians]/ and do { push(@f, "Badmatch($f[$i])"); next }; } } }; # # Add a size argument if requested. # $flags =~ /-size/ and do { push(@f, $size); }; # Generate the macro if requested. my($code); if (defined $macro{$name}) { my($macro_code) = "$prefix$macro(" . join(', ', @f) . ");"; $var_decls .= "Uint tmp_packed1;" if $macro_code =~ /tmp_packed1/; $var_decls .= "Uint tmp_packed2;" if $macro_code =~ /tmp_packed2/; if ($flags =~ /-nonext/) { $code = "$macro_code\n"; } else { $code = join("\n", "{ $var_decls", "Eterm* next;", "PreFetch($size, next);", "$macro_code", "NextPF($size, next);", "}", ""); } } # Return the size and code for the macro (if any). $size++; ($size, $code, $pack_spec);}sub do_pack { my(@args) = @_; my($i); my($packable_args) = 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]/) { $packable_args++; } elsif ($args[$i] =~ /[sd]/) { return ('', '', @args); } } # # Get out of here if too few or too many arguments. # return ('', '', @args) if $packable_args < 2; &error("too many packable arguments") if $packable_args > 4; my($size) = 0; my($pack_prefix) = ''; my($down) = ''; # Pack commands (towards instruction # 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]}; # # Now generate the packing instructions. One complication is that # the packing engine works from right-to-left, but we must generate # the instructions from left-to-right because we must calculate # instruction sizes from left-to-right. # # XXX Packing 3 't's in one word won't work. Sorry. my $did_some_packing = 0; # Nothing packed yet. my($ap) = 0; # Argument number within word. my($tmpnum) = 1; # Number of temporary variable. my($expr) = ''; for ($i = 0; $i < @args; $i++) { my($reg) = $args[$i]; my($this_size) = $arg_size{$reg}; if ($reg =~ /[xyt]/) { $this_size = 0; $did_some_packing = 1; if ($ap == 0) { $pack_prefix .= "tmp_packed$tmpnum = Arg($size);\n"; $up .= "p"; $down = "P$down"; $this_size = 1; } $down = "$pack_instr[$ap]$down"; my($unpack) = &make_unpack($tmpnum, $shift[$ap], $mask[$ap]); $args[$i] = "pack:$this_size:$reg" . "b($unpack)"; if (++$ap == $args_per_word) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -