123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- #!/usr/bin/env perl
- ##
- ## Copyright (c) 2017 The WebM project authors. All Rights Reserved.
- ##
- ## Use of this source code is governed by a BSD-style license
- ## that can be found in the LICENSE file in the root of the source
- ## tree. An additional intellectual property rights grant can be found
- ## in the file PATENTS. All contributing project authors may
- ## be found in the AUTHORS file in the root of the source tree.
- ##
- no strict 'refs';
- use warnings;
- use Getopt::Long;
- Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
- my %ALL_FUNCS = ();
- my @ALL_ARCHS;
- my @ALL_FORWARD_DECLS;
- my @REQUIRES;
- my %opts = ();
- my %disabled = ();
- my %required = ();
- my @argv;
- foreach (@ARGV) {
- $disabled{$1} = 1, next if /--disable-(.*)/;
- $required{$1} = 1, next if /--require-(.*)/;
- push @argv, $_;
- }
- # NB: use GetOptions() instead of GetOptionsFromArray() for compatibility.
- @ARGV = @argv;
- GetOptions(
- \%opts,
- 'arch=s',
- 'sym=s',
- 'config=s',
- );
- foreach my $opt (qw/arch config/) {
- if (!defined($opts{$opt})) {
- warn "--$opt is required!\n";
- Getopt::Long::HelpMessage('-exit' => 1);
- }
- }
- foreach my $defs_file (@ARGV) {
- if (!-f $defs_file) {
- warn "$defs_file: $!\n";
- Getopt::Long::HelpMessage('-exit' => 1);
- }
- }
- open CONFIG_FILE, $opts{config} or
- die "Error opening config file '$opts{config}': $!\n";
- my %config = ();
- while (<CONFIG_FILE>) {
- next if !/^(?:CONFIG_|HAVE_)/;
- chomp;
- my @pair = split /=/;
- $config{$pair[0]} = $pair[1];
- }
- close CONFIG_FILE;
- #
- # Routines for the RTCD DSL to call
- #
- sub vpx_config($) {
- return (defined $config{$_[0]}) ? $config{$_[0]} : "";
- }
- sub specialize {
- my $fn=$_[0];
- shift;
- foreach my $opt (@_) {
- eval "\$${fn}_${opt}=${fn}_${opt}";
- }
- }
- sub add_proto {
- my $fn = splice(@_, -2, 1);
- $ALL_FUNCS{$fn} = \@_;
- specialize $fn, "c";
- }
- sub require {
- foreach my $fn (keys %ALL_FUNCS) {
- foreach my $opt (@_) {
- my $ofn = eval "\$${fn}_${opt}";
- next if !$ofn;
- # if we already have a default, then we can disable it, as we know
- # we can do better.
- my $best = eval "\$${fn}_default";
- if ($best) {
- my $best_ofn = eval "\$${best}";
- if ($best_ofn && "$best_ofn" ne "$ofn") {
- eval "\$${best}_link = 'false'";
- }
- }
- eval "\$${fn}_default=${fn}_${opt}";
- eval "\$${fn}_${opt}_link='true'";
- }
- }
- }
- sub forward_decls {
- push @ALL_FORWARD_DECLS, @_;
- }
- #
- # Include the user's directives
- #
- foreach my $f (@ARGV) {
- open FILE, "<", $f or die "cannot open $f: $!\n";
- my $contents = join('', <FILE>);
- close FILE;
- eval $contents or warn "eval failed: $@\n";
- }
- #
- # Process the directives according to the command line
- #
- sub process_forward_decls() {
- foreach (@ALL_FORWARD_DECLS) {
- $_->();
- }
- }
- sub determine_indirection {
- vpx_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
- foreach my $fn (keys %ALL_FUNCS) {
- my $n = "";
- my @val = @{$ALL_FUNCS{$fn}};
- my $args = pop @val;
- my $rtyp = "@val";
- my $dfn = eval "\$${fn}_default";
- $dfn = eval "\$${dfn}";
- foreach my $opt (@_) {
- my $ofn = eval "\$${fn}_${opt}";
- next if !$ofn;
- my $link = eval "\$${fn}_${opt}_link";
- next if $link && $link eq "false";
- $n .= "x";
- }
- if ($n eq "x") {
- eval "\$${fn}_indirect = 'false'";
- } else {
- eval "\$${fn}_indirect = 'true'";
- }
- }
- }
- sub declare_function_pointers {
- foreach my $fn (sort keys %ALL_FUNCS) {
- my @val = @{$ALL_FUNCS{$fn}};
- my $args = pop @val;
- my $rtyp = "@val";
- my $dfn = eval "\$${fn}_default";
- $dfn = eval "\$${dfn}";
- foreach my $opt (@_) {
- my $ofn = eval "\$${fn}_${opt}";
- next if !$ofn;
- print "$rtyp ${ofn}($args);\n";
- }
- if (eval "\$${fn}_indirect" eq "false") {
- print "#define ${fn} ${dfn}\n";
- } else {
- print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
- }
- print "\n";
- }
- }
- sub set_function_pointers {
- foreach my $fn (sort keys %ALL_FUNCS) {
- my @val = @{$ALL_FUNCS{$fn}};
- my $args = pop @val;
- my $rtyp = "@val";
- my $dfn = eval "\$${fn}_default";
- $dfn = eval "\$${dfn}";
- if (eval "\$${fn}_indirect" eq "true") {
- print " $fn = $dfn;\n";
- foreach my $opt (@_) {
- my $ofn = eval "\$${fn}_${opt}";
- next if !$ofn;
- next if "$ofn" eq "$dfn";
- my $link = eval "\$${fn}_${opt}_link";
- next if $link && $link eq "false";
- my $cond = eval "\$have_${opt}";
- print " if (${cond}) $fn = $ofn;\n"
- }
- }
- }
- }
- sub filter {
- my @filtered;
- foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
- return @filtered;
- }
- #
- # Helper functions for generating the arch specific RTCD files
- #
- sub common_top() {
- my $include_guard = uc($opts{sym})."_H_";
- print <<EOF;
- // This file is generated. Do not edit.
- #ifndef ${include_guard}
- #define ${include_guard}
- #ifdef RTCD_C
- #define RTCD_EXTERN
- #else
- #define RTCD_EXTERN extern
- #endif
- EOF
- process_forward_decls();
- print <<EOF;
- #ifdef __cplusplus
- extern "C" {
- #endif
- EOF
- declare_function_pointers("c", @ALL_ARCHS);
- print <<EOF;
- void $opts{sym}(void);
- EOF
- }
- sub common_bottom() {
- print <<EOF;
- #ifdef __cplusplus
- } // extern "C"
- #endif
- #endif
- EOF
- }
- sub x86() {
- determine_indirection("c", @ALL_ARCHS);
- # Assign the helper variable for each enabled extension
- foreach my $opt (@ALL_ARCHS) {
- my $opt_uc = uc $opt;
- eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
- }
- common_top;
- print <<EOF;
- #ifdef RTCD_C
- #include "vpx_ports/x86.h"
- static void setup_rtcd_internal(void)
- {
- int flags = x86_simd_caps();
- (void)flags;
- EOF
- set_function_pointers("c", @ALL_ARCHS);
- print <<EOF;
- }
- #endif
- EOF
- common_bottom;
- }
- sub arm() {
- determine_indirection("c", @ALL_ARCHS);
- # Assign the helper variable for each enabled extension
- foreach my $opt (@ALL_ARCHS) {
- my $opt_uc = uc $opt;
- # Enable neon assembly based on HAVE_NEON logic instead of adding new
- # HAVE_NEON_ASM logic
- if ($opt eq 'neon_asm') { $opt_uc = 'NEON' }
- eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
- }
- common_top;
- print <<EOF;
- #include "vpx_config.h"
- #ifdef RTCD_C
- #include "vpx_ports/arm.h"
- static void setup_rtcd_internal(void)
- {
- int flags = arm_cpu_caps();
- (void)flags;
- EOF
- set_function_pointers("c", @ALL_ARCHS);
- print <<EOF;
- }
- #endif
- EOF
- common_bottom;
- }
- sub mips() {
- determine_indirection("c", @ALL_ARCHS);
- common_top;
- print <<EOF;
- #include "vpx_config.h"
- #ifdef RTCD_C
- static void setup_rtcd_internal(void)
- {
- EOF
- set_function_pointers("c", @ALL_ARCHS);
- print <<EOF;
- #if HAVE_DSPR2
- void vpx_dsputil_static_init();
- #if CONFIG_VP8
- void dsputil_static_init();
- #endif
- vpx_dsputil_static_init();
- #if CONFIG_VP8
- dsputil_static_init();
- #endif
- #endif
- }
- #endif
- EOF
- common_bottom;
- }
- sub ppc() {
- determine_indirection("c", @ALL_ARCHS);
- # Assign the helper variable for each enabled extension
- foreach my $opt (@ALL_ARCHS) {
- my $opt_uc = uc $opt;
- eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
- }
- common_top;
- print <<EOF;
- #include "vpx_config.h"
- #ifdef RTCD_C
- #include "vpx_ports/ppc.h"
- static void setup_rtcd_internal(void)
- {
- int flags = ppc_simd_caps();
- (void)flags;
- EOF
- set_function_pointers("c", @ALL_ARCHS);
- print <<EOF;
- }
- #endif
- EOF
- common_bottom;
- }
- sub unoptimized() {
- determine_indirection "c";
- common_top;
- print <<EOF;
- #include "vpx_config.h"
- #ifdef RTCD_C
- static void setup_rtcd_internal(void)
- {
- EOF
- set_function_pointers "c";
- print <<EOF;
- }
- #endif
- EOF
- common_bottom;
- }
- #
- # Main Driver
- #
- &require("c");
- &require(keys %required);
- if ($opts{arch} eq 'x86') {
- @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
- x86;
- } elsif ($opts{arch} eq 'x86_64') {
- @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
- @REQUIRES = filter(qw/mmx sse sse2/);
- &require(@REQUIRES);
- x86;
- } elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
- @ALL_ARCHS = filter("$opts{arch}");
- open CONFIG_FILE, $opts{config} or
- die "Error opening config file '$opts{config}': $!\n";
- while (<CONFIG_FILE>) {
- if (/HAVE_DSPR2=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
- last;
- }
- if (/HAVE_MSA=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
- last;
- }
- if (/HAVE_MMI=yes/) {
- @ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
- last;
- }
- }
- close CONFIG_FILE;
- mips;
- } elsif ($opts{arch} =~ /armv7\w?/) {
- @ALL_ARCHS = filter(qw/neon_asm neon/);
- arm;
- } elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) {
- @ALL_ARCHS = filter(qw/neon/);
- &require("neon");
- arm;
- } elsif ($opts{arch} =~ /^ppc/ ) {
- @ALL_ARCHS = filter(qw/vsx/);
- ppc;
- } else {
- unoptimized;
- }
- __END__
- =head1 NAME
- rtcd -
- =head1 SYNOPSIS
- Usage: rtcd.pl [options] FILE
- See 'perldoc rtcd.pl' for more details.
- =head1 DESCRIPTION
- Reads the Run Time CPU Detections definitions from FILE and generates a
- C header file on stdout.
- =head1 OPTIONS
- Options:
- --arch=ARCH Architecture to generate defs for (required)
- --disable-EXT Disable support for EXT extensions
- --require-EXT Require support for EXT extensions
- --sym=SYMBOL Unique symbol to use for RTCD initialization function
- --config=FILE File with CONFIG_FOO=yes lines to parse
|