#!/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 () { 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 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 ";";