2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
23 #if !defined(ARCH_POWER64)
25 #define OP_SIZE_NATIVE OP_SIZE_4
26 #define OP_SIZE_ADDRESS OP_SIZE_4
28 #define FRAME_SIZE 128
29 #define REGS_OFFSET 56
30 #define LR_OFFSET (FRAME_SIZE + 8)
34 #define LR_OFFSET (FRAME_SIZE + 4)
39 #define OP_SIZE_NATIVE OP_SIZE_8
40 #define OP_SIZE_ADDRESS OP_SIZE_8
42 #define FRAME_SIZE 256
43 #define REGS_OFFSET 112
44 #define LR_OFFSET (FRAME_SIZE + 16)
45 #define STRUCT_RET_OFFSET 304
47 #define FRAME_SIZE 176
48 #define REGS_OFFSET 32
49 #define LR_OFFSET (FRAME_SIZE + 16)
54 #define JMP_LIMIT JMP_SHORT
56 #define UNALIGNED_TRAP 0
58 #define ALU_WRITES_FLAGS(alu, im) (!(im) ? \
59 ((alu) == ALU_SUB && !cpu_test_feature(CPU_FEATURE_ppc) ? 2 : (alu) == ALU_ADC || (alu) == ALU_SBB ? 2 : 0) :\
60 ((alu) == ALU_AND ? 1 : 0)\
62 #define ALU1_WRITES_FLAGS(alu) 0
63 #define ROT_WRITES_FLAGS(alu, size, im) 0
64 #define COND_IS_LOGICAL(cond) ((cond) == COND_B || (cond) == COND_AE || (cond) == COND_BE || (cond) == COND_A)
66 #define ARCH_PARTIAL_ALU(size) 0
67 #define ARCH_IS_3ADDRESS(alu, f) 1
68 #define ARCH_IS_3ADDRESS_IMM(alu, f) 1
69 #define ARCH_IS_3ADDRESS_ROT(alu, size) 1
70 #define ARCH_IS_3ADDRESS_ROT_IMM(alu) 1
71 #define ARCH_IS_2ADDRESS(alu) 1
72 #define ARCH_IS_3ADDRESS_FP 1
73 #define ARCH_HAS_JMP_2REGS(cond) 0
74 #define ARCH_HAS_FLAGS 1
75 #define ARCH_PREFERS_SX(size) 0
76 #define ARCH_HAS_BWX 1
77 #define ARCH_HAS_MUL 1
78 #define ARCH_HAS_DIV cpu_test_feature(CPU_FEATURE_ppc)
79 #define ARCH_HAS_ANDN 1
80 #define ARCH_HAS_SHIFTED_ADD(bits) 0
81 #define ARCH_HAS_BTX(btx, size, cnst) 0
82 #define ARCH_SHIFT_SIZE OP_SIZE_16
83 #define ARCH_BOOL_SIZE OP_SIZE_NATIVE
84 #define ARCH_HAS_FP_GP_MOV 0
85 #define ARCH_NEEDS_BARRIER 0
87 #define i_size(size) OP_SIZE_NATIVE
88 #define i_size_rot(size) maximum(size, OP_SIZE_4)
89 #define i_size_cmp(size) maximum(size, OP_SIZE_4)
192 #define R_CG_SCRATCH R_0
196 #define R_SCRATCH_1 R_3
197 #define R_SCRATCH_2 R_4
198 #define R_SCRATCH_3 R_5
199 #define R_SCRATCH_4 R_SAVED_2
201 #define R_SCRATCH_NA_1 R_7
202 #define R_SCRATCH_NA_2 R_8
203 #define R_SCRATCH_NA_3 R_9
206 #define R_UPCALL R_30
207 #define R_TIMESTAMP R_29
209 #define R_SAVED_1 R_28
210 #define R_SAVED_2 R_27
213 #define R_LOWEST_SAVED R_14
223 #define R_OFFSET_IMM R_10
224 #define R_CONST_IMM R_11
226 #define FR_SCRATCH_1 (real_type == 4 ? R_VS32 : R_F0)
227 #define FR_SCRATCH_2 (real_type == 4 ? R_VS33 : R_F1)
228 #define FR_SCRATCH_3 (real_type == 4 ? R_VS34 : R_F2)
230 #define SUPPORTED_FP (cpu_test_feature(CPU_FEATURE_ppc) * 0x2 + 0x4 + cpu_test_feature(CPU_FEATURE_v30) * 0x10)
232 static bool reg_is_fp(unsigned reg)
234 return reg >= 0x40 && reg < 0x80;
237 static bool reg_is_vs(unsigned reg)
239 return reg >= 0x60 && reg < 0x80;
242 static const uint8_t regs_saved[] = { R_14, R_15, R_16, R_17, R_18, R_19, R_20, R_21, R_22, R_23, R_24, R_25 };
243 static const uint8_t regs_volatile[] = { R_6, R_12 };
244 static const uint8_t fp_saved[] = { 0 };
245 #define n_fp_saved 0U
246 static const uint8_t fp_volatile[] = { R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10, R_F11, R_F12, R_F13 };
247 static const uint8_t vector_volatile[] = { R_VS35, R_VS36, R_VS37, R_VS38, R_VS39, R_VS40, R_VS41, R_VS42, R_VS43, R_VS44, R_VS45, R_VS46, R_VS47, R_VS48, R_VS49, R_VS50, R_VS51 };
248 #define reg_is_saved(r) (((r) >= R_14 && (r) <= R_31) || ((r) >= R_F14 && (r) <= R_F31) || ((r) >= R_VS52 && (r) <= R_VS63))
250 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
252 unsigned xreg = R_ZERO;
253 if (OP_SIZE_NATIVE == OP_SIZE_4)
255 if (c == (uint64_t)(int32_t)c) {
256 if (c == (uint64_t)(int16_t)c) {
257 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
260 gen_eight((int16_t)c);
263 if (c & 0xffffffffffff0000ULL) {
264 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
267 gen_eight(c & 0xffffffffffff0000ULL);
272 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
275 gen_eight((int32_t)((c >> 32) & 0xffff0000U));
278 if (c & 0x0000ffff00000000ULL) {
279 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
283 gen_eight((uint16_t)(c >> 32));
286 if (xreg != R_ZERO) {
287 gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
293 if (c & 0xffff0000U) {
294 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
298 gen_eight(c & 0xffff0000U);
303 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
307 gen_eight(c & 0xffffU);
310 if (xreg == R_ZERO) {
311 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
319 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
321 ctx->base_reg = base;
322 ctx->offset_imm = imm;
323 ctx->offset_reg = false;
325 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
326 if (size >= OP_SIZE_16 && imm & 15)
329 case IMM_PURPOSE_LDR_SX_OFFSET:
330 if (size >= OP_SIZE_4 && imm & 3)
333 case IMM_PURPOSE_LDR_OFFSET:
334 case IMM_PURPOSE_STR_OFFSET:
335 if (size >= OP_SIZE_8 && imm & 3)
338 case IMM_PURPOSE_MVI_CLI_OFFSET:
339 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
343 internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
345 g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
346 ctx->offset_reg = true;
350 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
353 case IMM_PURPOSE_STORE_VALUE:
354 case IMM_PURPOSE_CMOV:
358 case IMM_PURPOSE_ANDN:
360 case IMM_PURPOSE_ADD:
361 case IMM_PURPOSE_CMP:
362 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
366 if (likely(imm >= -0x80000000L) && likely(imm < 0x80000000L))
369 case IMM_PURPOSE_SUB:
370 if (likely(imm > -0x8000) && likely(imm <= 0x8000))
374 if (likely(imm > -0x80000000L) && likely(imm <= 0x80000000L))
377 case IMM_PURPOSE_CMP_LOGICAL:
378 case IMM_PURPOSE_AND:
380 case IMM_PURPOSE_XOR:
381 case IMM_PURPOSE_TEST:
382 if (likely(imm >= 0) && likely(imm < 0x10000))
386 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL))
389 case IMM_PURPOSE_MUL:
390 if (size != OP_SIZE_4)
392 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
396 internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
401 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
403 if (is_direct_const(imm, purpose, size)) {
404 ctx->const_imm = imm;
405 ctx->const_reg = false;
407 g(gen_load_constant(ctx, R_CONST_IMM, imm));
408 ctx->const_reg = true;
413 static bool attr_w gen_entry(struct codegen_context *ctx)
417 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
418 gen_one(ARG_ADDRESS_1_PRE_I);
420 gen_eight(-FRAME_SIZE);
423 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
424 gen_one(R_SCRATCH_NA_3);
427 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
428 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
429 gen_one(ARG_ADDRESS_1);
435 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
436 gen_one(ARG_ADDRESS_1);
438 gen_eight(LR_OFFSET);
439 gen_one(R_SCRATCH_NA_3);
441 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
446 #if !defined(STRUCT_RET_OFFSET)
447 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
451 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
455 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
456 gen_one(R_TIMESTAMP);
459 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
462 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
463 gen_one(ARG_ADDRESS_1);
465 gen_eight(STRUCT_RET_OFFSET);
468 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
472 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
476 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
477 gen_one(R_TIMESTAMP);
480 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
487 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
489 g(gen_load_constant(ctx, R_RET1, ip));
491 gen_insn(INSN_JMP, 0, 0, 0);
492 gen_four(escape_label);
497 static bool attr_w gen_escape(struct codegen_context *ctx)
501 #if !defined(STRUCT_RET_OFFSET)
502 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
506 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
508 gen_one(ARG_ADDRESS_1);
510 gen_eight(STRUCT_RET_OFFSET);
512 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
513 gen_one(ARG_ADDRESS_1);
518 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
519 gen_one(ARG_ADDRESS_1);
521 gen_eight(1U << OP_SIZE_NATIVE);
524 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
525 gen_one(R_SCRATCH_NA_1);
526 gen_one(ARG_ADDRESS_1);
528 gen_eight(LR_OFFSET);
530 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
531 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
533 gen_one(ARG_ADDRESS_1);
538 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
540 gen_one(R_SCRATCH_NA_1);
542 gen_insn(INSN_ALU, OP_SIZE_NATIVE, 0, 0);
546 gen_eight(FRAME_SIZE);
548 gen_insn(INSN_RET, 0, 0, 0);
553 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
558 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
561 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
562 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
564 gen_address_offset();
566 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
570 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
573 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
574 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
575 gen_one(R_SCRATCH_NA_2);
576 gen_address_offset();
578 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
579 gen_one(R_SCRATCH_NA_1);
580 gen_one(ARG_ADDRESS_1);
581 gen_one(R_SCRATCH_NA_2);
584 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
586 gen_one(R_SCRATCH_NA_1);
588 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
590 gen_one(ARG_ADDRESS_1);
591 gen_one(R_SCRATCH_NA_2);
592 gen_eight(1 << OP_SIZE_ADDRESS);
594 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
596 gen_one(ARG_ADDRESS_1);
597 gen_one(R_SCRATCH_NA_2);
598 gen_eight(2 << OP_SIZE_ADDRESS);
600 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
603 g(gen_upcall_end(ctx, n_args));
608 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
610 g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
611 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
612 gen_one(R_SCRATCH_1);
613 gen_address_offset();
615 gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
616 gen_one(R_SCRATCH_1);
617 gen_one(R_TIMESTAMP);
619 gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
620 gen_four(escape_label);