blob: bb3401161402a42413f1204d6d3beb025d9f5d2f [file] [log] [blame]
James Zern805078a2014-02-23 16:33:14 -08001#!/usr/bin/env perl
2
3no strict 'refs';
4use warnings;
5use Getopt::Long;
James Zern29943512014-07-24 14:55:19 -07006Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
James Zern805078a2014-02-23 16:33:14 -08007
8my %ALL_FUNCS = ();
9my @ALL_ARCHS;
10my @ALL_FORWARD_DECLS;
11my @REQUIRES;
12
13my %opts = ();
14my %disabled = ();
15my %required = ();
16
17my @argv;
18foreach (@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;
26GetOptions(
27 \%opts,
28 'arch=s',
29 'sym=s',
30 'config=s',
31);
32
33foreach 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
40foreach my $defs_file (@ARGV) {
41 if (!-f $defs_file) {
42 warn "$defs_file: $!\n";
43 Getopt::Long::HelpMessage('-exit' => 1);
44 }
45}
46
47open CONFIG_FILE, $opts{config} or
48 die "Error opening config file '$opts{config}': $!\n";
49
50my %config = ();
51while (<CONFIG_FILE>) {
Johann8645a532014-09-10 10:27:58 -070052 next if !/^(?:CONFIG_|HAVE_)/;
James Zern805078a2014-02-23 16:33:14 -080053 chomp;
James Zern2b3496f2017-02-13 18:52:09 -080054 s/\r$//;
James Zern805078a2014-02-23 16:33:14 -080055 my @pair = split /=/;
56 $config{$pair[0]} = $pair[1];
57}
58close CONFIG_FILE;
59
60#
61# Routines for the RTCD DSL to call
62#
Yaowu Xuf883b422016-08-30 14:01:10 -070063sub aom_config($) {
James Zern805078a2014-02-23 16:33:14 -080064 return (defined $config{$_[0]}) ? $config{$_[0]} : "";
65}
66
67sub specialize {
68 my $fn=$_[0];
69 shift;
70 foreach my $opt (@_) {
71 eval "\$${fn}_${opt}=${fn}_${opt}";
72 }
73}
74
75sub add_proto {
76 my $fn = splice(@_, -2, 1);
77 $ALL_FUNCS{$fn} = \@_;
78 specialize $fn, "c";
79}
80
81sub require {
82 foreach my $fn (keys %ALL_FUNCS) {
83 foreach my $opt (@_) {
84 my $ofn = eval "\$${fn}_${opt}";
85 next if !$ofn;
86
87 # if we already have a default, then we can disable it, as we know
88 # we can do better.
89 my $best = eval "\$${fn}_default";
90 if ($best) {
91 my $best_ofn = eval "\$${best}";
92 if ($best_ofn && "$best_ofn" ne "$ofn") {
93 eval "\$${best}_link = 'false'";
94 }
95 }
96 eval "\$${fn}_default=${fn}_${opt}";
97 eval "\$${fn}_${opt}_link='true'";
98 }
99 }
100}
101
102sub forward_decls {
103 push @ALL_FORWARD_DECLS, @_;
104}
105
106#
107# Include the user's directives
108#
109foreach my $f (@ARGV) {
110 open FILE, "<", $f or die "cannot open $f: $!\n";
111 my $contents = join('', <FILE>);
112 close FILE;
113 eval $contents or warn "eval failed: $@\n";
114}
115
116#
117# Process the directives according to the command line
118#
119sub process_forward_decls() {
120 foreach (@ALL_FORWARD_DECLS) {
121 $_->();
122 }
123}
124
125sub determine_indirection {
Yaowu Xuf883b422016-08-30 14:01:10 -0700126 aom_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
James Zern805078a2014-02-23 16:33:14 -0800127 foreach my $fn (keys %ALL_FUNCS) {
128 my $n = "";
129 my @val = @{$ALL_FUNCS{$fn}};
130 my $args = pop @val;
131 my $rtyp = "@val";
132 my $dfn = eval "\$${fn}_default";
133 $dfn = eval "\$${dfn}";
134 foreach my $opt (@_) {
135 my $ofn = eval "\$${fn}_${opt}";
136 next if !$ofn;
137 my $link = eval "\$${fn}_${opt}_link";
138 next if $link && $link eq "false";
139 $n .= "x";
140 }
141 if ($n eq "x") {
142 eval "\$${fn}_indirect = 'false'";
143 } else {
144 eval "\$${fn}_indirect = 'true'";
145 }
146 }
147}
148
149sub declare_function_pointers {
150 foreach my $fn (sort keys %ALL_FUNCS) {
151 my @val = @{$ALL_FUNCS{$fn}};
152 my $args = pop @val;
153 my $rtyp = "@val";
154 my $dfn = eval "\$${fn}_default";
155 $dfn = eval "\$${dfn}";
156 foreach my $opt (@_) {
157 my $ofn = eval "\$${fn}_${opt}";
158 next if !$ofn;
159 print "$rtyp ${ofn}($args);\n";
160 }
161 if (eval "\$${fn}_indirect" eq "false") {
162 print "#define ${fn} ${dfn}\n";
163 } else {
164 print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
165 }
166 print "\n";
167 }
168}
169
170sub set_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 if (eval "\$${fn}_indirect" eq "true") {
178 print " $fn = $dfn;\n";
179 foreach my $opt (@_) {
180 my $ofn = eval "\$${fn}_${opt}";
181 next if !$ofn;
182 next if "$ofn" eq "$dfn";
183 my $link = eval "\$${fn}_${opt}_link";
184 next if $link && $link eq "false";
185 my $cond = eval "\$have_${opt}";
186 print " if (${cond}) $fn = $ofn;\n"
187 }
188 }
189 }
190}
191
192sub filter {
193 my @filtered;
194 foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
195 return @filtered;
196}
197
198#
199# Helper functions for generating the arch specific RTCD files
200#
201sub common_top() {
202 my $include_guard = uc($opts{sym})."_H_";
203 print <<EOF;
204#ifndef ${include_guard}
205#define ${include_guard}
206
207#ifdef RTCD_C
208#define RTCD_EXTERN
209#else
210#define RTCD_EXTERN extern
211#endif
212
James Zern9d3fb752014-09-18 19:43:19 -0700213EOF
214
215process_forward_decls();
216print <<EOF;
217
James Zern805078a2014-02-23 16:33:14 -0800218#ifdef __cplusplus
219extern "C" {
220#endif
221
222EOF
James Zern805078a2014-02-23 16:33:14 -0800223declare_function_pointers("c", @ALL_ARCHS);
224
225print <<EOF;
226void $opts{sym}(void);
227
228EOF
229}
230
231sub common_bottom() {
232 print <<EOF;
233
234#ifdef __cplusplus
235} // extern "C"
236#endif
237
238#endif
239EOF
240}
241
242sub x86() {
243 determine_indirection("c", @ALL_ARCHS);
244
245 # Assign the helper variable for each enabled extension
246 foreach my $opt (@ALL_ARCHS) {
247 my $opt_uc = uc $opt;
248 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
249 }
250
251 common_top;
252 print <<EOF;
253#ifdef RTCD_C
Yaowu Xuc27fc142016-08-22 16:08:15 -0700254#include "aom_ports/x86.h"
James Zern805078a2014-02-23 16:33:14 -0800255static void setup_rtcd_internal(void)
256{
257 int flags = x86_simd_caps();
258
259 (void)flags;
260
261EOF
262
263 set_function_pointers("c", @ALL_ARCHS);
264
265 print <<EOF;
266}
267#endif
268EOF
269 common_bottom;
270}
271
272sub arm() {
273 determine_indirection("c", @ALL_ARCHS);
274
275 # Assign the helper variable for each enabled extension
276 foreach my $opt (@ALL_ARCHS) {
277 my $opt_uc = uc $opt;
Johannce239312014-05-07 11:01:31 -0700278 # Enable neon assembly based on HAVE_NEON logic instead of adding new
279 # HAVE_NEON_ASM logic
280 if ($opt eq 'neon_asm') { $opt_uc = 'NEON' }
James Zern805078a2014-02-23 16:33:14 -0800281 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
282 }
283
284 common_top;
285 print <<EOF;
Yaowu Xuf883b422016-08-30 14:01:10 -0700286#include "aom_config.h"
James Zern805078a2014-02-23 16:33:14 -0800287
288#ifdef RTCD_C
Yaowu Xuc27fc142016-08-22 16:08:15 -0700289#include "aom_ports/arm.h"
James Zern805078a2014-02-23 16:33:14 -0800290static void setup_rtcd_internal(void)
291{
292 int flags = arm_cpu_caps();
293
294 (void)flags;
295
296EOF
297
298 set_function_pointers("c", @ALL_ARCHS);
299
300 print <<EOF;
301}
302#endif
303EOF
304 common_bottom;
305}
306
307sub mips() {
308 determine_indirection("c", @ALL_ARCHS);
309 common_top;
310
311 print <<EOF;
Yaowu Xuf883b422016-08-30 14:01:10 -0700312#include "aom_config.h"
James Zern805078a2014-02-23 16:33:14 -0800313
314#ifdef RTCD_C
315static void setup_rtcd_internal(void)
316{
317EOF
318
319 set_function_pointers("c", @ALL_ARCHS);
320
321 print <<EOF;
322#if HAVE_DSPR2
Yaowu Xuf883b422016-08-30 14:01:10 -0700323void aom_dsputil_static_init();
324aom_dsputil_static_init();
James Zern805078a2014-02-23 16:33:14 -0800325#endif
326}
327#endif
328EOF
329 common_bottom;
330}
331
332sub unoptimized() {
333 determine_indirection "c";
334 common_top;
335 print <<EOF;
Yaowu Xuf883b422016-08-30 14:01:10 -0700336#include "aom_config.h"
James Zern805078a2014-02-23 16:33:14 -0800337
338#ifdef RTCD_C
339static void setup_rtcd_internal(void)
340{
341EOF
342
343 set_function_pointers "c";
344
345 print <<EOF;
346}
347#endif
348EOF
349 common_bottom;
350}
351
352#
353# Main Driver
354#
355
356&require("c");
357if ($opts{arch} eq 'x86') {
358 @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
359 x86;
360} elsif ($opts{arch} eq 'x86_64') {
361 @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
362 @REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/);
363 &require(@REQUIRES);
364 x86;
Gordana Cmiljanovic1c31e3e2014-08-07 19:09:47 +0200365} elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
366 @ALL_ARCHS = filter("$opts{arch}");
James Zern805078a2014-02-23 16:33:14 -0800367 open CONFIG_FILE, $opts{config} or
368 die "Error opening config file '$opts{config}': $!\n";
369 while (<CONFIG_FILE>) {
370 if (/HAVE_DSPR2=yes/) {
Gordana Cmiljanovic1c31e3e2014-08-07 19:09:47 +0200371 @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
James Zern805078a2014-02-23 16:33:14 -0800372 last;
373 }
Parag Salasakar84ec68d2015-03-16 12:36:59 +0530374 if (/HAVE_MSA=yes/) {
375 @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
376 last;
377 }
James Zern805078a2014-02-23 16:33:14 -0800378 }
379 close CONFIG_FILE;
380 mips;
James Zern805078a2014-02-23 16:33:14 -0800381} elsif ($opts{arch} eq 'armv6') {
Johann6eec73a2014-07-31 14:19:31 -0700382 @ALL_ARCHS = filter(qw/media/);
James Zern805078a2014-02-23 16:33:14 -0800383 arm;
James Zern6ea881c2014-12-15 18:39:51 -0800384} elsif ($opts{arch} =~ /armv7\w?/) {
Johann6eec73a2014-07-31 14:19:31 -0700385 @ALL_ARCHS = filter(qw/media neon_asm neon/);
Johann24fbfa42014-07-29 11:28:23 -0700386 @REQUIRES = filter(keys %required ? keys %required : qw/media/);
387 &require(@REQUIRES);
Johannce239312014-05-07 11:01:31 -0700388 arm;
Tom Fineganc47e4202014-09-19 10:45:15 -0700389} elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) {
Johannce239312014-05-07 11:01:31 -0700390 @ALL_ARCHS = filter(qw/neon/);
James Zern805078a2014-02-23 16:33:14 -0800391 arm;
392} else {
393 unoptimized;
394}
395
396__END__
397
398=head1 NAME
399
400rtcd -
401
402=head1 SYNOPSIS
403
404Usage: rtcd.pl [options] FILE
405
406See 'perldoc rtcd.pl' for more details.
407
408=head1 DESCRIPTION
409
410Reads the Run Time CPU Detections definitions from FILE and generates a
411C header file on stdout.
412
413=head1 OPTIONS
414
415Options:
416 --arch=ARCH Architecture to generate defs for (required)
417 --disable-EXT Disable support for EXT extensions
418 --require-EXT Require support for EXT extensions
419 --sym=SYMBOL Unique symbol to use for RTCD initialization function
420 --config=FILE File with CONFIG_FOO=yes lines to parse