James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 1 | #!/usr/bin/env perl |
Johann | aecbba6 | 2017-12-15 09:03:23 -0800 | [diff] [blame] | 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. |
| 11 | ## |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 12 | no strict 'refs'; |
| 13 | use warnings; |
| 14 | use Getopt::Long; |
James Zern | 2994351 | 2014-07-24 14:55:19 -0700 | [diff] [blame] | 15 | Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 16 | |
| 17 | my %ALL_FUNCS = (); |
| 18 | my @ALL_ARCHS; |
| 19 | my @ALL_FORWARD_DECLS; |
| 20 | my @REQUIRES; |
| 21 | |
| 22 | my %opts = (); |
| 23 | my %disabled = (); |
| 24 | my %required = (); |
| 25 | |
| 26 | my @argv; |
| 27 | foreach (@ARGV) { |
| 28 | $disabled{$1} = 1, next if /--disable-(.*)/; |
| 29 | $required{$1} = 1, next if /--require-(.*)/; |
| 30 | push @argv, $_; |
| 31 | } |
| 32 | |
| 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', |
| 40 | ); |
| 41 | |
| 42 | foreach my $opt (qw/arch config/) { |
| 43 | if (!defined($opts{$opt})) { |
| 44 | warn "--$opt is required!\n"; |
| 45 | Getopt::Long::HelpMessage('-exit' => 1); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | foreach my $defs_file (@ARGV) { |
| 50 | if (!-f $defs_file) { |
| 51 | warn "$defs_file: $!\n"; |
| 52 | Getopt::Long::HelpMessage('-exit' => 1); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | open CONFIG_FILE, $opts{config} or |
| 57 | die "Error opening config file '$opts{config}': $!\n"; |
| 58 | |
| 59 | my %config = (); |
| 60 | while (<CONFIG_FILE>) { |
Johann | 8645a53 | 2014-09-10 10:27:58 -0700 | [diff] [blame] | 61 | next if !/^(?:CONFIG_|HAVE_)/; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 62 | chomp; |
James Zern | 2b3496f | 2017-02-13 18:52:09 -0800 | [diff] [blame] | 63 | s/\r$//; |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 64 | my @pair = split /=/; |
| 65 | $config{$pair[0]} = $pair[1]; |
| 66 | } |
| 67 | close CONFIG_FILE; |
| 68 | |
| 69 | # |
| 70 | # Routines for the RTCD DSL to call |
| 71 | # |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 72 | sub aom_config($) { |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 73 | return (defined $config{$_[0]}) ? $config{$_[0]} : ""; |
| 74 | } |
| 75 | |
| 76 | sub specialize { |
Urvang Joshi | 5ddac0a | 2017-03-30 14:44:48 -0700 | [diff] [blame] | 77 | if (@_ <= 1) { |
| 78 | die "'specialize' must be called with a function name and at least one ", |
| 79 | "architecture ('C' is implied): \n@_\n"; |
| 80 | } |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 81 | my $fn=$_[0]; |
| 82 | shift; |
| 83 | foreach my $opt (@_) { |
| 84 | eval "\$${fn}_${opt}=${fn}_${opt}"; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | sub add_proto { |
| 89 | my $fn = splice(@_, -2, 1); |
| 90 | $ALL_FUNCS{$fn} = \@_; |
| 91 | specialize $fn, "c"; |
| 92 | } |
| 93 | |
| 94 | sub require { |
| 95 | foreach my $fn (keys %ALL_FUNCS) { |
| 96 | foreach my $opt (@_) { |
| 97 | my $ofn = eval "\$${fn}_${opt}"; |
| 98 | next if !$ofn; |
| 99 | |
| 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'"; |
| 107 | } |
| 108 | } |
| 109 | eval "\$${fn}_default=${fn}_${opt}"; |
| 110 | eval "\$${fn}_${opt}_link='true'"; |
| 111 | } |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | sub forward_decls { |
| 116 | push @ALL_FORWARD_DECLS, @_; |
| 117 | } |
| 118 | |
| 119 | # |
| 120 | # Include the user's directives |
| 121 | # |
| 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"; |
| 127 | } |
| 128 | |
| 129 | # |
| 130 | # Process the directives according to the command line |
| 131 | # |
| 132 | sub process_forward_decls() { |
| 133 | foreach (@ALL_FORWARD_DECLS) { |
| 134 | $_->(); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | sub determine_indirection { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 139 | aom_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 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"; |
| 153 | } |
| 154 | if ($n eq "x") { |
| 155 | eval "\$${fn}_indirect = 'false'"; |
| 156 | } else { |
| 157 | eval "\$${fn}_indirect = 'true'"; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | |
| 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"; |
| 173 | } |
| 174 | if (eval "\$${fn}_indirect" eq "false") { |
| 175 | print "#define ${fn} ${dfn}\n"; |
| 176 | } else { |
| 177 | print "RTCD_EXTERN $rtyp (*${fn})($args);\n"; |
| 178 | } |
| 179 | print "\n"; |
| 180 | } |
| 181 | } |
| 182 | |
| 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" |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | sub filter { |
| 206 | my @filtered; |
| 207 | foreach (@_) { push @filtered, $_ unless $disabled{$_}; } |
| 208 | return @filtered; |
| 209 | } |
| 210 | |
| 211 | # |
| 212 | # Helper functions for generating the arch specific RTCD files |
| 213 | # |
| 214 | sub common_top() { |
| 215 | my $include_guard = uc($opts{sym})."_H_"; |
| 216 | print <<EOF; |
Johann | 368c51a | 2017-12-15 09:08:41 -0800 | [diff] [blame] | 217 | // This file is generated. Do not edit. |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 218 | #ifndef ${include_guard} |
| 219 | #define ${include_guard} |
| 220 | |
| 221 | #ifdef RTCD_C |
| 222 | #define RTCD_EXTERN |
| 223 | #else |
| 224 | #define RTCD_EXTERN extern |
| 225 | #endif |
| 226 | |
James Zern | 9d3fb75 | 2014-09-18 19:43:19 -0700 | [diff] [blame] | 227 | EOF |
| 228 | |
| 229 | process_forward_decls(); |
| 230 | print <<EOF; |
| 231 | |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 232 | #ifdef __cplusplus |
| 233 | extern "C" { |
| 234 | #endif |
| 235 | |
| 236 | EOF |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 237 | declare_function_pointers("c", @ALL_ARCHS); |
| 238 | |
| 239 | print <<EOF; |
| 240 | void $opts{sym}(void); |
| 241 | |
| 242 | EOF |
| 243 | } |
| 244 | |
| 245 | sub common_bottom() { |
| 246 | print <<EOF; |
| 247 | |
| 248 | #ifdef __cplusplus |
| 249 | } // extern "C" |
| 250 | #endif |
| 251 | |
| 252 | #endif |
| 253 | EOF |
| 254 | } |
| 255 | |
| 256 | sub x86() { |
| 257 | determine_indirection("c", @ALL_ARCHS); |
| 258 | |
| 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}\""; |
| 263 | } |
| 264 | |
| 265 | common_top; |
| 266 | print <<EOF; |
| 267 | #ifdef RTCD_C |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 268 | #include "aom_ports/x86.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 269 | static void setup_rtcd_internal(void) |
| 270 | { |
| 271 | int flags = x86_simd_caps(); |
| 272 | |
| 273 | (void)flags; |
| 274 | |
| 275 | EOF |
| 276 | |
| 277 | set_function_pointers("c", @ALL_ARCHS); |
| 278 | |
| 279 | print <<EOF; |
| 280 | } |
| 281 | #endif |
| 282 | EOF |
| 283 | common_bottom; |
| 284 | } |
| 285 | |
| 286 | sub arm() { |
| 287 | determine_indirection("c", @ALL_ARCHS); |
| 288 | |
| 289 | # Assign the helper variable for each enabled extension |
| 290 | foreach my $opt (@ALL_ARCHS) { |
| 291 | my $opt_uc = uc $opt; |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 292 | # Enable neon assembly based on HAVE_NEON logic instead of adding new |
| 293 | # HAVE_NEON_ASM logic |
| 294 | if ($opt eq 'neon_asm') { $opt_uc = 'NEON' } |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 295 | eval "\$have_${opt}=\"flags & HAS_${opt_uc}\""; |
| 296 | } |
| 297 | |
| 298 | common_top; |
| 299 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 300 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 301 | |
| 302 | #ifdef RTCD_C |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 303 | #include "aom_ports/arm.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 304 | static void setup_rtcd_internal(void) |
| 305 | { |
| 306 | int flags = arm_cpu_caps(); |
| 307 | |
| 308 | (void)flags; |
| 309 | |
| 310 | EOF |
| 311 | |
| 312 | set_function_pointers("c", @ALL_ARCHS); |
| 313 | |
| 314 | print <<EOF; |
| 315 | } |
| 316 | #endif |
| 317 | EOF |
| 318 | common_bottom; |
| 319 | } |
| 320 | |
| 321 | sub mips() { |
| 322 | determine_indirection("c", @ALL_ARCHS); |
| 323 | common_top; |
| 324 | |
| 325 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 326 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 327 | |
| 328 | #ifdef RTCD_C |
| 329 | static void setup_rtcd_internal(void) |
| 330 | { |
| 331 | EOF |
| 332 | |
| 333 | set_function_pointers("c", @ALL_ARCHS); |
| 334 | |
| 335 | print <<EOF; |
| 336 | #if HAVE_DSPR2 |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 337 | void aom_dsputil_static_init(); |
| 338 | aom_dsputil_static_init(); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 339 | #endif |
| 340 | } |
| 341 | #endif |
| 342 | EOF |
| 343 | common_bottom; |
| 344 | } |
| 345 | |
| 346 | sub unoptimized() { |
| 347 | determine_indirection "c"; |
| 348 | common_top; |
| 349 | print <<EOF; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 350 | #include "aom_config.h" |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 351 | |
| 352 | #ifdef RTCD_C |
| 353 | static void setup_rtcd_internal(void) |
| 354 | { |
| 355 | EOF |
| 356 | |
| 357 | set_function_pointers "c"; |
| 358 | |
| 359 | print <<EOF; |
| 360 | } |
| 361 | #endif |
| 362 | EOF |
| 363 | common_bottom; |
| 364 | } |
| 365 | |
| 366 | # |
| 367 | # Main Driver |
| 368 | # |
| 369 | |
| 370 | &require("c"); |
| 371 | if ($opts{arch} eq 'x86') { |
| 372 | @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/); |
| 373 | x86; |
| 374 | } elsif ($opts{arch} eq 'x86_64') { |
| 375 | @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/); |
| 376 | @REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/); |
| 377 | &require(@REQUIRES); |
| 378 | x86; |
Gordana Cmiljanovic | 1c31e3e | 2014-08-07 19:09:47 +0200 | [diff] [blame] | 379 | } elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') { |
| 380 | @ALL_ARCHS = filter("$opts{arch}"); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 381 | open CONFIG_FILE, $opts{config} or |
| 382 | die "Error opening config file '$opts{config}': $!\n"; |
| 383 | while (<CONFIG_FILE>) { |
| 384 | if (/HAVE_DSPR2=yes/) { |
Gordana Cmiljanovic | 1c31e3e | 2014-08-07 19:09:47 +0200 | [diff] [blame] | 385 | @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 386 | last; |
| 387 | } |
Parag Salasakar | 84ec68d | 2015-03-16 12:36:59 +0530 | [diff] [blame] | 388 | if (/HAVE_MSA=yes/) { |
| 389 | @ALL_ARCHS = filter("$opts{arch}", qw/msa/); |
| 390 | last; |
| 391 | } |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 392 | } |
| 393 | close CONFIG_FILE; |
| 394 | mips; |
James Zern | 6ea881c | 2014-12-15 18:39:51 -0800 | [diff] [blame] | 395 | } elsif ($opts{arch} =~ /armv7\w?/) { |
Ralph Giles | be111b3 | 2017-05-12 16:44:45 -0700 | [diff] [blame] | 396 | @ALL_ARCHS = filter(qw/neon_asm neon/); |
Johann | 24fbfa4 | 2014-07-29 11:28:23 -0700 | [diff] [blame] | 397 | &require(@REQUIRES); |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 398 | arm; |
Tom Finegan | c47e420 | 2014-09-19 10:45:15 -0700 | [diff] [blame] | 399 | } elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) { |
Johann | ce23931 | 2014-05-07 11:01:31 -0700 | [diff] [blame] | 400 | @ALL_ARCHS = filter(qw/neon/); |
James Zern | 805078a | 2014-02-23 16:33:14 -0800 | [diff] [blame] | 401 | arm; |
| 402 | } else { |
| 403 | unoptimized; |
| 404 | } |
| 405 | |
| 406 | __END__ |
| 407 | |
| 408 | =head1 NAME |
| 409 | |
| 410 | rtcd - |
| 411 | |
| 412 | =head1 SYNOPSIS |
| 413 | |
| 414 | Usage: rtcd.pl [options] FILE |
| 415 | |
| 416 | See 'perldoc rtcd.pl' for more details. |
| 417 | |
| 418 | =head1 DESCRIPTION |
| 419 | |
| 420 | Reads the Run Time CPU Detections definitions from FILE and generates a |
| 421 | C header file on stdout. |
| 422 | |
| 423 | =head1 OPTIONS |
| 424 | |
| 425 | Options: |
| 426 | --arch=ARCH Architecture to generate defs for (required) |
| 427 | --disable-EXT Disable support for EXT extensions |
| 428 | --require-EXT Require support for EXT extensions |
| 429 | --sym=SYMBOL Unique symbol to use for RTCD initialization function |
| 430 | --config=FILE File with CONFIG_FOO=yes lines to parse |