pike.git / src / code / riscv.c

version» Context lines:

pike.git/src/code/riscv.c:262:   #define RV_Lx RV_LD   #define RV_Sx RV_SD   #endif      #define FLAG_SP_LOADED 1   #define FLAG_FP_LOADED 2   #define FLAG_LOCALS_LOADED 4   #define FLAG_GLOBALS_LOADED 8   #define FLAG_NOT_DESTRUCTED 16    + enum rv_millicode { +  RV_MILLICODE_PROLOGUE, +  RV_MILLICODE_EPILOGUE, +  RV_MILLICODE_RETURN, +  RV_MILLICODE_MAX = RV_MILLICODE_RETURN + }; +    static struct compiler_state {    unsigned INT32 flags; -  +  size_t millicode[RV_MILLICODE_MAX+1];   } compiler_state;         /* Create a <4 KiO jumptable */      enum rv_jumpentry {    RV_JUMPENTRY_BRANCH_CHECK_THREADS_ETC,    RV_JUMPENTRY_INTER_RETURN_OPCODE_F_CATCH,    RV_JUMPENTRY_COMPLEX_SVALUE_IS_TRUE, -  +  RV_JUMPENTRY_LOW_RETURN, +  RV_JUMPENTRY_LOW_RETURN_POP,    RV_JUMPENTRY_F_OFFSET,   };      #define JUMPTABLE_SECTION __attribute__((section(".text.jumptable")))      void riscv_jumptable(void) JUMPTABLE_SECTION;   void riscv_jumptable(void) { }      #define JUMP_ENTRY_NOPROTO(OP, TARGET, RETTYPE, ARGTYPES, RET, ARGS) \    static RETTYPE PIKE_CONCAT(rv_jumptable_, OP)ARGTYPES JUMPTABLE_SECTION; \    static RETTYPE PIKE_CONCAT(rv_jumptable_, OP)ARGTYPES { \    RET TARGET ARGS; \    }   #define JUMP_ENTRY(OP, TARGET, RETTYPE, ARGTYPES, RET, ARGS) \    extern RETTYPE TARGET ARGTYPES; \    JUMP_ENTRY_NOPROTO(OP, TARGET, RETTYPE, ARGTYPES, RET, ARGS)    - JUMP_ENTRY(branch_check_threads_etc, branch_check_threads_etc, void, (void), , ()) - JUMP_ENTRY(inter_return_opcode_F_CATCH, inter_return_opcode_F_CATCH, PIKE_OPCODE_T *, (PIKE_OPCODE_T *addr), return, (addr)) - JUMP_ENTRY(complex_svalue_is_true, complex_svalue_is_true, int, (const struct svalue *s), return, (s)) + JUMP_ENTRY_NOPROTO(branch_check_threads_etc, branch_check_threads_etc, void, (void), , ()) + JUMP_ENTRY_NOPROTO(inter_return_opcode_F_CATCH, inter_return_opcode_F_CATCH, PIKE_OPCODE_T *, (PIKE_OPCODE_T *addr), return, (addr)) + JUMP_ENTRY_NOPROTO(complex_svalue_is_true, complex_svalue_is_true, int, (const struct svalue *s), return, (s)) + JUMP_ENTRY_NOPROTO(low_return, low_return, void, (void), , ()) + JUMP_ENTRY_NOPROTO(low_return_pop, low_return_pop, void, (void), , ())      #define OPCODE_NOCODE(DESC, OP, FLAGS)   #define OPCODE0(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(opcode_, OP), void, (void), , ())   #define OPCODE1(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(opcode_, OP), void, (INT32 a), , (a))   #define OPCODE2(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(opcode_, OP), void, (INT32 a, INT32 b), , (a, b))   #define OPCODE0_JUMP(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(jump_opcode_, OP), void *, (void), return, ())   #define OPCODE1_JUMP(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(jump_opcode_, OP), void *, (INT32 a), return, (a))   #define OPCODE2_JUMP(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(jump_opcode_, OP), void *, (INT32 a, INT32 b), return, (a, b))   #define OPCODE0_BRANCH(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(test_opcode_,OP), ptrdiff_t, (void), return, ())   #define OPCODE1_BRANCH(OP,DESC,FLAGS) JUMP_ENTRY(OP, PIKE_CONCAT(test_opcode_,OP), ptrdiff_t, (INT32 a), return, (a))
pike.git/src/code/riscv.c:339:   #undef JUMP_ENTRY_NOPROTO   #define JUMP_ENTRY_NOPROTO(OP, TARGET, RETTYPE, ARGTYPES, RET, ARGS) \    [ (OP)-F_OFFSET+RV_JUMPENTRY_F_OFFSET ] = (void *)PIKE_CONCAT(rv_jumptable_, OP),   #undef JUMP_ENTRY   #define JUMP_ENTRY JUMP_ENTRY_NOPROTO   static void * const rv_jumptable_index[] =   {    [RV_JUMPENTRY_BRANCH_CHECK_THREADS_ETC] = rv_jumptable_branch_check_threads_etc,    [RV_JUMPENTRY_INTER_RETURN_OPCODE_F_CATCH] = rv_jumptable_inter_return_opcode_F_CATCH,    [RV_JUMPENTRY_COMPLEX_SVALUE_IS_TRUE] = rv_jumptable_complex_svalue_is_true, +  [RV_JUMPENTRY_LOW_RETURN] = rv_jumptable_low_return, +  [RV_JUMPENTRY_LOW_RETURN_POP] = rv_jumptable_low_return_pop,   #include "interpret_protos.h"   };         void riscv_ins_int(INT32 n)   {   #if PIKE_BYTEORDER == 1234    add_to_program((unsigned INT16)n);    add_to_program((unsigned INT16)(n >> 16));   #else
pike.git/src/code/riscv.c:389:   #endif   }      static void rv_emit(unsigned INT32 instr)   {    add_to_program((unsigned INT16)instr);    if ((instr & 3) == 3)    add_to_program((unsigned INT16)(instr >> 16));   }    + static void rv_call_millicode(enum rv_register reg, enum rv_millicode milli) + { +  INT32 delta = (PIKE_PC - compiler_state.millicode[milli]) * -2; +  if (delta < -1048576 || delta > 1048575) +  Pike_fatal("rv_call_millicode: branch out of range for JAL\n"); +  rv_emit(RV_JAL(reg, delta)); + } +    static void rv_func_epilogue(void)   { - #if __riscv_xlen == 32 -  rv_emit(RV_LW(RV_REG_S4, 8, RV_REG_SP)); -  rv_emit(RV_LW(RV_REG_S3, 12, RV_REG_SP)); -  rv_emit(RV_LW(RV_REG_S2, 16, RV_REG_SP)); -  rv_emit(RV_LW(RV_REG_S1, 20, RV_REG_SP)); -  rv_emit(RV_LW(RV_REG_S0, 24, RV_REG_SP)); -  rv_emit(RV_LW(RV_REG_RA, 28, RV_REG_SP)); -  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, 32)); - #else -  rv_emit(RV_LD(RV_REG_S4, 0, RV_REG_SP)); -  rv_emit(RV_LD(RV_REG_S3, 8, RV_REG_SP)); -  rv_emit(RV_LD(RV_REG_S2, 16, RV_REG_SP)); -  rv_emit(RV_LD(RV_REG_S1, 24, RV_REG_SP)); -  rv_emit(RV_LD(RV_REG_S0, 32, RV_REG_SP)); -  rv_emit(RV_LD(RV_REG_RA, 40, RV_REG_SP)); -  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, 48)); - #endif -  rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_RA, 0)); +  rv_call_millicode(RV_REG_ZERO, RV_MILLICODE_EPILOGUE);   }      void riscv_update_f_jump(INT32 offset, INT32 to_offset)   {    PIKE_OPCODE_T *op = &Pike_compiler->new_program->program[offset];    unsigned INT32 instr = op[0];    to_offset -= offset;    if ((instr & 3) == 3) {    instr |= op[1] << 16;    if ((instr & 0x7f) == 111) {
pike.git/src/code/riscv.c:611: Inside #if 0 /* Not needed */
   /* Adjust for signedness of lower 12 bits... */    if (addr & 0x800)    addr += 0x1000;    rv_emit(RV_LUI(RV_REG_T6, addr));    rv_emit(RV_JALR(RV_REG_RA, RV_REG_T6, addr));   #endif    }   }   #endif    - static void rv_call_via_jumptable(enum rv_jumpentry index) + static INT32 rv_get_jumptable_entry(enum rv_jumpentry index)   {    ptrdiff_t base = (ptrdiff_t)(void *)riscv_jumptable;    ptrdiff_t target = (ptrdiff_t)rv_jumptable_index[index];    if (!target)    Pike_fatal("rv_call_via_jumptable: missing target for index %d\n", (int)index);       ptrdiff_t delta = target - base;    if (!RV_IN_RANGE_IMM12(delta))    Pike_fatal("rv_call_via_jumptable: target outside of range for index %d\n", (int)index); -  +  return (INT32)delta; + }    -  rv_emit(RV_JALR(RV_REG_RA, RV_REG_PIKE_JUMPTABLE, (INT32)(target-base))); + static void rv_call_via_jumptable(enum rv_jumpentry index) + { +  INT32 delta = rv_get_jumptable_entry(index); +  rv_emit(RV_JALR(RV_REG_RA, RV_REG_PIKE_JUMPTABLE, delta));   }      static void rv_call_c_opcode(unsigned int opcode)   {    int flags = instrs[opcode-F_OFFSET].flags;    enum rv_jumpentry index = opcode-F_OFFSET+RV_JUMPENTRY_F_OFFSET;       rv_maybe_update_pc();       if (opcode == F_CATCH)
pike.git/src/code/riscv.c:646:       if (flags & I_UPDATE_SP) {    compiler_state.flags &= ~FLAG_SP_LOADED;    }    if (flags & I_UPDATE_M_SP) {}    if (flags & I_UPDATE_FP) {    compiler_state.flags &= ~FLAG_FP_LOADED;    }   }    - static void rv_return(unsigned int opcode) + static void rv_return(void)   {    rv_load_fp_reg(); -  +  rv_call_millicode(RV_REG_ZERO, RV_MILLICODE_RETURN); + } +  + static void rv_generate_millicode() + { +  compiler_state.millicode[RV_MILLICODE_PROLOGUE] = PIKE_PC; + #if __riscv_xlen == 32 +  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, -32)); +  rv_emit(RV_SW(RV_REG_RA, 28, RV_REG_SP)); +  rv_emit(RV_SW(RV_REG_S0, 24, RV_REG_SP)); +  rv_emit(RV_SW(RV_REG_S1, 20, RV_REG_SP)); +  rv_emit(RV_SW(RV_REG_S2, 16, RV_REG_SP)); +  rv_emit(RV_SW(RV_REG_S3, 12, RV_REG_SP)); +  rv_emit(RV_SW(RV_REG_S4, 8, RV_REG_SP)); + #else +  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, -48)); +  rv_emit(RV_SD(RV_REG_RA, 40, RV_REG_SP)); +  rv_emit(RV_SD(RV_REG_S0, 32, RV_REG_SP)); +  rv_emit(RV_SD(RV_REG_S1, 24, RV_REG_SP)); +  rv_emit(RV_SD(RV_REG_S2, 16, RV_REG_SP)); +  rv_emit(RV_SD(RV_REG_S3, 8, RV_REG_SP)); +  rv_emit(RV_SD(RV_REG_S4, 0, RV_REG_SP)); + #endif +  rv_emit(RV_MV(RV_REG_PIKE_IP, RV_REG_A0)); +  rv_emit(RV_MV(RV_REG_PIKE_JUMPTABLE, RV_REG_A1)); +  rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_T0, 0)); +  +  compiler_state.millicode[RV_MILLICODE_RETURN] = PIKE_PC;    rv_emit(RV_LHU(RV_REG_A5, OFFSETOF(pike_frame, flags), RV_REG_PIKE_FP)); -  rv_emit(RV_ANDI(RV_REG_A5, RV_REG_A5, PIKE_FRAME_RETURN_INTERNAL)); +  rv_emit(RV_ANDI(RV_REG_A4, RV_REG_A5, PIKE_FRAME_RETURN_INTERNAL));    INT32 branch_op = PIKE_PC; -  rv_emit(RV_BNE(RV_REG_A5, RV_REG_ZERO, 0)); +  rv_emit(RV_BNE(RV_REG_A4, RV_REG_ZERO, 0));    rv_emit(RV_LI(RV_REG_A0, -1)); -  rv_func_epilogue(); +  +  compiler_state.millicode[RV_MILLICODE_EPILOGUE] = PIKE_PC; + #if __riscv_xlen == 32 +  rv_emit(RV_LW(RV_REG_S4, 8, RV_REG_SP)); +  rv_emit(RV_LW(RV_REG_S3, 12, RV_REG_SP)); +  rv_emit(RV_LW(RV_REG_S2, 16, RV_REG_SP)); +  rv_emit(RV_LW(RV_REG_S1, 20, RV_REG_SP)); +  rv_emit(RV_LW(RV_REG_S0, 24, RV_REG_SP)); +  rv_emit(RV_LW(RV_REG_RA, 28, RV_REG_SP)); +  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, 32)); + #else +  rv_emit(RV_LD(RV_REG_S4, 0, RV_REG_SP)); +  rv_emit(RV_LD(RV_REG_S3, 8, RV_REG_SP)); +  rv_emit(RV_LD(RV_REG_S2, 16, RV_REG_SP)); +  rv_emit(RV_LD(RV_REG_S1, 24, RV_REG_SP)); +  rv_emit(RV_LD(RV_REG_S0, 32, RV_REG_SP)); +  rv_emit(RV_LD(RV_REG_RA, 40, RV_REG_SP)); +  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, 48)); + #endif +  rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_RA, 0)); +     UPDATE_F_JUMP(branch_op, PIKE_PC); -  rv_call_c_opcode(opcode); -  rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_A0, 0)); +  +  INT32 delta_return = rv_get_jumptable_entry(RV_JUMPENTRY_LOW_RETURN); +  INT32 delta_return_pop = rv_get_jumptable_entry(RV_JUMPENTRY_LOW_RETURN_POP); +  +  rv_emit(RV_ANDI(RV_REG_A5, RV_REG_A5, PIKE_FRAME_RETURN_POP)); +  rv_emit(RV_ADDI(RV_REG_T6, RV_REG_PIKE_JUMPTABLE, delta_return)); +  INT32 branch_op_2 = PIKE_PC; +  rv_emit(RV_BEQ(RV_REG_A5, RV_REG_ZERO, 0)); +  rv_emit(RV_ADDI(RV_REG_T6, RV_REG_PIKE_JUMPTABLE, delta_return_pop)); +  UPDATE_F_JUMP(branch_op_2, PIKE_PC); +  rv_emit(RV_JALR(RV_REG_RA, RV_REG_T6, 0)); +  rv_emit(RV_Lx(RV_REG_A5, OFFSETOF(Pike_interpreter_struct, frame_pointer), RV_REG_PIKE_IP)); +  rv_emit(RV_Lx(RV_REG_A5, OFFSETOF(pike_frame, return_addr), RV_REG_A5)); +  rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_A5, 0));   }    -  + static void rv_maybe_regenerate_millicode(void) + { +  if (Pike_compiler->new_program->num_program == 0 || +  /* If the distance to the millicode has exceeded 75% of the reach of JAL, +  generate a new instance to avoid accidents. +  (This only happens every 768K, so the overhead is quite small.) */ +  PIKE_PC - compiler_state.millicode[RV_MILLICODE_PROLOGUE] > 393216) { +  rv_generate_millicode(); +  } + } +    void riscv_ins_f_byte(unsigned int opcode)   {    int flags = instrs[opcode-F_OFFSET].flags;    INT32 rel_addr;       switch (opcode) {       case F_CATCH:    {    rel_addr = PIKE_PC;
pike.git/src/code/riscv.c:704:    rv_emit(RV_BEQ(RV_REG_A5, RV_REG_ZERO, 0));       rv_emit(RV_ADDI(RV_REG_A0, RV_REG_PIKE_SP, -(INT32)sizeof(struct svalue)));    rv_call_via_jumptable(RV_JUMPENTRY_COMPLEX_SVALUE_IS_TRUE);       UPDATE_F_JUMP(branch_op2, PIKE_PC);    INT32 branch_op3 = PIKE_PC;    rv_emit(RV_BEQ(RV_REG_A0, RV_REG_ZERO, 0));       UPDATE_F_JUMP(branch_op1, PIKE_PC); -  rv_return(F_RETURN); +  rv_return();    UPDATE_F_JUMP(branch_op3, PIKE_PC);    }    return;       case F_RETURN:    case F_DUMB_RETURN: -  rv_return(opcode); +  rv_return(); +  rv_maybe_regenerate_millicode();    return;    }       rv_call_c_opcode(opcode);       if (flags & I_RETURN) {    /* Test for -1 */    rv_emit(RV_ADDI(RV_REG_A5, RV_REG_A0, 1));    INT32 branch_op = PIKE_PC;    rv_emit(RV_BNE(RV_REG_A5, RV_REG_ZERO, 0));    rv_func_epilogue();    UPDATE_F_JUMP(branch_op, PIKE_PC);    }       if (flags & I_JUMP) {    /* This is the code that JUMP_EPILOGUE_SIZE compensates for. */    rv_emit(RV_JALR(RV_REG_ZERO, RV_REG_A0, 0)); -  +  rv_maybe_regenerate_millicode();       if (opcode == F_CATCH) {    rv_update_pcrel(rel_addr, RV_REG_A0, 2*(PIKE_PC - rel_addr));    }    }   }      void riscv_ins_f_byte_with_arg(unsigned int a, INT32 b)   {    rv_mov_int32(RV_REG_A0, b);
pike.git/src/code/riscv.c:803:    if (!(instrs[opcode - F_OFFSET].flags & I_BRANCH))    return -1;       rv_mov_int32(RV_REG_A0, arg1);    rv_mov_int32(RV_REG_A1, arg2);    return riscv_ins_f_jump(opcode, backward_jump);   }      void riscv_start_function(int UNUSED(no_pc))   { +  rv_maybe_regenerate_millicode();   }      void riscv_end_function(int UNUSED(no_pc))   {   }      void riscv_ins_entry(void)   {    /* corresponds to ENTRY_PROLOGUE_SIZE */ - #if __riscv_xlen == 32 -  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, -32)); -  rv_emit(RV_SW(RV_REG_RA, 28, RV_REG_SP)); -  rv_emit(RV_SW(RV_REG_S0, 24, RV_REG_SP)); -  rv_emit(RV_SW(RV_REG_S1, 20, RV_REG_SP)); -  rv_emit(RV_SW(RV_REG_S2, 16, RV_REG_SP)); -  rv_emit(RV_SW(RV_REG_S3, 12, RV_REG_SP)); -  rv_emit(RV_SW(RV_REG_S4, 8, RV_REG_SP)); - #else -  rv_emit(RV_ADDI(RV_REG_SP, RV_REG_SP, -48)); -  rv_emit(RV_SD(RV_REG_RA, 40, RV_REG_SP)); -  rv_emit(RV_SD(RV_REG_S0, 32, RV_REG_SP)); -  rv_emit(RV_SD(RV_REG_S1, 24, RV_REG_SP)); -  rv_emit(RV_SD(RV_REG_S2, 16, RV_REG_SP)); -  rv_emit(RV_SD(RV_REG_S3, 8, RV_REG_SP)); -  rv_emit(RV_SD(RV_REG_S4, 0, RV_REG_SP)); - #endif -  rv_emit(RV_MV(RV_REG_PIKE_IP, RV_REG_A0)); -  rv_emit(RV_MV(RV_REG_PIKE_JUMPTABLE, RV_REG_A1)); +  rv_call_millicode(RV_REG_T0, RV_MILLICODE_PROLOGUE);    riscv_flush_codegen_state();   }      void riscv_update_pc(void)   {    rv_emit(RV_AUIPC(RV_REG_A5, 0));    rv_load_fp_reg();    rv_emit(RV_Sx(RV_REG_A5, OFFSETOF(pike_frame, pc), RV_REG_PIKE_FP));   }   
pike.git/src/code/riscv.c:860:      void riscv_init_interpreter_state(void)   {   #ifdef PIKE_DEBUG    /* Check sizes */       assert(RV_IN_RANGE_IMM12(OFFSETOF(Pike_interpreter_struct, frame_pointer)));    assert(RV_IN_RANGE_IMM12(OFFSETOF(Pike_interpreter_struct, stack_pointer)));    assert(RV_IN_RANGE_IMM12(OFFSETOF(pike_frame, pc)));    assert(RV_IN_RANGE_IMM12(OFFSETOF(pike_frame, flags))); +  assert(RV_IN_RANGE_IMM12(OFFSETOF(pike_frame, return_addr)));       enum rv_jumpentry je;    ptrdiff_t base = (ptrdiff_t)(void *)riscv_jumptable;    for (je = (enum rv_jumpentry)0; je < sizeof(rv_jumptable_index)/sizeof(rv_jumptable_index[0]); je++) {    ptrdiff_t target = (ptrdiff_t)rv_jumptable_index[je];    assert (target == 0 || RV_IN_RANGE_IMM12(target - base));    }   #endif   }   
pike.git/src/code/riscv.c:1141:    else    fprintf(stderr, "%s %s,%s,%s\n",    rvcq1_op[RV_GET_BIT(instr,2,12)|RV_GET_BITS(instr,1,0,5)],    riscv_regname(RV_REGCS1_(instr)),    riscv_regname(RV_REGCS1_(instr)),    riscv_regname(RV_REGCS2_(instr)));    break;    }    break;    case 13: -  fprintf(stderr, "j %s,%p\n", -  riscv_regname(1), +  fprintf(stderr, "jal %s,%p\n", +  riscv_regname(0),    ((const char *)parcel)+RV_CJ_IMM(instr));    break;    case 14:    fprintf(stderr, "beq %s,%s,%p\n",    riscv_regname(RV_REGCS1_(instr)),    riscv_regname(0),    ((const char *)parcel)+RV_CB_IMM(instr));    break;    case 15:    fprintf(stderr, "bne %s,%s,%p\n",