@@ -992,7 +992,8 @@ sub gen_one_insn($$)
if (defined $constraint) {
# user-specified constraint: evaluate in an environment
# with variables set corresponding to the variable fields.
- my $v = eval_with_fields($insnname, $insn, $rec, "constraints", $constraint);
+ my %env = extract_fields($insn, $rec);
+ my $v = eval_block($insnname, "constraints", $constraint, \%env);
if (!$v) {
$constraintfailures++;
if ($constraintfailures > 10000) {
@@ -1020,7 +1021,8 @@ sub gen_one_insn($$)
} else {
align(4);
}
- $basereg = eval_with_fields($insnname, $insn, $rec, "memory", $memblock);
+ my %env = extract_fields($insn, $rec);
+ $basereg = eval_block($insnname, "memory", $memblock, \%env);
if ($is_aarch64) {
data_barrier();
@@ -25,8 +25,8 @@ BEGIN {
our @ISA = qw(Exporter);
our @EXPORT = qw(open_bin close_bin set_endian insn32 insn16
$bytecount insnv randint progress_start
- progress_update progress_end
- eval_with_fields is_pow_of_2 sextract ctz
+ progress_update progress_end extract_fields
+ eval_block is_pow_of_2 sextract ctz
dump_insn_details);
}
@@ -138,36 +138,48 @@ sub progress_end()
$| = 0;
}
-sub eval_with_fields($$$$$) {
- # Evaluate the given block in an environment with Perl variables
- # set corresponding to the variable fields for the insn.
- # Return the result of the eval; we die with a useful error
- # message in case of syntax error.
- #
- # At the moment we just evaluate the string in the environment
- # of the calling package.
- # What we *ought* to do here is to give the config snippets
- # their own package, and explicitly import into it only the
- # functions that we want to be accessible to the config.
- # That would provide better separation and an explicitly set up
- # environment that doesn't allow config file code to accidentally
- # change state it shouldn't have access to, and avoid the need to
- # use 'caller' to get the package name of our calling function.
- my ($insnname, $insn, $rec, $blockname, $block) = @_;
+sub extract_fields($$)
+{
+ my ($insn, $rec) = @_;
+
+ my %fields = ();
+ for my $tuple (@{ $rec->{fields} }) {
+ my ($var, $pos, $mask) = @$tuple;
+ $fields{$var} = ($insn >> $pos) & $mask;
+ }
+ return %fields;
+}
+
+# Evaluate the given block in an environment with Perl variables set
+# corresponding to env. Return the result of the eval; we die with a
+# useful error message in case of syntax error.
+#
+# At the moment we just evaluate the string in the environment of the
+# calling package. What we *ought* to do here is to give the config
+# snippets their own package, and explicitly import into it only the
+# functions that we want to be accessible to the config. That would
+# provide better separation and an explicitly set up environment that
+# doesn't allow config file code to accidentally change state it
+# shouldn't have access to, and avoid the need to use 'caller' to get
+# the package name of our calling function.
+sub eval_block($$$$)
+{
+ my ($insnname, $blockname, $block, $env) = @_;
+
my $calling_package = caller;
my $evalstr = "{ package $calling_package; ";
- for my $tuple (@{ $rec->{fields} }) {
- my ($var, $pos, $mask) = @$tuple;
- my $val = ($insn >> $pos) & $mask;
- $evalstr .= "my (\$$var) = $val; ";
+ for (keys %{$env}) {
+ $evalstr .= "my " unless $_ eq '_';
+ $evalstr .= "(\$$_) = \$env->{$_}; ";
}
$evalstr .= $block;
$evalstr .= "}";
+
my $v = eval $evalstr;
- if ($@) {
- print "Syntax error detected evaluating $insnname $blockname string:\n$block\n$@";
- exit(1);
- }
+ die "Syntax error detected evaluating $insnname $blockname string:\n"
+ . "$block\n"
+ . "$@"
+ if ($@);
return $v;
}
@@ -129,7 +129,8 @@ sub gen_one_insn($$)
if (defined $constraint) {
# user-specified constraint: evaluate in an environment
# with variables set corresponding to the variable fields.
- my $v = eval_with_fields($insnname, $insn, $rec, "constraints", $constraint);
+ my %env = extract_fields($insn, $rec);
+ my $v = eval_block($insnname, "constraints", $constraint, \%env);
if (!$v) {
$constraintfailures++;
if ($constraintfailures > 10000) {
@@ -311,7 +311,8 @@ sub gen_one_insn($$)
if (defined $constraint) {
# user-specified constraint: evaluate in an environment
# with variables set corresponding to the variable fields.
- my $v = eval_with_fields($insnname, $insn, $rec, "constraints", $constraint);
+ my %env = extract_fields($insn, $rec);
+ my $v = eval_block($insnname, "constraints", $constraint, \%env);
if (!$v) {
$constraintfailures++;
if ($constraintfailures > 10000) {
@@ -335,7 +336,8 @@ sub gen_one_insn($$)
# Default alignment requirement for ARM is 4 bytes,
# we use 16 for Aarch64, although often unnecessary and overkill.
align(16);
- $basereg = eval_with_fields($insnname, $insn, $rec, "memory", $memblock);
+ my %env = extract_fields($insn, $rec);
+ $basereg = eval_block($insnname, "memory", $memblock, \%env);
}
insn32($insn);
extract_fields can extract named variable fields from an opcode; it returns a hash which can be then passed as environment parameter to eval_block. More importantly, this allows the caller to augment the block environment with more variables, if they wish to do so. Signed-off-by: Jan Bobek <jan.bobek@gmail.com> --- risugen_arm.pm | 6 +++-- risugen_common.pm | 64 ++++++++++++++++++++++++++++------------------- risugen_m68k.pm | 3 ++- risugen_ppc64.pm | 6 +++-- 4 files changed, 48 insertions(+), 31 deletions(-)