⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beam_makeops

📁 OTP是开放电信平台的简称
💻
📖 第 1 页 / 共 3 页
字号:
    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(", &quote($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) -> {",	&quote($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 + -