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_FLAGS 1
74 #define ARCH_PREFERS_SX(size) 0
75 #define ARCH_HAS_BWX 1
76 #define ARCH_HAS_MUL 1
77 #define ARCH_HAS_DIV cpu_test_feature(CPU_FEATURE_ppc)
78 #define ARCH_HAS_ANDN 1
79 #define ARCH_HAS_SHIFTED_ADD(bits) 0
80 #define ARCH_HAS_BTX(btx, size, cnst) 0
81 #define ARCH_SHIFT_SIZE OP_SIZE_16
82 #define ARCH_NEEDS_BARRIER 0
84 #define i_size(size) OP_SIZE_NATIVE
85 #define i_size_rot(size) maximum(size, OP_SIZE_4)
86 #define i_size_cmp(size) maximum(size, OP_SIZE_4)
189 #define R_CG_SCRATCH R_0
193 #define R_SCRATCH_1 R_3
194 #define R_SCRATCH_2 R_4
195 #define R_SCRATCH_3 R_5
196 #define R_SCRATCH_4 R_SAVED_2
198 #define R_SCRATCH_NA_1 R_7
199 #define R_SCRATCH_NA_2 R_8
200 #define R_SCRATCH_NA_3 R_9
203 #define R_UPCALL R_30
204 #define R_TIMESTAMP R_29
206 #define R_SAVED_1 R_28
207 #define R_SAVED_2 R_27
210 #define R_LOWEST_SAVED R_14
220 #define R_OFFSET_IMM R_10
221 #define R_CONST_IMM R_11
223 #define FR_SCRATCH_1 (real_type == 4 ? R_VS32 : R_F0)
224 #define FR_SCRATCH_2 (real_type == 4 ? R_VS33 : R_F1)
225 #define FR_SCRATCH_3 (real_type == 4 ? R_VS34 : R_F2)
227 #define SUPPORTED_FP (cpu_test_feature(CPU_FEATURE_ppc) * 0x2 + 0x4 + cpu_test_feature(CPU_FEATURE_v30) * 0x10)
229 static bool reg_is_fp(unsigned reg)
231 return reg >= 0x40 && reg < 0x80;
234 static bool reg_is_vs(unsigned reg)
236 return reg >= 0x60 && reg < 0x80;
239 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 };
240 static const uint8_t regs_volatile[] = { R_6, R_12 };
241 static const uint8_t fp_saved[] = { 0 };
242 #define n_fp_saved 0U
243 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 };
244 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 };
245 #define reg_is_saved(r) (((r) >= R_14 && (r) <= R_31) || ((r) >= R_F14 && (r) <= R_F31) || ((r) >= R_VS52 && (r) <= R_VS63))
247 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
249 unsigned xreg = R_ZERO;
250 if (OP_SIZE_NATIVE == OP_SIZE_4)
252 if (c == (uint64_t)(int32_t)c) {
253 if (c == (uint64_t)(int16_t)c) {
254 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
257 gen_eight((int16_t)c);
260 if (c & 0xffffffffffff0000ULL) {
261 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
264 gen_eight(c & 0xffffffffffff0000ULL);
269 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
272 gen_eight((int32_t)((c >> 32) & 0xffff0000U));
275 if (c & 0x0000ffff00000000ULL) {
276 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
280 gen_eight((uint16_t)(c >> 32));
283 if (xreg != R_ZERO) {
284 gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
290 if (c & 0xffff0000U) {
291 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
295 gen_eight(c & 0xffff0000U);
300 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
304 gen_eight(c & 0xffffU);
307 if (xreg == R_ZERO) {
308 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
316 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
318 ctx->base_reg = base;
319 ctx->offset_imm = imm;
320 ctx->offset_reg = false;
322 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
323 if (size >= OP_SIZE_16 && imm & 15)
326 case IMM_PURPOSE_LDR_SX_OFFSET:
327 if (size >= OP_SIZE_4 && imm & 3)
330 case IMM_PURPOSE_LDR_OFFSET:
331 case IMM_PURPOSE_STR_OFFSET:
332 if (size >= OP_SIZE_8 && imm & 3)
335 case IMM_PURPOSE_MVI_CLI_OFFSET:
336 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
340 internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
342 g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
343 ctx->offset_reg = true;
347 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
350 case IMM_PURPOSE_STORE_VALUE:
351 case IMM_PURPOSE_CMOV:
355 case IMM_PURPOSE_ANDN:
357 case IMM_PURPOSE_ADD:
358 case IMM_PURPOSE_CMP:
359 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
363 if (likely(imm >= -0x80000000L) && likely(imm < 0x80000000L))
366 case IMM_PURPOSE_SUB:
367 if (likely(imm > -0x8000) && likely(imm <= 0x8000))
371 if (likely(imm > -0x80000000L) && likely(imm <= 0x80000000L))
374 case IMM_PURPOSE_CMP_LOGICAL:
375 case IMM_PURPOSE_AND:
377 case IMM_PURPOSE_XOR:
378 case IMM_PURPOSE_TEST:
379 if (likely(imm >= 0) && likely(imm < 0x10000))
383 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL))
386 case IMM_PURPOSE_MUL:
387 if (size != OP_SIZE_4)
389 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
393 internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
398 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
400 if (is_direct_const(imm, purpose, size)) {
401 ctx->const_imm = imm;
402 ctx->const_reg = false;
404 g(gen_load_constant(ctx, R_CONST_IMM, imm));
405 ctx->const_reg = true;
410 static bool attr_w gen_entry(struct codegen_context *ctx)
414 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
415 gen_one(ARG_ADDRESS_1_PRE_I);
417 gen_eight(-FRAME_SIZE);
420 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
421 gen_one(R_SCRATCH_NA_3);
424 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
425 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
426 gen_one(ARG_ADDRESS_1);
432 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
433 gen_one(ARG_ADDRESS_1);
435 gen_eight(LR_OFFSET);
436 gen_one(R_SCRATCH_NA_3);
438 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
443 #if !defined(STRUCT_RET_OFFSET)
444 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
448 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
452 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
453 gen_one(R_TIMESTAMP);
456 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
459 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
460 gen_one(ARG_ADDRESS_1);
462 gen_eight(STRUCT_RET_OFFSET);
465 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
469 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
473 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
474 gen_one(R_TIMESTAMP);
477 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
484 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
486 g(gen_load_constant(ctx, R_RET1, ip));
488 gen_insn(INSN_JMP, 0, 0, 0);
489 gen_four(escape_label);
494 static bool attr_w gen_escape(struct codegen_context *ctx)
498 #if !defined(STRUCT_RET_OFFSET)
499 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
503 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
505 gen_one(ARG_ADDRESS_1);
507 gen_eight(STRUCT_RET_OFFSET);
509 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
510 gen_one(ARG_ADDRESS_1);
515 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
516 gen_one(ARG_ADDRESS_1);
518 gen_eight(1U << OP_SIZE_NATIVE);
521 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
522 gen_one(R_SCRATCH_NA_1);
523 gen_one(ARG_ADDRESS_1);
525 gen_eight(LR_OFFSET);
527 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
528 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
530 gen_one(ARG_ADDRESS_1);
535 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
537 gen_one(R_SCRATCH_NA_1);
539 gen_insn(INSN_ALU, OP_SIZE_NATIVE, 0, 0);
543 gen_eight(FRAME_SIZE);
545 gen_insn(INSN_RET, 0, 0, 0);
550 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
555 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
558 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
559 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
561 gen_address_offset();
563 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
567 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
570 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
571 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
572 gen_one(R_SCRATCH_NA_2);
573 gen_address_offset();
575 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
576 gen_one(R_SCRATCH_NA_1);
577 gen_one(ARG_ADDRESS_1);
578 gen_one(R_SCRATCH_NA_2);
581 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
583 gen_one(R_SCRATCH_NA_1);
585 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
587 gen_one(ARG_ADDRESS_1);
588 gen_one(R_SCRATCH_NA_2);
589 gen_eight(1 << OP_SIZE_ADDRESS);
591 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
593 gen_one(ARG_ADDRESS_1);
594 gen_one(R_SCRATCH_NA_2);
595 gen_eight(2 << OP_SIZE_ADDRESS);
597 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
600 g(gen_upcall_end(ctx, n_args));
605 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
607 g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
608 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
609 gen_one(R_SCRATCH_1);
610 gen_address_offset();
612 gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
613 gen_one(R_SCRATCH_1);
614 gen_one(R_TIMESTAMP);
616 gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
617 gen_four(escape_label);