1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2016 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #include "frontend/A32/translate/impl/translate_arm.h"
7 
8 namespace Dynarmic::A32 {
9 
10 // MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_MLA(Cond cond,bool S,Reg d,Reg a,Reg m,Reg n)11 bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
12     if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
13         return UnpredictableInstruction();
14     }
15 
16     if (!ConditionPassed(cond)) {
17         return true;
18     }
19 
20     const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
21     ir.SetRegister(d, result);
22     if (S) {
23         ir.SetNFlag(ir.MostSignificantBit(result));
24         ir.SetZFlag(ir.IsZero(result));
25     }
26 
27     return true;
28 }
29 
30 // MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_MLS(Cond cond,Reg d,Reg a,Reg m,Reg n)31 bool ArmTranslatorVisitor::arm_MLS(Cond cond, Reg d, Reg a, Reg m, Reg n) {
32     if (d == Reg::PC || a == Reg::PC || m == Reg::PC || n == Reg::PC) {
33         return UnpredictableInstruction();
34     }
35 
36     if (!ConditionPassed(cond)) {
37         return true;
38     }
39 
40     const IR::U32 operand1 = ir.GetRegister(n);
41     const IR::U32 operand2 = ir.GetRegister(m);
42     const IR::U32 operand3 = ir.GetRegister(a);
43     const IR::U32 result = ir.Sub(operand3, ir.Mul(operand1, operand2));
44 
45     ir.SetRegister(d, result);
46     return true;
47 }
48 
49 // MUL{S}<c> <Rd>, <Rn>, <Rm>
arm_MUL(Cond cond,bool S,Reg d,Reg m,Reg n)50 bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
51     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
52         return UnpredictableInstruction();
53     }
54 
55     if (!ConditionPassed(cond)) {
56         return true;
57     }
58 
59     const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
60     ir.SetRegister(d, result);
61     if (S) {
62         ir.SetNFlag(ir.MostSignificantBit(result));
63         ir.SetZFlag(ir.IsZero(result));
64     }
65 
66     return true;
67 }
68 
69 
70 // SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLAL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)71 bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
72     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
73         return UnpredictableInstruction();
74     }
75 
76     if (dLo == dHi) {
77         return UnpredictableInstruction();
78     }
79 
80     if (!ConditionPassed(cond)) {
81         return true;
82     }
83 
84     const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
85     const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
86     const auto product = ir.Mul(n64, m64);
87     const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
88     const auto result = ir.Add(product, addend);
89     const auto lo = ir.LeastSignificantWord(result);
90     const auto hi = ir.MostSignificantWord(result).result;
91 
92     ir.SetRegister(dLo, lo);
93     ir.SetRegister(dHi, hi);
94     if (S) {
95         ir.SetNFlag(ir.MostSignificantBit(hi));
96         ir.SetZFlag(ir.IsZero(result));
97     }
98 
99     return true;
100 }
101 
102 // SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMULL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)103 bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
104     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
105         return UnpredictableInstruction();
106     }
107 
108     if (dLo == dHi) {
109         return UnpredictableInstruction();
110     }
111 
112     if (!ConditionPassed(cond)) {
113         return true;
114     }
115 
116     const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
117     const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
118     const auto result = ir.Mul(n64, m64);
119     const auto lo = ir.LeastSignificantWord(result);
120     const auto hi = ir.MostSignificantWord(result).result;
121 
122     ir.SetRegister(dLo, lo);
123     ir.SetRegister(dHi, hi);
124     if (S) {
125         ir.SetNFlag(ir.MostSignificantBit(hi));
126         ir.SetZFlag(ir.IsZero(result));
127     }
128 
129     return true;
130 }
131 
132 // UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMAAL(Cond cond,Reg dHi,Reg dLo,Reg m,Reg n)133 bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
134     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
135         return UnpredictableInstruction();
136     }
137 
138     if (dLo == dHi) {
139         return UnpredictableInstruction();
140     }
141 
142     if (!ConditionPassed(cond)) {
143         return true;
144     }
145 
146     const auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
147     const auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
148     const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
149     const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
150     const auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
151 
152     ir.SetRegister(dLo, ir.LeastSignificantWord(result));
153     ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
154     return true;
155 }
156 
157 // UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMLAL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)158 bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
159     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
160         return UnpredictableInstruction();
161     }
162 
163     if (dLo == dHi) {
164         return UnpredictableInstruction();
165     }
166 
167     if (!ConditionPassed(cond)) {
168         return true;
169     }
170 
171     const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
172     const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
173     const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
174     const auto result = ir.Add(ir.Mul(n64, m64), addend);
175     const auto lo = ir.LeastSignificantWord(result);
176     const auto hi = ir.MostSignificantWord(result).result;
177 
178     ir.SetRegister(dLo, lo);
179     ir.SetRegister(dHi, hi);
180     if (S) {
181         ir.SetNFlag(ir.MostSignificantBit(hi));
182         ir.SetZFlag(ir.IsZero(result));
183     }
184 
185     return true;
186 }
187 
188 // UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMULL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)189 bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
190     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
191         return UnpredictableInstruction();
192     }
193 
194     if (dLo == dHi) {
195         return UnpredictableInstruction();
196     }
197 
198     if (!ConditionPassed(cond)) {
199         return true;
200     }
201 
202     const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
203     const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
204     const auto result = ir.Mul(n64, m64);
205     const auto lo = ir.LeastSignificantWord(result);
206     const auto hi = ir.MostSignificantWord(result).result;
207 
208     ir.SetRegister(dLo, lo);
209     ir.SetRegister(dHi, hi);
210     if (S) {
211         ir.SetNFlag(ir.MostSignificantBit(hi));
212         ir.SetZFlag(ir.IsZero(result));
213     }
214 
215     return true;
216 }
217 
218 // SMLAL<x><y><c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLALxy(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,bool N,Reg n)219 bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) {
220     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
221         return UnpredictableInstruction();
222     }
223 
224     if (dLo == dHi) {
225         return UnpredictableInstruction();
226     }
227 
228     if (!ConditionPassed(cond)) {
229         return true;
230     }
231 
232     const IR::U32 n32 = ir.GetRegister(n);
233     const IR::U32 m32 = ir.GetRegister(m);
234     const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
235                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
236     const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
237                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
238     const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16));
239     const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
240     const auto result = ir.Add(product, addend);
241 
242     ir.SetRegister(dLo, ir.LeastSignificantWord(result));
243     ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
244     return true;
245 }
246 
247 // SMLA<x><y><c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAxy(Cond cond,Reg d,Reg a,Reg m,bool M,bool N,Reg n)248 bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n) {
249     if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
250         return UnpredictableInstruction();
251     }
252 
253     if (!ConditionPassed(cond)) {
254         return true;
255     }
256 
257     const IR::U32 n32 = ir.GetRegister(n);
258     const IR::U32 m32 = ir.GetRegister(m);
259     const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
260                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
261     const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
262                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
263     const IR::U32 product = ir.Mul(n16, m16);
264     const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
265 
266     ir.SetRegister(d, result_overflow.result);
267     ir.OrQFlag(result_overflow.overflow);
268     return true;
269 }
270 
271 // SMUL<x><y><c> <Rd>, <Rn>, <Rm>
arm_SMULxy(Cond cond,Reg d,Reg m,bool M,bool N,Reg n)272 bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n) {
273     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
274         return UnpredictableInstruction();
275     }
276 
277     if (!ConditionPassed(cond)) {
278         return true;
279     }
280 
281     const IR::U32 n32 = ir.GetRegister(n);
282     const IR::U32 m32 = ir.GetRegister(m);
283     const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
284                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
285     const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
286                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
287     const IR::U32 result = ir.Mul(n16, m16);
288 
289     ir.SetRegister(d, result);
290     return true;
291 }
292 
293 // SMLAW<y><c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAWy(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)294 bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
295     if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
296         return UnpredictableInstruction();
297     }
298 
299     if (!ConditionPassed(cond)) {
300         return true;
301     }
302 
303     const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
304     IR::U32 m32 = ir.GetRegister(m);
305     if (M) {
306         m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
307     }
308     const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
309     const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
310     const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
311 
312     ir.SetRegister(d, result_overflow.result);
313     ir.OrQFlag(result_overflow.overflow);
314     return true;
315 }
316 
317 // SMULW<y><c> <Rd>, <Rn>, <Rm>
arm_SMULWy(Cond cond,Reg d,Reg m,bool M,Reg n)318 bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) {
319     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
320         return UnpredictableInstruction();
321     }
322 
323     if (!ConditionPassed(cond)) {
324         return true;
325     }
326 
327     const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
328     IR::U32 m32 = ir.GetRegister(m);
329     if (M) {
330         m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
331     }
332     const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
333     const auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
334 
335     ir.SetRegister(d, ir.LeastSignificantWord(result));
336     return true;
337 }
338 
339 // SMMLA{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMMLA(Cond cond,Reg d,Reg a,Reg m,bool R,Reg n)340 bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
341     if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */) {
342         return UnpredictableInstruction();
343     }
344 
345     if (!ConditionPassed(cond)) {
346         return true;
347     }
348 
349     const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
350     const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
351     const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
352     const auto temp = ir.Add(a64, ir.Mul(n64, m64));
353     const auto result_carry = ir.MostSignificantWord(temp);
354     auto result = result_carry.result;
355     if (R) {
356         result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
357     }
358 
359     ir.SetRegister(d, result);
360     return true;
361 }
362 
363 // SMMLS{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMMLS(Cond cond,Reg d,Reg a,Reg m,bool R,Reg n)364 bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
365     if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
366         return UnpredictableInstruction();
367     }
368 
369     if (!ConditionPassed(cond)) {
370         return true;
371     }
372 
373     const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
374     const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
375     const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
376     const auto temp = ir.Sub(a64, ir.Mul(n64, m64));
377     const auto result_carry = ir.MostSignificantWord(temp);
378     auto result = result_carry.result;
379     if (R) {
380         result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
381     }
382 
383     ir.SetRegister(d, result);
384     return true;
385 }
386 
387 // SMMUL{R}<c> <Rd>, <Rn>, <Rm>
arm_SMMUL(Cond cond,Reg d,Reg m,bool R,Reg n)388 bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
389     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
390         return UnpredictableInstruction();
391     }
392 
393     if (!ConditionPassed(cond)) {
394         return true;
395     }
396 
397     const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
398     const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
399     const auto product = ir.Mul(n64, m64);
400     const auto result_carry = ir.MostSignificantWord(product);
401     auto result = result_carry.result;
402     if (R) {
403         result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
404     }
405 
406     ir.SetRegister(d, result);
407     return true;
408 }
409 
410 // SMLAD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAD(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)411 bool ArmTranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
412     if (a == Reg::PC) {
413         return arm_SMUAD(cond, d, m, M, n);
414     }
415 
416     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
417         return UnpredictableInstruction();
418     }
419 
420     if (!ConditionPassed(cond)) {
421         return true;
422     }
423 
424     const IR::U32 n32 = ir.GetRegister(n);
425     const IR::U32 m32 = ir.GetRegister(m);
426     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
427     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
428 
429     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
430     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
431     if (M) {
432         std::swap(m_lo, m_hi);
433     }
434 
435     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
436     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
437     const IR::U32 addend = ir.GetRegister(a);
438 
439     auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
440     ir.OrQFlag(result_overflow.overflow);
441     result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
442     ir.SetRegister(d, result_overflow.result);
443     ir.OrQFlag(result_overflow.overflow);
444     return true;
445 }
446 
447 // SMLALD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLALD(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,Reg n)448 bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
449     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
450         return UnpredictableInstruction();
451     }
452 
453     if (dLo == dHi) {
454         return UnpredictableInstruction();
455     }
456 
457     if (!ConditionPassed(cond)) {
458         return true;
459     }
460 
461     const IR::U32 n32 = ir.GetRegister(n);
462     const IR::U32 m32 = ir.GetRegister(m);
463     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
464     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
465 
466     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
467     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
468     if (M) {
469         std::swap(m_lo, m_hi);
470     }
471 
472     const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
473     const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
474     const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
475     const auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
476 
477     ir.SetRegister(dLo, ir.LeastSignificantWord(result));
478     ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
479     return true;
480 }
481 
482 // SMLSD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLSD(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)483 bool ArmTranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
484     if (a == Reg::PC) {
485         return arm_SMUSD(cond, d, m, M, n);
486     }
487 
488     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
489         return UnpredictableInstruction();
490     }
491 
492     if (!ConditionPassed(cond)) {
493         return true;
494     }
495 
496     const IR::U32 n32 = ir.GetRegister(n);
497     const IR::U32 m32 = ir.GetRegister(m);
498     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
499     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
500 
501     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
502     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
503     if (M) {
504         std::swap(m_lo, m_hi);
505     }
506 
507     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
508     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
509     const IR::U32 addend = ir.GetRegister(a);
510     const IR::U32 product = ir.Sub(product_lo, product_hi);
511     auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
512 
513     ir.SetRegister(d, result_overflow.result);
514     ir.OrQFlag(result_overflow.overflow);
515     return true;
516 }
517 
518 // SMLSLD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLSLD(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,Reg n)519 bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
520     if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
521         return UnpredictableInstruction();
522     }
523 
524     if (dLo == dHi) {
525         return UnpredictableInstruction();
526     }
527 
528     if (!ConditionPassed(cond)) {
529         return true;
530     }
531 
532     const IR::U32 n32 = ir.GetRegister(n);
533     const IR::U32 m32 = ir.GetRegister(m);
534     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
535     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
536 
537     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
538     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
539     if (M) {
540         std::swap(m_lo, m_hi);
541     }
542 
543     const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
544     const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
545     const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
546     const auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
547 
548     ir.SetRegister(dLo, ir.LeastSignificantWord(result));
549     ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
550     return true;
551 }
552 
553 // SMUAD{X}<c> <Rd>, <Rn>, <Rm>
arm_SMUAD(Cond cond,Reg d,Reg m,bool M,Reg n)554 bool ArmTranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) {
555     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
556         return UnpredictableInstruction();
557     }
558 
559     if (!ConditionPassed(cond)) {
560         return true;
561     }
562 
563     const IR::U32 n32 = ir.GetRegister(n);
564     const IR::U32 m32 = ir.GetRegister(m);
565     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
566     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
567 
568     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
569     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
570     if (M) {
571         std::swap(m_lo, m_hi);
572     }
573 
574     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
575     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
576     const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
577 
578     ir.SetRegister(d, result_overflow.result);
579     ir.OrQFlag(result_overflow.overflow);
580     return true;
581 }
582 
583 // SMUSD{X}<c> <Rd>, <Rn>, <Rm>
arm_SMUSD(Cond cond,Reg d,Reg m,bool M,Reg n)584 bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) {
585     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
586         return UnpredictableInstruction();
587     }
588 
589     if (!ConditionPassed(cond)) {
590         return true;
591     }
592 
593     const IR::U32 n32 = ir.GetRegister(n);
594     const IR::U32 m32 = ir.GetRegister(m);
595     const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
596     const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
597 
598     IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
599     IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
600     if (M) {
601         std::swap(m_lo, m_hi);
602     }
603 
604     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
605     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
606     auto result = ir.Sub(product_lo, product_hi);
607     ir.SetRegister(d, result);
608     return true;
609 }
610 
611 } // namespace Dynarmic::A32
612