rtcd.pl 9.2 KB

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