1#!/usr/bin/env perl
2#############################################################################
3##
4## Copyright (C) 2018 Intel Corporation.
5## Contact: https://www.qt.io/licensing/
6##
7## This file is part of the build configuration tools of the Qt Toolkit.
8##
9## $QT_BEGIN_LICENSE:MIT$
10## Permission is hereby granted, free of charge, to any person obtaining a copy
11## of this software and associated documentation files (the "Software"), to deal
12## in the Software without restriction, including without limitation the rights
13## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14## copies of the Software, and to permit persons to whom the Software is
15## furnished to do so, subject to the following conditions:
16##
17## The above copyright notice and this permission notice shall be included in
18## all copies or substantial portions of the Software.
19##
20## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26## THE SOFTWARE.
27## $QT_END_LICENSE$
28##
29#############################################################################
30
31use strict;
32$\ = "\n";
33$/ = "\n";
34my %leaves = (
35    Leaf1EDX        => "CPUID Leaf 1, EDX",
36    Leaf1ECX        => "CPUID Leaf 1, ECX",
37    Leaf7_0EBX      => "CPUID Leaf 7, Sub-leaf 0, EBX",
38    Leaf7_0ECX      => "CPUID Leaf 7, Sub-leaf 0, ECX",
39    Leaf7_0EDX      => "CPUID Leaf 7, Sub-leaf 0, EDX",
40);
41my @leafNames = sort keys %leaves;
42
43# Read data from stdin
44my $i = 1;
45my @features;
46while (<STDIN>) {
47    s/#.*$//;
48    chomp;
49    next if $_ eq "";
50
51    my ($name, $function, $bit, $depends) = split /\s+/;
52    die("Unknown CPUID function \"$function\"")
53        unless grep $function, @leafNames;
54
55    my $id = uc($name);
56    $id =~ s/[^A-Z0-9_]/_/g;
57    push @features,
58        { name => $name, depends => $depends, id => $id, bit => $bit, leaf => $function };
59    ++$i;
60}
61
62if (my $h = shift @ARGV) {
63    open HEADER, ">", $h;
64    select HEADER;
65}
66
67# Print the qsimd_x86_p.h output
68print q{// This is a generated file. DO NOT EDIT.
69// Please see util/x86simdgen/generate.pl";
70#ifndef QSIMD_P_H
71#  error "Please include <private/qsimd_p.h> instead"
72#endif
73#ifndef QSIMD_X86_P_H
74#define QSIMD_X86_P_H
75
76#include "qsimd_p.h"
77
78//
79//  W A R N I N G
80//  -------------
81//
82// This file is not part of the Qt API.  It exists purely as an
83// implementation detail.  This header file may change from version to
84// version without notice, or even be removed.
85//
86// We mean it.
87//
88
89QT_BEGIN_NAMESPACE
90
91// used only to indicate that the CPU detection was initialized
92#define QSimdInitialized                            (Q_UINT64_C(1) << 0)};
93
94# Print the enum
95my $lastleaf;
96for (my $i = 0; $i < scalar @features; ++$i) {
97    my $feature = $features[$i];
98    # Leaf header:
99    printf "\n// in %s:\n", $leaves{$feature->{leaf}}
100        if $feature->{leaf} ne $lastleaf;
101    $lastleaf = $feature->{leaf};
102
103    # Feature
104    printf "#define CpuFeature%-33s (Q_UINT64_C(1) << %d)\n", $feature->{id}, $i + 1;
105
106    # Feature string names for Clang and GCC
107    my $str = $feature->{name};
108    $str .= ",$feature->{depends}" if defined($feature->{depends});
109    printf "#define QT_FUNCTION_TARGET_STRING_%-17s \"%s\"\n",
110        $feature->{id}, $str;
111}
112
113print q{
114static const quint64 qCompilerCpuFeatures = 0};
115
116# And print the compiler-enabled features part:
117for (my $i = 0; $i < scalar @features; ++$i) {
118    my $feature = $features[$i];
119    printf
120        "#ifdef __%s__\n" .
121        "         | CpuFeature%s\n" .
122        "#endif\n",
123        $feature->{id}, $feature->{id};
124}
125
126print q{        ;
127
128QT_END_NAMESPACE
129
130#endif // QSIMD_X86_P_H
131};
132
133if (my $cpp = shift @ARGV) {
134    open CPP, ">", $cpp;
135    select CPP;
136} else {
137    print q{
138
139---- cut here, paste the rest into qsimd_x86.cpp ---
140
141
142};
143};
144
145print "// This is a generated file. DO NOT EDIT.";
146print "// Please see util/x86simdgen/generate.pl";
147print '#include "qsimd_p.h"';
148print "";
149
150# Now generate the string table and bit-location array
151my $offset = 0;
152my @offsets;
153print "static const char features_string[] =";
154for my $feature (@features) {
155    print "    \" $feature->{name}\\0\"";
156    push @offsets, $offset;
157    $offset += 2 + length($feature->{name});
158}
159print "    \"\\0\";";
160
161# Print the string offset table
162printf "\nstatic const %s features_indices[] = {\n    %3d",
163    $offset > 255 ? "quint16" : "quint8", $offset;
164for (my $j = 0; $j < scalar @offsets; ++$j) {
165    printf ",%s%3d",
166        ($j + 1) % 8 ? " " : "\n    ", $offsets[$j];
167}
168print "\n};";
169
170# Print the locator enum and table
171print "\nenum X86CpuidLeaves {";
172map { print "    $_," } @leafNames;
173print "    X86CpuidMaxLeaf\n};";
174
175my $type = scalar %leaves > 8 ? "quint16" : "quint8";
176printf "\nstatic const %s x86_locators[] = {",
177    $type, $type;
178my $lastname;
179for (my $j = 0; $j < scalar @features; ++$j) {
180    my $feature = $features[$j];
181    printf ", // %s", $lastname
182        if defined($lastname);
183    printf "\n    %s*32 + %2d",
184        $feature->{leaf}, $feature->{bit};
185    $lastname = $feature->{name};
186}
187printf qq{  // $lastname
188\};
189
190// List of AVX512 features (see detectProcessorFeatures())
191static const quint64 AllAVX512 = 0};
192
193# Print AVX512 features
194for (my $j = 0; $j < scalar @features; ++$j) {
195    my $feature = $features[$j];
196    $_ = $feature->{id};
197    printf "\n        | CpuFeature%s", $_ if /AVX512/;
198}
199print ";";
200