* SPARC: reworked 64-bit comparisons so their result is always in flags. Comparisons are emitted as subtractions, sides are optionally swapped to avoid using Z flag (since it is not set correctly in multi-word subtraction). This generates significantly shorter code: when both sides are in registers it is just 3 instructions for equal/unequal and 2 instructions otherwise.

git-svn-id: trunk@26433 -
This commit is contained in:
sergei 2014-01-12 15:11:47 +00:00
parent 204d0ac90a
commit 720b9bf560

View File

@ -42,6 +42,7 @@ interface
procedure second_cmpordinal;override; procedure second_cmpordinal;override;
procedure second_addordinal;override; procedure second_addordinal;override;
public public
function pass_1: tnode; override;
function use_generic_mul32to64: boolean; override; function use_generic_mul32to64: boolean; override;
end; end;
@ -297,67 +298,40 @@ interface
procedure tsparcaddnode.second_cmp64bit; procedure tsparcaddnode.second_cmp64bit;
var var
unsigned : boolean; unsigned : boolean;
hreg1,hreg2: tregister;
procedure firstjmp64bitcmp; procedure emit_compare(list:tasmlist; ls,rs:tnode);
var var
oldnodetype : tnodetype; lreg: tregister64;
begin begin
{ the jump the sequence is a little bit hairy } if (ls.location.loc=LOC_CONSTANT) then
case nodetype of begin
ltn,gtn: lreg.reghi:=NR_G0;
lreg.reglo:=NR_G0;
if lo(ls.location.value64)<>0 then
begin begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel); lreg.reglo:=cg.GetIntRegister(list,OS_INT);
{ cheat a little bit for the negative test } cg.a_load_const_reg(list,OS_INT,lo(ls.location.value64),lreg.reglo);
toggleflag(nf_swapped);
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
toggleflag(nf_swapped);
end; end;
lten,gten: if hi(ls.location.value64)<>0 then
begin begin
oldnodetype:=nodetype; lreg.reghi:=cg.GetIntRegister(list,OS_INT);
if nodetype=lten then cg.a_load_const_reg(list,OS_INT,hi(ls.location.value64),lreg.reghi);
nodetype:=ltn
else
nodetype:=gtn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
{ cheat for the negative test }
if nodetype=ltn then
nodetype:=gtn
else
nodetype:=ltn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
nodetype:=oldnodetype;
end; end;
equaln: end
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel); else
unequaln: lreg:=ls.location.register64;
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
end;
end;
procedure secondjmp64bitcmp; if (rs.location.loc=LOC_CONSTANT) then
begin
begin tcgsparc(cg).handle_reg_const_reg(list,A_SUBcc,lreg.reglo,lo(rs.location.value64),NR_G0);
{ the jump the sequence is a little bit hairy } tcgsparc(cg).handle_reg_const_reg(list,A_SUBXcc,lreg.reghi,hi(rs.location.value64),NR_G0);
case nodetype of end
ltn,gtn,lten,gten: else
begin begin
{ the comparisaion of the low dword have to be } list.concat(taicpu.op_reg_reg_reg(A_SUBcc,lreg.reglo,rs.location.register64.reglo,NR_G0));
{ always unsigned! } list.concat(taicpu.op_reg_reg_reg(A_SUBXcc,lreg.reghi,rs.location.register64.reghi,NR_G0));
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel); end;
cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
end;
equaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
end;
unequaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
end;
end;
end; end;
begin begin
@ -367,21 +341,65 @@ interface
unsigned:=not(is_signed(left.resultdef)) or unsigned:=not(is_signed(left.resultdef)) or
not(is_signed(right.resultdef)); not(is_signed(right.resultdef));
location_reset(location,LOC_JUMP,OS_NO); location_reset(location,LOC_FLAGS,OS_NO);
if (right.location.loc<>LOC_CONSTANT) then if (nodetype in [equaln,unequaln]) then
begin begin
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,left.location.register64.reghi,right.location.register64.reghi)); location.resflags:=getresflags(unsigned);
firstjmp64bitcmp; if (right.location.loc=LOC_CONSTANT) then
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,left.location.register64.reglo,right.location.register64.reglo)); begin
secondjmp64bitcmp; if hi(right.location.value64)<>0 then
begin
hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
tcgsparc(cg).handle_reg_const_reg(current_asmdata.CurrAsmList,A_XOR,left.location.register64.reghi,hi(right.location.value64),hreg1);
end
else
hreg1:=left.location.register64.reghi;
if lo(right.location.value64)<>0 then
begin
hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
tcgsparc(cg).handle_reg_const_reg(current_asmdata.CurrAsmList,A_XOR,left.location.register64.reglo,lo(right.location.value64),hreg2);
end
else
hreg2:=left.location.register64.reglo;
end
else
begin
hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_XOR,left.location.register64.reghi,right.location.register64.reghi,hreg1));
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_XOR,left.location.register64.reglo,right.location.register64.reglo,hreg2));
end;
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ORcc,hreg1,hreg2,NR_G0));
end end
else else
begin begin
tcgsparc(cg).handle_reg_const_reg(current_asmdata.CurrAsmList,A_SUBcc,left.location.register64.reghi,hi(right.location.value64),NR_G0); { undo possible swapped state }
firstjmp64bitcmp; if (nf_swapped in flags) then
tcgsparc(cg).handle_reg_const_reg(current_asmdata.CurrAsmList,A_SUBcc,left.location.register64.reglo,lo(right.location.value64),NR_G0); swapleftright;
secondjmp64bitcmp; { Subtracting sides sets N,V and C flags correctly, but not Z flag
(which ends up depending only on upper dword). So don't use conditions
that test Z flag:
unsigned signed
a < b => F_B F_L
a >= b => F_AE F_GE
a <= b => swap, F_AE F_GE
a > b => swap, F_B F_L }
if (nodetype in [ltn,gten]) then
begin
emit_compare(current_asmdata.CurrAsmList,left,right);
location.resflags:=getresflags(unsigned);
end
else if (nodetype in [lten,gtn]) then
begin
emit_compare(current_asmdata.CurrAsmList,right,left);
toggleflag(nf_swapped);
location.resflags:=getresflags(unsigned);
toggleflag(nf_swapped);
end
else
InternalError(2014011001);
end; end;
end; end;
@ -435,6 +453,18 @@ interface
result:=false; result:=false;
end; end;
function tsparcaddnode.pass_1: tnode;
begin
result:=inherited pass_1;
if not assigned(result) then
begin
if is_64bitint(left.resultdef) and
(nodetype in [equaln,unequaln,ltn,gtn,lten,gten]) then
expectloc:=LOC_FLAGS;
end;
end;
begin begin
caddnode:=tsparcaddnode; caddnode:=tsparcaddnode;
end. end.