Require armv6/media when building armv7
[platform/upstream/libvpx.git] / build / make / rtcd.pl
1 #!/usr/bin/env perl
2
3 no strict 'refs';
4 use warnings;
5 use Getopt::Long;
6 Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
7
8 my %ALL_FUNCS = ();
9 my @ALL_ARCHS;
10 my @ALL_FORWARD_DECLS;
11 my @REQUIRES;
12
13 my %opts = ();
14 my %disabled = ();
15 my %required = ();
16
17 my @argv;
18 foreach (@ARGV) {
19   $disabled{$1} = 1, next if /--disable-(.*)/;
20   $required{$1} = 1, next if /--require-(.*)/;
21   push @argv, $_;
22 }
23
24 # NB: use GetOptions() instead of GetOptionsFromArray() for compatibility.
25 @ARGV = @argv;
26 GetOptions(
27   \%opts,
28   'arch=s',
29   'sym=s',
30   'config=s',
31 );
32
33 foreach my $opt (qw/arch config/) {
34   if (!defined($opts{$opt})) {
35     warn "--$opt is required!\n";
36     Getopt::Long::HelpMessage('-exit' => 1);
37   }
38 }
39
40 foreach my $defs_file (@ARGV) {
41   if (!-f $defs_file) {
42     warn "$defs_file: $!\n";
43     Getopt::Long::HelpMessage('-exit' => 1);
44   }
45 }
46
47 open CONFIG_FILE, $opts{config} or
48   die "Error opening config file '$opts{config}': $!\n";
49
50 my %config = ();
51 while (<CONFIG_FILE>) {
52   next if !/^CONFIG_/;
53   chomp;
54   my @pair = split /=/;
55   $config{$pair[0]} = $pair[1];
56 }
57 close CONFIG_FILE;
58
59 #
60 # Routines for the RTCD DSL to call
61 #
62 sub vpx_config($) {
63   return (defined $config{$_[0]}) ? $config{$_[0]} : "";
64 }
65
66 sub specialize {
67   my $fn=$_[0];
68   shift;
69   foreach my $opt (@_) {
70     eval "\$${fn}_${opt}=${fn}_${opt}";
71   }
72 }
73
74 sub add_proto {
75   my $fn = splice(@_, -2, 1);
76   $ALL_FUNCS{$fn} = \@_;
77   specialize $fn, "c";
78 }
79
80 sub require {
81   foreach my $fn (keys %ALL_FUNCS) {
82     foreach my $opt (@_) {
83       my $ofn = eval "\$${fn}_${opt}";
84       next if !$ofn;
85
86       # if we already have a default, then we can disable it, as we know
87       # we can do better.
88       my $best = eval "\$${fn}_default";
89       if ($best) {
90         my $best_ofn = eval "\$${best}";
91         if ($best_ofn && "$best_ofn" ne "$ofn") {
92           eval "\$${best}_link = 'false'";
93         }
94       }
95       eval "\$${fn}_default=${fn}_${opt}";
96       eval "\$${fn}_${opt}_link='true'";
97     }
98   }
99 }
100
101 sub forward_decls {
102   push @ALL_FORWARD_DECLS, @_;
103 }
104
105 #
106 # Include the user's directives
107 #
108 foreach my $f (@ARGV) {
109   open FILE, "<", $f or die "cannot open $f: $!\n";
110   my $contents = join('', <FILE>);
111   close FILE;
112   eval $contents or warn "eval failed: $@\n";
113 }
114
115 #
116 # Process the directives according to the command line
117 #
118 sub process_forward_decls() {
119   foreach (@ALL_FORWARD_DECLS) {
120     $_->();
121   }
122 }
123
124 sub determine_indirection {
125   vpx_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
126   foreach my $fn (keys %ALL_FUNCS) {
127     my $n = "";
128     my @val = @{$ALL_FUNCS{$fn}};
129     my $args = pop @val;
130     my $rtyp = "@val";
131     my $dfn = eval "\$${fn}_default";
132     $dfn = eval "\$${dfn}";
133     foreach my $opt (@_) {
134       my $ofn = eval "\$${fn}_${opt}";
135       next if !$ofn;
136       my $link = eval "\$${fn}_${opt}_link";
137       next if $link && $link eq "false";
138       $n .= "x";
139     }
140     if ($n eq "x") {
141       eval "\$${fn}_indirect = 'false'";
142     } else {
143       eval "\$${fn}_indirect = 'true'";
144     }
145   }
146 }
147
148 sub declare_function_pointers {
149   foreach my $fn (sort keys %ALL_FUNCS) {
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       print "$rtyp ${ofn}($args);\n";
159     }
160     if (eval "\$${fn}_indirect" eq "false") {
161       print "#define ${fn} ${dfn}\n";
162     } else {
163       print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
164     }
165     print "\n";
166   }
167 }
168
169 sub set_function_pointers {
170   foreach my $fn (sort keys %ALL_FUNCS) {
171     my @val = @{$ALL_FUNCS{$fn}};
172     my $args = pop @val;
173     my $rtyp = "@val";
174     my $dfn = eval "\$${fn}_default";
175     $dfn = eval "\$${dfn}";
176     if (eval "\$${fn}_indirect" eq "true") {
177       print "    $fn = $dfn;\n";
178       foreach my $opt (@_) {
179         my $ofn = eval "\$${fn}_${opt}";
180         next if !$ofn;
181         next if "$ofn" eq "$dfn";
182         my $link = eval "\$${fn}_${opt}_link";
183         next if $link && $link eq "false";
184         my $cond = eval "\$have_${opt}";
185         print "    if (${cond}) $fn = $ofn;\n"
186       }
187     }
188   }
189 }
190
191 sub filter {
192   my @filtered;
193   foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
194   return @filtered;
195 }
196
197 #
198 # Helper functions for generating the arch specific RTCD files
199 #
200 sub common_top() {
201   my $include_guard = uc($opts{sym})."_H_";
202   print <<EOF;
203 #ifndef ${include_guard}
204 #define ${include_guard}
205
206 #ifdef RTCD_C
207 #define RTCD_EXTERN
208 #else
209 #define RTCD_EXTERN extern
210 #endif
211
212 #ifdef __cplusplus
213 extern "C" {
214 #endif
215
216 EOF
217
218 process_forward_decls();
219 print "\n";
220 declare_function_pointers("c", @ALL_ARCHS);
221
222 print <<EOF;
223 void $opts{sym}(void);
224
225 EOF
226 }
227
228 sub common_bottom() {
229   print <<EOF;
230
231 #ifdef __cplusplus
232 }  // extern "C"
233 #endif
234
235 #endif
236 EOF
237 }
238
239 sub x86() {
240   determine_indirection("c", @ALL_ARCHS);
241
242   # Assign the helper variable for each enabled extension
243   foreach my $opt (@ALL_ARCHS) {
244     my $opt_uc = uc $opt;
245     eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
246   }
247
248   common_top;
249   print <<EOF;
250 #ifdef RTCD_C
251 #include "vpx_ports/x86.h"
252 static void setup_rtcd_internal(void)
253 {
254     int flags = x86_simd_caps();
255
256     (void)flags;
257
258 EOF
259
260   set_function_pointers("c", @ALL_ARCHS);
261
262   print <<EOF;
263 }
264 #endif
265 EOF
266   common_bottom;
267 }
268
269 sub arm() {
270   determine_indirection("c", @ALL_ARCHS);
271
272   # Assign the helper variable for each enabled extension
273   foreach my $opt (@ALL_ARCHS) {
274     my $opt_uc = uc $opt;
275     # Enable neon assembly based on HAVE_NEON logic instead of adding new
276     # HAVE_NEON_ASM logic
277     if ($opt eq 'neon_asm') { $opt_uc = 'NEON' }
278     eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
279   }
280
281   common_top;
282   print <<EOF;
283 #include "vpx_config.h"
284
285 #ifdef RTCD_C
286 #include "vpx_ports/arm.h"
287 static void setup_rtcd_internal(void)
288 {
289     int flags = arm_cpu_caps();
290
291     (void)flags;
292
293 EOF
294
295   set_function_pointers("c", @ALL_ARCHS);
296
297   print <<EOF;
298 }
299 #endif
300 EOF
301   common_bottom;
302 }
303
304 sub mips() {
305   determine_indirection("c", @ALL_ARCHS);
306   common_top;
307
308   print <<EOF;
309 #include "vpx_config.h"
310
311 #ifdef RTCD_C
312 static void setup_rtcd_internal(void)
313 {
314 EOF
315
316   set_function_pointers("c", @ALL_ARCHS);
317
318   print <<EOF;
319 #if HAVE_DSPR2
320 #if CONFIG_VP8
321 void dsputil_static_init();
322 dsputil_static_init();
323 #endif
324 #if CONFIG_VP9
325 void vp9_dsputil_static_init();
326 vp9_dsputil_static_init();
327 #endif
328 #endif
329 }
330 #endif
331 EOF
332   common_bottom;
333 }
334
335 sub unoptimized() {
336   determine_indirection "c";
337   common_top;
338   print <<EOF;
339 #include "vpx_config.h"
340
341 #ifdef RTCD_C
342 static void setup_rtcd_internal(void)
343 {
344 EOF
345
346   set_function_pointers "c";
347
348   print <<EOF;
349 }
350 #endif
351 EOF
352   common_bottom;
353 }
354
355 #
356 # Main Driver
357 #
358
359 &require("c");
360 if ($opts{arch} eq 'x86') {
361   @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
362   x86;
363 } elsif ($opts{arch} eq 'x86_64') {
364   @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
365   @REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/);
366   &require(@REQUIRES);
367   x86;
368 } elsif ($opts{arch} eq 'mips32') {
369   @ALL_ARCHS = filter(qw/mips32/);
370   open CONFIG_FILE, $opts{config} or
371     die "Error opening config file '$opts{config}': $!\n";
372   while (<CONFIG_FILE>) {
373     if (/HAVE_DSPR2=yes/) {
374       @ALL_ARCHS = filter(qw/mips32 dspr2/);
375       last;
376     }
377   }
378   close CONFIG_FILE;
379   mips;
380 } elsif ($opts{arch} eq 'armv5te') {
381   @ALL_ARCHS = filter(qw/edsp/);
382   arm;
383 } elsif ($opts{arch} eq 'armv6') {
384   @ALL_ARCHS = filter(qw/edsp media/);
385   arm;
386 } elsif ($opts{arch} eq 'armv7') {
387   @ALL_ARCHS = filter(qw/edsp media neon_asm neon/);
388   @REQUIRES = filter(keys %required ? keys %required : qw/media/);
389   &require(@REQUIRES);
390   arm;
391 } elsif ($opts{arch} eq 'armv8') {
392   @ALL_ARCHS = filter(qw/neon/);
393   arm;
394 } else {
395   unoptimized;
396 }
397
398 __END__
399
400 =head1 NAME
401
402 rtcd -
403
404 =head1 SYNOPSIS
405
406 Usage: rtcd.pl [options] FILE
407
408 See 'perldoc rtcd.pl' for more details.
409
410 =head1 DESCRIPTION
411
412 Reads the Run Time CPU Detections definitions from FILE and generates a
413 C header file on stdout.
414
415 =head1 OPTIONS
416
417 Options:
418   --arch=ARCH       Architecture to generate defs for (required)
419   --disable-EXT     Disable support for EXT extensions
420   --require-EXT     Require support for EXT extensions
421   --sym=SYMBOL      Unique symbol to use for RTCD initialization function
422   --config=FILE     File with CONFIG_FOO=yes lines to parse