diff --git a/compiler/i386/n386mem.pas b/compiler/i386/n386mem.pas index ebc0f5dd6b..bab38422de 100644 --- a/compiler/i386/n386mem.pas +++ b/compiler/i386/n386mem.pas @@ -27,6 +27,7 @@ unit n386mem; interface uses + cpuinfo,cpubase, node,nmem,ncgmem; type @@ -39,6 +40,7 @@ interface end; ti386vecnode = class(tcgvecnode) + procedure update_reference_reg_mul(reg:tregister;l:aword);override; procedure pass_2;override; end; @@ -54,7 +56,6 @@ implementation aasmbase,aasmtai,aasmcpu, cginfo,cgbase,pass_2, pass_1,nld,ncon,nadd, - cpubase, cgobj,cga,tgobj,rgobj,ncgutil; {***************************************************************************** @@ -99,404 +100,52 @@ implementation TI386VECNODE *****************************************************************************} - procedure ti386vecnode.pass_2; - - procedure calc_emit_mul; - var - l1,l2 : longint; + procedure ti386vecnode.update_reference_reg_mul(reg:tregister;l:aword); + var + l2 : integer; + begin + { Optimized for x86 to use the index register and scalefactor } + if location.reference.index=R_NO then begin - l1:=get_mul_size; - case l1 of - 1,2,4,8 : location.reference.scalefactor:=l1; - else - begin - if ispowerof2(l1,l2) then - emit_const_reg(A_SHL,S_L,l2,right.location.register) - else - emit_const_reg(A_IMUL,S_L,l1,right.location.register); - end; + { no preparations needed } + end + else if location.reference.base=R_NO then + begin + case location.reference.scalefactor of + 2 : cg.a_op_const_reg(exprasmlist,OP_SHL,1,location.reference.index); + 4 : cg.a_op_const_reg(exprasmlist,OP_SHL,2,location.reference.index); + 8 : cg.a_op_const_reg(exprasmlist,OP_SHL,3,location.reference.index); end; + location.reference.base:=location.reference.index; + end + else + begin + cg.a_loadaddr_ref_reg(exprasmlist,location.reference,location.reference.base); + rg.ungetregisterint(exprasmlist,location.reference.index); + reference_reset_base(location.reference,location.reference.base,0); end; - - var - extraoffset : longint; - { rl stores the resulttype.def of the left node, this is necessary } - { to detect if it is an ansistring } - { because in constant nodes which constant index } - { the left tree is removed } - t : tnode; - href : treference; - srsym : tsym; - pushed : tpushedsaved; - hightree : tnode; - isjump : boolean; - otl,ofl : tasmlabel; - newsize : tcgsize; - pushedregs : tmaybesave; - begin - newsize:=def_cgsize(resulttype.def); - location_reset(location,LOC_REFERENCE,newsize); - - secondpass(left); - { we load the array reference to location } - - { an ansistring needs to be dereferenced } - if is_ansistring(left.resulttype.def) or - is_widestring(left.resulttype.def) then - begin - if nf_callunique in flags then - begin - if left.location.loc<>LOC_REFERENCE then - begin - CGMessage(cg_e_illegal_expression); - exit; - end; - rg.saveusedregisters(exprasmlist,pushed,all_registers); - cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(1)); - rg.saveregvars(exprasmlist,all_registers); - cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_UNIQUE'); - cg.g_maybe_loadself(exprasmlist); - rg.restoreusedregisters(exprasmlist,pushed); - end; - - case left.location.loc of - LOC_REGISTER, - LOC_CREGISTER : - location.reference.base:=left.location.register; - LOC_CREFERENCE, - LOC_REFERENCE : - begin - location_release(exprasmlist,left.location); - location.reference.base:=rg.getregisterint(exprasmlist); - cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.reference.base); - end; - else - internalerror(2002032218); - end; - - { check for a zero length string, - we can use the ansistring routine here } - if (cs_check_range in aktlocalswitches) then - begin - rg.saveusedregisters(exprasmlist,pushed,all_registers); - cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,paramanager.getintparaloc(1)); - rg.saveregvars(exprasmlist,all_registers); - cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO'); - cg.g_maybe_loadself(exprasmlist); - rg.restoreusedregisters(exprasmlist,pushed); - end; - - { in ansistrings/widestrings S[1] is pchar(S)[0] !! } - if is_ansistring(left.resulttype.def) then - dec(location.reference.offset) - else - dec(location.reference.offset,2); - - { we've also to keep left up-to-date, because it is used } - { if a constant array index occurs, subject to change (FK) } - location_copy(left.location,location); - end - else if is_dynamic_array(left.resulttype.def) then - { ... also a dynamic string } - begin - case left.location.loc of - LOC_REGISTER, - LOC_CREGISTER : - location.reference.base:=left.location.register; - LOC_REFERENCE, - LOC_CREFERENCE : - begin - location_release(exprasmlist,left.location); - location.reference.base:=rg.getregisterint(exprasmlist); - emit_ref_reg(A_MOV,S_L, - left.location.reference,location.reference.base); - end; - else - internalerror(2002032219); - end; - -{$warning FIXME} - { check for a zero length string, - we can use the ansistring routine here } - if (cs_check_range in aktlocalswitches) then - begin - rg.saveusedregisters(exprasmlist,pushed,all_registers); - emit_reg(A_PUSH,S_L,location.reference.base); - rg.saveregvars(exprasmlist,all_registers); - cg.a_call_name(exprasmlist,'FPC_ANSISTR_CHECKZERO'); - cg.g_maybe_loadself(exprasmlist); - rg.restoreusedregisters(exprasmlist,pushed); - end; - - { we've also to keep left up-to-date, because it is used } - { if a constant array index occurs, subject to change (FK) } - location_copy(left.location,location); - end + { insert the new index register and scalefactor or + do the multiplication manual } + case l of + 1,2,4,8 : location.reference.scalefactor:=l; else - location_copy(location,left.location); - - { offset can only differ from 0 if arraydef } - if (left.resulttype.def.deftype=arraydef) and - not(is_dynamic_array(left.resulttype.def)) then - dec(location.reference.offset, - get_mul_size*tarraydef(left.resulttype.def).lowrange); - if right.nodetype=ordconstn then begin - { offset can only differ from 0 if arraydef } - if (left.resulttype.def.deftype=arraydef) then - begin - if not(is_open_array(left.resulttype.def)) and - not(is_array_of_const(left.resulttype.def)) and - not(is_dynamic_array(left.resulttype.def)) then - begin - if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or - (tordconstnode(right).valuetarraydef(left.resulttype.def).highrange) or - (tordconstnode(right).valuetarraydef(left.resulttype.def).highrange) or + (tordconstnode(right).value