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) 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 1
68 #define ARCH_HAS_FLAGS 1
69 #define ARCH_PREFERS_SX(size) 0
70 #define ARCH_HAS_BWX 1
71 #define ARCH_HAS_MUL 1
72 #define ARCH_HAS_DIV cpu_test_feature(CPU_FEATURE_ppc)
73 #define ARCH_HAS_ANDN 1
74 #define ARCH_HAS_SHIFTED_ADD(bits) 0
75 #define ARCH_HAS_BTX(btx, size, cnst) 0
76 #define ARCH_SHIFT_SIZE OP_SIZE_16
77 #define ARCH_NEEDS_BARRIER 0
79 #define i_size(size) OP_SIZE_NATIVE
80 #define i_size_rot(size) maximum(size, OP_SIZE_4)
183 #define R_CG_SCRATCH R_0
187 #define R_SCRATCH_1 R_3
188 #define R_SCRATCH_2 R_4
189 #define R_SCRATCH_3 R_5
190 #define R_SCRATCH_4 R_SAVED_2
192 #define R_SCRATCH_NA_1 R_7
193 #define R_SCRATCH_NA_2 R_8
194 #define R_SCRATCH_NA_3 R_9
197 #define R_UPCALL R_30
198 #define R_TIMESTAMP R_29
200 #define R_SAVED_1 R_28
201 #define R_SAVED_2 R_27
204 #define R_LOWEST_SAVED R_14
214 #define R_OFFSET_IMM R_10
215 #define R_CONST_IMM R_11
217 #define FR_SCRATCH_1 (real_type == 4 ? R_VS32 : R_F0)
218 #define FR_SCRATCH_2 (real_type == 4 ? R_VS33 : R_F1)
219 #define FR_SCRATCH_3 (real_type == 4 ? R_VS34 : R_F2)
221 #define SUPPORTED_FP (cpu_test_feature(CPU_FEATURE_ppc) * 0x2 + 0x4 + cpu_test_feature(CPU_FEATURE_v30) * 0x10)
223 static bool reg_is_fp(unsigned reg)
225 return reg >= 0x40 && reg < 0x80;
228 static bool reg_is_vs(unsigned reg)
230 return reg >= 0x60 && reg < 0x80;
233 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 };
234 static const uint8_t regs_volatile[] = { R_6, R_12 };
235 static const uint8_t fp_saved[] = { 0 };
236 #define n_fp_saved 0U
237 static const uint8_t fp_volatile[] = { 0 };
238 #define n_fp_volatile 0U
239 #define reg_is_saved(r) ((r) >= R_14 && (r) <= R_31)
241 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
243 unsigned xreg = R_ZERO;
244 if (OP_SIZE_NATIVE == OP_SIZE_4)
246 if (c == (uint64_t)(int32_t)c) {
247 if (c == (uint64_t)(int16_t)c) {
248 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
251 gen_eight((int16_t)c);
254 if (c & 0xffffffffffff0000ULL) {
255 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
258 gen_eight(c & 0xffffffffffff0000ULL);
263 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
266 gen_eight((int32_t)((c >> 32) & 0xffff0000U));
269 if (c & 0x0000ffff00000000ULL) {
270 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
274 gen_eight((uint16_t)(c >> 32));
277 if (xreg != R_ZERO) {
278 gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
284 if (c & 0xffff0000U) {
285 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
289 gen_eight(c & 0xffff0000U);
294 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
298 gen_eight(c & 0xffffU);
301 if (xreg == R_ZERO) {
302 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
310 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
312 ctx->base_reg = base;
313 ctx->offset_imm = imm;
314 ctx->offset_reg = false;
316 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
317 if (size >= OP_SIZE_16 && imm & 15)
320 case IMM_PURPOSE_LDR_SX_OFFSET:
321 if (size >= OP_SIZE_4 && imm & 3)
324 case IMM_PURPOSE_LDR_OFFSET:
325 case IMM_PURPOSE_STR_OFFSET:
326 if (size >= OP_SIZE_8 && imm & 3)
329 case IMM_PURPOSE_MVI_CLI_OFFSET:
330 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
334 internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
336 g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
337 ctx->offset_reg = true;
341 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
344 case IMM_PURPOSE_STORE_VALUE:
345 case IMM_PURPOSE_CMOV:
349 case IMM_PURPOSE_ANDN:
351 case IMM_PURPOSE_ADD:
352 case IMM_PURPOSE_CMP:
353 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
357 if (likely(imm >= -0x80000000L) && likely(imm < 0x80000000L))
360 case IMM_PURPOSE_SUB:
361 if (likely(imm > -0x8000) && likely(imm <= 0x8000))
365 if (likely(imm > -0x80000000L) && likely(imm <= 0x80000000L))
368 case IMM_PURPOSE_CMP_LOGICAL:
369 case IMM_PURPOSE_AND:
371 case IMM_PURPOSE_XOR:
372 case IMM_PURPOSE_TEST:
373 if (likely(imm >= 0) && likely(imm < 0x10000))
377 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL))
380 case IMM_PURPOSE_MUL:
381 if (size != OP_SIZE_4)
383 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
387 internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
392 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
394 if (is_direct_const(imm, purpose, size)) {
395 ctx->const_imm = imm;
396 ctx->const_reg = false;
398 g(gen_load_constant(ctx, R_CONST_IMM, imm));
399 ctx->const_reg = true;
404 static bool attr_w gen_entry(struct codegen_context *ctx)
408 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
409 gen_one(ARG_ADDRESS_1_PRE_I);
411 gen_eight(-FRAME_SIZE);
414 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
415 gen_one(R_SCRATCH_NA_3);
418 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
419 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
420 gen_one(ARG_ADDRESS_1);
426 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
427 gen_one(ARG_ADDRESS_1);
429 gen_eight(LR_OFFSET);
430 gen_one(R_SCRATCH_NA_3);
432 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
437 #if !defined(STRUCT_RET_OFFSET)
438 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
442 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
446 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
447 gen_one(R_TIMESTAMP);
450 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
453 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
454 gen_one(ARG_ADDRESS_1);
456 gen_eight(STRUCT_RET_OFFSET);
459 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
463 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
467 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
468 gen_one(R_TIMESTAMP);
471 gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
478 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
480 g(gen_load_constant(ctx, R_RET1, ip));
482 gen_insn(INSN_JMP, 0, 0, 0);
483 gen_four(escape_label);
488 static bool attr_w gen_escape(struct codegen_context *ctx)
492 #if !defined(STRUCT_RET_OFFSET)
493 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
497 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
499 gen_one(ARG_ADDRESS_1);
501 gen_eight(STRUCT_RET_OFFSET);
503 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
504 gen_one(ARG_ADDRESS_1);
509 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
510 gen_one(ARG_ADDRESS_1);
512 gen_eight(1U << OP_SIZE_NATIVE);
515 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
516 gen_one(R_SCRATCH_NA_1);
517 gen_one(ARG_ADDRESS_1);
519 gen_eight(LR_OFFSET);
521 for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
522 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
524 gen_one(ARG_ADDRESS_1);
529 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
531 gen_one(R_SCRATCH_NA_1);
533 gen_insn(INSN_ALU, OP_SIZE_NATIVE, 0, 0);
537 gen_eight(FRAME_SIZE);
539 gen_insn(INSN_RET, 0, 0, 0);
544 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
549 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
552 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
553 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
555 gen_address_offset();
557 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
561 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
564 g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
565 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
566 gen_one(R_SCRATCH_NA_2);
567 gen_address_offset();
569 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
570 gen_one(R_SCRATCH_NA_1);
571 gen_one(ARG_ADDRESS_1);
572 gen_one(R_SCRATCH_NA_2);
575 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
577 gen_one(R_SCRATCH_NA_1);
579 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
581 gen_one(ARG_ADDRESS_1);
582 gen_one(R_SCRATCH_NA_2);
583 gen_eight(1 << OP_SIZE_ADDRESS);
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(2 << OP_SIZE_ADDRESS);
591 gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
594 g(gen_upcall_end(ctx, n_args));
599 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
601 g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
602 gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
603 gen_one(R_SCRATCH_1);
604 gen_address_offset();
606 gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
607 gen_one(R_SCRATCH_1);
608 gen_one(R_TIMESTAMP);
610 gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
611 gen_four(escape_label);