1 /* This file is part of the dynarmic project.
2 * Copyright (c) 2018 MerryMage
3 * SPDX-License-Identifier: 0BSD
4 */
5
6 #include "frontend/A64/translate/impl/impl.h"
7
8 namespace Dynarmic::A64 {
9 namespace {
10 enum class AbsoluteDifferenceBehavior {
11 None,
12 Accumulate
13 };
14
15 enum class Signedness {
16 Signed,
17 Unsigned
18 };
19
AbsoluteDifferenceLong(TranslatorVisitor & v,bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd,AbsoluteDifferenceBehavior behavior,Signedness sign)20 bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
21 AbsoluteDifferenceBehavior behavior, Signedness sign) {
22 if (size == 0b11) {
23 return v.ReservedValue();
24 }
25
26 const size_t esize = 8 << size.ZeroExtend();
27 const size_t datasize = 64;
28
29 const IR::U128 operand1 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vn, Q));
30 const IR::U128 operand2 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vm, Q));
31 IR::U128 result = sign == Signedness::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2)
32 : v.ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2);
33
34 if (behavior == AbsoluteDifferenceBehavior::Accumulate) {
35 const IR::U128 data = v.V(2 * datasize, Vd);
36 result = v.ir.VectorAdd(2 * esize, result, data);
37 }
38
39 v.V(2 * datasize, Vd, result);
40 return true;
41 }
42
43 enum class MultiplyLongBehavior {
44 None,
45 Accumulate,
46 Subtract
47 };
48
MultiplyLong(TranslatorVisitor & v,bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd,MultiplyLongBehavior behavior,Signedness sign)49 bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
50 MultiplyLongBehavior behavior, Signedness sign) {
51 if (size == 0b11) {
52 return v.ReservedValue();
53 }
54
55 const size_t esize = 8 << size.ZeroExtend();
56 const size_t doubled_esize = 2 * esize;
57 const size_t datasize = 64;
58 const size_t doubled_datasize = datasize * 2;
59
60 const auto get_operands = [&] {
61 const auto p1 = v.Vpart(datasize, Vn, Q);
62 const auto p2 = v.Vpart(datasize, Vm, Q);
63
64 if (sign == Signedness::Signed) {
65 return std::make_pair(v.ir.VectorSignExtend(esize, p1),
66 v.ir.VectorSignExtend(esize, p2));
67 }
68
69 return std::make_pair(v.ir.VectorZeroExtend(esize, p1),
70 v.ir.VectorZeroExtend(esize, p2));
71 };
72
73 const auto [operand1, operand2] = get_operands();
74 IR::U128 result = v.ir.VectorMultiply(doubled_esize, operand1, operand2);
75
76 if (behavior == MultiplyLongBehavior::Accumulate) {
77 const IR::U128 addend = v.V(doubled_datasize, Vd);
78 result = v.ir.VectorAdd(doubled_esize, addend, result);
79 } else if (behavior == MultiplyLongBehavior::Subtract) {
80 const IR::U128 minuend = v.V(doubled_datasize, Vd);
81 result = v.ir.VectorSub(doubled_esize, minuend, result);
82 }
83
84 v.V(doubled_datasize, Vd, result);
85 return true;
86 }
87
88 enum class LongOperationBehavior {
89 Addition,
90 Subtraction
91 };
92
LongOperation(TranslatorVisitor & v,bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd,LongOperationBehavior behavior,Signedness sign)93 bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
94 LongOperationBehavior behavior, Signedness sign) {
95 if (size == 0b11) {
96 return v.ReservedValue();
97 }
98
99 const size_t esize = 8 << size.ZeroExtend();
100 const size_t part = Q ? 1 : 0;
101
102 const auto get_operand = [&](Vec vec) {
103 const IR::U128 tmp = v.Vpart(64, vec, part);
104
105 if (sign == Signedness::Signed) {
106 return v.ir.VectorSignExtend(esize, tmp);
107 }
108
109 return v.ir.VectorZeroExtend(esize, tmp);
110 };
111
112 const IR::U128 operand1 = get_operand(Vn);
113 const IR::U128 operand2 = get_operand(Vm);
114 const IR::U128 result = [&] {
115 if (behavior == LongOperationBehavior::Addition) {
116 return v.ir.VectorAdd(esize * 2, operand1, operand2);
117 }
118
119 return v.ir.VectorSub(esize * 2, operand1, operand2);
120 }();
121
122 v.V(128, Vd, result);
123 return true;
124 }
125
126 enum class WideOperationBehavior {
127 Addition,
128 Subtraction
129 };
130
WideOperation(TranslatorVisitor & v,bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd,WideOperationBehavior behavior,Signedness sign)131 bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd,
132 WideOperationBehavior behavior, Signedness sign) {
133 if (size == 0b11) {
134 return v.ReservedValue();
135 }
136
137 const size_t esize = 8 << size.ZeroExtend();
138 const size_t part = Q ? 1 : 0;
139
140 const IR::U128 operand1 = v.V(128, Vn);
141 const IR::U128 operand2 = [&] {
142 const IR::U128 tmp = v.Vpart(64, Vm, part);
143
144 if (sign == Signedness::Signed) {
145 return v.ir.VectorSignExtend(esize, tmp);
146 }
147
148 return v.ir.VectorZeroExtend(esize, tmp);
149 }();
150 const IR::U128 result = [&] {
151 if (behavior == WideOperationBehavior::Addition) {
152 return v.ir.VectorAdd(esize * 2, operand1, operand2);
153 }
154
155 return v.ir.VectorSub(esize * 2, operand1, operand2);
156 }();
157
158 v.V(128, Vd, result);
159 return true;
160 }
161 } // Anonymous namespace
162
PMULL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)163 bool TranslatorVisitor::PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
164 if (size == 0b01 || size == 0b10) {
165 return ReservedValue();
166 }
167
168 const size_t esize = 8 << size.ZeroExtend();
169 const size_t datasize = 64;
170
171 const IR::U128 operand1 = Vpart(datasize, Vn, Q);
172 const IR::U128 operand2 = Vpart(datasize, Vm, Q);
173 const IR::U128 result = ir.VectorPolynomialMultiplyLong(esize, operand1, operand2);
174
175 V(128, Vd, result);
176 return true;
177 }
178
SABAL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)179 bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
180 return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed);
181 }
182
SABDL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)183 bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
184 return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed);
185 }
186
SADDL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)187 bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
188 return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Signed);
189 }
190
SADDW(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)191 bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
192 return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Signed);
193 }
194
SMLAL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)195 bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
196 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed);
197 }
198
SMLSL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)199 bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
200 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed);
201 }
202
SMULL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)203 bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
204 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed);
205 }
206
SSUBW(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)207 bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
208 return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Signed);
209 }
210
SSUBL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)211 bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
212 return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Signed);
213 }
214
UADDL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)215 bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
216 return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Unsigned);
217 }
218
UABAL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)219 bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
220 return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned);
221 }
222
UABDL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)223 bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
224 return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned);
225 }
226
UADDW(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)227 bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
228 return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Unsigned);
229 }
230
UMLAL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)231 bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
232 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned);
233 }
234
UMLSL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)235 bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
236 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned);
237 }
238
UMULL_vec(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)239 bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
240 return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned);
241 }
242
USUBW(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)243 bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
244 return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Unsigned);
245 }
246
USUBL(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)247 bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
248 return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Unsigned);
249 }
250
SQDMULL_vec_2(bool Q,Imm<2> size,Vec Vm,Vec Vn,Vec Vd)251 bool TranslatorVisitor::SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
252 if (size == 0b00 || size == 0b11) {
253 return ReservedValue();
254 }
255
256 const size_t esize = 8 << size.ZeroExtend();
257 const size_t part = Q ? 1 : 0;
258
259 const IR::U128 operand1 = Vpart(64, Vn, part);
260 const IR::U128 operand2 = Vpart(64, Vm, part);
261 const IR::U128 result = ir.VectorSignedSaturatedDoublingMultiplyLong(esize, operand1, operand2);
262
263 V(128, Vd, result);
264 return true;
265 }
266
267 } // namespace Dynarmic::A64
268