tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rtcd.pl (10809B)


      1 #!/usr/bin/env perl
      2 ##
      3 ## Copyright (c) 2017, Alliance for Open Media. All rights reserved.
      4 ##
      5 ## This source code is subject to the terms of the BSD 2 Clause License and
      6 ## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      7 ## was not distributed with this source code in the LICENSE file, you can
      8 ## obtain it at www.aomedia.org/license/software. If the Alliance for Open
      9 ## Media Patent License 1.0 was not distributed with this source code in the
     10 ## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     11 ##
     12 no strict 'refs';
     13 use warnings;
     14 use Getopt::Long;
     15 Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
     16 
     17 my %ALL_FUNCS = ();
     18 my @ALL_ARCHS;
     19 my @ALL_FORWARD_DECLS;
     20 my @REQUIRES;
     21 
     22 my %opts = ();
     23 my %disabled = ();
     24 my %required = ();
     25 
     26 my @argv;
     27 foreach (@ARGV) {
     28  $disabled{$1} = 1, next if /--disable-(.*)/;
     29  $required{$1} = 1, next if /--require-(.*)/;
     30  push @argv, $_;
     31 }
     32 
     33 # NB: use GetOptions() instead of GetOptionsFromArray() for compatibility.
     34 @ARGV = @argv;
     35 GetOptions(
     36  \%opts,
     37  'arch=s',
     38  'sym=s',
     39  'config=s',
     40 );
     41 
     42 foreach my $opt (qw/arch config/) {
     43  if (!defined($opts{$opt})) {
     44    warn "--$opt is required!\n";
     45    Getopt::Long::HelpMessage('-exit' => 1);
     46  }
     47 }
     48 
     49 foreach my $defs_file (@ARGV) {
     50  if (!-f $defs_file) {
     51    warn "$defs_file: $!\n";
     52    Getopt::Long::HelpMessage('-exit' => 1);
     53  }
     54 }
     55 
     56 open CONFIG_FILE, $opts{config} or
     57  die "Error opening config file '$opts{config}': $!\n";
     58 
     59 my %config = ();
     60 while (<CONFIG_FILE>) {
     61  # TODO(aomedia:349428506,349436249,349450845,349455146): remove AOM_ARCH_
     62  # after armv7 SIGBUS issues are fixed.
     63  next if !/^#define\s+(?:AOM_ARCH_|CONFIG_|HAVE_)/;
     64  chomp;
     65  my @line_components = split /\s/;
     66  scalar @line_components > 2 or
     67    die "Invalid input passed to rtcd.pl via $opts{config}.";
     68  # $line_components[0] = #define
     69  # $line_components[1] = flag name ({AOM_ARCH,CONFIG,HAVE}_SOMETHING)
     70  # $line_components[2] = flag value (0 or 1)
     71  $config{$line_components[1]} = "$line_components[2]" eq "1" ? "yes" : "";
     72 }
     73 close CONFIG_FILE;
     74 
     75 #
     76 # Routines for the RTCD DSL to call
     77 #
     78 sub aom_config($) {
     79  return (defined $config{$_[0]}) ? $config{$_[0]} : "";
     80 }
     81 
     82 sub specialize {
     83  if (@_ <= 1) {
     84    die "'specialize' must be called with a function name and at least one ",
     85        "architecture ('C' is implied): \n@_\n";
     86  }
     87  my $fn=$_[0];
     88  shift;
     89  foreach my $opt (@_) {
     90    eval "\$${fn}_${opt}=${fn}_${opt}";
     91  }
     92 }
     93 
     94 sub add_proto {
     95  my $fn = splice(@_, -2, 1);
     96  my @proto = @_;
     97  foreach (@proto) { tr/\t/ / }
     98  $ALL_FUNCS{$fn} = \@proto;
     99  specialize $fn, "c";
    100 }
    101 
    102 sub require {
    103  foreach my $fn (keys %ALL_FUNCS) {
    104    foreach my $opt (@_) {
    105      my $ofn = eval "\$${fn}_${opt}";
    106      next if !$ofn;
    107 
    108      # if we already have a default, then we can disable it, as we know
    109      # we can do better.
    110      my $best = eval "\$${fn}_default";
    111      if ($best) {
    112        my $best_ofn = eval "\$${best}";
    113        if ($best_ofn && "$best_ofn" ne "$ofn") {
    114          eval "\$${best}_link = 'false'";
    115        }
    116      }
    117      eval "\$${fn}_default=${fn}_${opt}";
    118      eval "\$${fn}_${opt}_link='true'";
    119    }
    120  }
    121 }
    122 
    123 sub forward_decls {
    124  push @ALL_FORWARD_DECLS, @_;
    125 }
    126 
    127 #
    128 # Include the user's directives
    129 #
    130 foreach my $f (@ARGV) {
    131  open FILE, "<", $f or die "cannot open $f: $!\n";
    132  my $contents = join('', <FILE>);
    133  close FILE;
    134  eval $contents or warn "eval failed: $@\n";
    135 }
    136 
    137 #
    138 # Process the directives according to the command line
    139 #
    140 sub process_forward_decls() {
    141  foreach (@ALL_FORWARD_DECLS) {
    142    $_->();
    143  }
    144 }
    145 
    146 sub determine_indirection {
    147  aom_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
    148  foreach my $fn (keys %ALL_FUNCS) {
    149    my $n = "";
    150    my @val = @{$ALL_FUNCS{$fn}};
    151    my $args = pop @val;
    152    my $rtyp = "@val";
    153    my $dfn = eval "\$${fn}_default";
    154    $dfn = eval "\$${dfn}";
    155    foreach my $opt (@_) {
    156      my $ofn = eval "\$${fn}_${opt}";
    157      next if !$ofn;
    158      my $link = eval "\$${fn}_${opt}_link";
    159      next if $link && $link eq "false";
    160      $n .= "x";
    161    }
    162    if ($n eq "x") {
    163      eval "\$${fn}_indirect = 'false'";
    164    } else {
    165      eval "\$${fn}_indirect = 'true'";
    166    }
    167  }
    168 }
    169 
    170 sub declare_function_pointers {
    171  foreach my $fn (sort keys %ALL_FUNCS) {
    172    my @val = @{$ALL_FUNCS{$fn}};
    173    my $args = pop @val;
    174    my $rtyp = "@val";
    175    my $dfn = eval "\$${fn}_default";
    176    $dfn = eval "\$${dfn}";
    177    foreach my $opt (@_) {
    178      my $ofn = eval "\$${fn}_${opt}";
    179      next if !$ofn;
    180      print "$rtyp ${ofn}($args);\n";
    181    }
    182    if (eval "\$${fn}_indirect" eq "false") {
    183      print "#define ${fn} ${dfn}\n";
    184    } else {
    185      print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
    186    }
    187    print "\n";
    188  }
    189 }
    190 
    191 sub set_function_pointers {
    192  foreach my $fn (sort keys %ALL_FUNCS) {
    193    my @val = @{$ALL_FUNCS{$fn}};
    194    my $args = pop @val;
    195    my $rtyp = "@val";
    196    my $dfn = eval "\$${fn}_default";
    197    $dfn = eval "\$${dfn}";
    198    if (eval "\$${fn}_indirect" eq "true") {
    199      print "    $fn = $dfn;\n";
    200      foreach my $opt (@_) {
    201        my $ofn = eval "\$${fn}_${opt}";
    202        next if !$ofn;
    203        next if "$ofn" eq "$dfn";
    204        my $link = eval "\$${fn}_${opt}_link";
    205        next if $link && $link eq "false";
    206        my $cond = eval "\$have_${opt}";
    207        print "    if (${cond}) $fn = $ofn;\n"
    208      }
    209    }
    210  }
    211 }
    212 
    213 sub filter {
    214  my @filtered;
    215  foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
    216  return @filtered;
    217 }
    218 
    219 #
    220 # Helper functions for generating the arch specific RTCD files
    221 #
    222 sub common_top() {
    223  my $include_guard = uc($opts{sym})."_H_";
    224  my @time = localtime;
    225  my $year = $time[5] + 1900;
    226  print <<EOF;
    227 /*
    228 * Copyright (c) ${year}, Alliance for Open Media. All rights reserved.
    229 *
    230 * This source code is subject to the terms of the BSD 2 Clause License and
    231 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
    232 * was not distributed with this source code in the LICENSE file, you can
    233 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
    234 * Media Patent License 1.0 was not distributed with this source code in the
    235 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
    236 */
    237 
    238 // This file is generated. Do not edit.
    239 #ifndef ${include_guard}
    240 #define ${include_guard}
    241 
    242 #ifdef RTCD_C
    243 #define RTCD_EXTERN
    244 #else
    245 #define RTCD_EXTERN extern
    246 #endif
    247 
    248 EOF
    249 
    250 process_forward_decls();
    251 print <<EOF;
    252 
    253 #ifdef __cplusplus
    254 extern "C" {
    255 #endif
    256 
    257 EOF
    258 declare_function_pointers("c", @ALL_ARCHS);
    259 
    260 print <<EOF;
    261 void $opts{sym}(void);
    262 
    263 EOF
    264 }
    265 
    266 sub common_bottom() {
    267  my $include_guard = uc($opts{sym})."_H_";
    268  print <<EOF;
    269 
    270 #ifdef __cplusplus
    271 }  // extern "C"
    272 #endif
    273 
    274 #endif  // ${include_guard}
    275 EOF
    276 }
    277 
    278 sub x86() {
    279  determine_indirection("c", @ALL_ARCHS);
    280 
    281  # Assign the helper variable for each enabled extension
    282  foreach my $opt (@ALL_ARCHS) {
    283    my $opt_uc = uc $opt;
    284    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
    285  }
    286 
    287  common_top;
    288  print <<EOF;
    289 #ifdef RTCD_C
    290 #include "aom_ports/x86.h"
    291 static void setup_rtcd_internal(void)
    292 {
    293    int flags = x86_simd_caps();
    294 
    295    (void)flags;
    296 
    297 EOF
    298 
    299  set_function_pointers("c", @ALL_ARCHS);
    300 
    301  print <<EOF;
    302 }
    303 #endif
    304 EOF
    305  common_bottom;
    306 }
    307 
    308 sub arm() {
    309  determine_indirection("c", @ALL_ARCHS);
    310 
    311  # Assign the helper variable for each enabled extension
    312  foreach my $opt (@ALL_ARCHS) {
    313    my $opt_uc = uc $opt;
    314    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
    315  }
    316 
    317  common_top;
    318  print <<EOF;
    319 #include "config/aom_config.h"
    320 
    321 #ifdef RTCD_C
    322 #include "aom_ports/arm.h"
    323 static void setup_rtcd_internal(void)
    324 {
    325    int flags = aom_arm_cpu_caps();
    326 
    327    (void)flags;
    328 
    329 EOF
    330 
    331  set_function_pointers("c", @ALL_ARCHS);
    332 
    333  print <<EOF;
    334 }
    335 #endif
    336 EOF
    337  common_bottom;
    338 }
    339 
    340 sub ppc() {
    341  determine_indirection("c", @ALL_ARCHS);
    342 
    343  # Assign the helper variable for each enabled extension
    344  foreach my $opt (@ALL_ARCHS) {
    345    my $opt_uc = uc $opt;
    346    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
    347  }
    348 
    349  common_top;
    350 
    351  print <<EOF;
    352 #include "config/aom_config.h"
    353 
    354 #ifdef RTCD_C
    355 #include "aom_ports/ppc.h"
    356 static void setup_rtcd_internal(void)
    357 {
    358  int flags = ppc_simd_caps();
    359 
    360  (void)flags;
    361 
    362 EOF
    363 
    364  set_function_pointers("c", @ALL_ARCHS);
    365 
    366  print <<EOF;
    367 }
    368 #endif
    369 EOF
    370  common_bottom;
    371 }
    372 
    373 sub riscv() {
    374  determine_indirection("c", @ALL_ARCHS);
    375 
    376  # Assign the helper variable for each enabled extension
    377  foreach my $opt (@ALL_ARCHS) {
    378    my $opt_uc = uc $opt;
    379    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
    380  }
    381 
    382  common_top;
    383  print <<EOF;
    384 #ifdef RTCD_C
    385 #include "aom_ports/riscv.h"
    386 static void setup_rtcd_internal(void)
    387 {
    388    int flags = riscv_simd_caps();
    389 
    390    (void)flags;
    391 
    392 EOF
    393 
    394  set_function_pointers("c", @ALL_ARCHS);
    395 
    396  print <<EOF;
    397 }
    398 #endif
    399 EOF
    400  common_bottom;
    401 }
    402 
    403 sub unoptimized() {
    404  determine_indirection "c";
    405  common_top;
    406  print <<EOF;
    407 #include "config/aom_config.h"
    408 
    409 #ifdef RTCD_C
    410 static void setup_rtcd_internal(void)
    411 {
    412 EOF
    413 
    414  set_function_pointers "c";
    415 
    416  print <<EOF;
    417 }
    418 #endif
    419 EOF
    420  common_bottom;
    421 }
    422 
    423 # List of architectures in low-to-high preference order.
    424 my @PRIORITY_ARCH = qw/
    425  c
    426  mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 avx avx2
    427  arm_crc32 neon neon_dotprod neon_i8mm sve sve2
    428  rvv
    429  vsx
    430  dspr2 msa
    431 /;
    432 my %PRIORITY_INDEX;
    433 for (my $i = 0; $i < @PRIORITY_ARCH; $i++) {
    434  $PRIORITY_INDEX{$PRIORITY_ARCH[$i]} = $i;
    435 }
    436 
    437 #
    438 # Main Driver
    439 #
    440 
    441 &require("c");
    442 &require(sort { $PRIORITY_INDEX{$a} <=> $PRIORITY_INDEX{$b} } keys %required);
    443 if ($opts{arch} eq 'x86') {
    444  @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 avx avx2/);
    445  x86;
    446 } elsif ($opts{arch} eq 'x86_64') {
    447  @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 avx avx2
    448                         avx512/);
    449  if (keys %required == 0) {
    450    @REQUIRES = filter(qw/mmx sse sse2/);
    451    &require(@REQUIRES);
    452  }
    453  x86;
    454 } elsif ($opts{arch} =~ /armv[78]\w?/) {
    455  @ALL_ARCHS = filter(qw/neon/);
    456  arm;
    457 } elsif ($opts{arch} eq 'arm64' ) {
    458  @ALL_ARCHS = filter(qw/neon arm_crc32 neon_dotprod neon_i8mm sve sve2/);
    459  if (keys %required == 0) {
    460    @REQUIRES = filter(qw/neon/);
    461    &require(@REQUIRES);
    462  }
    463  arm;
    464 } elsif ($opts{arch} eq 'ppc') {
    465  @ALL_ARCHS = filter(qw/vsx/);
    466  ppc;
    467 } elsif ($opts{arch} eq 'riscv') {
    468  @ALL_ARCHS = filter(qw/rvv/);
    469  riscv;
    470 } else {
    471  unoptimized;
    472 }
    473 
    474 __END__
    475 
    476 =head1 NAME
    477 
    478 rtcd -
    479 
    480 =head1 SYNOPSIS
    481 
    482 Usage: rtcd.pl [options] FILE
    483 
    484 See 'perldoc rtcd.pl' for more details.
    485 
    486 =head1 DESCRIPTION
    487 
    488 Reads the Run Time CPU Detections definitions from FILE and generates a
    489 C header file on stdout.
    490 
    491 =head1 OPTIONS
    492 
    493 Options:
    494  --arch=ARCH       Architecture to generate defs for (required)
    495  --disable-EXT     Disable support for EXT extensions
    496  --require-EXT     Require support for EXT extensions
    497  --sym=SYMBOL      Unique symbol to use for RTCD initialization function
    498  --config=FILE     Path to file containing C preprocessor directives to parse