summaryrefslogtreecommitdiff
path: root/compiler/riscv/cgrv.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/riscv/cgrv.pas')
-rw-r--r--compiler/riscv/cgrv.pas758
1 files changed, 758 insertions, 0 deletions
diff --git a/compiler/riscv/cgrv.pas b/compiler/riscv/cgrv.pas
new file mode 100644
index 0000000000..7105207c67
--- /dev/null
+++ b/compiler/riscv/cgrv.pas
@@ -0,0 +1,758 @@
+{
+ Copyright (c) 2006 by Florian Klaempfl
+
+ This unit implements the common part of the code generator for the Risc-V
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgrv;
+
+{$i fpcdefs.inc}
+ interface
+
+ uses
+ globtype,symtype,symdef,
+ cgbase,cgobj,
+ aasmbase,aasmcpu,aasmtai,aasmdata,
+ cpubase,cpuinfo,cgutils,rgcpu,
+ parabase;
+
+ type
+
+ { tcgrv }
+
+ tcgrv = class(tcg)
+ procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
+
+ procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
+
+ procedure a_call_reg(list : TAsmList;reg: tregister); override;
+ procedure a_call_name(list : TAsmList;const s : string; weak: boolean); override;
+
+ procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override;
+ procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize; reg: tregister; const ref: treference); override;
+ procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+ procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
+
+ procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
+ procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
+
+ procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
+ procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
+
+ procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
+
+ procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel); override;
+ procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
+
+ procedure a_jmp_name(list : TAsmList;const s : string); override;
+ procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
+
+ procedure g_save_registers(list: TAsmList); override;
+ procedure g_restore_registers(list: TAsmList); override;
+
+ procedure g_profilecode(list: TAsmList); override;
+
+ { fpu move instructions }
+ procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
+ procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+ procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
+
+ procedure g_check_for_fpu_exception(list: TAsmList); override;
+ protected
+ function fixref(list: TAsmList; var ref: treference): boolean;
+ procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+ end;
+
+ const
+ TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE,
+ C_LT,C_GE,C_None,C_NE,C_NONE,C_LTU,C_GEU,C_NONE);
+
+ const
+ TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
+ A_NONE,A_ADDI,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
+ A_None,A_None,A_ORI,A_SRAI,A_SLLI,A_SRLI,A_NONE,A_XORI,A_None,A_None);
+ TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
+ A_NONE,A_ADD,A_AND,A_DIVU,A_DIV,A_MUL,A_MUL,
+ A_None,A_None,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR,A_None,A_None);
+
+
+ implementation
+
+ uses
+ {$ifdef extdebug}sysutils,{$endif}
+ globals,verbose,systems,cutils,
+ symconst,symsym,symtable,fmodule,
+ rgobj,tgobj,cpupi,procinfo,paramgr;
+
+
+ procedure tcgrv.a_call_name(list : TAsmList;const s : string; weak: boolean);
+ var
+ href: treference;
+ l: TAsmLabel;
+ begin
+ if not(weak) then
+ reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[])
+ else
+ reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+
+ current_asmdata.getjumplabel(l);
+
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,NR_RETURN_ADDRESS_REG,href));
+
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_RETURN_ADDRESS_REG,NR_RETURN_ADDRESS_REG,href));
+
+ { not assigned while generating external wrappers }
+ if assigned(current_procinfo) then
+ include(current_procinfo.flags,pi_do_call);
+ end;
+
+
+ procedure tcgrv.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
+ begin
+ if a=0 then
+ a_load_reg_ref(list,size,size,NR_X0,ref)
+ else
+ inherited a_load_const_ref(list, size, a, ref);
+ end;
+
+
+ procedure tcgrv.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
+ var
+ ref: treference;
+ tmpreg: tregister;
+
+ begin
+ paraloc.check_simple_location;
+ paramanager.allocparaloc(list,paraloc.location);
+ case paraloc.location^.loc of
+ LOC_REGISTER,LOC_CREGISTER:
+ a_loadaddr_ref_reg(list,r,paraloc.location^.register);
+ LOC_REFERENCE:
+ begin
+ reference_reset(ref,paraloc.alignment,[]);
+ ref.base := paraloc.location^.reference.index;
+ ref.offset := paraloc.location^.reference.offset;
+ tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
+ a_loadaddr_ref_reg(list,r,tmpreg);
+ a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
+ end;
+ else
+ internalerror(2002080701);
+ end;
+ end;
+
+
+ procedure tcgrv.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
+ begin
+ internalerror(2016060401);
+ end;
+
+
+ procedure tcgrv.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
+ begin
+ a_op_const_reg_reg(list,op,size,a,reg,reg);
+ end;
+
+
+ procedure tcgrv.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
+ begin
+ a_op_reg_reg_reg(list,op,size,src,dst,dst);
+ end;
+
+
+ procedure tcgrv.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
+ var
+ tmpreg: TRegister;
+ begin
+ optimize_op_const(size,op,a);
+
+ if op=OP_NONE then
+ begin
+ a_load_reg_reg(list,size,size,src,dst);
+ exit;
+ end;
+
+ if op=OP_SUB then
+ begin
+ op:=OP_ADD;
+ a:=-a;
+ end;
+
+{$ifdef RISCV64}
+ if (op=OP_SHL) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SHR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SAR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+{$endif RISCV64}
+ if (TOpCG2AsmConstOp[op]<>A_None) and
+ is_imm12(a) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+ begin
+ tmpreg:=getintregister(list,size);
+ a_load_const_reg(list,size,a,tmpreg);
+ a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
+ end;
+ end;
+
+
+ procedure tcgrv.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
+ begin
+ if op=OP_NOT then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_XORI,dst,src1,-1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if op=OP_NEG then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SUB,dst,NR_X0,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+ case op of
+ OP_MOVE:
+ a_load_reg_reg(list,size,size,src1,dst);
+ else
+{$ifdef RISCV64}
+ if (op=OP_SHL) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SHR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else if (op=OP_SAR) and
+ (size=OS_S32) then
+ begin
+ list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end
+ else
+{$endif RISCV64}
+ begin
+ list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
+ maybeadjustresult(list,op,size,dst);
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
+ var
+ href: treference;
+ b, tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if (not assigned(href.symbol)) and
+ (href.offset=0) then
+ a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
+ else if (assigned(href.symbol) or
+ (not is_imm12(href.offset))) and
+ (href.base<>NR_NO) then
+ begin
+ b:= href.base;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.base:=NR_NO;
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,r,href));
+
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,href));
+
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+ end
+ else if is_imm12(href.offset) and
+ (href.base<>NR_NO) then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,r,href.base,href.offset));
+ end
+ else if (href.refaddr=addr_pcrel) then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ b:=href.base;
+ href.base:=NR_NO;
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,tmpreg,href));
+
+ if b<>NR_NO then
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+ end
+ else
+ internalerror(2016060504);
+ end;
+
+
+ procedure tcgrv.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+ begin
+ if a=0 then
+ a_cmp_reg_reg_label(list,size,cmp_op,NR_X0,reg,l)
+ else
+ inherited;
+ end;
+
+
+ procedure tcgrv.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
+ var
+ tmpreg: TRegister;
+ ai: taicpu;
+ begin
+ if TOpCmp2AsmCond[cmp_op]=C_None then
+ begin
+ cmp_op:=swap_opcmp(cmp_op);
+ tmpreg:=reg1;
+ reg1:=reg2;
+ reg2:=tmpreg;
+ end;
+
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,reg2,reg1,l,0);
+ ai.is_jmp:=true;
+ ai.condition:=TOpCmp2AsmCond[cmp_op];
+ list.concat(ai);
+ end;
+
+
+ procedure tcgrv.a_jmp_name(list : TAsmList;const s : string);
+ var
+ ai: taicpu;
+ href: treference;
+ tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0,[]);
+ href.refaddr:=addr_pcrel_lo12;
+ ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+ ai.is_jmp:=true;
+ list.concat(ai);
+
+ //ai:=taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(s));
+ //ai.is_jmp:=true;
+ end;
+
+
+ procedure tcgrv.a_jmp_always(list : TAsmList;l: tasmlabel);
+ var
+ ai: taicpu;
+ {href: treference;
+ tmpreg: TRegister;}
+ begin
+ {reference_reset_symbol(href,l,0,0);
+
+ tmpreg:=getintregister(list,OS_ADDR);
+
+ current_asmdata.getjumplabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0);
+ href.refaddr:=addr_pcrel_lo12;
+ ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+ ai.is_jmp:=true;
+ list.concat(ai);}
+
+ ai:=taicpu.op_reg_sym(A_JAL,NR_X0,l);
+ ai.is_jmp:=true;
+ list.concat(ai);
+ end;
+
+
+ procedure tcgrv.g_save_registers(list: TAsmList);
+ begin
+ end;
+
+
+ procedure tcgrv.g_restore_registers(list: TAsmList);
+ begin
+ end;
+
+
+ procedure tcgrv.g_profilecode(list: TAsmList);
+ begin
+ if target_info.system in [system_riscv32_linux,system_riscv64_linux] then
+ begin
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_X10,NR_RETURN_ADDRESS_REG,0));
+ a_call_name(list,'_mcount',false);
+ end
+ else
+ internalerror(2018092201);
+ end;
+
+
+ procedure tcgrv.a_call_reg(list : TAsmList;reg: tregister);
+ begin
+ list.concat(taicpu.op_reg_reg(A_JALR,NR_RETURN_ADDRESS_REG,reg));
+ include(current_procinfo.flags,pi_do_call);
+ end;
+
+
+ procedure tcgrv.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
+ reg: tregister; const ref: treference);
+
+ const
+ StoreInstr: array[OS_8..OS_INT] of TAsmOp =
+ (A_SB,A_SH,A_SW
+{$ifdef cpu64bitalu}
+ ,
+ A_SD
+{$endif cpu64bitalu}
+ );
+ var
+ ref2: TReference;
+ tmpreg: tregister;
+ op: TAsmOp;
+ begin
+ if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+ internalerror(2002090904);
+ if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+ internalerror(2002090905);
+
+ tosize:=tcgsize2unsigned[tosize];
+
+ ref2 := ref;
+ fixref(list, ref2);
+
+ op := storeinstr[tcgsize2unsigned[tosize]];
+ list.concat(taicpu.op_reg_ref(op, reg,ref2));
+ end;
+
+
+ procedure tcgrv.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ case fromsize of
+ OS_8: op:=A_LBU;
+ OS_16: op:=A_LHU;
+ OS_S8: op:=A_LB;
+ OS_S16: op:=A_LH;
+{$ifdef RISCV64}
+ OS_32: op:=A_LWU;
+ OS_S32: op:=A_LW;
+ OS_64,
+ OS_S64: op:=A_LD;
+{$else}
+ OS_32,
+ OS_S32: op:=A_LW;
+{$endif}
+ else
+ internalerror(2016060502);
+ end;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+ if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) then
+ a_load_reg_reg(list,fromsize,tosize,reg,reg);
+ end;
+
+
+ procedure tcgrv.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+ begin
+ if a=0 then
+ a_load_reg_reg(list,size,size,NR_X0,register)
+ else
+ begin
+ if is_imm12(a) then
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
+ else if is_lui_imm(a) then
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
+ else
+ begin
+ if (a and $800)<>0 then
+ list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
+ else
+ list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
+
+ list.concat(taicpu.op_reg_reg_const(A_ADDI,register,register,SarSmallint(a shl 4,4)));
+ end;
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+ var
+ op: TAsmOp;
+ ai: taicpu;
+
+ const
+ convOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
+ ((A_None,A_FCVT_D_S),
+ (A_FCVT_S_D,A_None));
+
+ begin
+ if fromsize<>tosize then
+ begin
+ list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1));
+ g_check_for_fpu_exception(list);
+ end
+ else
+ begin
+ if tosize=OS_F32 then
+ op:=A_FSGNJ_S
+ else
+ op:=A_FSGNJ_D;
+
+ ai:=taicpu.op_reg_reg_reg(op,reg2,reg1,reg1);
+ list.concat(ai);
+ rg[R_FPUREGISTER].add_move_instruction(ai);
+ end;
+ end;
+
+
+ procedure tcgrv.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ l: TAsmLabel;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ if fromsize=OS_F32 then
+ op:=A_FLW
+ else
+ op:=A_FLD;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+
+ if fromsize<>tosize then
+ a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
+ end;
+
+
+ procedure tcgrv.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
+ var
+ href: treference;
+ op: TAsmOp;
+ tmpreg: TRegister;
+ begin
+ href:=ref;
+ fixref(list,href);
+
+ if href.refaddr=addr_pcrel then
+ begin
+ tmpreg:=getintregister(list,OS_ADDR);
+ a_loadaddr_ref_reg(list,href,tmpreg);
+ reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+ end;
+
+ if fromsize<>tosize then
+ begin
+ tmpreg:=getfpuregister(list,tosize);
+ a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
+ reg:=tmpreg;
+ end;
+
+ if tosize=OS_F32 then
+ op:=A_FSW
+ else
+ op:=A_FSD;
+
+ list.concat(taicpu.op_reg_ref(op,reg,href));
+ end;
+
+
+ function tcgrv.fixref(list: TAsmList; var ref: treference): boolean;
+ var
+ tmpreg: TRegister;
+ href: treference;
+ l: TAsmLabel;
+ begin
+ result:=true;
+
+ if ref.refaddr=addr_pcrel then
+ exit;
+
+ if assigned(ref.symbol) then
+ begin
+ reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
+ ref.symbol:=nil;
+ ref.offset:=0;
+
+ tmpreg:=getintregister(list,OS_INT);
+
+ current_asmdata.getaddrlabel(l);
+ a_label(list,l);
+
+ href.refaddr:=addr_pcrel_hi20;
+ list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+ reference_reset_symbol(href,l,0,0,ref.volatility);
+ href.refaddr:=addr_pcrel_lo12;
+ list.concat(taicpu.op_reg_reg_ref(A_ADDI,tmpreg,tmpreg,href));
+
+ if (ref.index<>NR_NO) and
+ (ref.base<>NR_NO) then
+ begin
+ a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
+ ref.base:=tmpreg;
+ end
+ else if (ref.index=NR_NO) and
+ (ref.base<>NR_NO) then
+ ref.index:=tmpreg
+ else
+ ref.base:=tmpreg;
+ end
+ else if (ref.index=NR_NO) and
+ (ref.base=NR_NO) then
+ begin
+ tmpreg:=getintregister(list,OS_INT);
+
+ a_load_const_reg(list, OS_ADDR,ref.offset,tmpreg);
+
+ reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
+ end;
+
+ if (ref.index<>NR_NO) and
+ (ref.base=NR_NO) then
+ begin
+ ref.base:=ref.index;
+ ref.index:=NR_NO;
+ end;
+
+ if not is_imm12(ref.offset) then
+ begin
+ tmpreg:=getintregister(list,OS_INT);
+ a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
+
+ ref.offset:=0;
+
+ if (ref.index<>NR_NO) and
+ (ref.base<>NR_NO) then
+ begin
+ a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
+ ref.index:=tmpreg;
+ end
+ else
+ ref.index:=tmpreg;
+ end;
+
+ if (ref.index<>NR_NO) and
+ (ref.base<>NR_NO) then
+ begin
+ tmpreg:=getaddressregister(list);
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
+ ref.base:=tmpreg;
+ ref.index:=NR_NO;
+ end;
+ end;
+
+
+ procedure tcgrv.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+ const
+ overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
+ begin
+ if (op in overflowops) and
+ (size in [OS_8,OS_S8,OS_16,OS_S16{$ifdef RISCV64},OS_32,OS_S32{$endif RISCV64}]) then
+ a_load_reg_reg(list,OS_INT,size,dst,dst)
+ end;
+
+
+ procedure tcgrv.g_check_for_fpu_exception(list: TAsmList);
+ var
+ r : TRegister;
+ ai: taicpu;
+ l: TAsmLabel;
+ begin
+ if cs_check_fpu_exceptions in current_settings.localswitches then
+ begin
+ r:=getintregister(list,OS_INT);
+ list.concat(taicpu.op_reg(A_FRFLAGS,r));
+ current_asmdata.getjumplabel(l);
+ ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,r,NR_X0,l,0);
+ ai.is_jmp:=true;
+ ai.condition:=C_EQ;
+ list.concat(ai);
+ alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+ cg.a_call_name(current_asmdata.CurrAsmList,'FPC_THROWFPUEXCEPTION',false);
+ dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+ a_label(list,l);
+ end;
+ end;
+
+end.