| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004 | {    Copyright (c) 1998-2002 by Florian Klaempfl    Helper routines for all code generators    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 ncgutil;{$i fpcdefs.inc}interface    uses      node,cpuinfo,      globtype,      cpubase,cgbase,parabase,cgutils,      aasmbase,aasmtai,aasmdata,aasmcpu,      symconst,symbase,symdef,symsym,symtype,symtable{$ifndef cpu64bitalu}      ,cg64f32{$endif not cpu64bitalu}      ;    type      tloadregvars = (lr_dont_load_regvars, lr_load_regvars);      pusedregvars = ^tusedregvars;      tusedregvars = record        intregvars, fpuregvars, mmregvars: Tsuperregisterworklist;      end;{      Not used currently, implemented because I thought we had to      synchronise around if/then/else as well, but not needed. May      still be useful for SSA once we get around to implementing      that (JM)      pusedregvarscommon = ^tusedregvarscommon;      tusedregvarscommon = record        allregvars, commonregvars, myregvars: tusedregvars;      end;}    procedure firstcomplex(p : tbinarynode);    procedure maketojumpbool(list:TAsmList; p : tnode; loadregvars: tloadregvars);//    procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset);    procedure location_force_mmreg(list:TAsmList;var l: tlocation;maybeconst:boolean);    procedure location_allocate_register(list:TAsmList;out l: tlocation;def: tdef;constant: boolean);    { loads a cgpara into a tlocation; assumes that loc.loc is already      initialised }    procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);    { allocate registers for a tlocation; assumes that loc.loc is already      set to LOC_CREGISTER/LOC_CFPUREGISTER/... }    procedure gen_alloc_regloc(list:TAsmList;var loc: tlocation);    procedure register_maybe_adjust_setbase(list: TAsmList; var l: tlocation; setbase: aint);    function  has_alias_name(pd:tprocdef;const s:string):boolean;    procedure alloc_proc_symbol(pd: tprocdef);    procedure gen_proc_entry_code(list:TAsmList);    procedure gen_proc_exit_code(list:TAsmList);    procedure gen_stack_check_size_para(list:TAsmList);    procedure gen_stack_check_call(list:TAsmList);    procedure gen_save_used_regs(list:TAsmList);    procedure gen_restore_used_regs(list:TAsmList);    procedure gen_load_para_value(list:TAsmList);    procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);    procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);    procedure get_used_regvars(n: tnode; var rv: tusedregvars);    { adds the regvars used in n and its children to rv.allregvars,      those which were already in rv.allregvars to rv.commonregvars and      uses rv.myregvars as scratch (so that two uses of the same regvar      in a single tree to make it appear in commonregvars). Useful to      find out which regvars are used in two different node trees      e.g. in the "else" and "then" path, or in various case blocks }//    procedure get_used_regvars_common(n: tnode; var rv: tusedregvarscommon);    procedure gen_sync_regvars(list:TAsmList; var rv: tusedregvars);   {  Allocate the buffers for exception management and setjmp environment.      Return a pointer to these buffers, send them to the utility routine      so they are registered, and then call setjmp.      Then compare the result of setjmp with 0, and if not equal      to zero, then jump to exceptlabel.      Also store the result of setjmp to a temporary space by calling g_save_exception_reason      It is to note that this routine may be called *after* the stackframe of a      routine has been called, therefore on machines where the stack cannot      be modified, all temps should be allocated on the heap instead of the      stack. }    type      texceptiontemps=record        jmpbuf,        envbuf,        reasonbuf  : treference;      end;    procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);    procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);    procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);    procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);    procedure gen_alloc_symtable(list:TAsmList;pd:tprocdef;st:TSymtable);    procedure gen_free_symtable(list:TAsmList;st:TSymtable);    procedure location_free(list: TAsmList; const location : TLocation);    function getprocalign : shortint;    procedure gen_fpc_dummy(list : TAsmList);    procedure gen_load_frame_for_exceptfilter(list : TAsmList);implementation  uses    version,    cutils,cclasses,    globals,systems,verbose,export,    ppu,defutil,    procinfo,paramgr,fmodule,    regvars,dbgbase,    pass_1,pass_2,    nbas,ncon,nld,nmem,nutils,ngenutil,    tgobj,cgobj,cgcpu,hlcgobj,hlcgcpu{$ifdef powerpc}    , cpupi{$endif}{$ifdef powerpc64}    , cpupi{$endif}{$ifdef SUPPORT_MMX}    , cgx86{$endif SUPPORT_MMX};{*****************************************************************************                                  Misc Helpers*****************************************************************************}{$if first_mm_imreg = 0}  {$WARN 4044 OFF} { Comparison might be always false ... }{$endif}    procedure location_free(list: TAsmList; const location : TLocation);      begin        case location.loc of          LOC_VOID:            ;          LOC_REGISTER,          LOC_CREGISTER:            begin{$ifdef cpu64bitalu}                { x86-64 system v abi:                  structs with up to 16 bytes are returned in registers }                if location.size in [OS_128,OS_S128] then                  begin                    if getsupreg(location.register)<first_int_imreg then                      cg.ungetcpuregister(list,location.register);                    if getsupreg(location.registerhi)<first_int_imreg then                      cg.ungetcpuregister(list,location.registerhi);                  end{$else cpu64bitalu}                if location.size in [OS_64,OS_S64] then                  begin                    if getsupreg(location.register64.reglo)<first_int_imreg then                      cg.ungetcpuregister(list,location.register64.reglo);                    if getsupreg(location.register64.reghi)<first_int_imreg then                      cg.ungetcpuregister(list,location.register64.reghi);                  end{$endif cpu64bitalu}                else                  if getsupreg(location.register)<first_int_imreg then                    cg.ungetcpuregister(list,location.register);            end;          LOC_FPUREGISTER,          LOC_CFPUREGISTER:            begin              if getsupreg(location.register)<first_fpu_imreg then                cg.ungetcpuregister(list,location.register);            end;          LOC_MMREGISTER,          LOC_CMMREGISTER :            begin              if getsupreg(location.register)<first_mm_imreg then                cg.ungetcpuregister(list,location.register);            end;          LOC_REFERENCE,          LOC_CREFERENCE :            begin              if paramanager.use_fixed_stack then                location_freetemp(list,location);            end;          else            internalerror(2004110211);        end;      end;    procedure firstcomplex(p : tbinarynode);      var        fcl, fcr: longint;        ncl, ncr: longint;      begin         { always calculate boolean AND and OR from left to right }         if (p.nodetype in [orn,andn]) and            is_boolean(p.left.resultdef) then           begin             if nf_swapped in p.flags then               internalerror(200709253);           end         else           begin             fcl:=node_resources_fpu(p.left);             fcr:=node_resources_fpu(p.right);             ncl:=node_complexity(p.left);             ncr:=node_complexity(p.right);             { We swap left and right if                a) right needs more floating point registers than left, and                   left needs more than 0 floating point registers (if it                   doesn't need any, swapping won't change the floating                   point register pressure)                b) both left and right need an equal amount of floating                   point registers or right needs no floating point registers,                   and in addition right has a higher complexity than left                   (+- needs more integer registers, but not necessarily)             }             if ((fcr>fcl) and                 (fcl>0)) or                (((fcr=fcl) or                  (fcr=0)) and                 (ncr>ncl)) then               p.swapleftright           end;      end;    procedure maketojumpbool(list:TAsmList; p : tnode; loadregvars: tloadregvars);    {      produces jumps to true respectively false labels using boolean expressions      depending on whether the loading of regvars is currently being      synchronized manually (such as in an if-node) or automatically (most of      the other cases where this procedure is called), loadregvars can be      "lr_load_regvars" or "lr_dont_load_regvars"    }      var        opsize : tcgsize;        storepos : tfileposinfo;        tmpreg : tregister;      begin         if nf_error in p.flags then           exit;         storepos:=current_filepos;         current_filepos:=p.fileinfo;         if is_boolean(p.resultdef) then           begin{$ifdef OLDREGVARS}              if loadregvars = lr_load_regvars then                load_all_regvars(list);{$endif OLDREGVARS}              if is_constboolnode(p) then                begin                   if Tordconstnode(p).value.uvalue<>0 then                     cg.a_jmp_always(list,current_procinfo.CurrTrueLabel)                   else                     cg.a_jmp_always(list,current_procinfo.CurrFalseLabel)                end              else                begin                   opsize:=def_cgsize(p.resultdef);                   case p.location.loc of                     LOC_SUBSETREG,LOC_CSUBSETREG,                     LOC_SUBSETREF,LOC_CSUBSETREF:                       begin                         tmpreg := cg.getintregister(list,OS_INT);                         hlcg.a_load_loc_reg(list,p.resultdef,osuinttype,p.location,tmpreg);                         cg.a_cmp_const_reg_label(list,OS_INT,OC_NE,0,tmpreg,current_procinfo.CurrTrueLabel);                         cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);                       end;                     LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE :                       begin{$ifdef cpu64bitalu}                         if opsize in [OS_128,OS_S128] then                           begin                             hlcg.location_force_reg(list,p.location,p.resultdef,cgsize_orddef(opsize),true);                             tmpreg:=cg.getintregister(list,OS_64);                             cg.a_op_reg_reg_reg(list,OP_OR,OS_64,p.location.register128.reglo,p.location.register128.reghi,tmpreg);                             location_reset(p.location,LOC_REGISTER,OS_64);                             p.location.register:=tmpreg;                             opsize:=OS_64;                           end;{$else cpu64bitalu}                         if opsize in [OS_64,OS_S64] then                           begin                             hlcg.location_force_reg(list,p.location,p.resultdef,cgsize_orddef(opsize),true);                             tmpreg:=cg.getintregister(list,OS_32);                             cg.a_op_reg_reg_reg(list,OP_OR,OS_32,p.location.register64.reglo,p.location.register64.reghi,tmpreg);                             location_reset(p.location,LOC_REGISTER,OS_32);                             p.location.register:=tmpreg;                             opsize:=OS_32;                           end;{$endif cpu64bitalu}                         cg.a_cmp_const_loc_label(list,opsize,OC_NE,0,p.location,current_procinfo.CurrTrueLabel);                         cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);                       end;                     LOC_JUMP:                       ;{$ifdef cpuflags}                     LOC_FLAGS :                       begin                         cg.a_jmp_flags(list,p.location.resflags,current_procinfo.CurrTrueLabel);                         cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);                         cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);                       end;{$endif cpuflags}                     else                       begin                         printnode(output,p);                         internalerror(200308241);                       end;                   end;                end;           end         else           internalerror(200112305);         current_filepos:=storepos;      end;        (*        This code needs fixing. It is not safe to use rgint; on the m68000 it        would be rgaddr.    procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset);      begin        case t.loc of          LOC_REGISTER:            begin              { can't be a regvar, since it would be LOC_CREGISTER then }              exclude(regs,getsupreg(t.register));              if t.register64.reghi<>NR_NO then                exclude(regs,getsupreg(t.register64.reghi));            end;          LOC_CREFERENCE,LOC_REFERENCE:            begin              if not(cs_opt_regvar in current_settings.optimizerswitches) or                 (getsupreg(t.reference.base) in cg.rgint.usableregs) then                exclude(regs,getsupreg(t.reference.base));              if not(cs_opt_regvar in current_settings.optimizerswitches) or                 (getsupreg(t.reference.index) in cg.rgint.usableregs) then                exclude(regs,getsupreg(t.reference.index));            end;        end;      end;        *){*****************************************************************************                            EXCEPTION MANAGEMENT*****************************************************************************}    procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);     var       except_buf_size: longint;     begin        { todo: is there a way to retrieve the except_buf_size from the size of          the TExceptAddr record from the system unit (like we do for jmp_buf_size),          without moving TExceptAddr to the interface part? }        except_buf_size:=voidpointertype.size*2+sizeof(pint);        get_jumpbuf_size;        tg.GetTemp(list,except_buf_size,sizeof(pint),tt_persistent,t.envbuf);        tg.GetTemp(list,jmp_buf_size,jmp_buf_align,tt_persistent,t.jmpbuf);        tg.GetTemp(list,sizeof(pint),sizeof(pint),tt_persistent,t.reasonbuf);      end;    procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);      begin        tg.Ungettemp(list,t.jmpbuf);        tg.ungettemp(list,t.envbuf);        tg.ungettemp(list,t.reasonbuf);      end;    procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);      const{$ifdef cpu16bitaddr}        pushexceptaddr_frametype_cgsize = OS_S16;        setjmp_result_cgsize = OS_S16;{$else cpu16bitaddr}        pushexceptaddr_frametype_cgsize = OS_S32;        setjmp_result_cgsize = OS_S32;{$endif cpu16bitaddr}      var        paraloc1,paraloc2,paraloc3 : tcgpara;        pd: tprocdef;{$ifdef i8086}        tmpreg: TRegister;{$endif i8086}      begin        pd:=search_system_proc('fpc_pushexceptaddr');        paraloc1.init;        paraloc2.init;        paraloc3.init;        paramanager.getintparaloc(pd,1,paraloc1);        paramanager.getintparaloc(pd,2,paraloc2);        paramanager.getintparaloc(pd,3,paraloc3);        if pd.is_pushleftright then          begin            { push type of exceptionframe }            cg.a_load_const_cgpara(list,pushexceptaddr_frametype_cgsize,1,paraloc1);            cg.a_loadaddr_ref_cgpara(list,t.jmpbuf,paraloc2);            cg.a_loadaddr_ref_cgpara(list,t.envbuf,paraloc3);          end        else          begin            cg.a_loadaddr_ref_cgpara(list,t.envbuf,paraloc3);            cg.a_loadaddr_ref_cgpara(list,t.jmpbuf,paraloc2);            { push type of exceptionframe }            cg.a_load_const_cgpara(list,pushexceptaddr_frametype_cgsize,1,paraloc1);          end;        paramanager.freecgpara(list,paraloc3);        paramanager.freecgpara(list,paraloc2);        paramanager.freecgpara(list,paraloc1);        cg.allocallcpuregisters(list);        cg.a_call_name(list,'FPC_PUSHEXCEPTADDR',false);        cg.deallocallcpuregisters(list);        pd:=search_system_proc('fpc_setjmp');        paramanager.getintparaloc(pd,1,paraloc1);{$ifdef i8086}        if current_settings.x86memorymodel in x86_far_data_models then          begin            tmpreg:=cg.getintregister(list,OS_32);            cg.a_load_reg_reg(list,OS_16,OS_16,NR_FUNCTION_RESULT32_LOW_REG,tmpreg);            cg.a_load_reg_reg(list,OS_16,OS_16,NR_FUNCTION_RESULT32_HIGH_REG,GetNextReg(tmpreg));            cg.a_load_reg_cgpara(list,OS_32,tmpreg,paraloc1);          end        else{$endif i8086}          cg.a_load_reg_cgpara(list,OS_ADDR,NR_FUNCTION_RESULT_REG,paraloc1);        paramanager.freecgpara(list,paraloc1);        cg.allocallcpuregisters(list);        cg.a_call_name(list,'FPC_SETJMP',false);        cg.deallocallcpuregisters(list);        cg.alloccpuregisters(list,R_INTREGISTER,[RS_FUNCTION_RESULT_REG]);        cg.g_exception_reason_save(list, t.reasonbuf);        cg.a_cmp_const_reg_label(list,setjmp_result_cgsize,OC_NE,0,cg.makeregsize(list,NR_FUNCTION_RESULT_REG,setjmp_result_cgsize),exceptlabel);        cg.dealloccpuregisters(list,R_INTREGISTER,[RS_FUNCTION_RESULT_REG]);        paraloc1.done;        paraloc2.done;        paraloc3.done;     end;    procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);     begin         cg.allocallcpuregisters(list);         cg.a_call_name(list,'FPC_POPADDRSTACK',false);         cg.deallocallcpuregisters(list);         if not onlyfree then          begin            { g_exception_reason_load already allocates NR_FUNCTION_RESULT_REG }            cg.g_exception_reason_load(list, t.reasonbuf);            cg.a_cmp_const_reg_label(list,OS_INT,OC_EQ,a,NR_FUNCTION_RESULT_REG,endexceptlabel);            cg.a_reg_dealloc(list,NR_FUNCTION_RESULT_REG);          end;     end;{*****************************************************************************                                     TLocation*****************************************************************************}    procedure register_maybe_adjust_setbase(list: TAsmList; var l: tlocation; setbase: aint);      var        tmpreg: tregister;      begin        if (setbase<>0) then          begin            if not(l.loc in [LOC_REGISTER,LOC_CREGISTER]) then              internalerror(2007091502);            { subtract the setbase }            case l.loc of              LOC_CREGISTER:                begin                  tmpreg := cg.getintregister(list,l.size);                  cg.a_op_const_reg_reg(list,OP_SUB,l.size,setbase,l.register,tmpreg);                  l.loc:=LOC_REGISTER;                  l.register:=tmpreg;                end;              LOC_REGISTER:                begin                  cg.a_op_const_reg(list,OP_SUB,l.size,setbase,l.register);                end;            end;          end;      end;    procedure location_force_mmreg(list:TAsmList;var l: tlocation;maybeconst:boolean);      var        reg : tregister;      begin        if (l.loc<>LOC_MMREGISTER)  and           ((l.loc<>LOC_CMMREGISTER) or (not maybeconst)) then          begin            reg:=cg.getmmregister(list,OS_VECTOR);            cg.a_loadmm_loc_reg(list,OS_VECTOR,l,reg,nil);            location_freetemp(list,l);            location_reset(l,LOC_MMREGISTER,OS_VECTOR);            l.register:=reg;          end;      end;    procedure location_allocate_register(list: TAsmList;out l: tlocation;def: tdef;constant: boolean);      begin        l.size:=def_cgsize(def);        if (def.typ=floatdef) and           not(cs_fp_emulation in current_settings.moduleswitches) then          begin            if use_vectorfpu(def) then              begin                if constant then                  location_reset(l,LOC_CMMREGISTER,l.size)                else                  location_reset(l,LOC_MMREGISTER,l.size);                l.register:=cg.getmmregister(list,l.size);              end            else              begin                if constant then                  location_reset(l,LOC_CFPUREGISTER,l.size)                else                  location_reset(l,LOC_FPUREGISTER,l.size);                l.register:=cg.getfpuregister(list,l.size);              end;          end        else          begin            if constant then              location_reset(l,LOC_CREGISTER,l.size)            else              location_reset(l,LOC_REGISTER,l.size);{$ifdef cpu64bitalu}            if l.size in [OS_128,OS_S128,OS_F128] then              begin                l.register128.reglo:=cg.getintregister(list,OS_64);                l.register128.reghi:=cg.getintregister(list,OS_64);              end            else{$else cpu64bitalu}            if l.size in [OS_64,OS_S64,OS_F64] then              begin                l.register64.reglo:=cg.getintregister(list,OS_32);                l.register64.reghi:=cg.getintregister(list,OS_32);              end            else{$endif cpu64bitalu}            { Note: for widths of records (and maybe objects, classes, etc.) an                    address register could be set here, but that is later                    changed to an intregister neverthless when in the                    tcgassignmentnode thlcgobj.maybe_change_load_node_reg is                    called for the temporary node; so the workaround for now is                    to fix the symptoms... }              l.register:=cg.getintregister(list,l.size);          end;      end;{****************************************************************************                            Init/Finalize Code****************************************************************************}    procedure copyvalueparas(p:TObject;arg:pointer);      var        href : treference;        hreg : tregister;        list : TAsmList;        hsym : tparavarsym;        l    : longint;        localcopyloc : tlocation;        sizedef : tdef;      begin        list:=TAsmList(arg);        if (tsym(p).typ=paravarsym) and           (tparavarsym(p).varspez=vs_value) and          (paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then          begin            { we have no idea about the alignment at the caller side }            hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,true,1);            if is_open_array(tparavarsym(p).vardef) or               is_array_of_const(tparavarsym(p).vardef) then              begin                { cdecl functions don't have a high pointer so it is not possible to generate                  a local copy }                if not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then                  begin                    hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));                    if not assigned(hsym) then                      internalerror(200306061);                    sizedef:=getpointerdef(tparavarsym(p).vardef);                    hreg:=hlcg.getaddressregister(list,sizedef);                    if not is_packed_array(tparavarsym(p).vardef) then                      hlcg.g_copyvaluepara_openarray(list,href,hsym.initialloc,tarraydef(tparavarsym(p).vardef),hreg)                    else                      internalerror(2006080401);//                      cg.g_copyvaluepara_packedopenarray(list,href,hsym.intialloc,tarraydef(tparavarsym(p).vardef).elepackedbitsize,hreg);                    hlcg.a_load_reg_loc(list,sizedef,sizedef,hreg,tparavarsym(p).initialloc);                  end;              end            else              begin                { Allocate space for the local copy }                l:=tparavarsym(p).getsize;                localcopyloc.loc:=LOC_REFERENCE;                localcopyloc.size:=int_cgsize(l);                tg.GetLocal(list,l,tparavarsym(p).vardef,localcopyloc.reference);                { Copy data }                if is_shortstring(tparavarsym(p).vardef) then                  begin                    { this code is only executed before the code for the body and the entry/exit code is generated                      so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore                    }                    include(current_procinfo.flags,pi_do_call);                    hlcg.g_copyshortstring(list,href,localcopyloc.reference,tstringdef(tparavarsym(p).vardef));                  end                else if tparavarsym(p).vardef.typ = variantdef then                  begin                    { this code is only executed before the code for the body and the entry/exit code is generated                      so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore                    }                    include(current_procinfo.flags,pi_do_call);                    hlcg.g_copyvariant(list,href,localcopyloc.reference,tvariantdef(tparavarsym(p).vardef))                  end                else                  begin                    { pass proper alignment info }                    localcopyloc.reference.alignment:=tparavarsym(p).vardef.alignment;                    cg.g_concatcopy(list,href,localcopyloc.reference,tparavarsym(p).vardef.size);                  end;                { update localloc of varsym }                tg.Ungetlocal(list,tparavarsym(p).localloc.reference);                tparavarsym(p).localloc:=localcopyloc;                tparavarsym(p).initialloc:=localcopyloc;              end;          end;      end;    { generates the code for incrementing the reference count of parameters and      initialize out parameters }    procedure init_paras(p:TObject;arg:pointer);      var        href : treference;        hsym : tparavarsym;        eldef : tdef;        list : TAsmList;        needs_inittable : boolean;      begin        list:=TAsmList(arg);        if (tsym(p).typ=paravarsym) then         begin           needs_inittable:=is_managed_type(tparavarsym(p).vardef);           if not needs_inittable then             exit;           case tparavarsym(p).varspez of             vs_value :               begin                 { variants are already handled by the call to fpc_variant_copy_overwrite if                   they are passed by reference }                 if not((tparavarsym(p).vardef.typ=variantdef) and                    paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then                   begin                     hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint));                     if is_open_array(tparavarsym(p).vardef) then                       begin                         { open arrays do not contain correct element count in their rtti,                           the actual count must be passed separately. }                         hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));                         eldef:=tarraydef(tparavarsym(p).vardef).elementdef;                         if not assigned(hsym) then                           internalerror(201003031);                         hlcg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'fpc_addref_array');                       end                     else                      hlcg.g_incrrefcount(list,tparavarsym(p).vardef,href);                   end;               end;             vs_out :               begin                 { we have no idea about the alignment at the callee side,                   and the user also cannot specify "unaligned" here, so                   assume worst case }                 hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,true,1);                 if is_open_array(tparavarsym(p).vardef) then                   begin                     hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));                     eldef:=tarraydef(tparavarsym(p).vardef).elementdef;                     if not assigned(hsym) then                       internalerror(201103033);                     hlcg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'fpc_initialize_array');                   end                 else                   hlcg.g_initialize(list,tparavarsym(p).vardef,href);               end;           end;         end;      end;    procedure gen_alloc_regloc(list:TAsmList;var loc: tlocation);      begin        case loc.loc of          LOC_CREGISTER:            begin{$ifdef cpu64bitalu}              if loc.size in [OS_128,OS_S128] then                begin                  loc.register128.reglo:=cg.getintregister(list,OS_64);                  loc.register128.reghi:=cg.getintregister(list,OS_64);                end              else{$else cpu64bitalu}              if loc.size in [OS_64,OS_S64] then                begin                  loc.register64.reglo:=cg.getintregister(list,OS_32);                  loc.register64.reghi:=cg.getintregister(list,OS_32);                end              else{$endif cpu64bitalu}                loc.register:=cg.getintregister(list,loc.size);            end;          LOC_CFPUREGISTER:            begin              loc.register:=cg.getfpuregister(list,loc.size);            end;          LOC_CMMREGISTER:            begin             loc.register:=cg.getmmregister(list,loc.size);            end;        end;      end;    procedure gen_alloc_regvar(list:TAsmList;sym: tabstractnormalvarsym; allocreg: boolean);      begin        if allocreg then          gen_alloc_regloc(list,sym.initialloc);        if (pi_has_label in current_procinfo.flags) then          begin            { Allocate register already, to prevent first allocation to be              inside a loop }{$if defined(cpu64bitalu)}            if sym.initialloc.size in [OS_128,OS_S128] then              begin                cg.a_reg_sync(list,sym.initialloc.register128.reglo);                cg.a_reg_sync(list,sym.initialloc.register128.reghi);              end            else{$elseif defined(cpu32bitalu)}            if sym.initialloc.size in [OS_64,OS_S64] then              begin                cg.a_reg_sync(list,sym.initialloc.register64.reglo);                cg.a_reg_sync(list,sym.initialloc.register64.reghi);              end            else{$elseif defined(cpu16bitalu)}            if sym.initialloc.size in [OS_64,OS_S64] then              begin                cg.a_reg_sync(list,sym.initialloc.register64.reglo);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register64.reglo));                cg.a_reg_sync(list,sym.initialloc.register64.reghi);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register64.reghi));              end            else            if sym.initialloc.size in [OS_32,OS_S32] then              begin                cg.a_reg_sync(list,sym.initialloc.register);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register));              end            else{$elseif defined(cpu8bitalu)}            if sym.initialloc.size in [OS_64,OS_S64] then              begin                cg.a_reg_sync(list,sym.initialloc.register64.reglo);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register64.reglo));                cg.a_reg_sync(list,GetNextReg(GetNextReg(sym.initialloc.register64.reglo)));                cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(sym.initialloc.register64.reglo))));                cg.a_reg_sync(list,sym.initialloc.register64.reghi);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register64.reghi));                cg.a_reg_sync(list,GetNextReg(GetNextReg(sym.initialloc.register64.reghi)));                cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(sym.initialloc.register64.reghi))));              end            else            if sym.initialloc.size in [OS_32,OS_S32] then              begin                cg.a_reg_sync(list,sym.initialloc.register);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register));                cg.a_reg_sync(list,GetNextReg(GetNextReg(sym.initialloc.register)));                cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(sym.initialloc.register))));              end            else            if sym.initialloc.size in [OS_16,OS_S16] then              begin                cg.a_reg_sync(list,sym.initialloc.register);                cg.a_reg_sync(list,GetNextReg(sym.initialloc.register));              end            else{$endif}             cg.a_reg_sync(list,sym.initialloc.register);          end;        sym.localloc:=sym.initialloc;      end;    procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);      procedure unget_para(const paraloc:TCGParaLocation);        begin           case paraloc.loc of             LOC_REGISTER :               begin                 if getsupreg(paraloc.register)<first_int_imreg then                   cg.ungetcpuregister(list,paraloc.register);               end;             LOC_MMREGISTER :               begin                 if getsupreg(paraloc.register)<first_mm_imreg then                   cg.ungetcpuregister(list,paraloc.register);               end;             LOC_FPUREGISTER :               begin                 if getsupreg(paraloc.register)<first_fpu_imreg then                   cg.ungetcpuregister(list,paraloc.register);               end;           end;        end;      var        paraloc  : pcgparalocation;        href     : treference;        sizeleft : aint;{$if defined(sparc) or defined(arm) or defined(mips)}        tempref  : treference;{$endif defined(sparc) or defined(arm) or defined(mips)}{$ifdef mips}        tmpreg   : tregister;{$endif mips}{$ifndef cpu64bitalu}        tempreg  : tregister;        reg64    : tregister64;{$endif not cpu64bitalu}      begin        paraloc:=para.location;        if not assigned(paraloc) then          internalerror(200408203);        { skip e.g. empty records }        if (paraloc^.loc = LOC_VOID) then          exit;        case destloc.loc of          LOC_REFERENCE :            begin              { If the parameter location is reused we don't need to copy                anything }              if not reusepara then                begin                  href:=destloc.reference;                  sizeleft:=para.intsize;                  while assigned(paraloc) do                    begin                      if (paraloc^.size=OS_NO) then                        begin                          { Can only be a reference that contains the rest                            of the parameter }                          if (paraloc^.loc<>LOC_REFERENCE) or                             assigned(paraloc^.next) then                            internalerror(2005013010);                          cg.a_load_cgparaloc_ref(list,paraloc^,href,sizeleft,destloc.reference.alignment);                          inc(href.offset,sizeleft);                          sizeleft:=0;                        end                      else                        begin                          cg.a_load_cgparaloc_ref(list,paraloc^,href,tcgsize2size[paraloc^.size],destloc.reference.alignment);                          inc(href.offset,TCGSize2Size[paraloc^.size]);                          dec(sizeleft,TCGSize2Size[paraloc^.size]);                        end;                      unget_para(paraloc^);                      paraloc:=paraloc^.next;                    end;                end;            end;          LOC_REGISTER,          LOC_CREGISTER :            begin{$ifdef cpu64bitalu}              if (para.size in [OS_128,OS_S128,OS_F128]) and                 ({ in case of fpu emulation, or abi's that pass fpu values                    via integer registers }                  (vardef.typ=floatdef) or                   is_methodpointer(vardef) or                   is_record(vardef)) then                begin                  case paraloc^.loc of                    LOC_REGISTER:                      begin                        if not assigned(paraloc^.next) then                          internalerror(200410104);                        if (target_info.endian=ENDIAN_BIG) then                          begin                            { paraloc^ -> high                              paraloc^.next -> low }                            unget_para(paraloc^);                            gen_alloc_regloc(list,destloc);                            { reg->reg, alignment is irrelevant }                            cg.a_load_cgparaloc_anyreg(list,OS_64,paraloc^,destloc.register128.reghi,8);                            unget_para(paraloc^.next^);                            cg.a_load_cgparaloc_anyreg(list,OS_64,paraloc^.next^,destloc.register128.reglo,8);                          end                        else                          begin                            { paraloc^ -> low                              paraloc^.next -> high }                            unget_para(paraloc^);                            gen_alloc_regloc(list,destloc);                            cg.a_load_cgparaloc_anyreg(list,OS_64,paraloc^,destloc.register128.reglo,8);                            unget_para(paraloc^.next^);                            cg.a_load_cgparaloc_anyreg(list,OS_64,paraloc^.next^,destloc.register128.reghi,8);                          end;                      end;                    LOC_REFERENCE:                      begin                        gen_alloc_regloc(list,destloc);                        reference_reset_base(href,paraloc^.reference.index,paraloc^.reference.offset,para.alignment);                        cg128.a_load128_ref_reg(list,href,destloc.register128);                        unget_para(paraloc^);                      end;                    else                      internalerror(2012090607);                  end                end              else{$else cpu64bitalu}              if (para.size in [OS_64,OS_S64,OS_F64]) and                 (is_64bit(vardef) or                  { in case of fpu emulation, or abi's that pass fpu values                    via integer registers }                  (vardef.typ=floatdef) or                   is_methodpointer(vardef) or                   is_record(vardef)) then                begin                  case paraloc^.loc of                    LOC_REGISTER:                      begin                        case para.locations_count of{$if defined(cpu16bitalu) or defined(cpu8bitalu)}                          { 4 paralocs? }                          4:                            if (target_info.endian=ENDIAN_BIG) then                              begin                                { paraloc^ -> high                                  paraloc^.next^.next -> low }                                unget_para(paraloc^);                                gen_alloc_regloc(list,destloc);                                { reg->reg, alignment is irrelevant }                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^,GetNextReg(destloc.register64.reghi),2);                                unget_para(paraloc^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^,destloc.register64.reghi,2);                                unget_para(paraloc^.next^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^.next^,GetNextReg(destloc.register64.reglo),2);                                unget_para(paraloc^.next^.next^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^.next^.next^,destloc.register64.reglo,2);                              end                            else                              begin                                { paraloc^ -> low                                  paraloc^.next^.next -> high }                                unget_para(paraloc^);                                gen_alloc_regloc(list,destloc);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^,destloc.register64.reglo,2);                                unget_para(paraloc^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^,GetNextReg(destloc.register64.reglo),2);                                unget_para(paraloc^.next^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^.next^,destloc.register64.reghi,2);                                unget_para(paraloc^.next^.next^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_16,paraloc^.next^.next^.next^,GetNextReg(destloc.register64.reghi),2);                              end;{$endif defined(cpu16bitalu) or defined(cpu8bitalu)}                          2:                            if (target_info.endian=ENDIAN_BIG) then                              begin                                { paraloc^ -> high                                  paraloc^.next -> low }                                unget_para(paraloc^);                                gen_alloc_regloc(list,destloc);                                { reg->reg, alignment is irrelevant }                                cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^,destloc.register64.reghi,4);                                unget_para(paraloc^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.next^,destloc.register64.reglo,4);                              end                            else                              begin                                { paraloc^ -> low                                  paraloc^.next -> high }                                unget_para(paraloc^);                                gen_alloc_regloc(list,destloc);                                cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^,destloc.register64.reglo,4);                                unget_para(paraloc^.next^);                                cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.next^,destloc.register64.reghi,4);                              end;                          else                            { unexpected number of paralocs }                            internalerror(200410104);                        end;                      end;                    LOC_REFERENCE:                      begin                        gen_alloc_regloc(list,destloc);                        reference_reset_base(href,paraloc^.reference.index,paraloc^.reference.offset,para.alignment);                        cg64.a_load64_ref_reg(list,href,destloc.register64);                        unget_para(paraloc^);                      end;                    else                      internalerror(2005101501);                  end                end              else{$endif cpu64bitalu}                begin                  if assigned(paraloc^.next) then                    begin                      if (destloc.size in [OS_PAIR,OS_SPAIR]) and                        (para.Size in [OS_PAIR,OS_SPAIR]) then                        begin                          unget_para(paraloc^);                          gen_alloc_regloc(list,destloc);                          cg.a_load_cgparaloc_anyreg(list,OS_INT,paraloc^,destloc.register,sizeof(aint));                          unget_para(paraloc^.Next^);                          {$if defined(cpu16bitalu) or defined(cpu8bitalu)}                            cg.a_load_cgparaloc_anyreg(list,OS_INT,paraloc^.Next^,GetNextReg(destloc.register),sizeof(aint));                          {$else}                            cg.a_load_cgparaloc_anyreg(list,OS_INT,paraloc^.Next^,destloc.registerhi,sizeof(aint));                          {$endif}                        end{$if defined(cpu8bitalu)}                      else if (destloc.size in [OS_32,OS_S32]) and                        (para.Size in [OS_32,OS_S32]) then                        begin                          unget_para(paraloc^);                          gen_alloc_regloc(list,destloc);                          cg.a_load_cgparaloc_anyreg(list,OS_8,paraloc^,destloc.register,sizeof(aint));                          unget_para(paraloc^.Next^);                          cg.a_load_cgparaloc_anyreg(list,OS_8,paraloc^.Next^,GetNextReg(destloc.register),sizeof(aint));                          unget_para(paraloc^.Next^.Next^);                          cg.a_load_cgparaloc_anyreg(list,OS_8,paraloc^.Next^.Next^,GetNextReg(GetNextReg(destloc.register)),sizeof(aint));                          unget_para(paraloc^.Next^.Next^.Next^);                          cg.a_load_cgparaloc_anyreg(list,OS_8,paraloc^.Next^.Next^.Next^,GetNextReg(GetNextReg(GetNextReg(destloc.register))),sizeof(aint));                        end{$endif defined(cpu8bitalu)}                      else                        internalerror(200410105);                    end                  else                    begin                      unget_para(paraloc^);                      gen_alloc_regloc(list,destloc);                      cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));                    end;                end;            end;          LOC_FPUREGISTER,          LOC_CFPUREGISTER :            begin{$ifdef mips}              if (destloc.size = paraloc^.Size) and                 (paraloc^.Loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER,LOC_REFERENCE,LOC_CREFERENCE]) then                begin                  unget_para(paraloc^);                  gen_alloc_regloc(list,destloc);                  cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,para.alignment);                end              else if (destloc.size = OS_F32) and                 (paraloc^.Loc in [LOC_REGISTER,LOC_CREGISTER]) then                begin                  gen_alloc_regloc(list,destloc);                  unget_para(paraloc^);                  list.Concat(taicpu.op_reg_reg(A_MTC1,paraloc^.register,destloc.register));                end{ TODO: Produces invalid code, needs fixing together with regalloc setup. }{              else if (destloc.size = OS_F64) and                      (paraloc^.Loc in [LOC_REGISTER,LOC_CREGISTER]) and                      (paraloc^.next^.Loc in [LOC_REGISTER,LOC_CREGISTER]) then                begin                  gen_alloc_regloc(list,destloc);                  tmpreg:=destloc.register;                  unget_para(paraloc^);                  list.Concat(taicpu.op_reg_reg(A_MTC1,paraloc^.register,tmpreg));                  setsupreg(tmpreg,getsupreg(tmpreg)+1);                  unget_para(paraloc^.next^);                  list.Concat(taicpu.op_reg_reg(A_MTC1,paraloc^.Next^.register,tmpreg));                end}              else                begin                  sizeleft := TCGSize2Size[destloc.size];                  tg.GetTemp(list,sizeleft,sizeleft,tt_normal,tempref);                  href:=tempref;                  while assigned(paraloc) do                    begin                      unget_para(paraloc^);                      cg.a_load_cgparaloc_ref(list,paraloc^,href,sizeleft,destloc.reference.alignment);                      inc(href.offset,TCGSize2Size[paraloc^.size]);                      dec(sizeleft,TCGSize2Size[paraloc^.size]);                      paraloc:=paraloc^.next;                    end;                  gen_alloc_regloc(list,destloc);                  cg.a_loadfpu_ref_reg(list,destloc.size,destloc.size,tempref,destloc.register);                  tg.UnGetTemp(list,tempref);                end;{$else mips}{$if defined(sparc) or defined(arm)}              { Arm and Sparc passes floats in int registers, when loading to fpu register                we need a temp }              sizeleft := TCGSize2Size[destloc.size];              tg.GetTemp(list,sizeleft,sizeleft,tt_normal,tempref);              href:=tempref;              while assigned(paraloc) do                begin                  unget_para(paraloc^);                  cg.a_load_cgparaloc_ref(list,paraloc^,href,sizeleft,destloc.reference.alignment);                  inc(href.offset,TCGSize2Size[paraloc^.size]);                  dec(sizeleft,TCGSize2Size[paraloc^.size]);                  paraloc:=paraloc^.next;                end;              gen_alloc_regloc(list,destloc);              cg.a_loadfpu_ref_reg(list,destloc.size,destloc.size,tempref,destloc.register);              tg.UnGetTemp(list,tempref);{$else defined(sparc) or defined(arm)}              unget_para(paraloc^);              gen_alloc_regloc(list,destloc);              { from register to register -> alignment is irrelevant }              cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0);              if assigned(paraloc^.next) then                internalerror(200410109);{$endif defined(sparc) or defined(arm)}{$endif mips}            end;          LOC_MMREGISTER,          LOC_CMMREGISTER :            begin{$ifndef cpu64bitalu}              { ARM vfp floats are passed in integer registers }              if (para.size=OS_F64) and                 (paraloc^.size in [OS_32,OS_S32]) and                 use_vectorfpu(vardef) then                begin                  { we need 2x32bit reg }                  if not assigned(paraloc^.next) or                     assigned(paraloc^.next^.next) then                    internalerror(2009112421);                  unget_para(paraloc^.next^);                  case paraloc^.next^.loc of                    LOC_REGISTER:                      tempreg:=paraloc^.next^.register;                    LOC_REFERENCE:                      begin                        tempreg:=cg.getintregister(list,OS_32);                        cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.next^,tempreg,4);                      end;                    else                      internalerror(2012051301);                  end;                  { don't free before the above, because then the getintregister                    could reallocate this register and overwrite it }                  unget_para(paraloc^);                  gen_alloc_regloc(list,destloc);                  if (target_info.endian=endian_big) then                    { paraloc^ -> high                      paraloc^.next -> low }                    reg64:=joinreg64(tempreg,paraloc^.register)                  else                    reg64:=joinreg64(paraloc^.register,tempreg);                  cg64.a_loadmm_intreg64_reg(list,OS_F64,reg64,destloc.register);                end              else{$endif not cpu64bitalu}                begin                  unget_para(paraloc^);                  gen_alloc_regloc(list,destloc);                  { from register to register -> alignment is irrelevant }                  cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0);                  { data could come in two memory locations, for now                    we simply ignore the sanity check (FK)                  if assigned(paraloc^.next) then                    internalerror(200410108);                  }                end;            end;          else            internalerror(2010052903);        end;      end;    procedure gen_load_para_value(list:TAsmList);       procedure get_para(const paraloc:TCGParaLocation);         begin            case paraloc.loc of              LOC_REGISTER :                begin                  if getsupreg(paraloc.register)<first_int_imreg then                    cg.getcpuregister(list,paraloc.register);                end;              LOC_MMREGISTER :                begin                  if getsupreg(paraloc.register)<first_mm_imreg then                    cg.getcpuregister(list,paraloc.register);                end;              LOC_FPUREGISTER :                begin                  if getsupreg(paraloc.register)<first_fpu_imreg then                    cg.getcpuregister(list,paraloc.register);                end;            end;         end;      var        i : longint;        currpara : tparavarsym;        paraloc  : pcgparalocation;      begin        if (po_assembler in current_procinfo.procdef.procoptions) or        { exceptfilters have a single hidden 'parentfp' parameter, which          is handled by tcg.g_proc_entry. }           (current_procinfo.procdef.proctypeoption=potype_exceptfilter) then          exit;        { Allocate registers used by parameters }        for i:=0 to current_procinfo.procdef.paras.count-1 do          begin            currpara:=tparavarsym(current_procinfo.procdef.paras[i]);            paraloc:=currpara.paraloc[calleeside].location;            while assigned(paraloc) do              begin                if paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER] then                  get_para(paraloc^);                paraloc:=paraloc^.next;              end;          end;        { Copy parameters to local references/registers }        for i:=0 to current_procinfo.procdef.paras.count-1 do          begin            currpara:=tparavarsym(current_procinfo.procdef.paras[i]);            gen_load_cgpara_loc(list,currpara.vardef,currpara.paraloc[calleeside],currpara.initialloc,paramanager.param_use_paraloc(currpara.paraloc[calleeside]));            { gen_load_cgpara_loc() already allocated the initialloc              -> don't allocate again }            if currpara.initialloc.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMREGISTER] then              gen_alloc_regvar(list,currpara,false);          end;        { generate copies of call by value parameters, must be done before          the initialization and body is parsed because the refcounts are          incremented using the local copies }        current_procinfo.procdef.parast.SymList.ForEachCall(@copyvalueparas,list);        if not(po_assembler in current_procinfo.procdef.procoptions) then          begin            { initialize refcounted paras, and trash others. Needed here              instead of in gen_initialize_code, because when a reference is              intialised or trashed while the pointer to that reference is kept              in a regvar, we add a register move and that one again has to              come after the parameter loading code as far as the register              allocator is concerned }            current_procinfo.procdef.parast.SymList.ForEachCall(@init_paras,list);          end;      end;{****************************************************************************                                Entry/Exit****************************************************************************}    function has_alias_name(pd:tprocdef;const s:string):boolean;      var        item : TCmdStrListItem;      begin        result:=true;        if pd.mangledname=s then          exit;        item := TCmdStrListItem(pd.aliasnames.first);        while assigned(item) do          begin            if item.str=s then              exit;            item := TCmdStrListItem(item.next);          end;        result:=false;      end;    procedure alloc_proc_symbol(pd: tprocdef);      var        item : TCmdStrListItem;      begin        item := TCmdStrListItem(pd.aliasnames.first);        while assigned(item) do          begin            { The condition to use global or local symbol must match              the code written in hlcg.gen_proc_symbol to               avoid change from AB_LOCAL to AB_GLOBAL, which generates              erroneous code (at least for targets using GOT) }             if (cs_profile in current_settings.moduleswitches) or               (po_global in current_procinfo.procdef.procoptions) then              current_asmdata.DefineAsmSymbol(item.str,AB_GLOBAL,AT_FUNCTION)            else              current_asmdata.DefineAsmSymbol(item.str,AB_LOCAL,AT_FUNCTION);           item := TCmdStrListItem(item.next);         end;      end;    procedure gen_proc_entry_code(list:TAsmList);      var        hitemp,        lotemp, stack_frame_size : longint;      begin        { generate call frame marker for dwarf call frame info }        current_asmdata.asmcfi.start_frame(list);        { All temps are know, write offsets used for information }        if (cs_asm_source in current_settings.globalswitches) and           (current_procinfo.tempstart<>tg.lasttemp) then          begin            if tg.direction>0 then              begin                lotemp:=current_procinfo.tempstart;                hitemp:=tg.lasttemp;              end            else              begin                lotemp:=tg.lasttemp;                hitemp:=current_procinfo.tempstart;              end;            list.concat(Tai_comment.Create(strpnew('Temps allocated between '+std_regname(current_procinfo.framepointer)+              tostr_with_plus(lotemp)+' and '+std_regname(current_procinfo.framepointer)+tostr_with_plus(hitemp))));          end;         { generate target specific proc entry code }         stack_frame_size := current_procinfo.calc_stackframe_size;         if (stack_frame_size <> 0) and            (po_nostackframe in current_procinfo.procdef.procoptions) then           message1(parser_e_nostackframe_with_locals,tostr(stack_frame_size));         hlcg.g_proc_entry(list,stack_frame_size,(po_nostackframe in current_procinfo.procdef.procoptions));      end;    procedure gen_proc_exit_code(list:TAsmList);      var        parasize : longint;      begin        { c style clearstack does not need to remove parameters from the stack, only the          return value when it was pushed by arguments }        if current_procinfo.procdef.proccalloption in clearstack_pocalls then          begin            parasize:=0;            if paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef) then              inc(parasize,sizeof(pint));          end        else          begin            parasize:=current_procinfo.para_stack_size;            { the parent frame pointer para has to be removed by the caller in              case of Delphi-style parent frame pointer passing }            if not paramanager.use_fixed_stack and               (po_delphi_nested_cc in current_procinfo.procdef.procoptions) then              dec(parasize,sizeof(pint));          end;        { generate target specific proc exit code }        hlcg.g_proc_exit(list,parasize,(po_nostackframe in current_procinfo.procdef.procoptions));        { release return registers, needed for optimizer }        if not is_void(current_procinfo.procdef.returndef) then          paramanager.freecgpara(list,current_procinfo.procdef.funcretloc[calleeside]);        { end of frame marker for call frame info }        current_asmdata.asmcfi.end_frame(list);      end;    procedure gen_stack_check_size_para(list:TAsmList);      var        paraloc1 : tcgpara;        pd       : tprocdef;      begin        pd:=search_system_proc('fpc_stackcheck');        paraloc1.init;        paramanager.getintparaloc(pd,1,paraloc1);        cg.a_load_const_cgpara(list,OS_INT,current_procinfo.calc_stackframe_size,paraloc1);        paramanager.freecgpara(list,paraloc1);        paraloc1.done;      end;    procedure gen_stack_check_call(list:TAsmList);      var        paraloc1 : tcgpara;        pd       : tprocdef;      begin        pd:=search_system_proc('fpc_stackcheck');        paraloc1.init;        { Also alloc the register needed for the parameter }        paramanager.getintparaloc(pd,1,paraloc1);        paramanager.freecgpara(list,paraloc1);        { Call the helper }        cg.allocallcpuregisters(list);        cg.a_call_name(list,'FPC_STACKCHECK',false);        cg.deallocallcpuregisters(list);        paraloc1.done;      end;    procedure gen_save_used_regs(list:TAsmList);      begin        { Pure assembler routines need to save the registers themselves }        if (po_assembler in current_procinfo.procdef.procoptions) then          exit;        { oldfpccall expects all registers to be destroyed }        if current_procinfo.procdef.proccalloption<>pocall_oldfpccall then            cg.g_save_registers(list);      end;    procedure gen_restore_used_regs(list:TAsmList);      begin        { Pure assembler routines need to save the registers themselves }        if (po_assembler in current_procinfo.procdef.procoptions) then          exit;        { oldfpccall expects all registers to be destroyed }        if current_procinfo.procdef.proccalloption<>pocall_oldfpccall then          cg.g_restore_registers(list);      end;{****************************************************************************                           External handling****************************************************************************}    procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);      begin        create_hlcodegen;        { add the procedure to the al_procedures }        maybe_new_object_file(list);        new_section(list,sec_code,lower(pd.mangledname),current_settings.alignment.procalign);        if (po_global in pd.procoptions) then          list.concat(Tai_symbol.createname_global(pd.mangledname,AT_FUNCTION,0))        else          list.concat(Tai_symbol.createname(pd.mangledname,AT_FUNCTION,0));        cg.g_external_wrapper(list,pd,externalname);        destroy_hlcodegen;      end;{****************************************************************************                               Const Data****************************************************************************}    procedure gen_alloc_symtable(list:TAsmList;pd:tprocdef;st:TSymtable);      procedure setlocalloc(vs:tabstractnormalvarsym);        begin          if cs_asm_source in current_settings.globalswitches then            begin              case vs.initialloc.loc of                LOC_REFERENCE :                  begin                    if not assigned(vs.initialloc.reference.symbol) then                      list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at '+                         std_regname(vs.initialloc.reference.base)+tostr_with_plus(vs.initialloc.reference.offset)+                         ', size='+tcgsize2str(vs.initialloc.size))));                  end;              end;            end;          vs.localloc:=vs.initialloc;          FillChar(vs.currentregloc,sizeof(vs.currentregloc),0);        end;      var        i       : longint;        highsym,        sym     : tsym;        vs      : tabstractnormalvarsym;        isaddr  : boolean;      begin        for i:=0 to st.SymList.Count-1 do          begin            sym:=tsym(st.SymList[i]);            case sym.typ of              staticvarsym :                begin                  vs:=tabstractnormalvarsym(sym);                  { The code in loadnode.pass_generatecode will create the                    LOC_REFERENCE instead for all none register variables. This is                    required because we can't store an asmsymbol in the localloc because                    the asmsymbol is invalid after an unit is compiled. This gives                    problems when this procedure is inlined in another unit (PFV) }                  if vs.is_regvar(false) then                    begin                      vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable];                      vs.initialloc.size:=def_cgsize(vs.vardef);                      gen_alloc_regvar(list,vs,true);                      setlocalloc(vs);                    end;                end;              paravarsym :                begin                  vs:=tabstractnormalvarsym(sym);                  { Parameters passed to assembler procedures need to be kept                    in the original location }                  if (po_assembler in pd.procoptions) then                    tparavarsym(vs).paraloc[calleeside].get_location(vs.initialloc)                  { exception filters receive their frame pointer as a parameter }                  else if (pd.proctypeoption=potype_exceptfilter) and                    (vo_is_parentfp in vs.varoptions) then                    begin                      location_reset(vs.initialloc,LOC_REGISTER,OS_ADDR);                      vs.initialloc.register:=NR_FRAME_POINTER_REG;                    end                  else                    begin                      { if an open array is used, also its high parameter is used,                        since the hidden high parameters are inserted after the corresponding symbols,                        we can increase the ref. count here }                      if is_open_array(vs.vardef) or is_array_of_const(vs.vardef) then                        begin                          highsym:=get_high_value_sym(tparavarsym(vs));                          if assigned(highsym) then                            inc(highsym.refs);                        end;                      isaddr:=paramanager.push_addr_param(vs.varspez,vs.vardef,pd.proccalloption);                      if isaddr then                        vs.initialloc.size:=def_cgsize(voidpointertype)                      else                        vs.initialloc.size:=def_cgsize(vs.vardef);                      if vs.is_regvar(isaddr) then                        vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable]                      else                        begin                          vs.initialloc.loc:=LOC_REFERENCE;                          { Reuse the parameter location for values to are at a single location on the stack }                          if paramanager.param_use_paraloc(tparavarsym(sym).paraloc[calleeside]) then                            begin                              reference_reset_base(vs.initialloc.reference,tparavarsym(sym).paraloc[calleeside].location^.reference.index,                                  tparavarsym(sym).paraloc[calleeside].location^.reference.offset,tparavarsym(sym).paraloc[calleeside].alignment);                            end                          else                            begin                              if isaddr then                                tg.GetLocal(list,voidpointertype.size,voidpointertype,vs.initialloc.reference)                              else                                tg.GetLocal(list,vs.getsize,tparavarsym(sym).paraloc[calleeside].alignment,vs.vardef,vs.initialloc.reference);                            end;                        end;                    end;                  setlocalloc(vs);                end;              localvarsym :                begin                  vs:=tabstractnormalvarsym(sym);                  vs.initialloc.size:=def_cgsize(vs.vardef);                  if ([po_assembler,po_nostackframe] * pd.procoptions = [po_assembler,po_nostackframe]) and                     (vo_is_funcret in vs.varoptions) then                    begin                      paramanager.create_funcretloc_info(pd,calleeside);                      if assigned(pd.funcretloc[calleeside].location^.next) then                        begin                          { can't replace references to "result" with a complex                            location expression inside assembler code }                          location_reset(vs.initialloc,LOC_INVALID,OS_NO);                        end                      else                        pd.funcretloc[calleeside].get_location(vs.initialloc);                    end                  else if (m_delphi in current_settings.modeswitches) and                     (po_assembler in pd.procoptions) and                     (vo_is_funcret in vs.varoptions) and                     (vs.refs=0) then                    begin                      { not referenced, so don't allocate. Use dummy to }                      { avoid ie's later on because of LOC_INVALID      }                      vs.initialloc.loc:=LOC_REGISTER;                      vs.initialloc.size:=OS_INT;                      vs.initialloc.register:=NR_FUNCTION_RESULT_REG;                    end                  else if vs.is_regvar(false) then                    begin                      vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable];                      gen_alloc_regvar(list,vs,true);                    end                  else                    begin                      vs.initialloc.loc:=LOC_REFERENCE;                      tg.GetLocal(list,vs.getsize,vs.vardef,vs.initialloc.reference);                    end;                  setlocalloc(vs);                end;            end;          end;      end;    procedure add_regvars(var rv: tusedregvars; const location: tlocation);      begin        case location.loc of          LOC_CREGISTER:{$if defined(cpu64bitalu)}            if location.size in [OS_128,OS_S128] then              begin                rv.intregvars.addnodup(getsupreg(location.register128.reglo));                rv.intregvars.addnodup(getsupreg(location.register128.reghi));              end            else{$elseif defined(cpu32bitalu)}            if location.size in [OS_64,OS_S64] then              begin                rv.intregvars.addnodup(getsupreg(location.register64.reglo));                rv.intregvars.addnodup(getsupreg(location.register64.reghi));              end            else{$elseif defined(cpu16bitalu)}            if location.size in [OS_64,OS_S64] then              begin                rv.intregvars.addnodup(getsupreg(location.register64.reglo));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register64.reglo)));                rv.intregvars.addnodup(getsupreg(location.register64.reghi));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register64.reghi)));              end            else            if location.size in [OS_32,OS_S32] then              begin                rv.intregvars.addnodup(getsupreg(location.register));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register)));              end            else{$elseif defined(cpu8bitalu)}            if location.size in [OS_64,OS_S64] then              begin                rv.intregvars.addnodup(getsupreg(location.register64.reglo));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register64.reglo)));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(location.register64.reglo))));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(GetNextReg(location.register64.reglo)))));                rv.intregvars.addnodup(getsupreg(location.register64.reghi));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register64.reghi)));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(location.register64.reghi))));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(GetNextReg(location.register64.reghi)))));              end            else            if location.size in [OS_32,OS_S32] then              begin                rv.intregvars.addnodup(getsupreg(location.register));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register)));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(location.register))));                rv.intregvars.addnodup(getsupreg(GetNextReg(GetNextReg(GetNextReg(location.register)))));              end            else            if location.size in [OS_16,OS_S16] then              begin                rv.intregvars.addnodup(getsupreg(location.register));                rv.intregvars.addnodup(getsupreg(GetNextReg(location.register)));              end            else{$endif}              rv.intregvars.addnodup(getsupreg(location.register));          LOC_CFPUREGISTER:            rv.fpuregvars.addnodup(getsupreg(location.register));          LOC_CMMREGISTER:            rv.mmregvars.addnodup(getsupreg(location.register));        end;      end;    function do_get_used_regvars(var n: tnode; arg: pointer): foreachnoderesult;      var        rv: pusedregvars absolute arg;      begin        case (n.nodetype) of          temprefn:            { We only have to synchronise a tempnode before a loop if it is }            { not created inside the loop, and only synchronise after the   }            { loop if it's not destroyed inside the loop. If it's created   }            { before the loop and not yet destroyed, then before the loop   }            { is secondpassed tempinfo^.valid will be true, and we get the  }            { correct registers. If it's not destroyed inside the loop,     }            { then after the loop has been secondpassed tempinfo^.valid     }            { be true and we also get the right registers. In other cases,  }            { tempinfo^.valid will be false and so we do not add            }            { unnecessary registers. This way, we don't have to look at     }            { tempcreate and tempdestroy nodes to get this info (JM)        }            if (ti_valid in ttemprefnode(n).tempinfo^.flags) then              add_regvars(rv^,ttemprefnode(n).tempinfo^.location);          loadn:            if (tloadnode(n).symtableentry.typ in [staticvarsym,localvarsym,paravarsym]) then              add_regvars(rv^,tabstractnormalvarsym(tloadnode(n).symtableentry).localloc);          vecn:            { range checks sometimes need the high parameter }            if (cs_check_range in current_settings.localswitches) and               (is_open_array(tvecnode(n).left.resultdef) or                is_array_of_const(tvecnode(n).left.resultdef)) and               not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then              add_regvars(rv^,tabstractnormalvarsym(get_high_value_sym(tparavarsym(tloadnode(tvecnode(n).left).symtableentry))).localloc)        end;        result := fen_true;      end;    procedure get_used_regvars(n: tnode; var rv: tusedregvars);      begin        foreachnodestatic(n,@do_get_used_regvars,@rv);      end;(*    See comments at declaration of pusedregvarscommon    function do_get_used_regvars_common(var n: tnode; arg: pointer): foreachnoderesult;      var        rv: pusedregvarscommon absolute arg;      begin        if (n.nodetype = loadn) and           (tloadnode(n).symtableentry.typ in [staticvarsym,localvarsym,paravarsym]) then          with tabstractnormalvarsym(tloadnode(n).symtableentry).localloc do            case loc of              LOC_CREGISTER:                  { if not yet encountered in this node tree }                if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and                  { but nevertheless already encountered somewhere }                   not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then                  { then it's a regvar used in two or more node trees }                  rv^.commonregvars.intregvars.addnodup(getsupreg(register));              LOC_CFPUREGISTER:                if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and                   not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then                  rv^.commonregvars.intregvars.addnodup(getsupreg(register));              LOC_CMMREGISTER:                if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and                   not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then                  rv^.commonregvars.intregvars.addnodup(getsupreg(register));            end;        result := fen_true;      end;    procedure get_used_regvars_common(n: tnode; var rv: tusedregvarscommon);      begin        rv.myregvars.intregvars.clear;        rv.myregvars.fpuregvars.clear;        rv.myregvars.mmregvars.clear;        foreachnodestatic(n,@do_get_used_regvars_common,@rv);      end;*)    procedure gen_sync_regvars(list:TAsmList; var rv: tusedregvars);      var        count: longint;      begin        for count := 1 to rv.intregvars.length do          cg.a_reg_sync(list,newreg(R_INTREGISTER,rv.intregvars.readidx(count-1),R_SUBWHOLE));        for count := 1 to rv.fpuregvars.length do          cg.a_reg_sync(list,newreg(R_FPUREGISTER,rv.fpuregvars.readidx(count-1),R_SUBWHOLE));        for count := 1 to rv.mmregvars.length do          cg.a_reg_sync(list,newreg(R_MMREGISTER,rv.mmregvars.readidx(count-1),R_SUBWHOLE));      end;    procedure gen_free_symtable(list:TAsmList;st:TSymtable);      var        i   : longint;        sym : tsym;      begin        for i:=0 to st.SymList.Count-1 do          begin            sym:=tsym(st.SymList[i]);            if (sym.typ in [staticvarsym,localvarsym,paravarsym]) then              begin                with tabstractnormalvarsym(sym) do                  begin                    { Note: We need to keep the data available in memory                      for the sub procedures that can access local data                      in the parent procedures }                    case localloc.loc of                      LOC_CREGISTER :                        if (pi_has_label in current_procinfo.flags) then{$if defined(cpu64bitalu)}                          if def_cgsize(vardef) in [OS_128,OS_S128] then                            begin                              cg.a_reg_sync(list,localloc.register128.reglo);                              cg.a_reg_sync(list,localloc.register128.reghi);                            end                          else{$elseif defined(cpu32bitalu)}                          if def_cgsize(vardef) in [OS_64,OS_S64] then                            begin                              cg.a_reg_sync(list,localloc.register64.reglo);                              cg.a_reg_sync(list,localloc.register64.reghi);                            end                          else{$elseif defined(cpu16bitalu)}                          if def_cgsize(vardef) in [OS_64,OS_S64] then                            begin                              cg.a_reg_sync(list,localloc.register64.reglo);                              cg.a_reg_sync(list,GetNextReg(localloc.register64.reglo));                              cg.a_reg_sync(list,localloc.register64.reghi);                              cg.a_reg_sync(list,GetNextReg(localloc.register64.reghi));                            end                          else                          if def_cgsize(vardef) in [OS_32,OS_S32] then                            begin                              cg.a_reg_sync(list,localloc.register);                              cg.a_reg_sync(list,GetNextReg(localloc.register));                            end                          else{$elseif defined(cpu8bitalu)}                          if def_cgsize(vardef) in [OS_64,OS_S64] then                            begin                              cg.a_reg_sync(list,localloc.register64.reglo);                              cg.a_reg_sync(list,GetNextReg(localloc.register64.reglo));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(localloc.register64.reglo)));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(localloc.register64.reglo))));                              cg.a_reg_sync(list,localloc.register64.reghi);                              cg.a_reg_sync(list,GetNextReg(localloc.register64.reghi));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(localloc.register64.reghi)));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(localloc.register64.reghi))));                            end                          else                          if def_cgsize(vardef) in [OS_32,OS_S32] then                            begin                              cg.a_reg_sync(list,localloc.register);                              cg.a_reg_sync(list,GetNextReg(localloc.register));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(localloc.register)));                              cg.a_reg_sync(list,GetNextReg(GetNextReg(GetNextReg(localloc.register))));                            end                          else                          if def_cgsize(vardef) in [OS_16,OS_S16] then                            begin                              cg.a_reg_sync(list,localloc.register);                              cg.a_reg_sync(list,GetNextReg(localloc.register));                            end                          else{$endif}                            cg.a_reg_sync(list,localloc.register);                      LOC_CFPUREGISTER,                      LOC_CMMREGISTER:                        if (pi_has_label in current_procinfo.flags) then                          cg.a_reg_sync(list,localloc.register);                      LOC_REFERENCE :                        begin                          if typ in [localvarsym,paravarsym] then                            tg.Ungetlocal(list,localloc.reference);                        end;                    end;                  end;              end;          end;      end;    procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);      var        href : treference;        selfdef: tdef;      begin        if is_object(objdef) then          begin            case selfloc.loc of              LOC_CREFERENCE,              LOC_REFERENCE:                begin                  hlcg.reference_reset_base(href,voidpointertype,hlcg.getaddressregister(list,voidpointertype),objdef.vmt_offset,voidpointertype.size);                  hlcg.a_loadaddr_ref_reg(list,voidpointertype,voidpointertype,selfloc.reference,href.base);                  selfdef:=getpointerdef(objdef);                end;              else                internalerror(200305056);            end;          end        else          { This is also valid for Objective-C classes: vmt_offset is 0 there,            and the first "field" of an Objective-C class instance is a pointer            to its "meta-class".  }          begin            selfdef:=objdef;            case selfloc.loc of              LOC_REGISTER:                begin{$ifdef cpu_uses_separate_address_registers}                  if getregtype(left.location.register)<>R_ADDRESSREGISTER then                    begin                      reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset,sizeof(pint));                      cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,selfloc.register,href.base);                    end                  else{$endif cpu_uses_separate_address_registers}                    hlcg.reference_reset_base(href,voidpointertype,selfloc.register,objdef.vmt_offset,voidpointertype.size);                end;              LOC_CONSTANT,              LOC_CREGISTER,              LOC_CREFERENCE,              LOC_REFERENCE,              LOC_CSUBSETREG,              LOC_SUBSETREG,              LOC_CSUBSETREF,              LOC_SUBSETREF:                begin                  hlcg.reference_reset_base(href,voidpointertype,hlcg.getaddressregister(list,voidpointertype),objdef.vmt_offset,voidpointertype.size);                  { todo: pass actual vmt pointer type to hlcg }                  hlcg.a_load_loc_reg(list,voidpointertype,voidpointertype,selfloc,href.base);                end;              else                internalerror(200305057);            end;          end;        vmtreg:=hlcg.getaddressregister(list,voidpointertype);        hlcg.g_maybe_testself(list,selfdef,href.base);        hlcg.a_load_ref_reg(list,voidpointertype,voidpointertype,href,vmtreg);        { test validity of VMT }        if not(is_interface(objdef)) and           not(is_cppclass(objdef)) and           not(is_objc_class_or_protocol(objdef)) then           cg.g_maybe_testvmt(list,vmtreg,objdef);      end;    function getprocalign : shortint;      begin        { gprof uses 16 byte granularity }        if (cs_profile in current_settings.moduleswitches) then          result:=16        else         result:=current_settings.alignment.procalign;      end;    procedure gen_fpc_dummy(list : TAsmList);      begin{$ifdef i386}        { fix me! }        list.concat(Taicpu.Op_const_reg(A_MOV,S_L,1,NR_EAX));        list.concat(Taicpu.Op_const(A_RET,S_W,12));{$endif i386}      end;    procedure gen_load_frame_for_exceptfilter(list : TAsmList);      var        para: tparavarsym;      begin        para:=tparavarsym(current_procinfo.procdef.paras[0]);        if not (vo_is_parentfp in para.varoptions) then          InternalError(201201142);        if (para.paraloc[calleeside].location^.loc<>LOC_REGISTER) or          (para.paraloc[calleeside].location^.next<>nil) then          InternalError(201201143);        cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,para.paraloc[calleeside].location^.register,          NR_FRAME_POINTER_REG);      end;end.
 |