diff options
Diffstat (limited to 'riscv/trunk/compiler/riscv/cgrv.pas')
-rw-r--r-- | riscv/trunk/compiler/riscv/cgrv.pas | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/riscv/trunk/compiler/riscv/cgrv.pas b/riscv/trunk/compiler/riscv/cgrv.pas new file mode 100644 index 0000000000..5ac5e112ce --- /dev/null +++ b/riscv/trunk/compiler/riscv/cgrv.pas @@ -0,0 +1,479 @@ +{ + 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 = 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_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_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);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; + + { 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; + protected + function fixref(list: TAsmList; var ref: treference): boolean; + end; + + const + TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE, + C_LT,C_GE,C_None,C_NE,C_NONE,C_LT,C_GE,C_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); + begin + if not(weak) then + list.concat(taicpu.op_reg_sym(A_JAL,NR_RETURN_ADDRESS_REG,current_asmdata.RefAsmSymbol(s,AT_FUNCTION))) + else + list.concat(taicpu.op_reg_sym(A_JAL,NR_RETURN_ADDRESS_REG,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION))); + { not assigned while generating external wrappers } + if assigned(current_procinfo) then + include(current_procinfo.flags,pi_do_call); + 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_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; + + href.base:=NR_NO; + href.refaddr:=addr_hi20; + list.concat(taicpu.op_reg_ref(A_LUI,r,href)); + href.refaddr:=addr_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); + + current_asmdata.getaddrlabel(l); + + a_label(list,l); + + b:=href.base; + href.base:=NR_NO; + + href.refaddr:=addr_hi20; + href.relsymbol:=l; + list.concat(taicpu.op_reg_ref(A_LUI,tmpreg,href)); + href.refaddr:=addr_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_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; + begin + ai:=taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(s)); + ai.is_jmp:=true; + list.concat(ai); + end; + + + procedure tcgrv.a_jmp_always(list : TAsmList;l: tasmlabel); + var + ai: taicpu; + begin + ai:=taicpu.op_reg_sym(A_JAL,NR_X0,l); + ai.is_jmp:=true; + list.concat(ai); + 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,0); + 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: op:=A_LW; + OS_S32: op:=A_LW; +{$endif} + else + internalerror(2016060502); + end; + + list.concat(taicpu.op_reg_ref(op,reg,href)); + if fromsize<>tosize 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 + list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1)) + 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 fromsize=OS_F32 then + op:=A_FLW + else + op:=A_FLD; + + if href.refaddr=addr_pcrel then + begin + tmpreg:=getintregister(list,OS_ADDR); + + current_asmdata.getaddrlabel(l); + + a_label(list,l); + + href.refaddr:=addr_hi20; + href.relsymbol:=l; + list.concat(taicpu.op_reg_ref(A_LUI,tmpreg,href)); + href.refaddr:=addr_lo12; + href.base:=nr_x0; + list.concat(taicpu.op_reg_ref(op,reg,href)); + end + else + 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 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; + begin + result:=true; + + if ref.refaddr=addr_pcrel then + begin + exit; + end; + + if assigned(ref.symbol) then + begin + reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment); + ref.symbol:=nil; + ref.offset:=0; + + tmpreg:=getintregister(list,OS_INT); + + href.refaddr:=addr_hi20; + list.concat(taicpu.op_reg_ref(A_LUI,tmpreg,href)); + href.refaddr:=addr_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; + + 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; + +end. |