From f80ce76a693f620b1b9c07f4c55798f465c2c793 Mon Sep 17 00:00:00 2001 From: sergei Date: Fri, 19 Jul 2013 14:06:47 +0000 Subject: [PATCH] + MIPS: emulate "flags", i.e. support LOC_FLAGS location. This allows to generate differently optimized code for branching and for conversion to register, typically saving a register and instruction per compare. git-svn-id: trunk@25131 - --- compiler/fpcdefs.inc | 2 +- compiler/mips/cgcpu.pas | 84 ++++++++++++++++++++++++++++++++++++ compiler/mips/cpubase.pas | 10 +++++ compiler/mips/ncpuadd.pas | 89 ++++++--------------------------------- compiler/mips/ncpucnv.pas | 5 +++ compiler/mips/ncpumat.pas | 30 +++---------- compiler/ncgcnv.pas | 6 ++- 7 files changed, 126 insertions(+), 100 deletions(-) diff --git a/compiler/fpcdefs.inc b/compiler/fpcdefs.inc index b54065e011..5f162d8d67 100644 --- a/compiler/fpcdefs.inc +++ b/compiler/fpcdefs.inc @@ -211,7 +211,7 @@ {$else} {$error mips64 not yet supported} {$endif} - { define cpuflags} + {$define cpuflags} { Flags are emulated } {$define cputargethasfixedstack} {$define cpurequiresproperalignment} { define cpumm} diff --git a/compiler/mips/cgcpu.pas b/compiler/mips/cgcpu.pas index b298907b18..185b7582ba 100644 --- a/compiler/mips/cgcpu.pas +++ b/compiler/mips/cgcpu.pas @@ -72,6 +72,8 @@ type { comparison operations } 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_flags(list: tasmlist; const f: TResFlags; l: tasmlabel); override; + procedure g_flags2reg(list: tasmlist; size: TCgSize; const f: TResFlags; reg: tregister); override; procedure a_jmp_always(List: tasmlist; l: TAsmLabel); override; procedure a_jmp_name(list: tasmlist; const s: string); override; procedure g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); override; @@ -1073,6 +1075,88 @@ begin end; +procedure TCGMIPS.a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel); + begin + if f.use_const then + a_cmp_const_reg_label(list,OS_INT,f.cond,f.value,f.reg1,l) + else + a_cmp_reg_reg_label(list,OS_INT,f.cond,f.reg2,f.reg1,l); + end; + + +procedure TCGMIPS.g_flags2reg(list: tasmlist; size: tcgsize; const f: tresflags; reg: tregister); + var + left,right: tregister; + unsigned: boolean; + begin + if (f.cond in [OC_EQ,OC_NE]) then + begin + left:=reg; + if f.use_const and (f.value>=0) and (f.value<=65535) then + begin + if (f.value<>0) then + list.concat(taicpu.op_reg_reg_const(A_XORI,reg,f.reg1,f.value)) + else + left:=f.reg1; + end + else + begin + if f.use_const then + begin + right:=GetIntRegister(list,OS_INT); + a_load_const_reg(list,OS_INT,f.value,right); + end + else + right:=f.reg2; + list.concat(taicpu.op_reg_reg_reg(A_XOR,reg,f.reg1,right)); + end; + + if f.cond=OC_EQ then + list.concat(taicpu.op_reg_reg_const(A_SLTIU,reg,left,1)) + else + list.concat(taicpu.op_reg_reg_reg(A_SLTU,reg,NR_R0,left)); + end + else + begin + { + sle x,a,b --> slt x,b,a; xori x,x,1 immediate not possible (or must be at left) + sgt x,a,b --> slt x,b,a likewise + sge x,a,b --> slt x,a,b; xori x,x,1 + slt x,a,b --> unchanged + } + + unsigned:=f.cond in [OC_GT,OC_LT,OC_GTE,OC_LTE]; + if (f.cond in [OC_GTE,OC_LT,OC_B,OC_AE]) and + f.use_const and + (f.value>=simm16lo) and + (f.value<=simm16hi) then + list.Concat(taicpu.op_reg_reg_const(ops_slti[unsigned],reg,f.reg1,f.value)) + else + begin + if f.use_const then + begin + if (f.value=0) then + right:=NR_R0 + else + begin + right:=GetIntRegister(list,OS_INT); + a_load_const_reg(list,OS_INT,f.value,right); + end; + end + else + right:=f.reg2; + + if (f.cond in [OC_LTE,OC_GT,OC_BE,OC_A]) then + list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,right,f.reg1)) + else + list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,f.reg1,right)); + end; + if (f.cond in [OC_LTE,OC_GTE,OC_BE,OC_AE]) then + list.Concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1)); + end; + end; + + procedure TCGMIPS.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); begin // this is an empty procedure diff --git a/compiler/mips/cpubase.pas b/compiler/mips/cpubase.pas index ea5032613c..87f4c4c73a 100644 --- a/compiler/mips/cpubase.pas +++ b/compiler/mips/cpubase.pas @@ -124,6 +124,15 @@ unit cpubase; 'c1t','c1f' ); + type + TResFlags=record + reg1: TRegister; + cond: TOpCmp; + case use_const: boolean of + False: (reg2: TRegister); + True: (value: aint); + end; + {***************************************************************************** Constants *****************************************************************************} @@ -222,6 +231,7 @@ unit cpubase; NR_FPU_RESULT_REG = NR_F0; NR_MM_RESULT_REG = NR_NO; + NR_DEFAULTFLAGS = NR_NO; {***************************************************************************** GCC /ABI linking information diff --git a/compiler/mips/ncpuadd.pas b/compiler/mips/ncpuadd.pas index e61b4c0ebd..c7bbade065 100644 --- a/compiler/mips/ncpuadd.pas +++ b/compiler/mips/ncpuadd.pas @@ -69,92 +69,34 @@ uses tmipsaddnode *****************************************************************************} const - swapped_nodetype: array[ltn..gten] of tnodetype = + swapped_nodetype: array[ltn..unequaln] of tnodetype = //lt lte gt gte - (gtn, gten,ltn,lten); + (gtn, gten,ltn,lten, equaln, unequaln); - ops: array[boolean] of tasmop = (A_SLT,A_SLTU); - ops_immed: array[boolean] of tasmop = (A_SLTI,A_SLTIU); + nodetype2opcmp: array[boolean,ltn..unequaln] of TOpCmp = ( + (OC_LT, OC_LTE, OC_GT, OC_GTE, OC_EQ, OC_NE), + (OC_B, OC_BE, OC_A, OC_AE, OC_EQ, OC_NE) + ); procedure tmipsaddnode.second_generic_cmp32(unsigned: boolean); var ntype: tnodetype; - tmp_left,tmp_right: TRegister; begin pass_left_right; force_reg_left_right(True, True); - location_reset(location,LOC_REGISTER,OS_INT); - location.register:=cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); - - if nodetype in [equaln,unequaln] then - begin - tmp_left:=location.register; - { XORI needs unsigned immediate in range 0-65535 } - if (right.location.loc=LOC_CONSTANT) and (right.location.value>=0) and - (right.location.value<=65535) then - begin - if right.location.value<>0 then - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_XORI,location.register,left.location.register,right.location.value)) - else - tmp_left:=left.location.register; - end - else - begin - if (right.location.loc<>LOC_CONSTANT) then - tmp_right:=right.location.register - else - begin - tmp_right:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT); - cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,right.location.value,tmp_right); - end; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_XOR,location.register,left.location.register,tmp_right)); - end; - - if nodetype=equaln then - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,tmp_left,1)) - else - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU,location.register,NR_R0,tmp_left)); - exit; - end; + location_reset(location,LOC_FLAGS,OS_NO); ntype:=nodetype; if nf_swapped in flags then ntype:=swapped_nodetype[nodetype]; - { - sle x,a,b --> slt x,b,a; xori x,x,1 immediate not possible (or must be at left) - sgt x,a,b --> slt x,b,a likewise - sge x,a,b --> slt x,a,b; xori x,x,1 - slt x,a,b --> unchanged - } - - if (ntype in [gten,ltn]) and - (right.location.loc=LOC_CONSTANT) and - (right.location.value>=simm16lo) and - (right.location.value<=simm16hi) then - current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(ops_immed[unsigned],location.register,left.location.register,right.location.value)) + location.resflags.cond:=nodetype2opcmp[unsigned,ntype]; + 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 - begin - if (right.location.loc=LOC_CONSTANT) then - begin - if (right.location.value=0) then - tmp_right:=NR_R0 - else - begin - tmp_right:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT); - cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,right.location.value,tmp_right); - end; - end - else - tmp_right:=right.location.register; - - if (ntype in [lten,gtn]) then - current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(ops[unsigned],location.register,tmp_right,left.location.register)) - else - current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(ops[unsigned],location.register,left.location.register,tmp_right)); - end; - if (ntype in [lten,gten]) then - current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1)); + location.resflags.reg2:=right.location.register; end; @@ -261,10 +203,7 @@ function tmipsaddnode.pass_1 : tnode; if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) then begin if (left.resultdef.typ=floatdef) or (right.resultdef.typ=floatdef) then - expectloc:=LOC_JUMP - else if ((left.resultdef.typ<>orddef) or - (not (torddef(left.resultdef).ordtype in [s64bit,u64bit,scurrency]))) then - expectloc:=LOC_REGISTER; + expectloc:=LOC_JUMP; end; end; end; diff --git a/compiler/mips/ncpucnv.pas b/compiler/mips/ncpucnv.pas index 119e86a2d2..46b5283569 100644 --- a/compiler/mips/ncpucnv.pas +++ b/compiler/mips/ncpucnv.pas @@ -284,6 +284,11 @@ begin cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, hreg1); cg.a_label(current_asmdata.CurrAsmList, hlabel); end; + LOC_FLAGS: + begin + hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT); + cg.g_flags2reg(current_asmdata.CurrAsmList,OS_INT,left.location.resflags,hreg1); + end else internalerror(10062); end; diff --git a/compiler/mips/ncpumat.pas b/compiler/mips/ncpumat.pas index 84a9b42699..8287b40bf0 100644 --- a/compiler/mips/ncpumat.pas +++ b/compiler/mips/ncpumat.pas @@ -291,34 +291,18 @@ begin LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF: begin hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True); + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags.reg2:=NR_R0; + location.resflags.cond:=OC_EQ; if is_64bit(resultdef) then begin - r64.reglo:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT); - r64.reghi:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT); + tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT); { OR low and high parts together } - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR,r64.reglo,left.location.register64.reglo,left.location.register64.reghi)); - { x=0 <=> unsigned(x)<1 } - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SLTIU,r64.reglo,r64.reglo,1)); - if is_cbool(resultdef) then - begin - cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_S32,r64.reglo,r64.reglo); - cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,r64.reglo,r64.reghi); - end - else - cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,r64.reghi); - location_reset(location,LOC_REGISTER,OS_64); - location.Register64:=r64; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR,tmpreg,left.location.register64.reglo,left.location.register64.reghi)); + location.resflags.reg1:=tmpreg; end else - begin - tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); - { x=0 <=> unsigned(x)<1 } - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SLTIU, tmpreg, left.location.Register, 1)); - if is_cbool(resultdef) then - cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_S32,tmpreg,tmpreg); - location_reset(location, LOC_REGISTER, OS_INT); - location.Register := tmpreg; - end; + location.resflags.reg1:=left.location.register; end; else internalerror(2003042401); diff --git a/compiler/ncgcnv.pas b/compiler/ncgcnv.pas index 6a12ea2c5e..745c93d26f 100644 --- a/compiler/ncgcnv.pas +++ b/compiler/ncgcnv.pas @@ -192,7 +192,11 @@ interface {$if defined(POWERPC) or defined(POWERPC64)} resflags.cr := RS_CR0; resflags.flag:=F_NE; -{$else defined(POWERPC) or defined(POWERPC64)} +{$elseif defined(mips)} + resflags.reg1:=NR_NO; + resflags.reg2:=NR_NO; + resflags.cond:=OC_NONE; +{$else} { Load left node into flag F_NE/F_E } resflags:=F_NE; {$endif defined(POWERPC) or defined(POWERPC64)}