Просмотр исходного кода

+ 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

Jonas Maebe 26 лет назад
Родитель
Сommit
89405ceeed
1 измененных файлов с 81 добавлено и 27 удалено
  1. 81 27
      compiler/cg386mat.pas

+ 81 - 27
compiler/cg386mat.pas

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