James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 1 | #!/usr/bin/env perl |
| 2 | |
| 3 | no strict 'refs'; |
| 4 | use warnings; |
| 5 | use Getopt::Long; |
James Zern | 2994351 | 2014-07-24 14:55:19 -0700 | [diff] [blame] | 6 | Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 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>) { |
Johann | 8645a53 | 2014-09-10 10:27:58 -0700 | [diff] [blame] | 52 | next if !/^(?:CONFIG_|HAVE_)/; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 53 | chomp; |
James Zern | 2b3496f | 2017-02-13 18:52:09 -0800 | [diff] [blame] | 54 | s/\r$//; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 55 | my @pair = split /=/; |
| 56 | $config{$pair[0]} = $pair[1]; |
| 57 | } |
| 58 | close CONFIG_FILE; |
| 59 | |
| 60 | # |
| 61 | # Routines for the RTCD DSL to call |
| 62 | # |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 63 | sub aom_config($) { |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 64 | return (defined $config{$_[0]}) ? $config{$_[0]} : ""; |
| 65 | } |
| 66 | |
| 67 | sub specialize { |
| 68 | my $fn=$_[0]; |
| 69 | shift; |
| 70 | foreach my $opt (@_) { |
| 71 | eval "\$${fn}_${opt}=${fn}_${opt}"; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | sub add_proto { |
| 76 | my $fn = splice(@_, -2, 1); |
| 77 | $ALL_FUNCS{$fn} = \@_; |
| 78 | specialize $fn, "c"; |
| 79 | } |
| 80 | |
| 81 | sub 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 | |
| 102 | sub forward_decls { |
| 103 | push @ALL_FORWARD_DECLS, @_; |
| 104 | } |
| 105 | |
| 106 | # |
| 107 | # Include the user's directives |
| 108 | # |
| 109 | foreach 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 | # |
| 119 | sub process_forward_decls() { |
| 120 | foreach (@ALL_FORWARD_DECLS) { |
| 121 | $_->(); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | sub determine_indirection { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 126 | aom_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 127 | 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 | |
| 149 | sub 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 | |
| 170 | sub 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 | |
| 192 | sub 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 | # |
| 201 | sub 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 Zern | 9d3fb75 | 2014-09-18 19:43:19 -0700 | [diff] [blame] | 213 | EOF |
| 214 | |
| 215 | process_forward_decls(); |
| 216 | print <<EOF; |
| 217 | |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 218 | #ifdef __cplusplus |
| 219 | extern "C" { |
| 220 | #endif |
| 221 | |
| 222 | EOF |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 223 | declare_function_pointers("c", @ALL_ARCHS); |
| 224 | |
| 225 | print <<EOF; |
| 226 | void $opts{sym}(void); |
| 227 | |
| 228 | EOF |
| 229 | } |
| 230 | |
| 231 | sub common_bottom() { |
| 232 | print <<EOF; |
| 233 | |
| 234 | #ifdef __cplusplus |
| 235 | } // extern "C" |
| 236 | #endif |
| 237 | |
| 238 | #endif |
| 239 | EOF |
| 240 | } |
| 241 | |
| 242 | sub 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 Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 254 | #include "aom_ports/x86.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 255 | static void setup_rtcd_internal(void) |
| 256 | { |
| 257 | int flags = x86_simd_caps(); |
| 258 | |
| 259 | (void)flags; |
| 260 | |
| 261 | EOF |
| 262 | |
| 263 | set_function_pointers("c", @ALL_ARCHS); |
| 264 | |
| 265 | print <<EOF; |
| 266 | } |
| 267 | #endif |
| 268 | EOF |
| 269 | common_bottom; |
| 270 | } |
| 271 | |
| 272 | sub 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; |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 278 | # 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 Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 281 | eval "\$have_${opt}=\"flags & HAS_${opt_uc}\""; |
| 282 | } |
| 283 | |
| 284 | common_top; |
| 285 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 286 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 287 | |
| 288 | #ifdef RTCD_C |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 289 | #include "aom_ports/arm.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 290 | static void setup_rtcd_internal(void) |
| 291 | { |
| 292 | int flags = arm_cpu_caps(); |
| 293 | |
| 294 | (void)flags; |
| 295 | |
| 296 | EOF |
| 297 | |
| 298 | set_function_pointers("c", @ALL_ARCHS); |
| 299 | |
| 300 | print <<EOF; |
| 301 | } |
| 302 | #endif |
| 303 | EOF |
| 304 | common_bottom; |
| 305 | } |
| 306 | |
| 307 | sub mips() { |
| 308 | determine_indirection("c", @ALL_ARCHS); |
| 309 | common_top; |
| 310 | |
| 311 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 312 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 313 | |
| 314 | #ifdef RTCD_C |
| 315 | static void setup_rtcd_internal(void) |
| 316 | { |
| 317 | EOF |
| 318 | |
| 319 | set_function_pointers("c", @ALL_ARCHS); |
| 320 | |
| 321 | print <<EOF; |
| 322 | #if HAVE_DSPR2 |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 323 | void aom_dsputil_static_init(); |
| 324 | aom_dsputil_static_init(); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 325 | #endif |
| 326 | } |
| 327 | #endif |
| 328 | EOF |
| 329 | common_bottom; |
| 330 | } |
| 331 | |
| 332 | sub unoptimized() { |
| 333 | determine_indirection "c"; |
| 334 | common_top; |
| 335 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 336 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 337 | |
| 338 | #ifdef RTCD_C |
| 339 | static void setup_rtcd_internal(void) |
| 340 | { |
| 341 | EOF |
| 342 | |
| 343 | set_function_pointers "c"; |
| 344 | |
| 345 | print <<EOF; |
| 346 | } |
| 347 | #endif |
| 348 | EOF |
| 349 | common_bottom; |
| 350 | } |
| 351 | |
| 352 | # |
| 353 | # Main Driver |
| 354 | # |
| 355 | |
| 356 | &require("c"); |
| 357 | if ($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 Cmiljanovic | 1c31e3e | 2014-08-07 19:09:47 +0200 | [diff] [blame] | 365 | } elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') { |
| 366 | @ALL_ARCHS = filter("$opts{arch}"); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 367 | 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 Cmiljanovic | 1c31e3e | 2014-08-07 19:09:47 +0200 | [diff] [blame] | 371 | @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 372 | last; |
| 373 | } |
Parag Salasakar | 84ec68d | 2015-03-16 12:36:59 +0530 | [diff] [blame] | 374 | if (/HAVE_MSA=yes/) { |
| 375 | @ALL_ARCHS = filter("$opts{arch}", qw/msa/); |
| 376 | last; |
| 377 | } |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 378 | } |
| 379 | close CONFIG_FILE; |
| 380 | mips; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 381 | } elsif ($opts{arch} eq 'armv6') { |
Johann | 6eec73a | 2014-07-31 14:19:31 -0700 | [diff] [blame] | 382 | @ALL_ARCHS = filter(qw/media/); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 383 | arm; |
James Zern | 6ea881c | 2014-12-15 18:39:51 -0800 | [diff] [blame] | 384 | } elsif ($opts{arch} =~ /armv7\w?/) { |
Johann | 6eec73a | 2014-07-31 14:19:31 -0700 | [diff] [blame] | 385 | @ALL_ARCHS = filter(qw/media neon_asm neon/); |
Johann | 24fbfa4 | 2014-07-29 11:28:23 -0700 | [diff] [blame] | 386 | @REQUIRES = filter(keys %required ? keys %required : qw/media/); |
| 387 | &require(@REQUIRES); |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 388 | arm; |
Tom Finegan | c47e420 | 2014-09-19 10:45:15 -0700 | [diff] [blame] | 389 | } elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) { |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 390 | @ALL_ARCHS = filter(qw/neon/); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 391 | arm; |
| 392 | } else { |
| 393 | unoptimized; |
| 394 | } |
| 395 | |
| 396 | __END__ |
| 397 | |
| 398 | =head1 NAME |
| 399 | |
| 400 | rtcd - |
| 401 | |
| 402 | =head1 SYNOPSIS |
| 403 | |
| 404 | Usage: rtcd.pl [options] FILE |
| 405 | |
| 406 | See 'perldoc rtcd.pl' for more details. |
| 407 | |
| 408 | =head1 DESCRIPTION |
| 409 | |
| 410 | Reads the Run Time CPU Detections definitions from FILE and generates a |
| 411 | C header file on stdout. |
| 412 | |
| 413 | =head1 OPTIONS |
| 414 | |
| 415 | Options: |
| 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 |