mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-07 05:08:06 +02:00
+ 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:
parent
9a6edd0fb8
commit
f80ce76a69
@ -211,7 +211,7 @@
|
||||
{$else}
|
||||
{$error mips64 not yet supported}
|
||||
{$endif}
|
||||
{ define cpuflags}
|
||||
{$define cpuflags} { Flags are emulated }
|
||||
{$define cputargethasfixedstack}
|
||||
{$define cpurequiresproperalignment}
|
||||
{ define cpumm}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)}
|
||||
|
Loading…
Reference in New Issue
Block a user