+ 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 -
This commit is contained in:
sergei 2013-07-19 14:06:47 +00:00
parent 9a6edd0fb8
commit f80ce76a69
7 changed files with 126 additions and 100 deletions

View File

@ -211,7 +211,7 @@
{$else}
{$error mips64 not yet supported}
{$endif}
{ define cpuflags}
{$define cpuflags} { Flags are emulated }
{$define cputargethasfixedstack}
{$define cpurequiresproperalignment}
{ define cpumm}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)}