* support for range checking when converting from 64bit to something

smaller (32bit, 16bit, 8bit)
  * fixed range checking between longint/cardinal and for array indexing
    with cardinal (values > $7fffffff were considered negative)
This commit is contained in:
Jonas Maebe 2000-11-13 14:47:46 +00:00
parent 4706eff850
commit 75ad22bf64
2 changed files with 137 additions and 10 deletions

View File

@ -56,7 +56,7 @@ implementation
globtype,globals,systems,verbose,
cutils,cobjects,
aasm,cpubase,cpuasm,
symconst,symdef,symsym,symtable,
symconst,symbase,symdef,symsym,symtable,
{$ifdef GDB}
gdb,
{$endif GDB}
@ -917,11 +917,104 @@ implementation
{ produces range check code, while one of the operands is a 64 bit
integer }
procedure emitrangecheck64(p : tnode;todef : pdef);
var
neglabel,
poslabel,
endlabel: pasmlabel;
href : preference;
hreg : tregister;
hdef : porddef;
fromdef : pdef;
oldregisterdef: boolean;
from_signed,to_signed: boolean;
begin
fromdef:=p.resulttype;
if is_64bitint(todef) then
CGMessage(cg_w_64bit_range_check_not_supported)
else
begin
oldregisterdef := registerdef;
registerdef := false;
CGMessage(cg_w_64bit_range_check_not_supported);
{internalerror(28699);}
from_signed := is_signed(fromdef);
to_signed := is_signed(todef);
{ get the high dword in a register }
if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
hreg := p.location.registerhigh
else
begin
hreg := getexplicitregister32(R_EDI);
href := newreference(p.location.reference);
inc(href^.offset,4);
emit_ref_reg(A_MOV,S_L,href,hreg);
end;
getlabel(poslabel);
{ check high dword, must be 0 (for positive numbers) }
emit_reg_reg(A_TEST,S_L,hreg,hreg);
emitjmp(C_E,poslabel);
{ It can also be $ffffffff, but only for negative numbers }
if from_signed and to_signed then
begin
getlabel(neglabel);
emit_const_reg(A_CMP,S_L,$ffffffff,hreg);
emitjmp(C_E,neglabel);
end;
if hreg = R_EDI then
ungetregister32(hreg);
{ For all other values we have a range check error }
emitcall('FPC_RANGEERROR');
{ if the high dword = 0, the low dword can be considered a }
{ simple cardinal }
emitlab(poslabel);
new(hdef,init(u32bit,0,$ffffffff));
{ the real p.resulttype is already saved in fromdef }
p.resulttype := hdef;
emitrangecheck(p,todef);
dispose(hdef,done);
{ restore original resulttype }
p.resulttype := todef;
if from_signed and to_signed then
begin
getlabel(endlabel);
emitjmp(C_NO,endlabel);
{ if the high dword = $ffffffff, then the low dword (when }
{ considered as a longint) must be < 0 (JM) }
emitlab(neglabel);
if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
hreg := p.location.registerlow
else
begin
hreg := getexplicitregister32(R_EDI);
emit_ref_reg(A_MOV,S_L,
newreference(p.location.reference),hreg);
end;
{ get a new neglabel (JM) }
getlabel(neglabel);
emit_reg_reg(A_TEST,S_L,hreg,hreg);
if hreg = R_EDI then
ungetregister32(hreg);
emitjmp(C_L,neglabel);
emitcall('FPC_RANGEERROR');
{ if we get here, the 64bit value lies between }
{ longint($80000000) and -1 (JM) }
emitlab(neglabel);
new(hdef,init(s32bit,$80000000,-1));
p.resulttype := hdef;
emitrangecheck(p,todef);
dispose(hdef,done);
emitlab(endlabel);
{ restore p's resulttype }
p.resulttype := fromdef;
end;
registerdef := oldregisterdef;
end;
end;
{ produces if necessary rangecheckcode }
@ -979,7 +1072,10 @@ implementation
begin
porddef(todef)^.genrangecheck;
rstr:=porddef(todef)^.getrangecheckstring;
doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
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
@ -1042,10 +1138,23 @@ implementation
begin
emitjmp(C_None,poslabel);
emitlab(neglabel);
getexplicitregister32(R_EDI);
exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
emitcall('FPC_BOUNDCHECK');
ungetregister32(R_EDI);
{ 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(new(paicpu,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
@ -1363,7 +1472,13 @@ implementation
end.
{
$Log$
Revision 1.3 2000-11-04 14:25:25 florian
Revision 1.4 2000-11-13 14:47:46 jonas
* support for range checking when converting from 64bit to something
smaller (32bit, 16bit, 8bit)
* fixed range checking between longint/cardinal and for array indexing
with cardinal (values > $7fffffff were considered negative)
Revision 1.3 2000/11/04 14:25:25 florian
+ merged Attila's changes for interfaces, not tested yet
Revision 1.2 2000/10/31 22:02:57 peter

View File

@ -338,6 +338,12 @@ end;
Miscellaneous
*****************************************************************************}
procedure int_rangeerror;[public,alias:'FPC_RANGEERROR'];
begin
HandleErrorFrame(201,get_frame);
end;
procedure int_overflow;[public,alias:'FPC_OVERFLOW'];
begin
HandleErrorFrame(215,get_frame);
@ -639,7 +645,13 @@ end;
{
$Log$
Revision 1.9 2000-11-11 16:12:01 peter
Revision 1.10 2000-11-13 14:47:46 jonas
* support for range checking when converting from 64bit to something
smaller (32bit, 16bit, 8bit)
* fixed range checking between longint/cardinal and for array indexing
with cardinal (values > $7fffffff were considered negative)
Revision 1.9 2000/11/11 16:12:01 peter
* ptr returns farpointer
Revision 1.8 2000/11/06 21:35:59 peter