Add dr prediction test
[aom.git] / build / make / rtcd.pl
blob8d8be25c04136728000065b66e50c055e2d47a21
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.
12 no strict 'refs';
13 use warnings;
14 use Getopt::Long;
15 Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
17 my %ALL_FUNCS = ();
18 my @ALL_ARCHS;
19 my @ALL_FORWARD_DECLS;
20 my @REQUIRES;
22 my %opts = ();
23 my %disabled = ();
24 my %required = ();
26 my @argv;
27 foreach (@ARGV) {
28 $disabled{$1} = 1, next if /--disable-(.*)/;
29 $required{$1} = 1, next if /--require-(.*)/;
30 push @argv, $_;
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',
42 foreach my $opt (qw/arch config/) {
43 if (!defined($opts{$opt})) {
44 warn "--$opt is required!\n";
45 Getopt::Long::HelpMessage('-exit' => 1);
49 foreach my $defs_file (@ARGV) {
50 if (!-f $defs_file) {
51 warn "$defs_file: $!\n";
52 Getopt::Long::HelpMessage('-exit' => 1);
56 open CONFIG_FILE, $opts{config} or
57 die "Error opening config file '$opts{config}': $!\n";
59 my %config = ();
60 while (<CONFIG_FILE>) {
61 next if !/^(?:CONFIG_|HAVE_)/;
62 chomp;
63 s/\r$//;
64 my @pair = split /=/;
65 $config{$pair[0]} = $pair[1];
67 close CONFIG_FILE;
70 # Routines for the RTCD DSL to call
72 sub aom_config($) {
73 return (defined $config{$_[0]}) ? $config{$_[0]} : "";
76 sub specialize {
77 if (@_ <= 1) {
78 die "'specialize' must be called with a function name and at least one ",
79 "architecture ('C' is implied): \n@_\n";
81 my $fn=$_[0];
82 shift;
83 foreach my $opt (@_) {
84 eval "\$${fn}_${opt}=${fn}_${opt}";
88 sub add_proto {
89 my $fn = splice(@_, -2, 1);
90 $ALL_FUNCS{$fn} = \@_;
91 specialize $fn, "c";
94 sub require {
95 foreach my $fn (keys %ALL_FUNCS) {
96 foreach my $opt (@_) {
97 my $ofn = eval "\$${fn}_${opt}";
98 next if !$ofn;
100 # if we already have a default, then we can disable it, as we know
101 # we can do better.
102 my $best = eval "\$${fn}_default";
103 if ($best) {
104 my $best_ofn = eval "\$${best}";
105 if ($best_ofn && "$best_ofn" ne "$ofn") {
106 eval "\$${best}_link = 'false'";
109 eval "\$${fn}_default=${fn}_${opt}";
110 eval "\$${fn}_${opt}_link='true'";
115 sub forward_decls {
116 push @ALL_FORWARD_DECLS, @_;
120 # Include the user's directives
122 foreach my $f (@ARGV) {
123 open FILE, "<", $f or die "cannot open $f: $!\n";
124 my $contents = join('', <FILE>);
125 close FILE;
126 eval $contents or warn "eval failed: $@\n";
130 # Process the directives according to the command line
132 sub process_forward_decls() {
133 foreach (@ALL_FORWARD_DECLS) {
134 $_->();
138 sub determine_indirection {
139 aom_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
140 foreach my $fn (keys %ALL_FUNCS) {
141 my $n = "";
142 my @val = @{$ALL_FUNCS{$fn}};
143 my $args = pop @val;
144 my $rtyp = "@val";
145 my $dfn = eval "\$${fn}_default";
146 $dfn = eval "\$${dfn}";
147 foreach my $opt (@_) {
148 my $ofn = eval "\$${fn}_${opt}";
149 next if !$ofn;
150 my $link = eval "\$${fn}_${opt}_link";
151 next if $link && $link eq "false";
152 $n .= "x";
154 if ($n eq "x") {
155 eval "\$${fn}_indirect = 'false'";
156 } else {
157 eval "\$${fn}_indirect = 'true'";
162 sub declare_function_pointers {
163 foreach my $fn (sort keys %ALL_FUNCS) {
164 my @val = @{$ALL_FUNCS{$fn}};
165 my $args = pop @val;
166 my $rtyp = "@val";
167 my $dfn = eval "\$${fn}_default";
168 $dfn = eval "\$${dfn}";
169 foreach my $opt (@_) {
170 my $ofn = eval "\$${fn}_${opt}";
171 next if !$ofn;
172 print "$rtyp ${ofn}($args);\n";
174 if (eval "\$${fn}_indirect" eq "false") {
175 print "#define ${fn} ${dfn}\n";
176 } else {
177 print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
179 print "\n";
183 sub set_function_pointers {
184 foreach my $fn (sort keys %ALL_FUNCS) {
185 my @val = @{$ALL_FUNCS{$fn}};
186 my $args = pop @val;
187 my $rtyp = "@val";
188 my $dfn = eval "\$${fn}_default";
189 $dfn = eval "\$${dfn}";
190 if (eval "\$${fn}_indirect" eq "true") {
191 print " $fn = $dfn;\n";
192 foreach my $opt (@_) {
193 my $ofn = eval "\$${fn}_${opt}";
194 next if !$ofn;
195 next if "$ofn" eq "$dfn";
196 my $link = eval "\$${fn}_${opt}_link";
197 next if $link && $link eq "false";
198 my $cond = eval "\$have_${opt}";
199 print " if (${cond}) $fn = $ofn;\n"
205 sub filter {
206 my @filtered;
207 foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
208 return @filtered;
212 # Helper functions for generating the arch specific RTCD files
214 sub common_top() {
215 my $include_guard = uc($opts{sym})."_H_";
216 print <<EOF;
217 // This file is generated. Do not edit.
218 #ifndef ${include_guard}
219 #define ${include_guard}
221 #ifdef RTCD_C
222 #define RTCD_EXTERN
223 #else
224 #define RTCD_EXTERN extern
225 #endif
229 process_forward_decls();
230 print <<EOF;
232 #ifdef __cplusplus
233 extern "C" {
234 #endif
237 declare_function_pointers("c", @ALL_ARCHS);
239 print <<EOF;
240 void $opts{sym}(void);
245 sub common_bottom() {
246 print <<EOF;
248 #ifdef __cplusplus
249 } // extern "C"
250 #endif
252 #endif
256 sub x86() {
257 determine_indirection("c", @ALL_ARCHS);
259 # Assign the helper variable for each enabled extension
260 foreach my $opt (@ALL_ARCHS) {
261 my $opt_uc = uc $opt;
262 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
265 common_top;
266 print <<EOF;
267 #ifdef RTCD_C
268 #include "aom_ports/x86.h"
269 static void setup_rtcd_internal(void)
271 int flags = x86_simd_caps();
273 (void)flags;
277 set_function_pointers("c", @ALL_ARCHS);
279 print <<EOF;
281 #endif
283 common_bottom;
286 sub arm() {
287 determine_indirection("c", @ALL_ARCHS);
289 # Assign the helper variable for each enabled extension
290 foreach my $opt (@ALL_ARCHS) {
291 my $opt_uc = uc $opt;
292 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
295 common_top;
296 print <<EOF;
297 #include "config/aom_config.h"
299 #ifdef RTCD_C
300 #include "aom_ports/arm.h"
301 static void setup_rtcd_internal(void)
303 int flags = arm_cpu_caps();
305 (void)flags;
309 set_function_pointers("c", @ALL_ARCHS);
311 print <<EOF;
313 #endif
315 common_bottom;
318 sub mips() {
319 determine_indirection("c", @ALL_ARCHS);
321 # Assign the helper variable for each enabled extension
322 foreach my $opt (@ALL_ARCHS) {
323 my $opt_uc = uc $opt;
324 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
327 common_top;
329 print <<EOF;
330 #include "config/aom_config.h"
332 #ifdef RTCD_C
333 static void setup_rtcd_internal(void)
337 set_function_pointers("c", @ALL_ARCHS);
339 print <<EOF;
340 #if HAVE_DSPR2
341 void aom_dsputil_static_init();
342 aom_dsputil_static_init();
343 #endif
345 #endif
347 common_bottom;
350 sub ppc() {
351 determine_indirection("c", @ALL_ARCHS);
353 # Assign the helper variable for each enabled extension
354 foreach my $opt (@ALL_ARCHS) {
355 my $opt_uc = uc $opt;
356 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
359 common_top;
361 print <<EOF;
362 #include "config/aom_config.h"
364 #ifdef RTCD_C
365 #include "aom_ports/ppc.h"
366 static void setup_rtcd_internal(void)
368 int flags = ppc_simd_caps();
370 (void)flags;
374 set_function_pointers("c", @ALL_ARCHS);
376 print <<EOF;
378 #endif
380 common_bottom;
383 sub unoptimized() {
384 determine_indirection "c";
385 common_top;
386 print <<EOF;
387 #include "config/aom_config.h"
389 #ifdef RTCD_C
390 static void setup_rtcd_internal(void)
394 set_function_pointers "c";
396 print <<EOF;
398 #endif
400 common_bottom;
404 # Main Driver
407 &require("c");
408 if ($opts{arch} eq 'x86') {
409 @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 avx avx2/);
410 x86;
411 } elsif ($opts{arch} eq 'x86_64') {
412 @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 avx avx2/);
413 @REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/);
414 &require(@REQUIRES);
415 x86;
416 } elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
417 @ALL_ARCHS = filter("$opts{arch}");
418 open CONFIG_FILE, $opts{config} or
419 die "Error opening config file '$opts{config}': $!\n";
420 while (<CONFIG_FILE>) {
421 if (/HAVE_DSPR2=yes/) {
422 @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
423 last;
425 if (/HAVE_MSA=yes/) {
426 @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
427 last;
430 close CONFIG_FILE;
431 mips;
432 } elsif ($opts{arch} =~ /armv7\w?/) {
433 @ALL_ARCHS = filter(qw/neon/);
434 arm;
435 } elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) {
436 @ALL_ARCHS = filter(qw/neon/);
437 arm;
438 } elsif ($opts{arch} eq 'ppc') {
439 @ALL_ARCHS = filter(qw/vsx/);
440 ppc;
441 } else {
442 unoptimized;
445 __END__
447 =head1 NAME
449 rtcd -
451 =head1 SYNOPSIS
453 Usage: rtcd.pl [options] FILE
455 See 'perldoc rtcd.pl' for more details.
457 =head1 DESCRIPTION
459 Reads the Run Time CPU Detections definitions from FILE and generates a
460 C header file on stdout.
462 =head1 OPTIONS
464 Options:
465 --arch=ARCH Architecture to generate defs for (required)
466 --disable-EXT Disable support for EXT extensions
467 --require-EXT Require support for EXT extensions
468 --sym=SYMBOL Unique symbol to use for RTCD initialization function
469 --config=FILE File with CONFIG_FOO=yes lines to parse