123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- {
- $Id$
- Copyright (c) 1998-2000 by Florian Klaempfl
- Generate i386 assembler for type converting nodes
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit n386cnv;
- {$i defines.inc}
- interface
- uses
- node,ncnv,ncgcnv,types;
- type
- ti386typeconvnode = class(tcgtypeconvnode)
- protected
- procedure second_int_to_int;override;
- { procedure second_string_to_string;override; }
- { procedure second_cstring_to_pchar;override; }
- { procedure second_string_to_chararray;override; }
- { procedure second_array_to_pointer;override; }
- { procedure second_pointer_to_array;override; }
- { procedure second_chararray_to_string;override; }
- { procedure second_char_to_string;override; }
- procedure second_int_to_real;override;
- { procedure second_real_to_real;override; }
- { procedure second_cord_to_pointer;override; }
- { procedure second_proc_to_procvar;override; }
- { procedure second_bool_to_int;override; }
- procedure second_int_to_bool;override;
- { procedure second_load_smallset;override; }
- { procedure second_ansistring_to_pchar;override; }
- { procedure second_pchar_to_string;override; }
- { procedure second_class_to_intf;override; }
- { procedure second_char_to_char;override; }
- procedure pass_2;override;
- procedure second_call_helper(c : tconverttype);
- end;
- implementation
- uses
- verbose,systems,
- symconst,symdef,aasm,
- cgbase,temp_gen,pass_2,
- ncon,ncal,
- cpubase,
- cgobj,cga,tgcpu,n386util;
- {*****************************************************************************
- SecondTypeConv
- *****************************************************************************}
- procedure ti386typeconvnode.second_int_to_int;
- var
- op : tasmop;
- opsize : topsize;
- hregister,
- hregister2 : tregister;
- begin
- { insert range check if not explicit conversion }
- if not(nf_explizit in flags) then
- cg.g_rangecheck(exprasmlist,left,resulttype.def);
- { is the result size smaller ? }
- if resulttype.def.size<left.resulttype.def.size then
- begin
- { only need to set the new size of a register }
- if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
- begin
- case resulttype.def.size of
- 1 : location.register:=makereg8(left.location.register);
- 2 : location.register:=makereg16(left.location.register);
- 4 : location.register:=makereg32(left.location.register);
- end;
- { we can release the upper register }
- if is_64bitint(left.resulttype.def) then
- ungetregister32(left.location.registerhigh);
- end;
- end
- { is the result size bigger ? }
- else if resulttype.def.size>left.resulttype.def.size then
- begin
- { remove reference }
- if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
- begin
- del_reference(left.location.reference);
- { we can do this here as we need no temp inside }
- ungetiftemp(left.location.reference);
- end;
- { get op and opsize, handle separate for constants, because
- movz doesn't support constant values }
- if (left.location.loc=LOC_MEM) and (left.location.reference.is_immediate) then
- begin
- if is_64bitint(resulttype.def) then
- opsize:=S_L
- else
- opsize:=def_opsize(resulttype.def);
- op:=A_MOV;
- end
- else
- begin
- opsize:=def2def_opsize(left.resulttype.def,resulttype.def);
- if opsize in [S_B,S_W,S_L] then
- op:=A_MOV
- else
- if is_signed(left.resulttype.def) then
- op:=A_MOVSX
- else
- op:=A_MOVZX;
- end;
- { load the register we need }
- if left.location.loc<>LOC_REGISTER then
- hregister:=getregisterint
- else
- hregister:=left.location.register;
- { set the correct register size and location }
- clear_location(location);
- location.loc:=LOC_REGISTER;
- { do we need a second register for a 64 bit type ? }
- if is_64bitint(resulttype.def) then
- begin
- hregister2:=getregisterint;
- location.registerhigh:=hregister2;
- end;
- case resulttype.def.size of
- 1:
- location.register:=makereg8(hregister);
- 2:
- location.register:=makereg16(hregister);
- 4,8:
- location.register:=makereg32(hregister);
- end;
- { insert the assembler code }
- if left.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
- emit_reg_reg(op,opsize,left.location.register,location.register)
- else
- emit_ref_reg(op,opsize,
- newreference(left.location.reference),location.register);
- { do we need a sign extension for int64? }
- if is_64bitint(resulttype.def) then
- { special case for constants (JM) }
- if is_constintnode(left) then
- begin
- if tordconstnode(left).value >= 0 then
- emit_reg_reg(A_XOR,S_L,
- hregister2,hregister2)
- else
- emit_const_reg(A_MOV,S_L,longint($ffffffff),hregister2);
- end
- else
- begin
- if (torddef(resulttype.def).typ=s64bit) and
- is_signed(left.resulttype.def) then
- begin
- emit_reg_reg(A_MOV,S_L,location.register,hregister2);
- emit_const_reg(A_SAR,S_L,31,hregister2);
- end
- else
- emit_reg_reg(A_XOR,S_L,hregister2,hregister2);
- end;
- end;
- end;
- procedure ti386typeconvnode.second_int_to_real;
- var
- r : preference;
- hregister : tregister;
- l1,l2 : tasmlabel;
- begin
- { for u32bit a solution is to push $0 and to load a comp }
- { does this first, it destroys maybe EDI }
- hregister:=R_EDI;
- if torddef(left.resulttype.def).typ=u32bit then
- push_int(0);
- if (left.location.loc=LOC_REGISTER) or
- (left.location.loc=LOC_CREGISTER) then
- begin
- if not (torddef(left.resulttype.def).typ in [u32bit,s32bit,u64bit,s64bit]) then
- getexplicitregister32(R_EDI);
- case torddef(left.resulttype.def).typ of
- s8bit : emit_reg_reg(A_MOVSX,S_BL,left.location.register,R_EDI);
- u8bit : emit_reg_reg(A_MOVZX,S_BL,left.location.register,R_EDI);
- s16bit : emit_reg_reg(A_MOVSX,S_WL,left.location.register,R_EDI);
- u16bit : emit_reg_reg(A_MOVZX,S_WL,left.location.register,R_EDI);
- u32bit,s32bit:
- hregister:=left.location.register;
- u64bit,s64bit:
- begin
- emit_reg(A_PUSH,S_L,left.location.registerhigh);
- hregister:=left.location.registerlow;
- end;
- end;
- ungetregister(left.location.register);
- end
- else
- begin
- r:=newreference(left.location.reference);
- getexplicitregister32(R_EDI);
- case torddef(left.resulttype.def).typ of
- s8bit:
- emit_ref_reg(A_MOVSX,S_BL,r,R_EDI);
- u8bit:
- emit_ref_reg(A_MOVZX,S_BL,r,R_EDI);
- s16bit:
- emit_ref_reg(A_MOVSX,S_WL,r,R_EDI);
- u16bit:
- emit_ref_reg(A_MOVZX,S_WL,r,R_EDI);
- u32bit,s32bit:
- emit_ref_reg(A_MOV,S_L,r,R_EDI);
- u64bit,s64bit:
- begin
- inc(r^.offset,4);
- emit_ref_reg(A_MOV,S_L,r,R_EDI);
- emit_reg(A_PUSH,S_L,R_EDI);
- r:=newreference(left.location.reference);
- emit_ref_reg(A_MOV,S_L,r,R_EDI);
- end;
- end;
- del_reference(left.location.reference);
- ungetiftemp(left.location.reference);
- end;
- { for 64 bit integers, the high dword is already pushed }
- emit_reg(A_PUSH,S_L,hregister);
- if hregister = R_EDI then
- ungetregister32(R_EDI);
- r:=new_reference(R_ESP,0);
- case torddef(left.resulttype.def).typ of
- u32bit:
- begin
- emit_ref(A_FILD,S_IQ,r);
- emit_const_reg(A_ADD,S_L,8,R_ESP);
- end;
- s64bit:
- begin
- emit_ref(A_FILD,S_IQ,r);
- emit_const_reg(A_ADD,S_L,8,R_ESP);
- end;
- u64bit:
- begin
- { unsigned 64 bit ints are harder to handle: }
- { we load bits 0..62 and then check bit 63: }
- { if it is 1 then we add $80000000 000000000 }
- { as double }
- inc(r^.offset,4);
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_MOV,S_L,r,R_EDI);
- r:=new_reference(R_ESP,4);
- emit_const_ref(A_AND,S_L,$7fffffff,r);
- emit_const_reg(A_TEST,S_L,longint($80000000),R_EDI);
- ungetregister32(R_EDI);
- r:=new_reference(R_ESP,0);
- emit_ref(A_FILD,S_IQ,r);
- getdatalabel(l1);
- getlabel(l2);
- emitjmp(C_Z,l2);
- Consts.concat(Tai_label.Create(l1));
- { I got this constant from a test progtram (FK) }
- Consts.concat(Tai_const.Create_32bit(0));
- Consts.concat(Tai_const.Create_32bit(1138753536));
- r:=new_reference(R_NO,0);
- r^.symbol:=l1;
- emit_ref(A_FADD,S_FL,r);
- emitlab(l2);
- emit_const_reg(A_ADD,S_L,8,R_ESP);
- end
- else
- begin
- emit_ref(A_FILD,S_IL,r);
- getexplicitregister32(R_EDI);
- emit_reg(A_POP,S_L,R_EDI);
- ungetregister32(R_EDI);
- end;
- end;
- inc(fpuvaroffset);
- clear_location(location);
- location.loc:=LOC_FPU;
- end;
- procedure ti386typeconvnode.second_int_to_bool;
- var
- hregister : tregister;
- resflags : tresflags;
- opsize : topsize;
- pref : preference;
- begin
- clear_location(location);
- { byte(boolean) or word(wordbool) or longint(longbool) must }
- { be accepted for var parameters }
- if (nf_explizit in flags) and
- (left.resulttype.def.size=resulttype.def.size) and
- (left.location.loc in [LOC_REFERENCE,LOC_MEM,LOC_CREGISTER]) then
- begin
- set_location(location,left.location);
- exit;
- end;
- location.loc:=LOC_REGISTER;
- del_location(left.location);
- opsize:=def_opsize(left.resulttype.def);
- case left.location.loc of
- LOC_MEM,LOC_REFERENCE :
- begin
- if is_64bitint(left.resulttype.def) then
- begin
- hregister:=getregisterint;
- emit_ref_reg(A_MOV,opsize,
- newreference(left.location.reference),hregister);
- pref:=newreference(left.location.reference);
- inc(pref^.offset,4);
- emit_reg_ref(A_OR,opsize,
- hregister,pref);
- end
- else
- begin
- hregister:=def_getreg(left.resulttype.def);
- emit_ref_reg(A_MOV,opsize,
- newreference(left.location.reference),hregister);
- emit_reg_reg(A_OR,opsize,hregister,hregister);
- end;
- resflags:=F_NE;
- end;
- LOC_FLAGS :
- begin
- hregister:=getregisterint;
- resflags:=left.location.resflags;
- end;
- LOC_REGISTER,LOC_CREGISTER :
- begin
- hregister:=left.location.register;
- emit_reg_reg(A_OR,opsize,hregister,hregister);
- resflags:=F_NE;
- end;
- else
- internalerror(10062);
- end;
- case resulttype.def.size of
- 1 : location.register:=makereg8(hregister);
- 2 : location.register:=makereg16(hregister);
- 4 : location.register:=makereg32(hregister);
- else
- internalerror(10064);
- end;
- emit_flag2reg(resflags,location.register);
- end;
- {****************************************************************************
- TI386TYPECONVNODE
- ****************************************************************************}
- procedure ti386typeconvnode.second_call_helper(c : tconverttype);
- const
- secondconvert : array[tconverttype] of pointer = (
- @second_nothing, {equal}
- @second_nothing, {not_possible}
- @second_nothing, {second_string_to_string, handled in resulttype pass }
- @second_char_to_string,
- @second_nothing, {char_to_charray}
- @second_nothing, { pchar_to_string, handled in resulttype pass }
- @second_nothing, {cchar_to_pchar}
- @second_cstring_to_pchar,
- @second_ansistring_to_pchar,
- @second_string_to_chararray,
- @second_nothing, { chararray_to_string, handled in resulttype pass }
- @second_array_to_pointer,
- @second_pointer_to_array,
- @second_int_to_int,
- @second_int_to_bool,
- @second_bool_to_int, { bool_to_bool }
- @second_bool_to_int,
- @second_real_to_real,
- @second_int_to_real,
- @second_proc_to_procvar,
- @second_nothing, { arrayconstructor_to_set }
- @second_nothing, { second_load_smallset, handled in first pass }
- @second_cord_to_pointer,
- @second_nothing, { interface 2 string }
- @second_nothing, { interface 2 guid }
- @second_class_to_intf,
- @second_char_to_char,
- @second_nothing, { normal_2_smallset }
- @second_nothing { dynarray_2_openarray }
- );
- type
- tprocedureofobject = procedure of object;
- var
- r : packed record
- proc : pointer;
- obj : pointer;
- end;
- begin
- { this is a little bit dirty but it works }
- { and should be quite portable too }
- r.proc:=secondconvert[c];
- r.obj:=self;
- tprocedureofobject(r){$ifdef FPC}();{$endif FPC}
- end;
- procedure ti386typeconvnode.pass_2;
- {$ifdef TESTOBJEXT2}
- var
- r : preference;
- nillabel : plabel;
- {$endif TESTOBJEXT2}
- begin
- { this isn't good coding, I think tc_bool_2_int, shouldn't be }
- { type conversion (FK) }
- if not(convtype in [tc_bool_2_int,tc_bool_2_bool]) then
- begin
- secondpass(left);
- set_location(location,left.location);
- if codegenerror then
- exit;
- end;
- second_call_helper(convtype);
- {$ifdef TESTOBJEXT2}
- { Check explicit conversions to objects pointers !! }
- if p^.explizit and
- (p^.resulttype.def.deftype=pointerdef) and
- (tpointerdef(p^.resulttype.def).definition.deftype=objectdef) and not
- (tobjectdef(tpointerdef(p^.resulttype.def).definition).isclass) and
- ((tobjectdef(tpointerdef(p^.resulttype.def).definition).options and oo_hasvmt)<>0) and
- (cs_check_range in aktlocalswitches) then
- begin
- new(r);
- reset_reference(r^);
- if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
- r^.base:=p^.location.register
- else
- begin
- getexplicitregister32(R_EDI);
- emit_mov_loc_reg(p^.location,R_EDI);
- r^.base:=R_EDI;
- end;
- { NIL must be accepted !! }
- emit_reg_reg(A_OR,S_L,r^.base,r^.base);
- ungetregister32(R_EDI);
- getlabel(nillabel);
- emitjmp(C_E,nillabel);
- { this is one point where we need vmt_offset (PM) }
- r^.offset:= tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_offset;
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_MOV,S_L,r,R_EDI);
- emit_sym(A_PUSH,S_L,
- newasmsymbol(tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_mangledname));
- emit_reg(A_PUSH,S_L,R_EDI);
- ungetregister32(R_EDI);
- emitcall('FPC_CHECK_OBJECT_EXT');
- emitlab(nillabel);
- end;
- {$endif TESTOBJEXT2}
- end;
- begin
- ctypeconvnode:=ti386typeconvnode;
- end.
- {
- $Log$
- Revision 1.29 2001-12-30 17:24:46 jonas
- * range checking is now processor independent (part in cgobj, part in
cg64f32) and should work correctly again (it needed some changes after
the changes of the low and high of tordef's to int64)
* maketojumpbool() is now processor independent (in ncgutil)
* getregister32 is now called getregisterint
- Revision 1.28 2001/12/11 08:14:17 jonas
- * part of my fix for dynarray -> open array conversion, forgot to
- commit yesterday :(
- Revision 1.27 2001/11/02 23:24:12 jonas
- * fixed web bug 1665 (allow char to chararray type conversion) ("merged")
- Revision 1.26 2001/09/30 21:28:34 peter
- * int64->boolean fixed
- Revision 1.25 2001/09/30 16:12:47 jonas
- - removed unnecessary i386 pass_2 of as- and isnode and added dummy generic ones
- Revision 1.24 2001/09/29 21:32:47 jonas
- * almost all second pass typeconvnode helpers are now processor independent
- * fixed converting boolean to int64/qword
- * fixed register allocation bugs which could cause internalerror 10
- * isnode and asnode are completely processor indepent now as well
- * fpc_do_as now returns its class argument (necessary to be able to use it
- properly with compilerproc)
- Revision 1.23 2001/09/03 13:27:42 jonas
- * compilerproc implementation of set addition/substraction/...
- * changed the declaration of some set helpers somewhat to accomodate the
- above change
- * i386 still uses the old code for comparisons of sets, because its
- helpers return the results in the flags
- * dummy tc_normal_2_small_set type conversion because I need the original
- resulttype of the set add nodes
- NOTE: you have to start a cycle with 1.0.5!
- Revision 1.22 2001/08/29 19:49:03 jonas
- * some fixes in compilerprocs for chararray to string conversions
- * conversion from string to chararray is now also done via compilerprocs
- Revision 1.21 2001/08/28 13:24:47 jonas
- + compilerproc implementation of most string-related type conversions
- - removed all code from the compiler which has been replaced by
- compilerproc implementations (using {$ifdef hascompilerproc} is not
- necessary in the compiler)
- Revision 1.20 2001/08/26 13:36:57 florian
- * some cg reorganisation
- * some PPC updates
- Revision 1.19 2001/08/01 21:44:59 peter
- * fixed empty pwidechar register allocation
- Revision 1.18 2001/07/30 20:59:29 peter
- * m68k updates from v10 merged
- Revision 1.17 2001/07/16 13:19:08 jonas
- * fixed allocation of register before release in second_cstring_to_pchar
- Revision 1.16 2001/07/08 21:00:17 peter
- * various widestring updates, it works now mostly without charset
- mapping supported
- Revision 1.15 2001/05/08 21:06:33 florian
- * some more support for widechars commited especially
- regarding type casting and constants
- Revision 1.14 2001/04/13 01:22:18 peter
- * symtable change to classes
- * range check generation and errors fixed, make cycle DEBUG=1 works
- * memory leaks fixed
- Revision 1.13 2001/04/02 21:20:36 peter
- * resulttype rewrite
- Revision 1.12 2001/01/08 21:45:11 peter
- * internalerror for string to chararray
- Revision 1.11 2000/12/25 00:07:32 peter
- + new tlinkedlist class (merge of old tstringqueue,tcontainer and
- tlinkedlist objects)
- Revision 1.10 2000/12/07 17:19:46 jonas
- * new constant handling: from now on, hex constants >$7fffffff are
- parsed as unsigned constants (otherwise, $80000000 got sign extended
- and became $ffffffff80000000), all constants in the longint range
- become longints, all constants >$7fffffff and <=cardinal($ffffffff)
- are cardinals and the rest are int64's.
- * added lots of longint typecast to prevent range check errors in the
- compiler and rtl
- * type casts of symbolic ordinal constants are now preserved
- * fixed bug where the original resulttype.def wasn't restored correctly
- after doing a 64bit rangecheck
- Revision 1.9 2000/12/05 11:44:33 jonas
- + new integer regvar handling, should be much more efficient
- Revision 1.8 2000/11/29 00:30:46 florian
- * unused units removed from uses clause
- * some changes for widestrings
- Revision 1.7 2000/11/16 15:27:48 jonas
- * fixed web bug 1242
- Revision 1.6 2000/11/13 11:30:56 florian
- * some bugs with interfaces and NIL fixed
- Revision 1.5 2000/11/12 23:24:14 florian
- * interfaces are basically running
- Revision 1.4 2000/11/11 16:00:10 jonas
- * optimize converting of 8/16/32 bit constants to 64bit ones
- Revision 1.3 2000/11/04 14:25:23 florian
- + merged Attila's changes for interfaces, not tested yet
- Revision 1.2 2000/10/31 22:02:56 peter
- * symtable splitted, no real code changes
- Revision 1.1 2000/10/15 09:33:31 peter
- * moved n386*.pas to i386/ cpu_target dir
- Revision 1.1 2000/10/14 10:14:48 peter
- * moehrendorf oct 2000 rewrite
- }
|