+ positive number MOD power of 2 now done with AND instruction

* fix to division of positive numbers by power of 2
  * the result of a MOD is left in EDX if possible
This commit is contained in:
Jonas Maebe 1999-05-08 20:41:08 +00:00
parent 26fa893ed7
commit 89405ceeed

View File

@ -53,11 +53,14 @@ implementation
procedure secondmoddiv(var p : ptree);
var
hreg1 : tregister;
pushed,popeax,popedx : boolean;
shrdiv, andmod, pushed,popeax,popedx : boolean;
power : longint;
hl : plabel;
begin
shrdiv := false;
andmod := false;
secondpass(p^.left);
set_location(p^.location,p^.left^.location);
pushed:=maybe_push(p^.right^.registers32,p);
@ -87,29 +90,46 @@ implementation
if (p^.treetype=divn) and (p^.right^.treetype=ordconstn) and
ispowerof2(p^.right^.value,power) then
begin
exprasmlist^.concat(new(pai386,op_reg_reg(A_OR,S_L,hreg1,hreg1)));
getlabel(hl);
emitjmp(C_NS,hl);
if power=1 then
exprasmlist^.concat(new(pai386,op_reg(A_INC,S_L,hreg1)))
else
exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,p^.right^.value-1,hreg1)));
emitlab(hl);
exprasmlist^.concat(new(pai386,op_const_reg(A_SAR,S_L,power,hreg1)));
end
Begin
shrdiv := true;
{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(p^.left^.resulttype) Then
Begin
exprasmlist^.concat(new(pai386,op_reg_reg(A_OR,S_L,hreg1,hreg1)));
getlabel(hl);
emitjmp(C_NS,hl);
if power=1 then
exprasmlist^.concat(new(pai386,op_reg(A_INC,S_L,hreg1)))
else
exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,p^.right^.value-1,hreg1)));
emitlab(hl);
exprasmlist^.concat(new(pai386,op_const_reg(A_SAR,S_L,power,hreg1)));
End
Else
exprasmlist^.concat(new(pai386,op_const_reg(A_SHR,S_L,power,hreg1)));
End
else
if (p^.treetype=modn) and (p^.right^.treetype=ordconstn) and
ispowerof2(p^.right^.value,power) and Not(is_signed(p^.left^.resulttype)) Then
{is there a similar trick for MOD'ing signed numbers? (JM)}
Begin
exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,p^.right^.value-1,hreg1)));
andmod := true;
End
else
begin
{ bring denominator to EDI }
{ EDI is always free, it's }
{ only used for temporary }
{ purposes }
if (p^.right^.location.loc<>LOC_REGISTER) and
(p^.right^.location.loc<>LOC_CREGISTER) then
begin
del_reference(p^.right^.location.reference);
p^.left^.location.loc:=LOC_REGISTER;
exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),R_EDI)));
if (p^.right^.location.loc<>LOC_REGISTER) and
(p^.right^.location.loc<>LOC_CREGISTER) then
begin
del_reference(p^.right^.location.reference);
p^.left^.location.loc:=LOC_REGISTER;
exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),R_EDI)));
end
else
begin
@ -120,14 +140,14 @@ implementation
popeax:=false;
if hreg1=R_EDX then
begin
if not(R_EAX in unused) then
if not(R_EAX in unused) then
begin
exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EAX)));
popeax:=true;
end;
emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
end
else
else
begin
if not(R_EDX in unused) then
begin
@ -166,18 +186,47 @@ implementation
end
else
if hreg1<>R_EAX then
emit_reg_reg(A_MOV,S_L,R_EAX,hreg1);
Begin
ungetregister32(hreg1);
hreg1 := getexplicitregister32(R_EAX);
{ I don't think it's possible that now hreg1 <> R_EAX
since popeax is false, but for all certainty I do
support that situation (JM)}
if hreg1 <> R_EAX then
emit_reg_reg(A_MOV,S_L,R_EAX,hreg1);
end;
end
else
emit_reg_reg(A_MOV,S_L,R_EDX,hreg1);
{if we did the mod by an "and", the result is in hreg1 and
EDX certainly hasn't been pushed (JM)}
if not(andmod) Then
if popedx then
{the mod was done by an (i)div (so the result is now in
edx), but edx was occupied prior to the division, so
move the result into a safe place (JM)}
emit_reg_reg(A_MOV,S_L,R_EDX,hreg1)
else
Begin
{Get rid of the unnecessary hreg1 if possible (same as with
EAX in divn) (JM)}
ungetregister32(hreg1);
hreg1 := getexplicitregister32(R_EDX);
if hreg1 <> R_EDX then
emit_reg_reg(A_MOV,S_L,R_EDX,hreg1);;
End;
if popeax then
exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EAX)));
if popedx then
exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDX)));
end;
{ this registers are always used when div/mod are present }
usedinproc:=usedinproc or ($80 shr byte(R_EAX));
usedinproc:=usedinproc or ($80 shr byte(R_EDX));
If not(andmod or shrdiv) then
{andmod and shrdiv only use hreg1 (which is already in usedinproc,
since it was acquired with getregister), the others also use both
EAX and EDX (JM)}
Begin
usedinproc:=usedinproc or ($80 shr byte(R_EAX));
usedinproc:=usedinproc or ($80 shr byte(R_EDX));
End;
clear_location(p^.location);
p^.location.loc:=LOC_REGISTER;
p^.location.register:=hreg1;
@ -768,7 +817,12 @@ implementation
end.
{
$Log$
Revision 1.22 1999-05-01 13:24:11 peter
Revision 1.23 1999-05-08 20:41:08 jonas
+ positive number MOD power of 2 now done with AND instruction
* fix to division of positive numbers by power of 2
* the result of a MOD is left in EDX if possible
Revision 1.22 1999/05/01 13:24:11 peter
* merged nasm compiler
* old asm moved to oldasm/