qtbase-opensource-src/util/x86simdgen/generate.pl

200 lines
5.6 KiB
Perl
Executable File

#!/usr/bin/env perl
#############################################################################
##
## Copyright (C) 2018 Intel Corporation.
## Contact: https://www.qt.io/licensing/
##
## This file is part of the build configuration tools of the Qt Toolkit.
##
## $QT_BEGIN_LICENSE:MIT$
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in
## all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
## THE SOFTWARE.
## $QT_END_LICENSE$
##
#############################################################################
use strict;
$\ = "\n";
$/ = "\n";
my %leaves = (
Leaf1EDX => "CPUID Leaf 1, EDX",
Leaf1ECX => "CPUID Leaf 1, ECX",
Leaf7_0EBX => "CPUID Leaf 7, Sub-leaf 0, EBX",
Leaf7_0ECX => "CPUID Leaf 7, Sub-leaf 0, ECX",
Leaf7_0EDX => "CPUID Leaf 7, Sub-leaf 0, EDX",
);
my @leafNames = sort keys %leaves;
# Read data from stdin
my $i = 1;
my @features;
while (<STDIN>) {
s/#.*$//;
chomp;
next if $_ eq "";
my ($name, $function, $bit, $depends) = split /\s+/;
die("Unknown CPUID function \"$function\"")
unless grep $function, @leafNames;
my $id = uc($name);
$id =~ s/[^A-Z0-9_]/_/g;
push @features,
{ name => $name, depends => $depends, id => $id, bit => $bit, leaf => $function };
++$i;
}
if (my $h = shift @ARGV) {
open HEADER, ">", $h;
select HEADER;
}
# Print the qsimd_x86_p.h output
print q{// This is a generated file. DO NOT EDIT.
// Please see util/x86simdgen/generate.pl";
#ifndef QSIMD_P_H
# error "Please include <private/qsimd_p.h> instead"
#endif
#ifndef QSIMD_X86_P_H
#define QSIMD_X86_P_H
#include "qsimd_p.h"
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
QT_BEGIN_NAMESPACE
// used only to indicate that the CPU detection was initialized
#define QSimdInitialized (Q_UINT64_C(1) << 0)};
# Print the enum
my $lastleaf;
for (my $i = 0; $i < scalar @features; ++$i) {
my $feature = $features[$i];
# Leaf header:
printf "\n// in %s:\n", $leaves{$feature->{leaf}}
if $feature->{leaf} ne $lastleaf;
$lastleaf = $feature->{leaf};
# Feature
printf "#define CpuFeature%-33s (Q_UINT64_C(1) << %d)\n", $feature->{id}, $i + 1;
# Feature string names for Clang and GCC
my $str = $feature->{name};
$str .= ",$feature->{depends}" if defined($feature->{depends});
printf "#define QT_FUNCTION_TARGET_STRING_%-17s \"%s\"\n",
$feature->{id}, $str;
}
print q{
static const quint64 qCompilerCpuFeatures = 0};
# And print the compiler-enabled features part:
for (my $i = 0; $i < scalar @features; ++$i) {
my $feature = $features[$i];
printf
"#ifdef __%s__\n" .
" | CpuFeature%s\n" .
"#endif\n",
$feature->{id}, $feature->{id};
}
print q{ ;
QT_END_NAMESPACE
#endif // QSIMD_X86_P_H
};
if (my $cpp = shift @ARGV) {
open CPP, ">", $cpp;
select CPP;
} else {
print q{
---- cut here, paste the rest into qsimd_x86.cpp ---
};
};
print "// This is a generated file. DO NOT EDIT.";
print "// Please see util/x86simdgen/generate.pl";
print '#include "qsimd_p.h"';
print "";
# Now generate the string table and bit-location array
my $offset = 0;
my @offsets;
print "static const char features_string[] =";
for my $feature (@features) {
print " \" $feature->{name}\\0\"";
push @offsets, $offset;
$offset += 2 + length($feature->{name});
}
print " \"\\0\";";
# Print the string offset table
printf "\nstatic const %s features_indices[] = {\n %3d",
$offset > 255 ? "quint16" : "quint8", $offset;
for (my $j = 0; $j < scalar @offsets; ++$j) {
printf ",%s%3d",
($j + 1) % 8 ? " " : "\n ", $offsets[$j];
}
print "\n};";
# Print the locator enum and table
print "\nenum X86CpuidLeaves {";
map { print " $_," } @leafNames;
print " X86CpuidMaxLeaf\n};";
my $type = scalar %leaves > 8 ? "quint16" : "quint8";
printf "\nstatic const %s x86_locators[] = {",
$type, $type;
my $lastname;
for (my $j = 0; $j < scalar @features; ++$j) {
my $feature = $features[$j];
printf ", // %s", $lastname
if defined($lastname);
printf "\n %s*32 + %2d",
$feature->{leaf}, $feature->{bit};
$lastname = $feature->{name};
}
printf qq{ // $lastname
\};
// List of AVX512 features (see detectProcessorFeatures())
static const quint64 AllAVX512 = 0};
# Print AVX512 features
for (my $j = 0; $j < scalar @features; ++$j) {
my $feature = $features[$j];
$_ = $feature->{id};
printf "\n | CpuFeature%s", $_ if /AVX512/;
}
print ";";