|
@@ -496,6 +496,8 @@ unit hlcgobj;
|
|
|
the assembler/object file }
|
|
|
procedure record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList); virtual;
|
|
|
|
|
|
+ { generate a call to a routine in the system unit }
|
|
|
+ procedure g_call_system_proc(list: TAsmList; const procname: string);
|
|
|
end;
|
|
|
|
|
|
var
|
|
@@ -510,7 +512,7 @@ implementation
|
|
|
globals,options,systems,
|
|
|
fmodule,export,
|
|
|
verbose,defutil,paramgr,
|
|
|
- symbase,symsym,
|
|
|
+ symbase,symsym,symtable,
|
|
|
ncon,nld,pass_1,pass_2,
|
|
|
cpuinfo,cgobj,tgobj,cutils,procinfo,
|
|
|
ncgutil,ngenutil;
|
|
@@ -1662,10 +1664,195 @@ implementation
|
|
|
end;
|
|
|
|
|
|
procedure thlcgobj.g_rangecheck(list: TAsmList; const l: tlocation; fromdef, todef: tdef);
|
|
|
- begin
|
|
|
- if not(cs_check_range in current_settings.localswitches) then
|
|
|
+ var
|
|
|
+ aintmax: aint;
|
|
|
+ neglabel : tasmlabel;
|
|
|
+ hreg : tregister;
|
|
|
+ lto,hto,
|
|
|
+ lfrom,hfrom : TConstExprInt;
|
|
|
+ fromsize, tosize: cardinal;
|
|
|
+ maxdef: tdef;
|
|
|
+ from_signed, to_signed: boolean;
|
|
|
+ begin
|
|
|
+ { range checking on and range checkable value? }
|
|
|
+ if not(cs_check_range in current_settings.localswitches) or
|
|
|
+ not(fromdef.typ in [orddef,enumdef]) or
|
|
|
+ { C-style booleans can't really fail range checks, }
|
|
|
+ { all values are always valid }
|
|
|
+ is_cbool(todef) then
|
|
|
exit;
|
|
|
- internalerror(2011010610);
|
|
|
+ { only check when assigning to scalar, subranges are different, }
|
|
|
+ { when todef=fromdef then the check is always generated }
|
|
|
+ getrange(fromdef,lfrom,hfrom);
|
|
|
+ getrange(todef,lto,hto);
|
|
|
+ from_signed := is_signed(fromdef);
|
|
|
+ to_signed := is_signed(todef);
|
|
|
+ { check the rangedef of the array, not the array itself }
|
|
|
+ { (only change now, since getrange needs the arraydef) }
|
|
|
+ if (todef.typ = arraydef) then
|
|
|
+ todef := tarraydef(todef).rangedef;
|
|
|
+ { no range check if from and to are equal and are both longint/dword }
|
|
|
+ { (if we have a 32bit processor) or int64/qword, since such }
|
|
|
+ { operations can at most cause overflows (JM) }
|
|
|
+ { Note that these checks are mostly processor independent, they only }
|
|
|
+ { have to be changed once we introduce 64bit subrange types }
|
|
|
+ if (fromdef = todef) and
|
|
|
+ (fromdef.typ=orddef) and
|
|
|
+ (((((torddef(fromdef).ordtype = s64bit) and
|
|
|
+ (lfrom = low(int64)) and
|
|
|
+ (hfrom = high(int64))) or
|
|
|
+ ((torddef(fromdef).ordtype = u64bit) and
|
|
|
+ (lfrom = low(qword)) and
|
|
|
+ (hfrom = high(qword))) or
|
|
|
+ ((torddef(fromdef).ordtype = scurrency) and
|
|
|
+ (lfrom = low(int64)) and
|
|
|
+ (hfrom = high(int64)))))) then
|
|
|
+ exit;
|
|
|
+ { 32 bit operations are automatically widened to 64 bit on 64 bit addr
|
|
|
+ targets }
|
|
|
+{$ifdef cpu32bitaddr}
|
|
|
+ if (fromdef = todef) and
|
|
|
+ (fromdef.typ=orddef) and
|
|
|
+ (((((torddef(fromdef).ordtype = s32bit) and
|
|
|
+ (lfrom = int64(low(longint))) and
|
|
|
+ (hfrom = int64(high(longint)))) or
|
|
|
+ ((torddef(fromdef).ordtype = u32bit) and
|
|
|
+ (lfrom = low(cardinal)) and
|
|
|
+ (hfrom = high(cardinal)))))) then
|
|
|
+ exit;
|
|
|
+{$endif cpu32bitaddr}
|
|
|
+
|
|
|
+ { optimize some range checks away in safe cases }
|
|
|
+ fromsize := fromdef.size;
|
|
|
+ tosize := todef.size;
|
|
|
+ if ((from_signed = to_signed) or
|
|
|
+ (not from_signed)) and
|
|
|
+ (lto<=lfrom) and (hto>=hfrom) and
|
|
|
+ (fromsize <= tosize) then
|
|
|
+ begin
|
|
|
+ { if fromsize < tosize, and both have the same signed-ness or }
|
|
|
+ { fromdef is unsigned, then all bit patterns from fromdef are }
|
|
|
+ { valid for todef as well }
|
|
|
+ if (fromsize < tosize) then
|
|
|
+ exit;
|
|
|
+ if (fromsize = tosize) and
|
|
|
+ (from_signed = to_signed) then
|
|
|
+ { only optimize away if all bit patterns which fit in fromsize }
|
|
|
+ { are valid for the todef }
|
|
|
+ begin
|
|
|
+{$ifopt Q+}
|
|
|
+{$define overflowon}
|
|
|
+{$Q-}
|
|
|
+{$endif}
|
|
|
+{$ifopt R+}
|
|
|
+{$define rangeon}
|
|
|
+{$R-}
|
|
|
+{$endif}
|
|
|
+ if to_signed then
|
|
|
+ begin
|
|
|
+ { calculation of the low/high ranges must not overflow 64 bit
|
|
|
+ otherwise we end up comparing with zero for 64 bit data types on
|
|
|
+ 64 bit processors }
|
|
|
+ if (lto = (int64(-1) << (tosize * 8 - 1))) and
|
|
|
+ (hto = (-((int64(-1) << (tosize * 8 - 1))+1))) then
|
|
|
+ exit
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { calculation of the low/high ranges must not overflow 64 bit
|
|
|
+ otherwise we end up having all zeros for 64 bit data types on
|
|
|
+ 64 bit processors }
|
|
|
+ if (lto = 0) and
|
|
|
+ (qword(hto) = (qword(-1) >> (64-(tosize * 8))) ) then
|
|
|
+ exit
|
|
|
+ end;
|
|
|
+{$ifdef overflowon}
|
|
|
+{$Q+}
|
|
|
+{$undef overflowon}
|
|
|
+{$endif}
|
|
|
+{$ifdef rangeon}
|
|
|
+{$R+}
|
|
|
+{$undef rangeon}
|
|
|
+{$endif}
|
|
|
+ end
|
|
|
+ end;
|
|
|
+
|
|
|
+ { depending on the types involved, we perform the range check for 64 or
|
|
|
+ for 32 bit }
|
|
|
+ if fromsize=8 then
|
|
|
+ maxdef:=fromdef
|
|
|
+ else
|
|
|
+ maxdef:=todef;
|
|
|
+{$if sizeof(aintmax) = 8}
|
|
|
+ if maxdef.size=8 then
|
|
|
+ aintmax:=high(int64)
|
|
|
+ else
|
|
|
+{$endif}
|
|
|
+ begin
|
|
|
+ aintmax:=high(longint);
|
|
|
+ maxdef:=u32inttype;
|
|
|
+ end;
|
|
|
+
|
|
|
+ { generate the rangecheck code for the def where we are going to }
|
|
|
+ { store the result }
|
|
|
+
|
|
|
+ { use the trick that }
|
|
|
+ { a <= x <= b <=> 0 <= x-a <= b-a <=> unsigned(x-a) <= unsigned(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 }
|
|
|
+
|
|
|
+ if from_signed xor to_signed then
|
|
|
+ begin
|
|
|
+ if from_signed then
|
|
|
+ { from is signed, to is unsigned }
|
|
|
+ begin
|
|
|
+ { if high(from) < 0 -> always range error }
|
|
|
+ if (hfrom < 0) or
|
|
|
+ { if low(to) > maxlongint also range error }
|
|
|
+ (lto > aintmax) then
|
|
|
+ begin
|
|
|
+ g_call_system_proc(list,'fpc_rangeerror');
|
|
|
+ exit
|
|
|
+ end;
|
|
|
+ { from is signed and to is unsigned -> when looking at to }
|
|
|
+ { as an signed value, it must be < maxaint (otherwise }
|
|
|
+ { it will become negative, which is invalid since "to" is unsigned) }
|
|
|
+ if hto > aintmax then
|
|
|
+ hto := aintmax;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ { from is unsigned, to is signed }
|
|
|
+ begin
|
|
|
+ if (lfrom > aintmax) or
|
|
|
+ (hto < 0) then
|
|
|
+ begin
|
|
|
+ g_call_system_proc(list,'fpc_rangeerror');
|
|
|
+ exit
|
|
|
+ end;
|
|
|
+ { from is unsigned and to is signed -> when looking at to }
|
|
|
+ { as an unsigned value, it must be >= 0 (since negative }
|
|
|
+ { values are the same as values > maxlongint) }
|
|
|
+ if lto < 0 then
|
|
|
+ lto := 0;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ hreg:=getintregister(list,maxdef);
|
|
|
+ a_load_loc_reg(list,fromdef,maxdef,l,hreg);
|
|
|
+ a_op_const_reg(list,OP_SUB,maxdef,tcgint(int64(lto)),hreg);
|
|
|
+ current_asmdata.getjumplabel(neglabel);
|
|
|
+ {
|
|
|
+ if from_signed then
|
|
|
+ a_cmp_const_reg_label(list,OS_INT,OC_GTE,aint(hto-lto),hreg,neglabel)
|
|
|
+ else
|
|
|
+ }
|
|
|
+ if qword(hto-lto)>qword(aintmax) then
|
|
|
+ a_cmp_const_reg_label(list,maxdef,OC_BE,aintmax,hreg,neglabel)
|
|
|
+ else
|
|
|
+ a_cmp_const_reg_label(list,maxdef,OC_BE,tcgint(int64(hto-lto)),hreg,neglabel);
|
|
|
+ g_call_system_proc(list,'fpc_rangeerror');
|
|
|
+ a_label(list,neglabel);
|
|
|
end;
|
|
|
|
|
|
procedure thlcgobj.g_profilecode(list: TAsmList);
|
|
@@ -2723,4 +2910,19 @@ implementation
|
|
|
current_asmdata.asmlists[al_procedures].concatlist(data);
|
|
|
end;
|
|
|
|
|
|
+ procedure thlcgobj.g_call_system_proc(list: TAsmList; const procname: string);
|
|
|
+ var
|
|
|
+ srsym: tsym;
|
|
|
+ pd: tprocdef;
|
|
|
+ begin
|
|
|
+ srsym:=tsym(systemunit.find(procname));
|
|
|
+ if not assigned(srsym) or
|
|
|
+ (srsym.typ<>procsym) then
|
|
|
+ Message1(cg_f_unknown_compilerproc,procname);
|
|
|
+ pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
|
|
|
+ a_call_name(list,pd,pd.mangledname,false);
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
end.
|