wingo pushed a commit to branch main
in repository guile.

commit 7c20ba77672df6a5d6f8ffc6aab00b5693087f92
Author: Ekaitz Zarraga <eka...@elenq.tech>
AuthorDate: Mon Nov 18 21:08:41 2024 +0100

    riscv: float/double call convention implementation
    
    RISC-V uses a0-a7 registers for argument passing. Float/double arguments
    use f0-f7 first and continue in a0-a7 if needed.
    
    Once registers are consumed, stack is used.
    
    This commit changes how lightening passes arguments in order to allow
    this behavior.
---
 lightening/lightening.c | 27 ++++++++++++++++++++++++++-
 lightening/riscv-fpu.c  | 25 +++++++++++++++++++++++++
 lightening/riscv.c      | 13 +++++++++++++
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/lightening/lightening.c b/lightening/lightening.c
index c66b3a132..f26a467ff 100644
--- a/lightening/lightening.c
+++ b/lightening/lightening.c
@@ -807,6 +807,14 @@ abi_mem_to_gpr(jit_state_t *_jit, enum jit_operand_abi abi,
   case JIT_OPERAND_ABI_INT16:
     jit_ldxi_s(_jit, dst, base, offset);
     break;
+  case JIT_OPERAND_ABI_FLOAT:
+  {
+    jit_fpr_t tmp = get_temp_fpr(_jit);
+    jit_ldxi_f(_jit, tmp, base, offset);
+    jit_movr_i_f(_jit, dst, tmp);
+    unget_temp_fpr(_jit);
+    break;
+  }
 #if __WORDSIZE == 32
   case JIT_OPERAND_ABI_UINT32:
   case JIT_OPERAND_ABI_POINTER:
@@ -823,6 +831,14 @@ abi_mem_to_gpr(jit_state_t *_jit, enum jit_operand_abi abi,
   case JIT_OPERAND_ABI_INT64:
     jit_ldxi_l(_jit, dst, base, offset);
     break;
+  case JIT_OPERAND_ABI_DOUBLE:
+  {
+    jit_fpr_t tmp = get_temp_fpr(_jit);
+    jit_ldxi_d(_jit, tmp, base, offset);
+    jit_movr_l_d(_jit, dst, tmp);
+    unget_temp_fpr(_jit);
+    break;
+  }
 #endif
   default:
     abort();
@@ -887,7 +903,8 @@ enum move_kind {
   MOVE_KIND_ENUM(IMM, MEM),
   MOVE_KIND_ENUM(GPR, MEM),
   MOVE_KIND_ENUM(FPR, MEM),
-  MOVE_KIND_ENUM(MEM, MEM)
+  MOVE_KIND_ENUM(MEM, MEM),
+  MOVE_KIND_ENUM(FPR, GPR)
 };
 #undef MOVE_KIND_ENUM
 
@@ -901,6 +918,14 @@ move_operand(jit_state_t *_jit, jit_operand_t dst, 
jit_operand_t src)
   case MOVE_GPR_TO_GPR:
     return jit_movr(_jit, dst.loc.gpr.gpr, src.loc.gpr.gpr);
 
+  case MOVE_FPR_TO_GPR:
+#if __WORDSIZE > 32
+    if (src.abi == JIT_OPERAND_ABI_DOUBLE)
+      return jit_movr_l_d(_jit, dst.loc.gpr.gpr, src.loc.fpr);
+    else
+#endif
+      return jit_movr_i_f(_jit, dst.loc.gpr.gpr, src.loc.fpr);
+
   case MOVE_MEM_TO_GPR:
     return abi_mem_to_gpr(_jit, src.abi, dst.loc.gpr.gpr, src.loc.mem.base,
                           src.loc.mem.offset);
diff --git a/lightening/riscv-fpu.c b/lightening/riscv-fpu.c
index 315ed8d14..b4e7546c7 100644
--- a/lightening/riscv-fpu.c
+++ b/lightening/riscv-fpu.c
@@ -103,6 +103,10 @@ static void absr_d(jit_state_t *_jit, int32_t r0, int32_t 
r1);
 // Transfer operations
 static void movr_f(jit_state_t *_jit, int32_t r0, int32_t r1);
 static void movr_d(jit_state_t *_jit, int32_t r0, int32_t r1);
+static void movr_i_f(jit_state_t *_jit, int32_t r0, int32_t r1);
+static void movr_l_d(jit_state_t *_jit, int32_t r0, int32_t r1);
+static void movr_f_i(jit_state_t *_jit, int32_t r0, int32_t r1);
+static void movr_d_l(jit_state_t *_jit, int32_t r0, int32_t r1);
 
 // Argument management
 static void retr_f(jit_state_t *_jit, int32_t u);
@@ -398,6 +402,27 @@ movr_d(jit_state_t *_jit, int32_t r0, int32_t r1)
   if (r0 != r1)
     em_wp(_jit, _FMV_D(r0, r1));
 }
+static void
+movr_i_f(jit_state_t *_jit, int32_t r0, int32_t r1)
+{
+  em_wp(_jit, _FMV_X_W(r0, r1));
+}
+static void
+movr_f_i(jit_state_t *_jit, int32_t r0, int32_t r1)
+{
+  em_wp(_jit, _FMV_W_X(r0, r1));
+}
+static void
+movr_l_d(jit_state_t *_jit, int32_t r0, int32_t r1)
+{
+  em_wp(_jit, _FMV_X_D(r0, r1));
+}
+static void
+movr_d_l(jit_state_t *_jit, int32_t r0, int32_t r1)
+{
+  em_wp(_jit, _FMV_D_X(r0, r1));
+}
+
 static void
 truncr_f_i(jit_state_t *_jit, int32_t r0, int32_t r1)
 {
diff --git a/lightening/riscv.c b/lightening/riscv.c
index 3f0adce46..d3e4efaa3 100644
--- a/lightening/riscv.c
+++ b/lightening/riscv.c
@@ -111,6 +111,16 @@ reset_abi_arg_iterator(struct abi_arg_iterator *iter, 
size_t argc,
 static void
 next_abi_arg(struct abi_arg_iterator *iter, jit_operand_t *arg)
 {
+  // RISC-V Calling convention:
+  // https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf
+  //
+  // The RISC-V calling convention passes arguments in registers when possible.
+  // Up to eight integer registers, a0–a7, and up to eight floating-point
+  // registers, fa0–fa7, are used for this purpose.
+  //
+  // If argument i < 8 is a floating-point type, it is passed in floating-point
+  // register fai; otherwise, it is passed in integer register ai.
+
   ASSERT(iter->arg_idx < iter->argc);
   enum jit_operand_abi abi = iter->args[iter->arg_idx].abi;
   iter->arg_idx++;
@@ -121,6 +131,9 @@ next_abi_arg(struct abi_arg_iterator *iter, jit_operand_t 
*arg)
   if (is_fpr_arg(abi) && iter->fpr_idx < abi_fpr_arg_count) {
     *arg = jit_operand_fpr (abi, abi_fpr_args[iter->fpr_idx++]);
     return;
+  } else if (is_fpr_arg(abi) && iter->gpr_idx < abi_gpr_arg_count) {
+    *arg = jit_operand_gpr (abi, abi_gpr_args[iter->gpr_idx++]);
+    return;
   }
   *arg = jit_operand_mem (abi, JIT_SP, iter->stack_size);
 #if __WORDSIZE == 32

Reply via email to