123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- {
- Copyright (c) 2000-2009 by Florian Klaempfl and David Zhang
- Code generation for add nodes on the FVM32
- 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 ncpuadd;
- {$i fpcdefs.inc}
- interface
- uses
- node, ncgadd, cpubase, aasmbase, cgbase;
- type
- { tmipsaddnode }
- tmipsaddnode = class(tcgaddnode)
- private
- procedure cmp64_lt(left_reg, right_reg: TRegister64;unsigned:boolean);
- procedure cmp64_le(left_reg, right_reg: TRegister64;unsigned:boolean);
- procedure second_generic_cmp32(unsigned,is_smallset: boolean);
- procedure second_mul64bit;
- protected
- procedure second_addfloat; override;
- procedure second_cmpfloat; override;
- procedure second_cmpboolean; override;
- procedure second_cmpsmallset; override;
- procedure second_add64bit; override;
- procedure second_cmp64bit; override;
- procedure second_cmpordinal; override;
- procedure second_addordinal; override;
- public
- function use_generic_mul32to64: boolean; override;
- function use_generic_mul64bit: boolean; override;
- end;
- implementation
- uses
- systems, globtype, globals,
- cutils, verbose,
- paramgr,
- aasmtai, aasmcpu, aasmdata,
- defutil,
- cpuinfo,
- {cgbase,} cgcpu, cgutils,
- cpupara,
- procinfo,
- symconst,symdef,
- ncon, nset, nadd,
- ncgutil, hlcgobj, cgobj;
- {*****************************************************************************
- tmipsaddnode
- *****************************************************************************}
- procedure tmipsaddnode.second_generic_cmp32(unsigned,is_smallset: boolean);
- var
- cond: TOpCmp;
- allow_constant : boolean;
- dreg : tregister;
- begin
- pass_left_right;
- allow_constant:=(not is_smallset) or not (nodetype in [lten,gten]);
- force_reg_left_right(True, allow_constant);
- location_reset(location,LOC_FLAGS,OS_NO);
- cond:=cmpnode2topcmp(unsigned);
- if nf_swapped in flags then
- cond:=swap_opcmp(cond);
- if is_smallset and (nodetype in [lten,gten]) then
- begin
- if ((nodetype=lten) and not (nf_swapped in flags)) or
- ((nodetype=gten) and (nf_swapped in flags)) then
- dreg:=right.location.register
- else
- dreg:=left.location.register;
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_AND,dreg,right.location.register,left.location.register));
- cond:=OC_EQ;
- end;
- location.resflags.cond:=cond;
- location.resflags.reg1:=left.location.register;
- location.resflags.use_const:=(right.location.loc=LOC_CONSTANT);
- if location.resflags.use_const then
- location.resflags.value:=right.location.value
- else
- location.resflags.reg2:=right.location.register;
- end;
- procedure tmipsaddnode.second_add64bit;
- begin
- if (nodetype=muln) then
- second_mul64bit
- else
- inherited second_add64bit;
- end;
- const
- cmpops: array[boolean] of TOpCmp = (OC_LT,OC_B);
- procedure tmipsaddnode.cmp64_lt(left_reg, right_reg: TRegister64;unsigned: boolean);
- begin
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],right_reg.reghi,left_reg.reghi,location.truelabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,right_reg.reglo,left_reg.reglo,location.truelabel);
- cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
- end;
- procedure tmipsaddnode.cmp64_le(left_reg, right_reg: TRegister64;unsigned: boolean);
- begin
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],left_reg.reghi,right_reg.reghi,location.falselabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,left_reg.reglo,right_reg.reglo,location.falselabel);
- cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
- end;
- procedure tmipsaddnode.second_cmp64bit;
- var
- truelabel,
- falselabel: tasmlabel;
- unsigned: boolean;
- left_reg,right_reg: TRegister64;
- begin
- current_asmdata.getjumplabel(truelabel);
- current_asmdata.getjumplabel(falselabel);
- location_reset_jump(location,truelabel,falselabel);
- pass_left_right;
- force_reg_left_right(true,true);
- unsigned:=not(is_signed(left.resultdef)) or
- not(is_signed(right.resultdef));
- left_reg:=left.location.register64;
- if (right.location.loc=LOC_CONSTANT) then
- begin
- if lo(right.location.value64)=0 then
- right_reg.reglo:=NR_R0
- else
- begin
- right_reg.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
- cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,lo(right.location.value64),right_reg.reglo);
- end;
- if hi(right.location.value64)=0 then
- right_reg.reghi:=NR_R0
- else
- begin
- right_reg.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
- cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,hi(right.location.value64),right_reg.reghi);
- end;
- end
- else
- right_reg:=right.location.register64;
- case NodeType of
- equaln:
- begin
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.falselabel);
- cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
- end;
- unequaln:
- begin
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
- cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.truelabel);
- cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
- end;
- else
- if nf_swapped in flags then
- case NodeType of
- ltn:
- cmp64_lt(right_reg, left_reg,unsigned);
- lten:
- cmp64_le(right_reg, left_reg,unsigned);
- gtn:
- cmp64_lt(left_reg, right_reg,unsigned);
- gten:
- cmp64_le(left_reg, right_reg,unsigned);
- end
- else
- case NodeType of
- ltn:
- cmp64_lt(left_reg, right_reg,unsigned);
- lten:
- cmp64_le(left_reg, right_reg,unsigned);
- gtn:
- cmp64_lt(right_reg, left_reg,unsigned);
- gten:
- cmp64_le(right_reg, left_reg,unsigned);
- end;
- end;
- end;
- procedure tmipsaddnode.second_addfloat;
- var
- op: TAsmOp;
- begin
- pass_left_right;
- if (nf_swapped in flags) then
- swapleftright;
- { force fpureg as location, left right doesn't matter
- as both will be in a fpureg }
- hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
- hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
- location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
- location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
- case nodetype of
- addn:
- begin
- if location.size = OS_F64 then
- op := A_ADD_D
- else
- op := A_ADD_S;
- end;
- muln:
- begin
- if location.size = OS_F64 then
- op := A_MUL_D
- else
- op := A_MUL_S;
- end;
- subn:
- begin
- if location.size = OS_F64 then
- op := A_SUB_D
- else
- op := A_SUB_S;
- end;
- slashn:
- begin
- if location.size = OS_F64 then
- op := A_DIV_D
- else
- op := A_DIV_S;
- end;
- else
- internalerror(200306014);
- end;
- current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,
- location.Register, left.location.Register, right.location.Register));
- end;
- const
- ops_cmpfloat: array[boolean,ltn..unequaln] of TAsmOp = (
- // ltn lten gtn gten equaln unequaln
- (A_C_LT_S, A_C_LE_S, A_C_LT_S, A_C_LE_S, A_C_EQ_S, A_C_EQ_S),
- (A_C_LT_D, A_C_LE_D, A_C_LT_D, A_C_LE_D, A_C_EQ_D, A_C_EQ_D)
- );
- procedure tmipsaddnode.second_cmpfloat;
- var
- op: tasmop;
- lreg,rreg: tregister;
- begin
- pass_left_right;
- if nf_swapped in flags then
- swapleftright;
- hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
- hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
- location_reset(location, LOC_FLAGS, OS_NO);
- op:=ops_cmpfloat[left.location.size=OS_F64,nodetype];
- if (nodetype in [gtn,gten]) then
- begin
- lreg:=right.location.register;
- rreg:=left.location.register;
- end
- else
- begin
- lreg:=left.location.register;
- rreg:=right.location.register;
- end;
- current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,lreg,rreg));
- location.resflags.reg1:=NR_FCC0;
- if (nodetype=unequaln) then
- location.resflags.cond:=OC_EQ
- else
- location.resflags.cond:=OC_NE;
- end;
- procedure tmipsaddnode.second_cmpboolean;
- begin
- second_generic_cmp32(true,false);
- end;
- procedure tmipsaddnode.second_cmpsmallset;
- begin
- second_generic_cmp32(true,true);
- end;
- procedure tmipsaddnode.second_cmpordinal;
- var
- unsigned: boolean;
- begin
- unsigned := not (is_signed(left.resultdef)) or not (is_signed(right.resultdef));
- second_generic_cmp32(unsigned,false);
- end;
- const
- multops: array[boolean] of TAsmOp = (A_MULT, A_MULTU);
- procedure tmipsaddnode.second_addordinal;
- var
- unsigned: boolean;
- begin
- unsigned:=not(is_signed(left.resultdef)) or
- not(is_signed(right.resultdef));
- if (nodetype=muln) and is_64bit(resultdef) then
- begin
- pass_left_right;
- force_reg_left_right(true,false);
- location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
- location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
- location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(multops[unsigned],left.location.register,right.location.register));
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
- end
- else
- inherited second_addordinal;
- end;
- procedure tmipsaddnode.second_mul64bit;
- var
- list: TAsmList;
- hreg1,hreg2,tmpreg: TRegister;
- begin
- list:=current_asmdata.CurrAsmList;
- pass_left_right;
- location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
- hlcg.location_force_reg(list,left.location,left.resultdef,left.resultdef,true);
- { calculate 32-bit terms lo(right)*hi(left) and hi(left)*lo(right) }
- hreg1:=NR_NO;
- hreg2:=NR_NO;
- tmpreg:=NR_NO;
- if (right.location.loc=LOC_CONSTANT) then
- begin
- { Omit zero terms, if any }
- if hi(right.location.value64)<>0 then
- begin
- hreg2:=cg.getintregister(list,OS_INT);
- tmpreg:=cg.getintregister(list,OS_INT);
- cg.a_load_const_reg(list,OS_INT,longint(hi(right.location.value64)),tmpreg);
- list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,tmpreg,left.location.register64.reglo));
- end;
- tmpreg:=NR_NO;
- if lo(right.location.value64)<>0 then
- begin
- hreg1:=cg.getintregister(list,OS_INT);
- tmpreg:=cg.getintregister(list,OS_INT);
- cg.a_load_const_reg(list,OS_INT,longint(lo(right.location.value64)),tmpreg);
- list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,tmpreg,left.location.register64.reghi));
- end;
- end
- else
- begin
- hlcg.location_force_reg(list,right.location,right.resultdef,right.resultdef,true);
- tmpreg:=right.location.register64.reglo;
- hreg1:=cg.getintregister(list,OS_INT);
- hreg2:=cg.getintregister(list,OS_INT);
- list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,right.location.register64.reglo,left.location.register64.reghi));
- list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,right.location.register64.reghi,left.location.register64.reglo));
- end;
- { At this point, tmpreg is either lo(right) or NR_NO if lo(left)*lo(right) is zero }
- if (tmpreg=NR_NO) then
- begin
- if (hreg2<>NR_NO) and (hreg1<>NR_NO) then
- begin
- location.register64.reghi:=cg.getintregister(list,OS_INT);
- list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,hreg1,hreg2));
- end
- else if (hreg2<>NR_NO) then
- location.register64.reghi:=hreg2
- else if (hreg1<>NR_NO) then
- location.register64.reghi:=hreg1
- else
- InternalError(2014122701);
- location.register64.reglo:=NR_R0;
- end
- else
- begin
- list.concat(taicpu.op_reg_reg(A_MULTU,left.location.register64.reglo,tmpreg));
- location.register64.reghi:=cg.getintregister(list,OS_INT);
- location.register64.reglo:=cg.getintregister(list,OS_INT);
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
- if (hreg2<>NR_NO) then
- list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg2));
- if (hreg1<>NR_NO) then
- list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg1));
- end;
- end;
- function tmipsaddnode.use_generic_mul32to64: boolean;
- begin
- result:=false;
- end;
- function tmipsaddnode.use_generic_mul64bit: boolean;
- begin
- result:=(cs_check_overflow in current_settings.localswitches) or
- (not (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]));
- end;
- begin
- caddnode := tmipsaddnode;
- end.
|