{ 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 = class(tcgaddnode) private function cmp64_lt(left_reg, right_reg: TRegister64): TRegister; function cmp64_le(left_reg, right_reg: TRegister64): TRegister; function cmp64_eq(left_reg, right_reg: TRegister64): TRegister; function cmp64_ne(left_reg, right_reg: TRegister64): TRegister; function cmp64_ltu(left_reg, right_reg: TRegister64): TRegister; function cmp64_leu(left_reg, right_reg: TRegister64): TRegister; function GetRes_register(unsigned: boolean; this_reg, left_reg, right_reg: TRegister): TRegister; function GetRes64_register(unsigned: boolean; {this_reg,} left_reg, right_reg: TRegister64): TRegister; protected procedure second_addfloat; override; procedure second_cmpfloat; override; procedure second_cmpboolean; override; procedure second_cmpsmallset; override; procedure second_cmp64bit; override; procedure second_cmpordinal; override; end; implementation uses systems, cutils, verbose, paramgr, aasmtai, aasmcpu, aasmdata, defutil, {cgbase,} cgcpu, cgutils, cpupara, ncon, nset, nadd, ncgutil, cgobj; {***************************************************************************** tmipsaddnode *****************************************************************************} function tmipsaddnode.GetRes_register(unsigned: boolean; this_reg, left_reg, right_reg: TRegister): TRegister; var tmp_asm_op: tasmop; begin case NodeType of equaln: tmp_asm_op := A_SEQ; unequaln: tmp_asm_op := A_SNE; else if not (unsigned) then begin if nf_swapped in flags then case NodeType of ltn: tmp_asm_op := A_SGT; lten: tmp_asm_op := A_SGE; gtn: tmp_asm_op := A_SLT; gten: tmp_asm_op := A_SLE; end else case NodeType of ltn: tmp_asm_op := A_SLT; lten: tmp_asm_op := A_SLE; gtn: tmp_asm_op := A_SGT; gten: tmp_asm_op := A_SGE; end; end else begin if nf_swapped in Flags then case NodeType of ltn: tmp_asm_op := A_SGTU; lten: tmp_asm_op := A_SGEU; gtn: tmp_asm_op := A_SLTU; gten: tmp_asm_op := A_SLEU; end else case NodeType of ltn: tmp_asm_op := A_SLTU; lten: tmp_asm_op := A_SLEU; gtn: tmp_asm_op := A_SGTU; gten: tmp_asm_op := A_SGEU; end; end; end; current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(tmp_asm_op, this_reg, left_reg, right_reg)); GetRes_register := this_reg; end; function tmipsaddnode.cmp64_eq(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4: tasmlabel; begin current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, left_reg.reghi, right_reg.reghi, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_sym(A_BNE, left_reg.reglo, right_reg.reglo, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_eq := NR_TCR10; end; function tmipsaddnode.cmp64_ne(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4: tasmlabel; begin current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, left_reg.reghi, right_reg.reghi, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_sym(A_BNE, left_reg.reglo, right_reg.reglo, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_ne := NR_TCR10; end; function tmipsaddnode.cmp64_lt(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4, lfcmp64_L5: tasmlabel; begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLT, NR_TCR11, left_reg.reghi, right_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, left_reg.reghi, right_reg.reghi, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, left_reg.reglo, right_reg.reglo)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_B, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_lt := NR_TCR10; end; function tmipsaddnode.cmp64_le(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4, lfcmp64_L5: tasmlabel; begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLT, NR_TCR11, right_reg.reghi, left_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, right_reg.reghi, left_reg.reghi, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, right_reg.reglo, left_reg.reglo)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_le := NR_TCR10; end; function tmipsaddnode.cmp64_ltu(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4, lfcmp64_L5: tasmlabel; begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, left_reg.reghi, right_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, left_reg.reghi, right_reg.reghi, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, left_reg.reglo, right_reg.reglo)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_B, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_ltu := NR_TCR10; end; function tmipsaddnode.cmp64_leu(left_reg, right_reg: TRegister64): TRegister; var lfcmp64_L4, lfcmp64_L5: tasmlabel; begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, right_reg.reghi, left_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, right_reg.reghi, left_reg.reghi, lfcmp64_L5)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, right_reg.reglo, left_reg.reglo)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmp64_L4); cmp64_leu := NR_TCR10; end; function tmipsaddnode.GetRes64_register(unsigned: boolean; //this_reg: TRegister; left_reg, right_reg: TRegister64): TRegister; var tmpreg: TRegister; lfcmp64_L4, lfcmp_L5: tasmlabel; begin case NodeType of equaln: begin GetRes64_register := cmp64_eq(left_reg, right_reg); end; unequaln: GetRes64_register := cmp64_ne(left_reg, right_reg); else if not (unsigned) then begin if nf_swapped in flags then case NodeType of ltn: GetRes64_register := cmp64_lt(right_reg, left_reg); lten: GetRes64_register := cmp64_le(right_reg, left_reg); gtn: GetRes64_register := cmp64_lt(left_reg, right_reg); gten: GetRes64_register := cmp64_le(left_reg, right_reg); end else case NodeType of ltn: GetRes64_register := cmp64_lt(left_reg, right_reg); lten: GetRes64_register := cmp64_le(left_reg, right_reg); gtn: GetRes64_register := cmp64_lt(right_reg, left_reg); gten: GetRes64_register := cmp64_le(right_reg, left_reg); end; end else begin if nf_swapped in Flags then case NodeType of ltn: GetRes64_register := cmp64_ltu(right_reg, left_reg); lten: GetRes64_register := cmp64_leu(right_reg, left_reg); gtn: GetRes64_register := cmp64_ltu(left_reg, right_reg); gten: GetRes64_register := cmp64_leu(left_reg, right_reg); end else case NodeType of ltn: GetRes64_register := cmp64_ltu(left_reg, right_reg); lten: GetRes64_register := cmp64_leu(left_reg, right_reg); gtn: GetRes64_register := cmp64_ltu(right_reg, left_reg); gten: GetRes64_register := cmp64_leu(right_reg, left_reg); end; 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 } location_force_fpureg(current_asmdata.CurrAsmList, left.location, True); location_force_fpureg(current_asmdata.CurrAsmList, right.location, (left.location.loc <> LOC_CFPUREGISTER)); location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef)); if left.location.loc <> LOC_CFPUREGISTER then location.Register := left.location.Register else location.Register := right.location.Register; 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; procedure tmipsaddnode.second_cmpfloat; var op: tasmop; lfcmptrue, lfcmpfalse: tasmlabel; 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 } location_force_fpureg(current_asmdata.CurrAsmList, left.location, True); location_force_fpureg(current_asmdata.CurrAsmList, right.location, True); location_reset(location, LOC_REGISTER, OS_INT); location.Register := NR_TCR0; case NodeType of equaln: begin if left.location.size = OS_F64 then op := A_C_EQ_D else op := A_C_EQ_S; current_asmdata.getjumplabel(lfcmpfalse); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1F, lfcmpfalse)); //lfcmpfalse current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); cg.a_label(current_asmdata.CurrAsmList, lfcmpfalse); end; unequaln: begin if left.location.size = OS_F64 then op := A_C_EQ_D else op := A_C_EQ_S; current_asmdata.getjumplabel(lfcmpfalse); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1F, lfcmpfalse)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); cg.a_label(current_asmdata.CurrAsmList, lfcmpfalse); end; ltn: begin if left.location.size = OS_F64 then op := A_C_LT_D else op := A_C_LT_S; current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); cg.a_label(current_asmdata.CurrAsmList, lfcmptrue); end; lten: begin if left.location.size = OS_F64 then op := A_C_LE_D else op := A_C_LE_S; current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); cg.a_label(current_asmdata.CurrAsmList, lfcmptrue); end; gtn: begin if left.location.size = OS_F64 then op := A_C_LT_D else op := A_C_LT_S; current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, right.location.Register, left.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); cg.a_label(current_asmdata.CurrAsmList, lfcmptrue); end; gten: begin if left.location.size = OS_F64 then op := A_C_LE_D else op := A_C_LE_S; current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, right.location.Register, left.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); current_asmdata.CurrAsmList.concat(TAiCpu.Op_none(A_NOP)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); cg.a_label(current_asmdata.CurrAsmList, lfcmptrue); end; end; {case} end; procedure tmipsaddnode.second_cmpboolean; var tmp_right_reg: TRegister; begin pass_left_right; force_reg_left_right(True, True); tmp_right_reg := NR_NO; if right.location.loc = LOC_CONSTANT then begin tmp_right_reg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, tmp_right_reg, right.location.Value)); end else begin tmp_right_reg := right.location.Register; end; location_reset(location, LOC_REGISTER, OS_INT); location.Register := GetRes_register(True, NR_TCR0, left.location.Register, tmp_right_reg); end; procedure tmipsaddnode.second_cmpsmallset; var tmp_right_reg: TRegister; begin pass_left_right; force_reg_left_right(True, True); tmp_right_reg := NR_NO; if right.location.loc = LOC_CONSTANT then begin tmp_right_reg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, tmp_right_reg, right.location.Value)); end else begin tmp_right_reg := right.location.Register; end; location_reset(location, LOC_REGISTER, OS_INT); location.Register := GetRes_register(True, NR_TCR0, left.location.Register, tmp_right_reg); end; procedure tmipsaddnode.second_cmp64bit; var unsigned : boolean; tmp_left_reg: TRegister; begin pass_left_right; force_reg_left_right(false,false); unsigned:=not(is_signed(left.resultdef)) or not(is_signed(right.resultdef)); location_reset(location, LOC_REGISTER, OS_INT); location.Register := GetRes64_register(unsigned, {NR_TCR0, }left.location.register64, right.location.register64); // NR_TCR0; end; procedure tmipsaddnode.second_cmpordinal; var unsigned: boolean; tmp_right_reg: TRegister; begin pass_left_right; force_reg_left_right(True, True); unsigned := not (is_signed(left.resultdef)) or not (is_signed(right.resultdef)); tmp_right_reg := NR_NO; if right.location.loc = LOC_CONSTANT then begin tmp_right_reg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, tmp_right_reg, right.location.Value)); end else begin tmp_right_reg := right.location.Register; end; location_reset(location, LOC_REGISTER, OS_INT); location.Register := getres_register(unsigned, NR_TCR0, left.location.Register, tmp_right_reg); end; begin caddnode := tmipsaddnode; end.