Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #include "api-build_p.h"
8 : #if !defined(ASMJIT_NO_AARCH64)
9 :
10 : #include "formatter.h"
11 : #include "funcargscontext_p.h"
12 : #include "moved_string.h"
13 : #include "support.h"
14 : #include "type.h"
15 : #include "a64emithelper_p.h"
16 : #include "a64formatter_p.h"
17 : #include "a64instapi_p.h"
18 : #include "a64operand.h"
19 :
20 : ASMJIT_BEGIN_SUB_NAMESPACE(a64)
21 :
22 : // a64::EmitHelper - Emit Operations
23 : // =================================
24 :
25 0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove(
26 : const Operand_& dst_,
27 : const Operand_& src_, TypeId typeId, const char* comment) {
28 :
29 0 : Emitter* emitter = _emitter->as<Emitter>();
30 :
31 : // Invalid or abstract TypeIds are not allowed.
32 : ASMJIT_ASSERT(TypeUtils::isValid(typeId) && !TypeUtils::isAbstract(typeId));
33 :
34 : emitter->setInlineComment(comment);
35 :
36 0 : if (dst_.isReg() && src_.isMem()) {
37 : Reg dst(dst_.as<Reg>());
38 : Mem src(src_.as<Mem>());
39 :
40 0 : switch (typeId) {
41 0 : case TypeId::kInt8:
42 : case TypeId::kUInt8:
43 0 : return emitter->ldrb(dst.as<Gp>(), src);
44 :
45 0 : case TypeId::kInt16:
46 : case TypeId::kUInt16:
47 0 : return emitter->ldrh(dst.as<Gp>(), src);
48 :
49 0 : case TypeId::kInt32:
50 : case TypeId::kUInt32:
51 0 : return emitter->ldr(dst.as<Gp>().w(), src);
52 :
53 0 : case TypeId::kInt64:
54 : case TypeId::kUInt64:
55 0 : return emitter->ldr(dst.as<Gp>().x(), src);
56 :
57 : default: {
58 0 : if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
59 0 : return emitter->ldr(dst.as<Vec>().s(), src);
60 :
61 0 : if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
62 0 : return emitter->ldr(dst.as<Vec>().d(), src);
63 :
64 0 : if (TypeUtils::isVec128(typeId))
65 0 : return emitter->ldr(dst.as<Vec>().q(), src);
66 :
67 : break;
68 : }
69 : }
70 : }
71 :
72 0 : if (dst_.isMem() && src_.isReg()) {
73 : Mem dst(dst_.as<Mem>());
74 : Reg src(src_.as<Reg>());
75 :
76 0 : switch (typeId) {
77 0 : case TypeId::kInt8:
78 : case TypeId::kUInt8:
79 0 : return emitter->strb(src.as<Gp>(), dst);
80 :
81 0 : case TypeId::kInt16:
82 : case TypeId::kUInt16:
83 0 : return emitter->strh(src.as<Gp>(), dst);
84 :
85 0 : case TypeId::kInt32:
86 : case TypeId::kUInt32:
87 0 : return emitter->str(src.as<Gp>().w(), dst);
88 :
89 0 : case TypeId::kInt64:
90 : case TypeId::kUInt64:
91 0 : return emitter->str(src.as<Gp>().x(), dst);
92 :
93 : default: {
94 0 : if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
95 0 : return emitter->str(src.as<Vec>().s(), dst);
96 :
97 0 : if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
98 0 : return emitter->str(src.as<Vec>().d(), dst);
99 :
100 0 : if (TypeUtils::isVec128(typeId))
101 0 : return emitter->str(src.as<Vec>().q(), dst);
102 :
103 : break;
104 : }
105 : }
106 : }
107 :
108 0 : if (dst_.isReg() && src_.isReg()) {
109 : Reg dst(dst_.as<Reg>());
110 : Reg src(src_.as<Reg>());
111 :
112 0 : switch (typeId) {
113 0 : case TypeId::kInt8:
114 : case TypeId::kUInt8:
115 : case TypeId::kInt16:
116 : case TypeId::kUInt16:
117 : case TypeId::kInt32:
118 : case TypeId::kUInt32:
119 : case TypeId::kInt64:
120 : case TypeId::kUInt64:
121 0 : return emitter->mov(dst.as<Gp>().x(), src.as<Gp>().x());
122 :
123 : default: {
124 0 : if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
125 0 : return emitter->fmov(dst.as<Vec>().s(), src.as<Vec>().s());
126 :
127 0 : if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
128 0 : return emitter->mov(dst.as<Vec>().b8(), src.as<Vec>().b8());
129 :
130 0 : if (TypeUtils::isVec128(typeId))
131 0 : return emitter->mov(dst.as<Vec>().b16(), src.as<Vec>().b16());
132 :
133 : break;
134 : }
135 : }
136 : }
137 :
138 : emitter->setInlineComment(nullptr);
139 0 : return DebugUtils::errored(kErrorInvalidState);
140 : }
141 :
142 0 : Error EmitHelper::emitRegSwap(
143 : const BaseReg& a,
144 : const BaseReg& b, const char* comment) {
145 :
146 : DebugUtils::unused(a, b, comment);
147 0 : return DebugUtils::errored(kErrorInvalidState);
148 : }
149 :
150 : // TODO: [ARM] EmitArgMove is unfinished.
151 0 : Error EmitHelper::emitArgMove(
152 : const BaseReg& dst_, TypeId dstTypeId,
153 : const Operand_& src_, TypeId srcTypeId, const char* comment) {
154 :
155 : // Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
156 0 : if (dstTypeId == TypeId::kVoid) {
157 0 : const ArchTraits& archTraits = ArchTraits::byArch(_emitter->arch());
158 : dstTypeId = archTraits.regTypeToTypeId(dst_.type());
159 : }
160 :
161 : // Invalid or abstract TypeIds are not allowed.
162 : ASMJIT_ASSERT(TypeUtils::isValid(dstTypeId) && !TypeUtils::isAbstract(dstTypeId));
163 : ASMJIT_ASSERT(TypeUtils::isValid(srcTypeId) && !TypeUtils::isAbstract(srcTypeId));
164 :
165 : Reg dst(dst_.as<Reg>());
166 : Operand src(src_);
167 :
168 : uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
169 : uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
170 :
171 : if (TypeUtils::isInt(dstTypeId)) {
172 : if (TypeUtils::isInt(srcTypeId)) {
173 : uint32_t x = dstSize == 8;
174 :
175 0 : dst.setSignature(OperandSignature{x ? uint32_t(GpX::kSignature) : uint32_t(GpW::kSignature)});
176 0 : _emitter->setInlineComment(comment);
177 :
178 0 : if (src.isReg()) {
179 : src.setSignature(dst.signature());
180 0 : return _emitter->emit(Inst::kIdMov, dst, src);
181 : }
182 0 : else if (src.isMem()) {
183 : InstId instId = Inst::kIdNone;
184 0 : switch (srcTypeId) {
185 : case TypeId::kInt8: instId = Inst::kIdLdrsb; break;
186 0 : case TypeId::kUInt8: instId = Inst::kIdLdrb; break;
187 0 : case TypeId::kInt16: instId = Inst::kIdLdrsh; break;
188 0 : case TypeId::kUInt16: instId = Inst::kIdLdrh; break;
189 0 : case TypeId::kInt32: instId = x ? Inst::kIdLdrsw : Inst::kIdLdr; break;
190 0 : case TypeId::kUInt32: instId = Inst::kIdLdr; x = 0; break;
191 0 : case TypeId::kInt64: instId = Inst::kIdLdr; break;
192 0 : case TypeId::kUInt64: instId = Inst::kIdLdr; break;
193 : default:
194 : return DebugUtils::errored(kErrorInvalidState);
195 : }
196 0 : return _emitter->emit(instId, dst, src);
197 : }
198 : }
199 : }
200 :
201 : if (TypeUtils::isFloat(dstTypeId) || TypeUtils::isVec(dstTypeId)) {
202 : if (TypeUtils::isFloat(srcTypeId) || TypeUtils::isVec(srcTypeId)) {
203 0 : switch (srcSize) {
204 0 : case 2: dst.as<Vec>().setSignature(OperandSignature{VecH::kSignature}); break;
205 0 : case 4: dst.as<Vec>().setSignature(OperandSignature{VecS::kSignature}); break;
206 0 : case 8: dst.as<Vec>().setSignature(OperandSignature{VecD::kSignature}); break;
207 0 : case 16: dst.as<Vec>().setSignature(OperandSignature{VecV::kSignature}); break;
208 : default:
209 : return DebugUtils::errored(kErrorInvalidState);
210 : }
211 :
212 0 : _emitter->setInlineComment(comment);
213 :
214 0 : if (src.isReg()) {
215 0 : InstId instId = srcSize <= 4 ? Inst::kIdFmov_v : Inst::kIdMov_v;
216 : src.setSignature(dst.signature());
217 0 : return _emitter->emit(instId, dst, src);
218 : }
219 0 : else if (src.isMem()) {
220 0 : return _emitter->emit(Inst::kIdLdr_v, dst, src);
221 : }
222 : }
223 : }
224 :
225 : return DebugUtils::errored(kErrorInvalidState);
226 : }
227 :
228 : // a64::EmitHelper - Emit Prolog & Epilog
229 : // ======================================
230 :
231 : struct LoadStoreInstructions {
232 : InstId singleInstId;
233 : InstId pairInstId;
234 : };
235 :
236 : struct PrologEpilogInfo {
237 : struct RegPair {
238 : uint8_t ids[2];
239 : uint16_t offset;
240 : };
241 :
242 : struct GroupData {
243 : RegPair pairs[16];
244 : uint32_t pairCount;
245 : };
246 :
247 : Support::Array<GroupData, 2> groups;
248 : uint32_t sizeTotal;
249 :
250 0 : Error init(const FuncFrame& frame) noexcept {
251 : uint32_t offset = 0;
252 :
253 0 : for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
254 : GroupData& data = groups[group];
255 :
256 : uint32_t n = 0;
257 : uint32_t pairCount = 0;
258 0 : RegPair* pairs = data.pairs;
259 :
260 : uint32_t slotSize = frame.saveRestoreRegSize(group);
261 : uint32_t savedRegs = frame.savedRegs(group);
262 :
263 0 : if (group == RegGroup::kGp && frame.hasPreservedFP()) {
264 : // Must be at the beginning of the push/pop sequence.
265 : ASMJIT_ASSERT(pairCount == 0);
266 :
267 0 : pairs[0].offset = uint16_t(offset);
268 0 : pairs[0].ids[0] = Gp::kIdFp;
269 0 : pairs[0].ids[1] = Gp::kIdLr;
270 0 : offset += slotSize * 2;
271 : pairCount++;
272 :
273 0 : savedRegs &= ~Support::bitMask(Gp::kIdFp, Gp::kIdLr);
274 : }
275 :
276 : Support::BitWordIterator<uint32_t> it(savedRegs);
277 0 : while (it.hasNext()) {
278 0 : pairs[pairCount].ids[n] = uint8_t(it.next());
279 :
280 0 : if (++n == 2) {
281 0 : pairs[pairCount].offset = uint16_t(offset);
282 0 : offset += slotSize * 2;
283 :
284 : n = 0;
285 0 : pairCount++;
286 : }
287 : }
288 :
289 0 : if (n == 1) {
290 0 : pairs[pairCount].ids[1] = uint8_t(BaseReg::kIdBad);
291 0 : pairs[pairCount].offset = uint16_t(offset);
292 0 : offset += slotSize * 2;
293 0 : pairCount++;
294 : }
295 :
296 0 : data.pairCount = pairCount;
297 : }
298 :
299 0 : sizeTotal = offset;
300 0 : return kErrorOk;
301 : }
302 : };
303 :
304 0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
305 0 : Emitter* emitter = _emitter->as<Emitter>();
306 :
307 : PrologEpilogInfo pei;
308 0 : ASMJIT_PROPAGATE(pei.init(frame));
309 :
310 : static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
311 : static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
312 : { Inst::kIdStr , Inst::kIdStp },
313 : { Inst::kIdStr_v, Inst::kIdStp_v }
314 : }};
315 :
316 0 : uint32_t adjustInitialOffset = pei.sizeTotal;
317 :
318 0 : for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
319 : const PrologEpilogInfo::GroupData& data = pei.groups[group];
320 0 : uint32_t pairCount = data.pairCount;
321 :
322 : Reg regs[2] = { groupRegs[group], groupRegs[group] };
323 0 : Mem mem = ptr(sp);
324 :
325 : const LoadStoreInstructions& insts = groupInsts[group];
326 0 : for (uint32_t i = 0; i < pairCount; i++) {
327 : const PrologEpilogInfo::RegPair& pair = data.pairs[i];
328 :
329 0 : regs[0].setId(pair.ids[0]);
330 0 : regs[1].setId(pair.ids[1]);
331 0 : mem.setOffsetLo32(pair.offset);
332 :
333 0 : if (pair.offset == 0 && adjustInitialOffset) {
334 0 : mem.setOffset(-int(adjustInitialOffset));
335 0 : mem.makePreIndex();
336 : }
337 :
338 0 : if (pair.ids[1] == BaseReg::kIdBad)
339 0 : ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
340 : else
341 0 : ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
342 :
343 : mem.resetToFixedOffset();
344 :
345 0 : if (i == 0 && frame.hasPreservedFP()) {
346 0 : ASMJIT_PROPAGATE(emitter->mov(x29, sp));
347 : }
348 : }
349 : }
350 :
351 0 : if (frame.hasStackAdjustment()) {
352 : uint32_t adj = frame.stackAdjustment();
353 0 : if (adj <= 0xFFFu) {
354 0 : ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj));
355 : }
356 0 : else if (adj <= 0xFFFFFFu) {
357 : // TODO: [ARM] Prolog - we must touch the pages otherwise it's undefined.
358 0 : ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0x000FFFu));
359 0 : ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0xFFF000u));
360 : }
361 : else {
362 : return DebugUtils::errored(kErrorInvalidState);
363 : }
364 : }
365 :
366 : return kErrorOk;
367 : }
368 :
369 : // TODO: [ARM] Emit epilog.
370 0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
371 0 : Emitter* emitter = _emitter->as<Emitter>();
372 :
373 : PrologEpilogInfo pei;
374 0 : ASMJIT_PROPAGATE(pei.init(frame));
375 :
376 : static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
377 : static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
378 : { Inst::kIdLdr , Inst::kIdLdp },
379 : { Inst::kIdLdr_v, Inst::kIdLdp_v }
380 : }};
381 :
382 0 : uint32_t adjustInitialOffset = pei.sizeTotal;
383 :
384 0 : if (frame.hasStackAdjustment()) {
385 : uint32_t adj = frame.stackAdjustment();
386 0 : if (adj <= 0xFFFu) {
387 0 : ASMJIT_PROPAGATE(emitter->add(sp, sp, adj));
388 : }
389 0 : else if (adj <= 0xFFFFFFu) {
390 0 : ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0x000FFFu));
391 0 : ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0xFFF000u));
392 : }
393 : else {
394 : return DebugUtils::errored(kErrorInvalidState);
395 : }
396 : }
397 :
398 0 : for (int g = 1; g >= 0; g--) {
399 : RegGroup group = RegGroup(g);
400 : const PrologEpilogInfo::GroupData& data = pei.groups[group];
401 0 : uint32_t pairCount = data.pairCount;
402 :
403 : Reg regs[2] = { groupRegs[group], groupRegs[group] };
404 0 : Mem mem = ptr(sp);
405 :
406 : const LoadStoreInstructions& insts = groupInsts[group];
407 :
408 0 : for (int i = int(pairCount) - 1; i >= 0; i--) {
409 : const PrologEpilogInfo::RegPair& pair = data.pairs[i];
410 :
411 0 : regs[0].setId(pair.ids[0]);
412 0 : regs[1].setId(pair.ids[1]);
413 0 : mem.setOffsetLo32(pair.offset);
414 :
415 0 : if (pair.offset == 0 && adjustInitialOffset) {
416 0 : mem.setOffset(int(adjustInitialOffset));
417 0 : mem.makePostIndex();
418 : }
419 :
420 0 : if (pair.ids[1] == BaseReg::kIdBad)
421 0 : ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
422 : else
423 0 : ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
424 :
425 : mem.resetToFixedOffset();
426 : }
427 : }
428 :
429 0 : ASMJIT_PROPAGATE(emitter->ret(x30));
430 :
431 : return kErrorOk;
432 : }
433 :
434 0 : static Error ASMJIT_CDECL Emitter_emitProlog(BaseEmitter* emitter, const FuncFrame& frame) {
435 : EmitHelper emitHelper(emitter);
436 0 : return emitHelper.emitProlog(frame);
437 : }
438 :
439 0 : static Error ASMJIT_CDECL Emitter_emitEpilog(BaseEmitter* emitter, const FuncFrame& frame) {
440 : EmitHelper emitHelper(emitter);
441 0 : return emitHelper.emitEpilog(frame);
442 : }
443 :
444 0 : static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) {
445 : EmitHelper emitHelper(emitter);
446 0 : return emitHelper.emitArgsAssignment(frame, args);
447 : }
448 :
449 0 : void assignEmitterFuncs(BaseEmitter* emitter) {
450 0 : emitter->_funcs.emitProlog = Emitter_emitProlog;
451 0 : emitter->_funcs.emitEpilog = Emitter_emitEpilog;
452 0 : emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
453 :
454 : #ifndef ASMJIT_NO_LOGGING
455 0 : emitter->_funcs.formatInstruction = FormatterInternal::formatInstruction;
456 : #endif
457 :
458 : #ifndef ASMJIT_NO_VALIDATION
459 0 : emitter->_funcs.validate = InstInternal::validate;
460 : #endif
461 0 : }
462 :
463 : ASMJIT_END_SUB_NAMESPACE
464 :
465 : #endif // !ASMJIT_NO_AARCH64
466 :
467 : #endif // __PLUMED_HAS_ASMJIT
|