Browse Source

* simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary

Jonas Maebe 24 years ago
parent
commit
af38291233
4 changed files with 62 additions and 136 deletions
  1. 38 129
      compiler/i386/n386util.pas
  2. 5 1
      compiler/options.pas
  3. 9 1
      rtl/i386/i386.inc
  4. 10 5
      rtl/inc/generic.inc

+ 38 - 129
compiler/i386/n386util.pas

@@ -994,7 +994,7 @@ implementation
              if from_signed and to_signed then
                begin
                  getlabel(endlabel);
-                 emitjmp(C_NO,endlabel);
+                 emitjmp(C_None,endlabel);
                  { if the high dword = $ffffffff, then the low dword (when }
                  { considered as a longint) must be < 0                    }
                  emitlab(neglabel);
@@ -1135,29 +1135,6 @@ implementation
          end;
         { generate the rangecheck code for the def where we are going to
           store the result }
-        doublebound:=false;
-        case todef^.deftype of
-          orddef :
-            begin
-              porddef(todef)^.genrangecheck;
-              rstr:=porddef(todef)^.getrangecheckstring;
-              doublebound:=
-                ((porddef(todef)^.typ=u32bit) and (lto>hto)) or
-                (is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
-                (is_signed(fromdef) and (porddef(todef)^.typ=u32bit));
-            end;
-          enumdef :
-            begin
-              penumdef(todef)^.genrangecheck;
-              rstr:=penumdef(todef)^.getrangecheckstring;
-            end;
-          arraydef :
-            begin
-              parraydef(todef)^.genrangecheck;
-              rstr:=parraydef(todef)^.getrangecheckstring;
-              doublebound:=(lto>hto);
-            end;
-        end;
       { get op and opsize }
         opsize:=def2def_opsize(fromdef,u32bitdef);
         if opsize in [S_B,S_W,S_L] then
@@ -1168,112 +1145,41 @@ implementation
          else
           op:=A_MOVZX;
         is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
-        if is_reg then
-          hreg:=p.location.register;
-        if not target_os.use_bound_instruction then
-         begin
-           { FPC_BOUNDCHECK needs to be called with
-              %ecx - value
-              %edi - pointer to the ranges }
-           popecx:=false;
-           if not(is_reg) or
-              (p.location.register<>R_ECX) then
-            begin
-              if not(R_ECX in unused) then
-               begin
-                 exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
-                 popecx:=true;
-               end
-                 else exprasmList.concat(Tairegalloc.Alloc(R_ECX));
-              if is_reg then
-               emit_reg_reg(op,opsize,p.location.register,R_ECX)
-              else
-               emit_ref_reg(op,opsize,newreference(p.location.reference),R_ECX);
-            end;
-           if doublebound then
-            begin
-              getlabel(neglabel);
-              getlabel(poslabel);
-              emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
-              emitjmp(C_L,neglabel);
-            end;
-           { insert bound instruction only }
-           getexplicitregister32(R_EDI);
-           exprasmList.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI));
-           emitcall('FPC_BOUNDCHECK');
-           ungetregister32(R_EDI);
-           { u32bit needs 2 checks }
-           if doublebound then
-            begin
-              emitjmp(C_None,poslabel);
-              emitlab(neglabel);
-              { if a cardinal is > $7fffffff, this is an illegal longint }
-              { value (and vice versa)! (JM)                             }
-              if ((todef^.deftype = orddef) and
-                  ((is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
-                   (is_signed(fromdef) and (porddef(todef)^.typ=u32bit)))) or
-                 { similar for array indexes (JM) }
-                 ((todef^.deftype = arraydef) and
-                  (((lto < 0) and (porddef(fromdef)^.typ=u32bit)) or
-                   ((lto >= 0) and is_signed(fromdef)))) then
-                emitcall('FPC_RANGEERROR')
-              else
-                begin
-                  getexplicitregister32(R_EDI);
-                  exprasmList.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI));
-                  emitcall('FPC_BOUNDCHECK');
-                  ungetregister32(R_EDI);
-                end;
-              emitlab(poslabel);
-            end;
-           if popecx then
-            exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
-           else exprasmList.concat(Tairegalloc.DeAlloc(R_ECX));
-         end
+        getexplicitregister32(R_EDI);
+
+        { use the trick that                                                 }
+        { a <= x <= b <=> 0 <= x-a <= b-a <=> cardinal(x-a) <= cardinal(b-a) }
+
+        { To be able to do that, we have to make sure however that either    }
+        { fromdef and todef are both signed or unsigned, or that we leave    }
+        { the parts < 0 and > maxlongint out                                 }
+
+        { is_signed now also works for arrays (it checks the rangetype) (JM) }
+        if is_signed(fromdef) xor is_signed(todef) then
+          begin
+            lto := max(lto,0);
+            hto := hto and $7fffffff;
+          end;
+
+        if is_reg and
+           (opsize = S_L) then
+          emit_ref_reg(A_LEA,opsize,new_reference(p.location.register,-lto),
+            R_EDI)
         else
-         begin
-           reset_reference(href);
-           href.symbol:=newasmsymbol(rstr);
-           { load the value in a register }
-           if is_reg then
-            begin
-              { be sure that hreg is a 32 bit reg, if not load it in %edi }
-              if p.location.register in [R_EAX..R_EDI] then
-               hreg:=p.location.register
-              else
-               begin
-                 getexplicitregister32(R_EDI);
-                 emit_reg_reg(op,opsize,p.location.register,R_EDI);
-                 hreg:=R_EDI;
-               end;
-            end
-           else
-            begin
-              getexplicitregister32(R_EDI);
+          begin
+            if is_reg then
+              emit_reg_reg(op,opsize,p.location.register,R_EDI)
+            else
               emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
-              hreg:=R_EDI;
-            end;
-           if doublebound then
-            begin
-              getlabel(neglabel);
-              getlabel(poslabel);
-              emit_reg_reg(A_TEST,S_L,hreg,hreg);
-              emitjmp(C_L,neglabel);
-            end;
-           { insert bound instruction only }
-           exprasmList.concat(Taicpu.Op_reg_ref(A_BOUND,S_L,hreg,newreference(href)));
-           { u32bit needs 2 checks }
-           if doublebound then
-            begin
-              href.offset:=8;
-              emitjmp(C_None,poslabel);
-              emitlab(neglabel);
-              exprasmList.concat(Taicpu.Op_reg_ref(A_BOUND,S_L,hreg,newreference(href)));
-              emitlab(poslabel);
-            end;
-           if hreg = R_EDI then
-             ungetregister32(R_EDI);
-         end;
+            if lto <> 0 then
+              emit_const_reg(A_SUB,S_L,lto,R_EDI);
+          end;
+        emit_const_reg(A_CMP,S_L,hto-lto,R_EDI);
+        ungetregister32(R_EDI);
+        getlabel(neglabel);
+        emitjmp(C_BE,neglabel);
+        emitcall('FPC_RANGEERROR');
+        emitlab(neglabel);
       end;
 
 
@@ -1548,7 +1454,10 @@ implementation
 end.
 {
   $Log$
-  Revision 1.10  2000-12-31 11:02:12  jonas
+  Revision 1.11  2001-03-03 12:41:22  jonas
+    * simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary
+
+  Revision 1.10  2000/12/31 11:02:12  jonas
     * optimized loadshortstring a bit
 
   Revision 1.9  2000/12/25 00:07:33  peter

+ 5 - 1
compiler/options.pas

@@ -1294,6 +1294,7 @@ begin
   def_symbol('INT64FUNCRESOK');
   def_symbol('PACKENUMFIXED');
   def_symbol('HAS_ADDR_STACK_ON_STACK');
+  def_symbol('NOBOPUNDCHECK');
 
 { some stuff for TP compatibility }
 {$ifdef i386}
@@ -1571,7 +1572,10 @@ finalization
 end.
 {
   $Log$
-  Revision 1.32  2001-02-26 19:44:53  peter
+  Revision 1.33  2001-03-03 12:41:22  jonas
+    * simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary
+
+  Revision 1.32  2001/02/26 19:44:53  peter
     * merged generic m68k updates from fixes branch
 
   Revision 1.31  2001/02/26 12:47:46  jonas

+ 9 - 1
rtl/i386/i386.inc

@@ -1088,6 +1088,8 @@ end;
                                Bounds Check
 ****************************************************************************}
 
+{$ifndef NOBOUNDCHECK}
+
 {$define FPC_SYSTEM_HAS_FPC_BOUNDCHECK}
 
 {$ifdef SYSTEMDEBUG}
@@ -1117,6 +1119,9 @@ end;
 {$ifdef SYSTEMDEBUG}
 end;
 {$endif def SYSTEMDEBUG}
+
+{$endif NOBOUNDCHECK}
+
 { do a thread save inc/dec }
 
 procedure declocked(var l : longint);assembler;
@@ -1159,7 +1164,10 @@ procedure inclocked(var l : longint);assembler;
 
 {
   $Log$
-  Revision 1.5  2000-11-12 23:23:34  florian
+  Revision 1.6  2001-03-03 12:41:22  jonas
+    * simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary
+
+  Revision 1.5  2000/11/12 23:23:34  florian
     * interfaces basically running
 
   Revision 1.4  2000/11/07 23:42:21  florian

+ 10 - 5
rtl/inc/generic.inc

@@ -293,11 +293,11 @@ begin
   if (Len<>0) and (@Buf1<>@Buf2) then
    begin
      while (I<Len) And
-           ((Pbyte(@Buf1)[i]<>0) and (PByte(@buf2)[i]<>0)) and 
+           ((Pbyte(@Buf1)[i]<>0) and (PByte(@buf2)[i]<>0)) and
            (pbyte(@Buf1)[I]=pbyte(@Buf2)[I])  do
       inc(I);
-     if (I=Len) or 
-        (PByte(@Buf1)[i]=0) or 
+     if (I=Len) or
+        (PByte(@Buf1)[i]=0) or
         (PByte(@buf2)[I]=0) then  {No difference or 0 reached }
       I:=0
      else
@@ -756,6 +756,7 @@ end;
                                Bounds Check
 ****************************************************************************}
 
+{$ifndef NOBOUNDCHECK}
 {$ifndef FPC_SYSTEM_HAS_FPC_BOUNDCHECK}
 
 procedure int_boundcheck(l : longint; range : pointer);[public,alias: 'FPC_BOUNDCHECK'];
@@ -771,11 +772,15 @@ begin
 end;
 
 {$endif ndef FPC_SYSTEM_HAS_FPC_BOUNDCHECK}
+{$endif NOBOUNDCHECK}
 
 
 {
   $Log$
-  Revision 1.5  2000-10-01 13:17:35  michael
+  Revision 1.6  2001-03-03 12:41:22  jonas
+    * simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary
+
+  Revision 1.5  2000/10/01 13:17:35  michael
   + Merged from fixbranch
 
   Revision 1.4  2000/08/09 11:29:01  jonas
@@ -792,5 +797,5 @@ end;
 
   Revision 1.2  2000/07/13 11:33:43  michael
   + removed logs
- 
+
 }