xref: /aosp_15_r20/external/libvpx/build/make/rtcd.pl (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
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
12no strict 'refs';
13use warnings;
14use Getopt::Long;
15Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
16
17my %ALL_FUNCS = ();
18my @ALL_ARCHS;
19my @ALL_FORWARD_DECLS;
20my @REQUIRES;
21
22my %opts = ();
23my %disabled = ();
24my %required = ();
25
26my @argv;
27foreach (@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;
35GetOptions(
36  \%opts,
37  'arch=s',
38  'sym=s',
39  'config=s',
40);
41
42foreach 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
49foreach my $defs_file (@ARGV) {
50  if (!-f $defs_file) {
51    warn "$defs_file: $!\n";
52    Getopt::Long::HelpMessage('-exit' => 1);
53  }
54}
55
56open CONFIG_FILE, $opts{config} or
57  die "Error opening config file '$opts{config}': $!\n";
58
59my %config = ();
60while (<CONFIG_FILE>) {
61  next if !/^(?:CONFIG_|HAVE_)/;
62  chomp;
63  my @pair = split /=/;
64  $config{$pair[0]} = $pair[1];
65}
66close CONFIG_FILE;
67
68#
69# Routines for the RTCD DSL to call
70#
71sub vpx_config($) {
72  return (defined $config{$_[0]}) ? $config{$_[0]} : "";
73}
74
75sub specialize {
76  if (@_ <= 1) {
77    die "'specialize' must be called with a function name and at least one ",
78        "architecture ('C' is implied): \n@_\n";
79  }
80  my $fn=$_[0];
81  shift;
82  foreach my $opt (@_) {
83    eval "\$${fn}_${opt}=${fn}_${opt}";
84  }
85}
86
87sub add_proto {
88  my $fn = splice(@_, -2, 1);
89  $ALL_FUNCS{$fn} = \@_;
90  specialize $fn, "c";
91}
92
93sub require {
94  foreach my $fn (keys %ALL_FUNCS) {
95    foreach my $opt (@_) {
96      my $ofn = eval "\$${fn}_${opt}";
97      next if !$ofn;
98
99      # if we already have a default, then we can disable it, as we know
100      # we can do better.
101      my $best = eval "\$${fn}_default";
102      if ($best) {
103        my $best_ofn = eval "\$${best}";
104        if ($best_ofn && "$best_ofn" ne "$ofn") {
105          eval "\$${best}_link = 'false'";
106        }
107      }
108      eval "\$${fn}_default=${fn}_${opt}";
109      eval "\$${fn}_${opt}_link='true'";
110    }
111  }
112}
113
114sub forward_decls {
115  push @ALL_FORWARD_DECLS, @_;
116}
117
118#
119# Include the user's directives
120#
121foreach my $f (@ARGV) {
122  open FILE, "<", $f or die "cannot open $f: $!\n";
123  my $contents = join('', <FILE>);
124  close FILE;
125  eval $contents or warn "eval failed: $@\n";
126}
127
128#
129# Process the directives according to the command line
130#
131sub process_forward_decls() {
132  foreach (@ALL_FORWARD_DECLS) {
133    $_->();
134  }
135}
136
137sub determine_indirection {
138  vpx_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
139  foreach my $fn (keys %ALL_FUNCS) {
140    my $n = "";
141    my @val = @{$ALL_FUNCS{$fn}};
142    my $args = pop @val;
143    my $rtyp = "@val";
144    my $dfn = eval "\$${fn}_default";
145    $dfn = eval "\$${dfn}";
146    foreach my $opt (@_) {
147      my $ofn = eval "\$${fn}_${opt}";
148      next if !$ofn;
149      my $link = eval "\$${fn}_${opt}_link";
150      next if $link && $link eq "false";
151      $n .= "x";
152    }
153    if ($n eq "x") {
154      eval "\$${fn}_indirect = 'false'";
155    } else {
156      eval "\$${fn}_indirect = 'true'";
157    }
158  }
159}
160
161sub declare_function_pointers {
162  foreach my $fn (sort keys %ALL_FUNCS) {
163    my @val = @{$ALL_FUNCS{$fn}};
164    my $args = pop @val;
165    my $rtyp = "@val";
166    my $dfn = eval "\$${fn}_default";
167    $dfn = eval "\$${dfn}";
168    foreach my $opt (@_) {
169      my $ofn = eval "\$${fn}_${opt}";
170      next if !$ofn;
171      print "$rtyp ${ofn}($args);\n";
172    }
173    if (eval "\$${fn}_indirect" eq "false") {
174      print "#define ${fn} ${dfn}\n";
175    } else {
176      print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
177    }
178    print "\n";
179  }
180}
181
182sub set_function_pointers {
183  foreach my $fn (sort keys %ALL_FUNCS) {
184    my @val = @{$ALL_FUNCS{$fn}};
185    my $args = pop @val;
186    my $rtyp = "@val";
187    my $dfn = eval "\$${fn}_default";
188    $dfn = eval "\$${dfn}";
189    if (eval "\$${fn}_indirect" eq "true") {
190      print "    $fn = $dfn;\n";
191      foreach my $opt (@_) {
192        my $ofn = eval "\$${fn}_${opt}";
193        next if !$ofn;
194        next if "$ofn" eq "$dfn";
195        my $link = eval "\$${fn}_${opt}_link";
196        next if $link && $link eq "false";
197        my $cond = eval "\$have_${opt}";
198        print "    if (${cond}) $fn = $ofn;\n"
199      }
200    }
201  }
202}
203
204sub filter {
205  my @filtered;
206  foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
207  return @filtered;
208}
209
210#
211# Helper functions for generating the arch specific RTCD files
212#
213sub common_top() {
214  my $include_guard = uc($opts{sym})."_H_";
215  my @time = localtime;
216  my $year = $time[5] + 1900;
217  print <<EOF;
218/*
219 *  Copyright (c) ${year} The WebM project authors. All Rights Reserved.
220 *
221 *  Use of this source code is governed by a BSD-style license
222 *  that can be found in the LICENSE file in the root of the source
223 *  tree. An additional intellectual property rights grant can be found
224 *  in the file PATENTS.  All contributing project authors may
225 *  be found in the AUTHORS file in the root of the source tree.
226 */
227
228// This file is generated. Do not edit.
229#ifndef ${include_guard}
230#define ${include_guard}
231
232#ifdef RTCD_C
233#define RTCD_EXTERN
234#else
235#define RTCD_EXTERN extern
236#endif
237
238EOF
239
240process_forward_decls();
241print <<EOF;
242
243#ifdef __cplusplus
244extern "C" {
245#endif
246
247EOF
248declare_function_pointers("c", @ALL_ARCHS);
249
250print <<EOF;
251void $opts{sym}(void);
252
253EOF
254}
255
256sub common_bottom() {
257  my $include_guard = uc($opts{sym})."_H_";
258  print <<EOF;
259
260#ifdef __cplusplus
261}  // extern "C"
262#endif
263
264#endif  // ${include_guard}
265EOF
266}
267
268sub x86() {
269  determine_indirection("c", @ALL_ARCHS);
270
271  # Assign the helper variable for each enabled extension
272  foreach my $opt (@ALL_ARCHS) {
273    my $opt_uc = uc $opt;
274    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
275  }
276
277  common_top;
278  print <<EOF;
279#ifdef RTCD_C
280#include "vpx_ports/x86.h"
281static void setup_rtcd_internal(void)
282{
283    int flags = x86_simd_caps();
284
285    (void)flags;
286
287EOF
288
289  set_function_pointers("c", @ALL_ARCHS);
290
291  print <<EOF;
292}
293#endif
294EOF
295  common_bottom;
296}
297
298sub arm() {
299  determine_indirection("c", @ALL_ARCHS);
300
301  # Assign the helper variable for each enabled extension
302  foreach my $opt (@ALL_ARCHS) {
303    my $opt_uc = uc $opt;
304    # Enable neon assembly based on HAVE_NEON logic instead of adding new
305    # HAVE_NEON_ASM logic
306    if ($opt eq 'neon_asm') { $opt_uc = 'NEON' }
307    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
308  }
309
310  common_top;
311  print <<EOF;
312#include "vpx_config.h"
313
314#ifdef RTCD_C
315#include "vpx_ports/arm.h"
316static void setup_rtcd_internal(void)
317{
318    int flags = arm_cpu_caps();
319
320    (void)flags;
321
322EOF
323
324  set_function_pointers("c", @ALL_ARCHS);
325
326  print <<EOF;
327}
328#endif
329EOF
330  common_bottom;
331}
332
333sub mips() {
334  determine_indirection("c", @ALL_ARCHS);
335
336  # Assign the helper variable for each enabled extension
337  foreach my $opt (@ALL_ARCHS) {
338    my $opt_uc = uc $opt;
339    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
340  }
341
342  common_top;
343
344  print <<EOF;
345#include "vpx_config.h"
346
347#ifdef RTCD_C
348#include "vpx_ports/mips.h"
349static void setup_rtcd_internal(void)
350{
351    int flags = mips_cpu_caps();
352
353    (void)flags;
354
355EOF
356
357  set_function_pointers("c", @ALL_ARCHS);
358
359  print <<EOF;
360#if HAVE_DSPR2
361void vpx_dsputil_static_init();
362#if CONFIG_VP8
363void dsputil_static_init();
364#endif
365
366vpx_dsputil_static_init();
367#if CONFIG_VP8
368dsputil_static_init();
369#endif
370#endif
371}
372#endif
373EOF
374  common_bottom;
375}
376
377sub ppc() {
378  determine_indirection("c", @ALL_ARCHS);
379
380  # Assign the helper variable for each enabled extension
381  foreach my $opt (@ALL_ARCHS) {
382    my $opt_uc = uc $opt;
383    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
384  }
385
386  common_top;
387  print <<EOF;
388#include "vpx_config.h"
389
390#ifdef RTCD_C
391#include "vpx_ports/ppc.h"
392static void setup_rtcd_internal(void)
393{
394    int flags = ppc_simd_caps();
395    (void)flags;
396EOF
397
398  set_function_pointers("c", @ALL_ARCHS);
399
400  print <<EOF;
401}
402#endif
403EOF
404  common_bottom;
405}
406
407sub loongarch() {
408  determine_indirection("c", @ALL_ARCHS);
409
410  # Assign the helper variable for each enabled extension
411  foreach my $opt (@ALL_ARCHS) {
412    my $opt_uc = uc $opt;
413    eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
414  }
415
416  common_top;
417  print <<EOF;
418#include "vpx_config.h"
419
420#ifdef RTCD_C
421#include "vpx_ports/loongarch.h"
422static void setup_rtcd_internal(void)
423{
424    int flags = loongarch_cpu_caps();
425
426    (void)flags;
427EOF
428
429  set_function_pointers("c", @ALL_ARCHS);
430
431  print <<EOF;
432}
433#endif
434EOF
435  common_bottom;
436}
437
438sub unoptimized() {
439  determine_indirection "c";
440  common_top;
441  print <<EOF;
442#include "vpx_config.h"
443
444#ifdef RTCD_C
445static void setup_rtcd_internal(void)
446{
447EOF
448
449  set_function_pointers "c";
450
451  print <<EOF;
452}
453#endif
454EOF
455  common_bottom;
456}
457
458#
459# Main Driver
460#
461
462&require("c");
463&require(keys %required);
464if ($opts{arch} eq 'x86') {
465  @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
466  x86;
467} elsif ($opts{arch} eq 'x86_64') {
468  @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
469  @REQUIRES = filter(qw/mmx sse sse2/);
470  &require(@REQUIRES);
471  x86;
472} elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
473  my $have_dspr2 = 0;
474  my $have_msa = 0;
475  my $have_mmi = 0;
476  @ALL_ARCHS = filter("$opts{arch}");
477  open CONFIG_FILE, $opts{config} or
478    die "Error opening config file '$opts{config}': $!\n";
479  while (<CONFIG_FILE>) {
480    if (/HAVE_DSPR2=yes/) {
481      $have_dspr2 = 1;
482    }
483    if (/HAVE_MSA=yes/) {
484      $have_msa = 1;
485    }
486    if (/HAVE_MMI=yes/) {
487      $have_mmi = 1;
488    }
489  }
490  close CONFIG_FILE;
491  if ($have_dspr2 == 1) {
492    @ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
493  } elsif ($have_msa == 1 && $have_mmi == 1) {
494    @ALL_ARCHS = filter("$opts{arch}", qw/mmi msa/);
495  } elsif ($have_msa == 1) {
496    @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
497  } elsif ($have_mmi == 1) {
498    @ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
499  } else {
500    unoptimized;
501  }
502  mips;
503} elsif ($opts{arch} =~ /armv7\w?/) {
504  @ALL_ARCHS = filter(qw/neon_asm neon/);
505  arm;
506} elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) {
507  @ALL_ARCHS = filter(qw/neon neon_dotprod neon_i8mm sve sve2/);
508  @REQUIRES = filter(qw/neon/);
509  &require(@REQUIRES);
510  arm;
511} elsif ($opts{arch} =~ /^ppc/ ) {
512  @ALL_ARCHS = filter(qw/vsx/);
513  ppc;
514} elsif ($opts{arch} =~ /loongarch/ ) {
515  @ALL_ARCHS = filter(qw/lsx lasx/);
516  loongarch;
517} else {
518  unoptimized;
519}
520
521__END__
522
523=head1 NAME
524
525rtcd -
526
527=head1 SYNOPSIS
528
529Usage: rtcd.pl [options] FILE
530
531See 'perldoc rtcd.pl' for more details.
532
533=head1 DESCRIPTION
534
535Reads the Run Time CPU Detections definitions from FILE and generates a
536C header file on stdout.
537
538=head1 OPTIONS
539
540Options:
541  --arch=ARCH       Architecture to generate defs for (required)
542  --disable-EXT     Disable support for EXT extensions
543  --require-EXT     Require support for EXT extensions
544  --sym=SYMBOL      Unique symbol to use for RTCD initialization function
545  --config=FILE     File with CONFIG_FOO=yes lines to parse
546