OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env perl |
| 2 |
| 3 no strict 'refs'; |
| 4 use warnings; |
| 5 use Getopt::Long; |
| 6 Getopt::Long::Configure("auto_help"); |
| 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 eval "\$have_${opt}=\"flags & HAS_${opt_uc}\""; |
| 276 } |
| 277 |
| 278 common_top; |
| 279 print <<EOF; |
| 280 #include "vpx_config.h" |
| 281 |
| 282 #ifdef RTCD_C |
| 283 #include "vpx_ports/arm.h" |
| 284 static void setup_rtcd_internal(void) |
| 285 { |
| 286 int flags = arm_cpu_caps(); |
| 287 |
| 288 (void)flags; |
| 289 |
| 290 EOF |
| 291 |
| 292 set_function_pointers("c", @ALL_ARCHS); |
| 293 |
| 294 print <<EOF; |
| 295 } |
| 296 #endif |
| 297 EOF |
| 298 common_bottom; |
| 299 } |
| 300 |
| 301 sub mips() { |
| 302 determine_indirection("c", @ALL_ARCHS); |
| 303 common_top; |
| 304 |
| 305 print <<EOF; |
| 306 #include "vpx_config.h" |
| 307 |
| 308 #ifdef RTCD_C |
| 309 static void setup_rtcd_internal(void) |
| 310 { |
| 311 EOF |
| 312 |
| 313 set_function_pointers("c", @ALL_ARCHS); |
| 314 |
| 315 print <<EOF; |
| 316 #if HAVE_DSPR2 |
| 317 #if CONFIG_VP8 |
| 318 void dsputil_static_init(); |
| 319 dsputil_static_init(); |
| 320 #endif |
| 321 #if CONFIG_VP9 |
| 322 void vp9_dsputil_static_init(); |
| 323 vp9_dsputil_static_init(); |
| 324 #endif |
| 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; |
| 336 #include "vpx_config.h" |
| 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; |
| 365 } elsif ($opts{arch} eq 'mips32') { |
| 366 @ALL_ARCHS = filter(qw/mips32/); |
| 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/) { |
| 371 @ALL_ARCHS = filter(qw/mips32 dspr2/); |
| 372 last; |
| 373 } |
| 374 } |
| 375 close CONFIG_FILE; |
| 376 mips; |
| 377 } elsif ($opts{arch} eq 'armv5te') { |
| 378 @ALL_ARCHS = filter(qw/edsp/); |
| 379 arm; |
| 380 } elsif ($opts{arch} eq 'armv6') { |
| 381 @ALL_ARCHS = filter(qw/edsp media/); |
| 382 arm; |
| 383 } elsif ($opts{arch} eq 'armv7') { |
| 384 @ALL_ARCHS = filter(qw/edsp media neon/); |
| 385 arm; |
| 386 } else { |
| 387 unoptimized; |
| 388 } |
| 389 |
| 390 __END__ |
| 391 |
| 392 =head1 NAME |
| 393 |
| 394 rtcd - |
| 395 |
| 396 =head1 SYNOPSIS |
| 397 |
| 398 Usage: rtcd.pl [options] FILE |
| 399 |
| 400 See 'perldoc rtcd.pl' for more details. |
| 401 |
| 402 =head1 DESCRIPTION |
| 403 |
| 404 Reads the Run Time CPU Detections definitions from FILE and generates a |
| 405 C header file on stdout. |
| 406 |
| 407 =head1 OPTIONS |
| 408 |
| 409 Options: |
| 410 --arch=ARCH Architecture to generate defs for (required) |
| 411 --disable-EXT Disable support for EXT extensions |
| 412 --require-EXT Require support for EXT extensions |
| 413 --sym=SYMBOL Unique symbol to use for RTCD initialization function |
| 414 --config=FILE File with CONFIG_FOO=yes lines to parse |
OLD | NEW |