mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 13:59:28 +02:00
+ generate better code for division by negative power of 2 constants in the x86
(i386 and x86_64) code generator (same as the division by a positive power of 2, followed by a NEG instruction, to invert the sign of the result; previously the code generator generated an IMUL instruction with a magic constant, followed by shift; the new code sequence should be both shorter and faster) git-svn-id: trunk@37003 -
This commit is contained in:
parent
99ce914a61
commit
6634141bf4
@ -385,7 +385,7 @@ interface
|
||||
opsize:topsize;
|
||||
e, sm: aint;
|
||||
d,m: aword;
|
||||
m_add: boolean;
|
||||
m_add, invertsign: boolean;
|
||||
s: byte;
|
||||
begin
|
||||
secondpass(left);
|
||||
@ -409,36 +409,39 @@ interface
|
||||
|
||||
if (nodetype=divn) and (right.nodetype=ordconstn) then
|
||||
begin
|
||||
if ispowerof2(int64(tordconstnode(right).value),power) then
|
||||
if isabspowerof2(int64(tordconstnode(right).value),power) then
|
||||
begin
|
||||
{ for signed numbers, the numerator must be adjusted before the
|
||||
shift instruction, but not wih unsigned numbers! Otherwise,
|
||||
"Cardinal($ffffffff) div 16" overflows! (JM) }
|
||||
if is_signed(left.resultdef) Then
|
||||
begin
|
||||
invertsign:=tordconstnode(right).value<0;
|
||||
{ use a sequence without jumps, saw this in
|
||||
comp.compilers (JM) }
|
||||
{ no jumps, but more operations }
|
||||
hreg2:=cg.getintregister(current_asmdata.CurrAsmList,cgsize);
|
||||
emit_reg_reg(A_MOV,opsize,hreg1,hreg2);
|
||||
if tordconstnode(right).value=2 then
|
||||
if power=1 then
|
||||
begin
|
||||
{If the left value is negative, hreg2=(right value-1)=1, otherwise 0.}
|
||||
{If the left value is negative, hreg2=(1 shl power)-1=1, otherwise 0.}
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHR,cgsize,resultdef.size*8-1,hreg2);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{If the left value is negative, hreg2=$ffffffff, otherwise 0.}
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SAR,cgsize,resultdef.size*8-1,hreg2);
|
||||
{If negative, hreg2=right value-1, otherwise 0.}
|
||||
{If negative, hreg2=(1 shl power)-1, otherwise 0.}
|
||||
{ (don't use emit_const_reg, because if value>high(longint)
|
||||
then it must first be loaded into a register) }
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,cgsize,tordconstnode(right).value-1,hreg2);
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,cgsize,(aint(1) shl power)-1,hreg2);
|
||||
end;
|
||||
{ add to the left value }
|
||||
emit_reg_reg(A_ADD,opsize,hreg2,hreg1);
|
||||
{ do the shift }
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SAR,cgsize,power,hreg1);
|
||||
if invertsign then
|
||||
emit_reg(A_NEG,opsize,hreg1);
|
||||
end
|
||||
else
|
||||
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHR,cgsize,power,hreg1);
|
||||
|
Loading…
Reference in New Issue
Block a user