blob: f917b06a52ecf4eb661f82e7dd95faefd289d81a [file] [log] [blame]
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +00001//===-- X86InstrFMA3Info.cpp - X86 FMA3 Instruction Information -----------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file contains the implementation of the classes providing information
10// about existing X86 FMA3 opcodes, classifying and grouping them.
11//
12//===----------------------------------------------------------------------===//
13
14#include "X86InstrFMA3Info.h"
15#include "X86InstrInfo.h"
16#include "llvm/Support/ManagedStatic.h"
17#include "llvm/Support/Threading.h"
Eugene Zelenkofbd13c52017-02-02 22:55:55 +000018#include <cassert>
19#include <cstdint>
20
Benjamin Kramer4c2582a2016-10-18 19:39:31 +000021using namespace llvm;
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000022
Craig Topper0661f672018-07-02 06:23:39 +000023#define FMA3GROUP(Name, Suf, Attrs) \
24 { { X86::Name##132##Suf, X86::Name##213##Suf, X86::Name##231##Suf }, Attrs },
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000025
Craig Topper0661f672018-07-02 06:23:39 +000026#define FMA3GROUP_MASKED(Name, Suf, Attrs) \
27 FMA3GROUP(Name, Suf, Attrs) \
28 FMA3GROUP(Name, Suf##k, Attrs | X86InstrFMA3Group::KMergeMasked) \
29 FMA3GROUP(Name, Suf##kz, Attrs | X86InstrFMA3Group::KZeroMasked)
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000030
Craig Topper0661f672018-07-02 06:23:39 +000031#define FMA3GROUP_PACKED_WIDTHS(Name, Suf, Attrs) \
32 FMA3GROUP(Name, Suf##Ym, Attrs) \
33 FMA3GROUP(Name, Suf##Yr, Attrs) \
34 FMA3GROUP_MASKED(Name, Suf##Z128m, Attrs) \
35 FMA3GROUP_MASKED(Name, Suf##Z128r, Attrs) \
36 FMA3GROUP_MASKED(Name, Suf##Z256m, Attrs) \
37 FMA3GROUP_MASKED(Name, Suf##Z256r, Attrs) \
38 FMA3GROUP_MASKED(Name, Suf##Zm, Attrs) \
39 FMA3GROUP_MASKED(Name, Suf##Zr, Attrs) \
40 FMA3GROUP(Name, Suf##m, Attrs) \
41 FMA3GROUP(Name, Suf##r, Attrs)
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000042
Craig Topper0661f672018-07-02 06:23:39 +000043#define FMA3GROUP_PACKED(Name, Attrs) \
44 FMA3GROUP_PACKED_WIDTHS(Name, PD, Attrs) \
45 FMA3GROUP_PACKED_WIDTHS(Name, PS, Attrs)
Craig Topperf0ab7bd2018-06-18 06:32:22 +000046
Craig Topper0661f672018-07-02 06:23:39 +000047#define FMA3GROUP_SCALAR_WIDTHS(Name, Suf, Attrs) \
48 FMA3GROUP(Name, Suf##Zm, Attrs) \
49 FMA3GROUP_MASKED(Name, Suf##Zm_Int, Attrs | X86InstrFMA3Group::Intrinsic) \
50 FMA3GROUP(Name, Suf##Zr, Attrs) \
51 FMA3GROUP_MASKED(Name, Suf##Zr_Int, Attrs | X86InstrFMA3Group::Intrinsic) \
52 FMA3GROUP(Name, Suf##m, Attrs) \
53 FMA3GROUP(Name, Suf##m_Int, Attrs | X86InstrFMA3Group::Intrinsic) \
54 FMA3GROUP(Name, Suf##r, Attrs) \
55 FMA3GROUP(Name, Suf##r_Int, Attrs | X86InstrFMA3Group::Intrinsic)
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000056
Craig Topper0661f672018-07-02 06:23:39 +000057#define FMA3GROUP_SCALAR(Name, Attrs) \
58 FMA3GROUP_SCALAR_WIDTHS(Name, SD, Attrs) \
Craig Topperbd032302019-06-07 20:30:40 +000059 FMA3GROUP_SCALAR_WIDTHS(Name, SS, Attrs)
Craig Topper33aba0e2018-06-27 00:42:24 +000060
Craig Topper0661f672018-07-02 06:23:39 +000061#define FMA3GROUP_FULL(Name, Attrs) \
62 FMA3GROUP_PACKED(Name, Attrs) \
63 FMA3GROUP_SCALAR(Name, Attrs)
Craig Topperf0ab7bd2018-06-18 06:32:22 +000064
65static const X86InstrFMA3Group Groups[] = {
Craig Topper0661f672018-07-02 06:23:39 +000066 FMA3GROUP_FULL(VFMADD, 0)
67 FMA3GROUP_PACKED(VFMADDSUB, 0)
68 FMA3GROUP_FULL(VFMSUB, 0)
69 FMA3GROUP_PACKED(VFMSUBADD, 0)
70 FMA3GROUP_FULL(VFNMADD, 0)
71 FMA3GROUP_FULL(VFNMSUB, 0)
Craig Topperf0ab7bd2018-06-18 06:32:22 +000072};
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000073
Craig Topper0661f672018-07-02 06:23:39 +000074#define FMA3GROUP_PACKED_AVX512_WIDTHS(Name, Type, Suf, Attrs) \
75 FMA3GROUP_MASKED(Name, Type##Z128##Suf, Attrs) \
76 FMA3GROUP_MASKED(Name, Type##Z256##Suf, Attrs) \
77 FMA3GROUP_MASKED(Name, Type##Z##Suf, Attrs)
Craig Topper84199de2018-06-30 22:38:42 +000078
Craig Topper0661f672018-07-02 06:23:39 +000079#define FMA3GROUP_PACKED_AVX512(Name, Suf, Attrs) \
80 FMA3GROUP_PACKED_AVX512_WIDTHS(Name, PD, Suf, Attrs) \
81 FMA3GROUP_PACKED_AVX512_WIDTHS(Name, PS, Suf, Attrs)
Craig Topper84199de2018-06-30 22:38:42 +000082
Craig Topper0661f672018-07-02 06:23:39 +000083#define FMA3GROUP_PACKED_AVX512_ROUND(Name, Suf, Attrs) \
84 FMA3GROUP_MASKED(Name, PDZ##Suf, Attrs) \
85 FMA3GROUP_MASKED(Name, PSZ##Suf, Attrs)
86
Craig Topperfdf3f1f2018-07-08 01:10:43 +000087#define FMA3GROUP_SCALAR_AVX512_ROUND(Name, Suf, Attrs) \
88 FMA3GROUP(Name, SDZ##Suf, Attrs) \
89 FMA3GROUP_MASKED(Name, SDZ##Suf##_Int, Attrs) \
90 FMA3GROUP(Name, SSZ##Suf, Attrs) \
91 FMA3GROUP_MASKED(Name, SSZ##Suf##_Int, Attrs)
Craig Topper0661f672018-07-02 06:23:39 +000092
93static const X86InstrFMA3Group BroadcastGroups[] = {
94 FMA3GROUP_PACKED_AVX512(VFMADD, mb, 0)
95 FMA3GROUP_PACKED_AVX512(VFMADDSUB, mb, 0)
96 FMA3GROUP_PACKED_AVX512(VFMSUB, mb, 0)
97 FMA3GROUP_PACKED_AVX512(VFMSUBADD, mb, 0)
98 FMA3GROUP_PACKED_AVX512(VFNMADD, mb, 0)
99 FMA3GROUP_PACKED_AVX512(VFNMSUB, mb, 0)
100};
101
102static const X86InstrFMA3Group RoundGroups[] = {
103 FMA3GROUP_PACKED_AVX512_ROUND(VFMADD, rb, 0)
Craig Topperfdf3f1f2018-07-08 01:10:43 +0000104 FMA3GROUP_SCALAR_AVX512_ROUND(VFMADD, rb, X86InstrFMA3Group::Intrinsic)
Craig Topper0661f672018-07-02 06:23:39 +0000105 FMA3GROUP_PACKED_AVX512_ROUND(VFMADDSUB, rb, 0)
106 FMA3GROUP_PACKED_AVX512_ROUND(VFMSUB, rb, 0)
Craig Topperfdf3f1f2018-07-08 01:10:43 +0000107 FMA3GROUP_SCALAR_AVX512_ROUND(VFMSUB, rb, X86InstrFMA3Group::Intrinsic)
Craig Topper0661f672018-07-02 06:23:39 +0000108 FMA3GROUP_PACKED_AVX512_ROUND(VFMSUBADD, rb, 0)
109 FMA3GROUP_PACKED_AVX512_ROUND(VFNMADD, rb, 0)
Craig Topperfdf3f1f2018-07-08 01:10:43 +0000110 FMA3GROUP_SCALAR_AVX512_ROUND(VFNMADD, rb, X86InstrFMA3Group::Intrinsic)
Craig Topper0661f672018-07-02 06:23:39 +0000111 FMA3GROUP_PACKED_AVX512_ROUND(VFNMSUB, rb, 0)
Craig Topperfdf3f1f2018-07-08 01:10:43 +0000112 FMA3GROUP_SCALAR_AVX512_ROUND(VFNMSUB, rb, X86InstrFMA3Group::Intrinsic)
Craig Topper0661f672018-07-02 06:23:39 +0000113};
114
115static void verifyTables() {
116#ifndef NDEBUG
117 static std::atomic<bool> TableChecked(false);
118 if (!TableChecked.load(std::memory_order_relaxed)) {
119 assert(std::is_sorted(std::begin(Groups), std::end(Groups)) &&
120 std::is_sorted(std::begin(RoundGroups), std::end(RoundGroups)) &&
121 std::is_sorted(std::begin(BroadcastGroups),
122 std::end(BroadcastGroups)) &&
123 "FMA3 tables not sorted!");
124 TableChecked.store(true, std::memory_order_relaxed);
Craig Topperf0ab7bd2018-06-18 06:32:22 +0000125 }
Craig Topper0661f672018-07-02 06:23:39 +0000126#endif
Craig Topper84199de2018-06-30 22:38:42 +0000127}
128
Craig Topper84199de2018-06-30 22:38:42 +0000129/// Returns a reference to a group of FMA3 opcodes to where the given
130/// \p Opcode is included. If the given \p Opcode is not recognized as FMA3
131/// and not included into any FMA3 group, then nullptr is returned.
Craig Topper0661f672018-07-02 06:23:39 +0000132const X86InstrFMA3Group *llvm::getFMA3Group(unsigned Opcode, uint64_t TSFlags) {
Craig Topper84199de2018-06-30 22:38:42 +0000133
Craig Topper0661f672018-07-02 06:23:39 +0000134 // FMA3 instructions have a well defined encoding pattern we can exploit.
135 uint8_t BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
136 bool IsFMA3 = ((TSFlags & X86II::EncodingMask) == X86II::VEX ||
137 (TSFlags & X86II::EncodingMask) == X86II::EVEX) &&
138 (TSFlags & X86II::OpMapMask) == X86II::T8 &&
139 (TSFlags & X86II::OpPrefixMask) == X86II::PD &&
140 ((BaseOpcode >= 0x96 && BaseOpcode <= 0x9F) ||
141 (BaseOpcode >= 0xA6 && BaseOpcode <= 0xAF) ||
142 (BaseOpcode >= 0xB6 && BaseOpcode <= 0xBF));
143 if (!IsFMA3)
144 return nullptr;
145
146 verifyTables();
147
148 ArrayRef<X86InstrFMA3Group> Table;
149 if (TSFlags & X86II::EVEX_RC)
150 Table = makeArrayRef(RoundGroups);
151 else if (TSFlags & X86II::EVEX_B)
152 Table = makeArrayRef(BroadcastGroups);
153 else
154 Table = makeArrayRef(Groups);
155
156 // FMA 132 instructions have an opcode of 0x96-0x9F
157 // FMA 213 instructions have an opcode of 0xA6-0xAF
158 // FMA 231 instructions have an opcode of 0xB6-0xBF
159 unsigned FormIndex = ((BaseOpcode - 0x90) >> 4) & 0x3;
160
161 auto I = std::lower_bound(Table.begin(), Table.end(), Opcode,
162 [FormIndex](const X86InstrFMA3Group &Group,
163 unsigned Opcode) {
164 return Group.Opcodes[FormIndex] < Opcode;
165 });
166 assert(I != Table.end() && I->Opcodes[FormIndex] == Opcode &&
167 "Couldn't find FMA3 opcode!");
168 return I;
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +0000169}