| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 | {    Copyright (c) 1998-2002 by Florian Klaempfl    Generate Risc-V32/64 inline nodes    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 nrvinl;{$i fpcdefs.inc}interface    uses       cpubase,       node,ninl,ncginl;    type       { trvinlinenode }       trvinlinenode = class(tcginlinenode)          { first pass override            so that the code generator will actually generate            these nodes.          }          function first_sqrt_real: tnode; override;          function first_abs_real: tnode; override;          function first_sqr_real: tnode; override;          function first_round_real: tnode; override;          function first_trunc_real: tnode; override;          function first_fma: tnode; override;          procedure second_sqrt_real; override;          procedure second_abs_real; override;          procedure second_sqr_real; override;          procedure second_round_real; override;          procedure second_trunc_real; override;          procedure second_fma; override;       protected          procedure load_fpu_location;       end;implementation    uses      ncal,      cutils,globals,verbose,globtype,      aasmtai,aasmdata,aasmcpu,      symconst,symdef,      defutil,      cgbase,pass_2,      cpuinfo,ncgutil,      hlcgobj,cgutils,cgobj,rgobj,tgobj;{*****************************************************************************                              trvinlinenode*****************************************************************************}     function trvinlinenode.first_sqrt_real : tnode;       begin         if (current_settings.fputype >= fpu_fd) then           begin             expectloc:=LOC_FPUREGISTER;             first_sqrt_real := nil;           end         else           result:=inherited first_sqrt_real;       end;     function trvinlinenode.first_abs_real : tnode;       begin         if (current_settings.fputype >= fpu_fd) then           begin             expectloc:=LOC_FPUREGISTER;             first_abs_real := nil;           end         else           result:=inherited first_abs_real;       end;     function trvinlinenode.first_sqr_real : tnode;       begin         if (current_settings.fputype >= fpu_fd) then           begin             expectloc:=LOC_FPUREGISTER;             first_sqr_real := nil;           end         else           result:=inherited first_sqr_real;       end;     function trvinlinenode.first_round_real: tnode;       begin         if (current_settings.fputype >= fpu_fd) then           begin             expectloc:=LOC_FPUREGISTER;             first_round_real := nil;           end         else           result:=inherited first_round_real;       end;     function trvinlinenode.first_trunc_real: tnode;       begin         if (current_settings.fputype >= fpu_fd) then           begin             expectloc:=LOC_FPUREGISTER;             first_trunc_real := nil;           end         else           result:=inherited first_trunc_real;       end;     function trvinlinenode.first_fma: tnode;       begin         Result:=nil;       end;     { load the FPU into the an fpu register }     procedure trvinlinenode.load_fpu_location;       begin         location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));         secondpass(left);         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);         location.loc := LOC_FPUREGISTER;         location.register := cg.getfpuregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));       end;    procedure trvinlinenode.second_sqrt_real;      begin        location.loc:=LOC_FPUREGISTER;        load_fpu_location;        case left.location.size of          OS_F32:            begin              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,                left.location.register));              cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);            end;          OS_F64:            begin              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_D,location.register,                left.location.register));              cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);             end          else            inherited;        end;      end;     procedure trvinlinenode.second_abs_real;       var         op: TAsmOp;       begin         location.loc:=LOC_FPUREGISTER;         load_fpu_location;         if (left.location.size = OS_F32) then           op := A_FSGNJX_S         else           op := A_FSGNJX_D;         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));       end;     procedure trvinlinenode.second_sqr_real;       var         op: tasmop;       begin         location.loc:=LOC_FPUREGISTER;         load_fpu_location;         if (left.location.size = OS_F32) then           op := A_FMUL_S         else           op := A_FMUL_D;         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);       end;     procedure trvinlinenode.second_round_real;       var         op: TAsmOp;       begin         secondpass(left);         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));{$ifdef RISCV32}         if (location.size in [OS_S64,OS_64]) then           begin             location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);             location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);           end         else           location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);{$else}         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);{$endif}         { convert to signed integer rounding towards zero (there's no "round to           integer using current rounding mode") }{$ifdef RISCV32}         if (left.location.size = OS_F32) then           op := A_FCVT_W_S         else           op := A_FCVT_W_D;{$else}         if (left.location.size = OS_F32) then           op := A_FCVT_L_S         else           op := A_FCVT_L_D;{$endif}         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);       end;     procedure trvinlinenode.second_trunc_real;       var         op: TAsmOp;       begin         secondpass(left);         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));{$ifdef RISCV32}         if (location.size in [OS_S64,OS_64]) then           begin             location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);             location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);           end         else           location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);{$else}         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);{$endif}         { convert to signed integer rounding towards zero (there's no "round to           integer using current rounding mode") }{$ifdef RISCV32}         if (left.location.size = OS_F32) then           op := A_FCVT_W_S         else           op := A_FCVT_W_D;{$else}         if (left.location.size = OS_F32) then           op := A_FCVT_L_S         else           op := A_FCVT_L_D;{$endif}         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));         cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);       end;     procedure trvinlinenode.second_fma;       const         op : array[os_f32..os_f64,false..true,false..true] of TAsmOp =           (            (             (A_FMADD_S,A_FMSUB_S),             (A_FNMADD_S,A_FNMSUB_S)            ),            (             (A_FMADD_D,A_FMSUB_D),             (A_FNMADD_D,A_FNMSUB_D)            )           );       var         paraarray : array[1..3] of tnode;         i : integer;         negop3,         negproduct : boolean;       begin         if current_settings.fputype in [fpu_fd] then           begin             negop3:=false;             negproduct:=false;             paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;             paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;             paraarray[3]:=tcallparanode(parameters).paravalue;             { check if a neg. node can be removed               this is possible because changing the sign of               a floating point number does not affect its absolute               value in any way             }             if paraarray[1].nodetype=unaryminusn then               begin                 paraarray[1]:=tunarynode(paraarray[1]).left;                 { do not release the unused unary minus node, it is kept and release together with the other nodes,                   only no code is generated for it }                 negproduct:=not(negproduct);               end;             if paraarray[2].nodetype=unaryminusn then               begin                 paraarray[2]:=tunarynode(paraarray[2]).left;                 { do not release the unused unary minus node, it is kept and release together with the other nodes,                   only no code is generated for it }                 negproduct:=not(negproduct);               end;             if paraarray[3].nodetype=unaryminusn then               begin                 paraarray[3]:=tunarynode(paraarray[3]).left;                 { do not release the unused unary minus node, it is kept and release together with the other nodes,                   only no code is generated for it }                 negop3:=true;               end;              for i:=1 to 3 do               secondpass(paraarray[i]);             { no memory operand is allowed }             for i:=1 to 3 do               begin                 if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then                   hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);               end;             location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size);             location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);             current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(op[def_cgsize(resultdef), negproduct,negop3],location.register,paraarray[1].location.register,paraarray[2].location.register,paraarray[2].location.register));             cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);           end         else           internalerror(2014032301);       end;begin   cinlinenode:=trvinlinenode;end.
 |