1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef DEFINE_MACRO_ASSEMBLER_GENERIC_FUNCTIONS
18 #error This file is supposed to be included from berberis/intrinsics/macro_assembler-inl.h
19 #else
20 #undef DEFINE_MACRO_ASSEMBLER_GENERIC_FUNCTIONS
21 #endif
22 
23 using Condition = typename Assembler::Condition;
24 using Label = typename Assembler::Label;
25 using Operand = typename Assembler::Operand;
26 using Register = typename Assembler::Register;
27 using ScaleFactor = typename Assembler::ScaleFactor;
28 using XMMRegister = typename Assembler::XMMRegister;
29 
30 using Float32 = intrinsics::Float32;
31 using Float64 = intrinsics::Float64;
32 
33 template <typename IntType>
34 using ImmFormat =
35     std::conditional_t<sizeof(IntType) <= sizeof(int32_t), std::make_signed_t<IntType>, int32_t>;
36 
37 template <typename format, typename... allowed_formats>
38 static constexpr bool kFormatIs = (std::is_same_v<format, allowed_formats> || ...);
39 
40 template <typename IntType>
41 static constexpr bool kIntType =
42     kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
43 
44 template <typename IntType>
45 static constexpr bool kIntTypeBW = kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t>;
46 
47 template <typename IntType>
48 static constexpr bool kIntTypeBWL =
49     kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t>;
50 
51 template <typename IntType>
52 static constexpr bool kIntTypeWL = kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t>;
53 
54 template <typename IntType>
55 static constexpr bool kIntTypeWLQ =
56     kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
57 
58 template <typename IntType>
59 static constexpr bool kIntTypeLQ = kFormatIs<IntType, int32_t, uint32_t, int64_t, uint64_t>;
60 
61 // Psr is the only asymmetric instruction where unsigned 64bit variant was supported in MMX in CPUs
62 // released last century while signed 64bit variant is only added in AVX10 which is not yet even
63 // available for purchase!
64 template <typename IntType>
65 static constexpr bool kIntTypePsr =
66     kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t, uint64_t>;
67 
68 template <typename IntType>
69 static constexpr bool kSignedIntType = kFormatIs<IntType, int8_t, int16_t, int32_t, int64_t>;
70 
71 template <typename IntType>
72 static constexpr bool kUnsignedIntType = kFormatIs<IntType, uint8_t, uint16_t, uint32_t, uint64_t>;
73 
74 template <typename FloatType>
75 static constexpr bool kFloatType = kFormatIs<FloatType, Float32, Float64>;
76 
77 #define DEFINE_EXPAND_INSTRUCTION(Declare_dest, Declare_src)         \
78   template <typename format_out, typename format_in>                 \
79   std::enable_if_t<kIntType<format_out> && kIntType<format_in> &&    \
80                    sizeof(format_in) <= sizeof(format_out)>          \
81   Expand(Declare_dest, Declare_src) {                                \
82     if constexpr (std::is_same_v<decltype(dest), decltype(src)> &&   \
83                   sizeof(format_out) == sizeof(format_in)) {         \
84       if (dest == src) {                                             \
85         return;                                                      \
86       }                                                              \
87     }                                                                \
88     if constexpr (kFormatIs<format_out, int8_t, uint8_t> &&          \
89                   kFormatIs<format_in, int8_t, uint8_t>) {           \
90       Assembler::Movb(dest, src);                                    \
91     } else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
92                          kFormatIs<format_in, int8_t>) {             \
93       if constexpr (std::is_same_v<decltype(dest), decltype(src)>) { \
94         if (dest == Assembler::gpr_a && src == Assembler::gpr_a) {   \
95           Assembler::Cbw();                                          \
96           return;                                                    \
97         }                                                            \
98       }                                                              \
99       Assembler::Movsxbw(dest, src);                                 \
100     } else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
101                          kFormatIs<format_in, uint8_t>) {            \
102       Assembler::Movzxbw(dest, src);                                 \
103     } else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
104                          kFormatIs<format_in, int16_t, uint16_t>) {  \
105       Assembler::Movw(dest, src);                                    \
106     } else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
107                          kFormatIs<format_in, int8_t>) {             \
108       Assembler::Movsxbl(dest, src);                                 \
109     } else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
110                          kFormatIs<format_in, uint8_t>) {            \
111       Assembler::Movzxbl(dest, src);                                 \
112     } else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
113                          kFormatIs<format_in, int16_t>) {            \
114       if constexpr (std::is_same_v<decltype(dest), decltype(src)>) { \
115         if (dest == Assembler::gpr_a && src == Assembler::gpr_a) {   \
116           Assembler::Cwde();                                         \
117           return;                                                    \
118         }                                                            \
119       }                                                              \
120       Assembler::Movsxwl(dest, src);                                 \
121     } else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
122                          kFormatIs<format_in, uint16_t>) {           \
123       Assembler::Movzxwl(dest, src);                                 \
124     } else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
125                          kFormatIs<format_in, int32_t, uint32_t>) {  \
126       Assembler::Movl(dest, src);                                    \
127     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
128                          kFormatIs<format_in, int8_t>) {             \
129       Assembler::Movsxbq(dest, src);                                 \
130     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
131                          kFormatIs<format_in, uint8_t>) {            \
132       Assembler::Movzxbl(dest, src);                                 \
133     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
134                          kFormatIs<format_in, int16_t>) {            \
135       Assembler::Movsxwq(dest, src);                                 \
136     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
137                          kFormatIs<format_in, uint16_t>) {           \
138       Assembler::Movzxwl(dest, src);                                 \
139     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
140                          kFormatIs<format_in, int32_t>) {            \
141       if constexpr (std::is_same_v<decltype(dest), decltype(src)>) { \
142         if (dest == Assembler::gpr_a && src == Assembler::gpr_a) {   \
143           Assembler::Cdqe();                                         \
144           return;                                                    \
145         }                                                            \
146       }                                                              \
147       Assembler::Movsxlq(dest, src);                                 \
148     } else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
149                          kFormatIs<format_in, uint32_t>) {           \
150       Assembler::Movl(dest, src);                                    \
151     } else {                                                         \
152       Assembler::Movq(dest, src);                                    \
153     }                                                                \
154   }
DEFINE_EXPAND_INSTRUCTION(Register dest,Operand src)155 DEFINE_EXPAND_INSTRUCTION(Register dest, Operand src)
156 DEFINE_EXPAND_INSTRUCTION(Register dest, Register src)
157 #undef DEFINE_EXPAND_INSTRUCTION
158 
159 #define DEFINE_INT_INSTRUCTION(                                            \
160     insn_name, asm_name, insn_siffix, type_check, parameters, arguments)   \
161   template <typename format>                                               \
162   std::enable_if_t<type_check<format>> insn_name##insn_siffix parameters { \
163     if constexpr (kFormatIs<format, int8_t, uint8_t>) {                    \
164       Assembler::asm_name##b##insn_siffix arguments;                       \
165     } else if constexpr (kFormatIs<format, int16_t, uint16_t>) {           \
166       Assembler::asm_name##w##insn_siffix arguments;                       \
167     } else if constexpr (kFormatIs<format, int32_t, uint32_t>) {           \
168       Assembler::asm_name##l##insn_siffix arguments;                       \
169     } else {                                                               \
170       Assembler::asm_name##q##insn_siffix arguments;                       \
171     }                                                                      \
172   }
173 DEFINE_INT_INSTRUCTION(CmpXchg, CmpXchg, , kIntType, (Operand dest, Register src), (dest, src))
174 DEFINE_INT_INSTRUCTION(CmpXchg, CmpXchg, , kIntType, (Register dest, Register src), (dest, src))
175 DEFINE_INT_INSTRUCTION(LockCmpXchg,
176                        LockCmpXchg,
177                        ,
178                        kIntType,
179                        (Operand dest, Register src),
180                        (dest, src))
181 DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm))
182 DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Operand dest, Register src), (dest, src))
183 DEFINE_INT_INSTRUCTION(Mov,
184                        Mov,
185                        ,
186                        kIntType,
187                        (Register dest, std::make_signed_t<format> imm),
188                        (dest, imm))
189 DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Register dest, Operand src), (dest, src))
190 DEFINE_INT_INSTRUCTION(Mul, Imul, , kIntTypeWLQ, (Operand dest, Register src), (dest, src))
191 DEFINE_INT_INSTRUCTION(Mul, Imul, , kIntTypeWLQ, (Operand dest, Operand src), (dest, src))
192 DEFINE_INT_INSTRUCTION(Mul,
193                        Imul,
194                        ,
195                        kIntTypeWLQ,
196                        (Operand dest, Register src, ImmFormat<format> imm),
197                        (dest, src, imm))
198 DEFINE_INT_INSTRUCTION(Mul,
199                        Imul,
200                        ,
201                        kIntTypeWLQ,
202                        (Operand dest, Operand src, ImmFormat<format> imm),
203                        (dest, src, imm))
204 DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm))
205 DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Operand dest, Register src), (dest, src))
206 DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Register dest, ImmFormat<format> imm), (dest, imm))
207 DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Register dest, Register src), (dest, src))
208 #define DEFINE_ARITH_INSTRUCTION(insn_name, asm_name, type_check)                 \
209   DEFINE_INT_INSTRUCTION(insn_name, asm_name, , type_check, (Operand arg), (arg)) \
210   DEFINE_INT_INSTRUCTION(insn_name, asm_name, , type_check, (Register arg), (arg))
211 DEFINE_ARITH_INSTRUCTION(Dec, Dec, kIntType)
212 DEFINE_ARITH_INSTRUCTION(Div, Div, kUnsignedIntType)
213 DEFINE_ARITH_INSTRUCTION(Div, Idiv, kSignedIntType)
214 DEFINE_ARITH_INSTRUCTION(Inc, Inc, kIntType)
215 DEFINE_ARITH_INSTRUCTION(Mul, Imul, kSignedIntType)
216 DEFINE_ARITH_INSTRUCTION(Mul, Mul, kUnsignedIntType)
217 DEFINE_ARITH_INSTRUCTION(Neg, Neg, kIntType)
218 DEFINE_ARITH_INSTRUCTION(Not, Not, kIntType)
219 #undef DEFINE_ARITH_INSTRUCTION
220 #define DEFINE_ARITH_INSTRUCTION(insn_name)                                                  \
221   DEFINE_INT_INSTRUCTION(                                                                    \
222       insn_name, insn_name, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm))  \
223   DEFINE_INT_INSTRUCTION(                                                                    \
224       insn_name, insn_name, , kIntType, (Operand dest, Register src), (dest, src))           \
225   DEFINE_INT_INSTRUCTION(                                                                    \
226       insn_name, insn_name, , kIntType, (Register dest, ImmFormat<format> imm), (dest, imm)) \
227   DEFINE_INT_INSTRUCTION(                                                                    \
228       insn_name, insn_name, , kIntType, (Register dest, Operand src), (dest, src))           \
229   DEFINE_INT_INSTRUCTION(                                                                    \
230       insn_name, insn_name, , kIntType, (Register dest, Register src), (dest, src))
231 DEFINE_ARITH_INSTRUCTION(Adc)
232 DEFINE_ARITH_INSTRUCTION(Add)
233 DEFINE_ARITH_INSTRUCTION(And)
234 DEFINE_ARITH_INSTRUCTION(Cmp)
235 DEFINE_ARITH_INSTRUCTION(Or)
236 DEFINE_ARITH_INSTRUCTION(Sbb)
237 DEFINE_ARITH_INSTRUCTION(Sub)
238 DEFINE_ARITH_INSTRUCTION(Xor)
239 #undef DEFINE_ARITH_INSTRUCTION
240 #define DEFINE_SHIFT_INSTRUCTION(insn_name)                                            \
241   DEFINE_INT_INSTRUCTION(                                                              \
242       insn_name, insn_name, , kIntType, (Operand dest, int8_t imm), (dest, imm))       \
243   DEFINE_INT_INSTRUCTION(insn_name, insn_name, ByCl, kIntType, (Operand dest), (dest)) \
244   DEFINE_INT_INSTRUCTION(                                                              \
245       insn_name, insn_name, , kIntType, (Register dest, int8_t imm), (dest, imm))      \
246   DEFINE_INT_INSTRUCTION(insn_name, insn_name, ByCl, kIntType, (Register dest), (dest))
247 DEFINE_SHIFT_INSTRUCTION(Rcl)
248 DEFINE_SHIFT_INSTRUCTION(Rcr)
249 DEFINE_SHIFT_INSTRUCTION(Rol)
250 DEFINE_SHIFT_INSTRUCTION(Ror)
251 DEFINE_SHIFT_INSTRUCTION(Sar)
252 DEFINE_SHIFT_INSTRUCTION(Shl)
253 DEFINE_SHIFT_INSTRUCTION(Shr)
254 #undef DEFINE_INT_INSTRUCTION
255 #undef DEFINE_SHIFT_INSTRUCTION
256 
257 #define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments) \
258   template <typename format>                                     \
259   std::enable_if_t<kIntTypeWLQ<format>> insn_name parameters {   \
260     if constexpr (kFormatIs<format, int16_t, uint16_t>) {        \
261       Assembler::insn_name##w arguments;                         \
262     } else if constexpr (kFormatIs<format, int32_t, uint32_t>) { \
263       Assembler::insn_name##l arguments;                         \
264     } else {                                                     \
265       Assembler::insn_name##q arguments;                         \
266     }                                                            \
267   }
268 DEFINE_INT_INSTRUCTION(Cmov, (Condition cond, Register dest, Operand src), (cond, dest, src))
269 DEFINE_INT_INSTRUCTION(Cmov, (Condition cond, Register dest, Register src), (cond, dest, src))
270 #define DEFINE_BIT_INSTRUCTION(insn_name)                                                \
271   DEFINE_INT_INSTRUCTION(insn_name, (Operand dest, ImmFormat<format> imm), (dest, imm))  \
272   DEFINE_INT_INSTRUCTION(insn_name, (Operand dest, Register src), (dest, src))           \
273   DEFINE_INT_INSTRUCTION(insn_name, (Register dest, ImmFormat<format> imm), (dest, imm)) \
274   DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Register src), (dest, src))
275 DEFINE_BIT_INSTRUCTION(Bt)
276 DEFINE_BIT_INSTRUCTION(Btc)
277 DEFINE_BIT_INSTRUCTION(Btr)
278 DEFINE_BIT_INSTRUCTION(Bts)
279 #undef DEFINE_BIT_INSTRUCTION
280 #define DEFINE_BIT_INSTRUCTION(insn_name)                                      \
281   DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Operand src), (dest, src)) \
282   DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Register src), (dest, src))
283 DEFINE_BIT_INSTRUCTION(Bsf)
284 DEFINE_BIT_INSTRUCTION(Bsr)
285 DEFINE_BIT_INSTRUCTION(Lzcnt)
286 DEFINE_BIT_INSTRUCTION(Tzcnt)
287 #undef DEFINE_BIT_INSTRUCTION
288 #undef DEFINE_INT_INSTRUCTION
289 
290 // Note: Mov<int32_t> from one register to that same register doesn't zero-out top 32bits,
291 // like real Movq would! If you want that effect then use Expand<tnt32_t, int32_t> instead!
292 template <typename format>
293 std::enable_if_t<kIntType<format>> Mov(Register dest, Register src) {
294   if (dest == src) {
295     return;
296   }
297   if constexpr (kFormatIs<format, int8_t, uint8_t>) {
298     Assembler::Movb(dest, src);
299   } else if constexpr (kFormatIs<format, int16_t, uint16_t>) {
300     Assembler::Movw(dest, src);
301   } else if constexpr (kFormatIs<format, int32_t, uint32_t>) {
302     Assembler::Movl(dest, src);
303   } else {
304     Assembler::Movq(dest, src);
305   }
306 }
307 
308 #define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments)     \
309   template <typename target_format>                                  \
310   std::enable_if_t<kIntTypeBW<target_format>> insn_name parameters { \
311     if constexpr (kFormatIs<target_format, int8_t>) {                \
312       Assembler::insn_name##sswb arguments;                          \
313     } else if constexpr (kFormatIs<target_format, uint8_t>) {        \
314       Assembler::insn_name##uswb arguments;                          \
315     } else if constexpr (kFormatIs<target_format, int16_t>) {        \
316       Assembler::insn_name##ssdw arguments;                          \
317     } else {                                                         \
318       Assembler::insn_name##usdw arguments;                          \
319     }                                                                \
320   }
321 #define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name)                                             \
322   DEFINE_INT_INSTRUCTION(P##insn_name, (XMMRegister dest, XMMRegister src), (dest, src))         \
323   DEFINE_INT_INSTRUCTION(P##insn_name, (XMMRegister dest, Operand src), (dest, src))             \
324   DEFINE_INT_INSTRUCTION(                                                                        \
325       Vp##insn_name, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2)) \
326   DEFINE_INT_INSTRUCTION(                                                                        \
327       Vp##insn_name, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2))
328 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(ack)
329 #undef DEFINE_INT_INSTRUCTION
330 #define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments)    \
331   template <typename format>                                        \
332   std::enable_if_t<kUnsignedIntType<format>> insn_name parameters { \
333     if constexpr (kFormatIs<format, uint8_t>) {                     \
334       Assembler::insn_name##bw arguments;                           \
335     } else if constexpr (kFormatIs<format, uint16_t>) {             \
336       Assembler::insn_name##wd arguments;                           \
337     } else if constexpr (kFormatIs<format, uint32_t>) {             \
338       Assembler::insn_name##dq arguments;                           \
339     } else {                                                        \
340       Assembler::insn_name##qdq arguments;                          \
341     }                                                               \
342   }
343 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(unpckh)
344 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(unpckl)
345 #undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
346 #undef DEFINE_INT_INSTRUCTION
347 
348 #define DEFINE_XMM_INT_INSTRUCTION(                                           \
349     insn_name, asm_name, type_check, parameters, arguments, signed, unsigned) \
350   template <typename format>                                                  \
351   std::enable_if_t<type_check<format>> insn_name parameters {                 \
352     if constexpr (kFormatIs<format, int8_t>) {                                \
353       Assembler::asm_name##signed##b arguments;                               \
354     } else if constexpr (kFormatIs<format, uint8_t>) {                        \
355       Assembler::asm_name##unsigned##b arguments;                             \
356     } else if constexpr (kFormatIs<format, int16_t>) {                        \
357       Assembler::asm_name##signed##w arguments;                               \
358     } else if constexpr (kFormatIs<format, uint16_t>) {                       \
359       Assembler::asm_name##unsigned##w arguments;                             \
360     } else if constexpr (kFormatIs<format, int32_t>) {                        \
361       Assembler::asm_name##signed##d arguments;                               \
362     } else if constexpr (kFormatIs<format, uint32_t>) {                       \
363       Assembler::asm_name##unsigned##d arguments;                             \
364     } else if constexpr (kFormatIs<format, int64_t>) {                        \
365       Assembler::asm_name##signed##q arguments;                               \
366     } else {                                                                  \
367       Assembler::asm_name##unsigned##q arguments;                             \
368     }                                                                         \
369   }
370 #define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name, asm_name, type_check, signed, unsigned) \
371   DEFINE_XMM_INT_INSTRUCTION(P##insn_name,                                                   \
372                              P##asm_name,                                                    \
373                              type_check,                                                     \
374                              (XMMRegister dest, Operand src),                                \
375                              (dest, src),                                                    \
376                              signed,                                                         \
377                              unsigned)                                                       \
378   DEFINE_XMM_INT_INSTRUCTION(P##insn_name,                                                   \
379                              P##asm_name,                                                    \
380                              type_check,                                                     \
381                              (XMMRegister dest, XMMRegister src),                            \
382                              (dest, src),                                                    \
383                              signed,                                                         \
384                              unsigned)                                                       \
385   DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name,                                                  \
386                              Vp##asm_name,                                                   \
387                              type_check,                                                     \
388                              (XMMRegister dest, XMMRegister src1, Operand src2),             \
389                              (dest, src1, src2),                                             \
390                              signed,                                                         \
391                              unsigned)                                                       \
392   DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name,                                                  \
393                              Vp##asm_name,                                                   \
394                              type_check,                                                     \
395                              (XMMRegister dest, XMMRegister src1, XMMRegister src2),         \
396                              (dest, src1, src2),                                             \
397                              signed,                                                         \
398                              unsigned)
399 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(add, add, kIntType, , )
400 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(adds, add, kIntTypeBW, s, us)
401 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(cmpeq, cmpeq, kIntType, , )
402 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(cmpgt, cmpgt, kSignedIntType, , )
403 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(max, max, kIntTypeBWL, s, u)
404 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(min, min, kIntTypeBWL, s, u)
405 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(mull, mull, kIntTypeWL, , )
406 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sl, sl, kIntTypeWLQ, l, l)
407 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sr, sr, kIntTypePsr, a, l)
408 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(subs, sub, kIntTypeBW, s, us)
409 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sub, sub, kIntType, , )
410 #undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
411 // Shifts have immediate form in addition to register-to-register form.
412 #define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name, asm_name, type_check, signed, unsigned) \
413   DEFINE_XMM_INT_INSTRUCTION(P##insn_name,                                                   \
414                              P##asm_name,                                                    \
415                              type_check,                                                     \
416                              (XMMRegister dest, int8_t imm),                                 \
417                              (dest, imm),                                                    \
418                              signed,                                                         \
419                              unsigned)                                                       \
420   DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name,                                                  \
421                              Vp##asm_name,                                                   \
422                              type_check,                                                     \
423                              (XMMRegister dest, XMMRegister src, int8_t imm),                \
424                              (dest, src, imm),                                               \
425                              signed,                                                         \
426                              unsigned)
427 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sl, sl, kIntTypeWLQ, l, l)
428 DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sr, sr, kIntTypePsr, a, l)
429 #undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
430 #undef DEFINE_XMM_INT_INSTRUCTION
431 
432 #define DEFINE_MOVS_INSTRUCTION(insn_name, opt_check, parameters, arguments) \
433   template <typename format>                                                 \
434   std::enable_if_t<kFloatType<format>> insn_name parameters {                \
435     if constexpr (kFormatIs<format, Float32>) {                              \
436       opt_check;                                                             \
437       Assembler::insn_name##s arguments;                                     \
438     } else {                                                                 \
439       opt_check;                                                             \
440       Assembler::insn_name##d arguments;                                     \
441     }                                                                        \
442   }
443 DEFINE_MOVS_INSTRUCTION(Movs, , (XMMRegister dest, Operand src), (dest, src))
444 DEFINE_MOVS_INSTRUCTION(Movs, , (Operand dest, XMMRegister src), (dest, src))
445 DEFINE_MOVS_INSTRUCTION(Movs,
446                         if (dest == src) return,
447                         (XMMRegister dest, XMMRegister src),
448                         (dest, src))
449 DEFINE_MOVS_INSTRUCTION(Vmovs, , (XMMRegister dest, Operand src), (dest, src))
450 DEFINE_MOVS_INSTRUCTION(Vmovs, , (Operand dest, XMMRegister src), (dest, src))
451 DEFINE_MOVS_INSTRUCTION(Vmovs,
452                         if ((dest == src1) && (dest == src2)) return,
453                         (XMMRegister dest, XMMRegister src1, XMMRegister src2),
454                         (dest, src1, src2))
455 #undef DEFINE_MOVS_INSTRUCTION
456 
457 #define DEFINE_XMM_MOV_INSTRUCTION(insn_name, parameters, arguments) \
458   template <typename format>                                         \
459   std::enable_if_t<kFloatType<format>> insn_name parameters {        \
460     if constexpr (kFormatIs<format, Float32>) {                      \
461       Assembler::insn_name##d arguments;                             \
462     } else {                                                         \
463       Assembler::insn_name##q arguments;                             \
464     }                                                                \
465   }
466 DEFINE_XMM_MOV_INSTRUCTION(Mov, (XMMRegister dest, Operand src), (dest, src))
467 DEFINE_XMM_MOV_INSTRUCTION(Mov, (Operand dest, XMMRegister src), (dest, src))
468 DEFINE_XMM_MOV_INSTRUCTION(Mov, (XMMRegister dest, Register src), (dest, src))
469 DEFINE_XMM_MOV_INSTRUCTION(Mov, (Register dest, XMMRegister src), (dest, src))
470 DEFINE_XMM_MOV_INSTRUCTION(Vmov, (XMMRegister dest, Operand src), (dest, src))
471 DEFINE_XMM_MOV_INSTRUCTION(Vmov, (Operand dest, XMMRegister src), (dest, src))
472 DEFINE_XMM_MOV_INSTRUCTION(Vmov, (XMMRegister dest, Register src), (dest, src))
473 DEFINE_XMM_MOV_INSTRUCTION(Vmov, (Register dest, XMMRegister src), (dest, src))
474 #undef DEFINE_XMM_MOV_INSTRUCTION
475 
476 #define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments)                           \
477   template <typename FormatFrom, typename FormatTo>                                            \
478   std::enable_if_t<kFloatType<FormatFrom> && kSignedIntType<FormatTo> && kIntTypeLQ<FormatTo>> \
479       insn_name parameters {                                                                   \
480     if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) {            \
481       Assembler::insn_name##ss2sil arguments;                                                  \
482     } else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) {     \
483       Assembler::insn_name##ss2siq(dest, src);                                                 \
484     } else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) {     \
485       Assembler::insn_name##sd2sil(dest, src);                                                 \
486     } else {                                                                                   \
487       Assembler::insn_name##sd2siq(dest, src);                                                 \
488     }                                                                                          \
489   }
490 DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, XMMRegister src), (dest, src))
491 DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, Operand src), (dest, src))
492 DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, XMMRegister src), (dest, src))
493 DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, Operand src), (dest, src))
494 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, XMMRegister src), (dest, src))
495 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, Operand src), (dest, src))
496 DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, XMMRegister src), (dest, src))
497 DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, Operand src), (dest, src))
498 #undef DEFINE_XMM_CVT_INSTRUCTION
499 
500 #define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments)                             \
501   template <typename FormatFrom, typename FormatTo>                                              \
502   std::enable_if_t<kSignedIntType<FormatFrom> && kIntTypeWL<FormatFrom> && kFloatType<FormatTo>> \
503       insn_name parameters {                                                                     \
504     if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) {              \
505       Assembler::insn_name##sil2ss arguments;                                                    \
506     } else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) {       \
507       Assembler::insn_name##siq2ss(dest, src);                                                   \
508     } else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) {       \
509       Assembler::insn_name##sil2sd(dest, src);                                                   \
510     } else {                                                                                     \
511       Assembler::insn_name##siq2sd(dest, src);                                                   \
512     }                                                                                            \
513   }
514 DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Register src), (dest, src))
515 DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Operand src), (dest, src))
516 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Register src), (dest, src))
517 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Operand src), (dest, src))
518 #undef DEFINE_XMM_CVT_INSTRUCTION
519 
520 #define DEFINE_XMM_CVT_INSTRUCTION(insn_name, insn_suffix, parameters, arguments)   \
521   template <typename FormatFrom, typename FormatTo>                                 \
522   std::enable_if_t<kFloatType<FormatFrom> && kFloatType<FormatTo> &&                \
523                    sizeof(FormatFrom) != sizeof(FormatTo)>                          \
524       insn_name##insn_suffix parameters {                                           \
525     if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, Float64>) { \
526       Assembler::insn_name##insn_suffix##s2##insn_suffix##d arguments;              \
527     } else {                                                                        \
528       Assembler::insn_name##insn_suffix##d2##insn_suffix##s arguments;              \
529     }                                                                               \
530   }
531 DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
532 DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, Operand src), (dest, src))
533 DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, XMMRegister src), (dest, src))
534 DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, Operand src), (dest, src))
535 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
536 DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, Operand src), (dest, src))
537 DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
538                            s,
539                            (XMMRegister dest, XMMRegister src1, XMMRegister src2),
540                            (dest, src1, src2))
541 DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
542                            s,
543                            (XMMRegister dest, XMMRegister src1, Operand src2),
544                            (dest, src1, src2))
545 #undef DEFINE_XMM_CVT_INSTRUCTION
546 
547 #define DEFINE_XMM_FLOAT_INSTRUCTION(insn_name, parameters, arguments) \
548   template <typename format>                                           \
549   std::enable_if_t<kFloatType<format>> insn_name parameters {          \
550     if constexpr (kFormatIs<format, Float32>) {                        \
551       Assembler::insn_name##s arguments;                               \
552     } else {                                                           \
553       Assembler::insn_name##d arguments;                               \
554     }                                                                  \
555   }
556 DEFINE_XMM_FLOAT_INSTRUCTION(Comis, (XMMRegister dest, Operand src), (dest, src))
557 DEFINE_XMM_FLOAT_INSTRUCTION(Comis, (XMMRegister dest, XMMRegister src), (dest, src))
558 DEFINE_XMM_FLOAT_INSTRUCTION(Ucomis, (XMMRegister dest, Operand src), (dest, src))
559 DEFINE_XMM_FLOAT_INSTRUCTION(Ucomis, (XMMRegister dest, XMMRegister src), (dest, src))
560 DEFINE_XMM_FLOAT_INSTRUCTION(Vcomis, (XMMRegister dest, Operand src), (dest, src))
561 DEFINE_XMM_FLOAT_INSTRUCTION(Vcomis, (XMMRegister dest, XMMRegister src), (dest, src))
562 DEFINE_XMM_FLOAT_INSTRUCTION(Vucomis, (XMMRegister dest, Operand src), (dest, src))
563 DEFINE_XMM_FLOAT_INSTRUCTION(Vucomis, (XMMRegister dest, XMMRegister src), (dest, src))
564 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name, vinsn_name)                      \
565   DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##s, (XMMRegister dest, Operand src), (dest, src))     \
566   DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##s, (XMMRegister dest, XMMRegister src), (dest, src)) \
567   DEFINE_XMM_FLOAT_INSTRUCTION(                                                                \
568       vinsn_name##s, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2))   \
569   DEFINE_XMM_FLOAT_INSTRUCTION(                                                                \
570       vinsn_name##s, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
571 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name, vinsn_name)                      \
572   DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##p, (XMMRegister dest, Operand src), (dest, src))     \
573   DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##p, (XMMRegister dest, XMMRegister src), (dest, src)) \
574   DEFINE_XMM_FLOAT_INSTRUCTION(                                                                \
575       vinsn_name##p, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2))   \
576   DEFINE_XMM_FLOAT_INSTRUCTION(                                                                \
577       vinsn_name##p, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
578 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(insn_name, vinsn_name)  \
579   DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name, vinsn_name) \
580   DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name, vinsn_name)
581 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Add, Vadd)
582 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpeq, Vcmpeq)
583 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmple, Vcmple)
584 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmplt, Vcmplt)
585 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpord, Vcmpord)
586 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpneq, Vcmpneq)
587 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpnle, Vcmpnle)
588 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpnlt, Vcmpnlt)
589 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpunord, Vcmpunord)
590 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Hadd, Vhadd)
591 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Max, Vmax)
592 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Min, Vmin)
593 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Mul, Vmul)
594 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Sub, Vsub)
595 // Note: logical operations ������������ don't have scalar versions!
596 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(And, Vand)
597 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(Or, Vor)
598 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(Xor, Vxor)
599 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
600 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
601 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP
602 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name)                               \
603   DEFINE_XMM_FLOAT_INSTRUCTION(                                                             \
604       insn_name##s, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
605   DEFINE_XMM_FLOAT_INSTRUCTION(                                                             \
606       insn_name##s, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
607 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name)                               \
608   DEFINE_XMM_FLOAT_INSTRUCTION(                                                             \
609       insn_name##p, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
610   DEFINE_XMM_FLOAT_INSTRUCTION(                                                             \
611       insn_name##p, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
612 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(insn_name)  \
613   DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name) \
614   DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name)
615 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd132)
616 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd213)
617 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd231)
618 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub132)
619 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub213)
620 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub231)
621 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub132)
622 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub213)
623 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub231)
624 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd132)
625 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd213)
626 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd231)
627 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd132)
628 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd213)
629 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd231)
630 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub132)
631 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub213)
632 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub231)
633 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
634 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
635 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name)                   \
636   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
637       insn_name##s,                                                             \
638       (XMMRegister dest, XMMRegister src1, XMMRegister src2, Operand src3),     \
639       (dest, src1, src2, src3))                                                 \
640   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
641       insn_name##s,                                                             \
642       (XMMRegister dest, XMMRegister src1, Operand src2, XMMRegister src3),     \
643       (dest, src1, src2, src3))                                                 \
644   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
645       insn_name##s,                                                             \
646       (XMMRegister dest, XMMRegister src1, XMMRegister src2, XMMRegister src3), \
647       (dest, src1, src2, src3))
648 #define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name)                   \
649   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
650       insn_name##p,                                                             \
651       (XMMRegister dest, XMMRegister src1, XMMRegister src2, Operand src3),     \
652       (dest, src1, src2, src3))                                                 \
653   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
654       insn_name##p,                                                             \
655       (XMMRegister dest, XMMRegister src1, Operand src2, XMMRegister src3),     \
656       (dest, src1, src2, src3))                                                 \
657   DEFINE_XMM_FLOAT_INSTRUCTION(                                                 \
658       insn_name##p,                                                             \
659       (XMMRegister dest, XMMRegister src1, XMMRegister src2, XMMRegister src3), \
660       (dest, src1, src2, src3))
661 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd)
662 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub)
663 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd)
664 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub)
665 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd)
666 DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub)
667 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
668 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
669 #undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP
670 // Special, unique, instructions
671 //   Movmskps/Movmskpd doesn't support memoru operand, Round[sp][sd] two arguments and immediate.
672 DEFINE_XMM_FLOAT_INSTRUCTION(Movmskp, (Register dest, XMMRegister src), (dest, src))
673 DEFINE_XMM_FLOAT_INSTRUCTION(Vmovmskp, (Register dest, XMMRegister src), (dest, src))
674 DEFINE_XMM_FLOAT_INSTRUCTION(Roundp,
675                              (XMMRegister dest, XMMRegister src, uint8_t imm8),
676                              (dest, src, imm8))
677 DEFINE_XMM_FLOAT_INSTRUCTION(Rounds,
678                              (XMMRegister dest, XMMRegister src, uint8_t imm8),
679                              (dest, src, imm8))
680 DEFINE_XMM_FLOAT_INSTRUCTION(Roundp,
681                              (XMMRegister dest, Operand src, uint8_t imm8),
682                              (dest, src, imm8))
683 DEFINE_XMM_FLOAT_INSTRUCTION(Rounds,
684                              (XMMRegister dest, Operand src, uint8_t imm8),
685                              (dest, src, imm8))
686 DEFINE_XMM_FLOAT_INSTRUCTION(Vroundp,
687                              (XMMRegister dest, XMMRegister src, uint8_t imm8),
688                              (dest, src, imm8))
689 DEFINE_XMM_FLOAT_INSTRUCTION(Vrounds,
690                              (XMMRegister dest, XMMRegister src, uint8_t imm8),
691                              (dest, src, imm8))
692 DEFINE_XMM_FLOAT_INSTRUCTION(Vroundp,
693                              (XMMRegister dest, Operand src, uint8_t imm8),
694                              (dest, src, imm8))
695 DEFINE_XMM_FLOAT_INSTRUCTION(Vrounds,
696                              (XMMRegister dest, Operand src, uint8_t imm8),
697                              (dest, src, imm8))
698 #undef DEFINE_XMM_FLOAT_INSTRUCTION
699