cgcpu.pas 138 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the i8086
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cgbase,cgobj,cg64f32,cgx86,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. cpubase,parabase,cgutils,
  25. symconst,symdef
  26. ;
  27. type
  28. { tcg8086 }
  29. tcg8086 = class(tcgx86)
  30. procedure init_register_allocators;override;
  31. procedure do_register_allocation(list:TAsmList;headertai:tai);override;
  32. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  33. procedure a_call_name_far(list : TAsmList;const s : string; weak: boolean);
  34. procedure a_call_name_static(list : TAsmList;const s : string);override;
  35. procedure a_call_name_static_far(list : TAsmList;const s : string);
  36. procedure a_call_reg(list : TAsmList;reg : tregister);override;
  37. procedure a_call_reg_far(list : TAsmList;reg : tregister);
  38. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  39. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  42. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  43. procedure push_const(list:TAsmList;size:tcgsize;a:tcgint);
  44. { passing parameter using push instead of mov }
  45. procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  46. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
  47. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  48. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
  49. { move instructions }
  50. procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
  51. procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
  52. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  53. { use a_load_ref_reg_internal() instead }
  54. //procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  55. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  56. { comparison operations }
  57. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  58. l : tasmlabel);override;
  59. procedure a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  60. l : tasmlabel);override;
  61. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  62. procedure a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  63. procedure a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg : tregister; const ref: treference; l : tasmlabel); override;
  64. procedure gen_cmp32_jmp1(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  65. procedure gen_cmp32_jmp2(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);override;
  67. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);override;
  68. procedure g_stackpointer_alloc(list : TAsmList;localsize: longint);override;
  69. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  70. procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  71. procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  72. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);override;
  73. procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
  74. procedure add_move_instruction(instr:Taicpu);override;
  75. protected
  76. procedure a_load_ref_reg_internal(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister;isdirect:boolean);override;
  77. end;
  78. tcg64f8086 = class(tcg64f32)
  79. procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
  80. procedure a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);override;
  81. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  82. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  83. procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
  84. private
  85. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  86. end;
  87. procedure create_codegen;
  88. implementation
  89. uses
  90. globals,verbose,systems,cutils,
  91. paramgr,procinfo,fmodule,
  92. rgcpu,rgx86,cpuinfo,
  93. symtype,symsym,symcpu,
  94. tgobj,
  95. hlcgobj;
  96. { Range check must be disabled explicitly as the code uses
  97. implicit typecast to aint troughout }
  98. {$R-}
  99. function use_push(const cgpara:tcgpara):boolean;
  100. begin
  101. result:=(not paramanager.use_fixed_stack) and
  102. assigned(cgpara.location) and
  103. (cgpara.location^.loc=LOC_REFERENCE) and
  104. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  105. end;
  106. procedure tcg8086.init_register_allocators;
  107. begin
  108. inherited init_register_allocators;
  109. if cs_create_pic in current_settings.moduleswitches then
  110. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI],first_int_imreg,[RS_BP])
  111. else
  112. if (cs_useebp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer<>NR_BP) then
  113. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI,RS_BP],first_int_imreg,[])
  114. else
  115. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI],first_int_imreg,[RS_BP]);
  116. rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  117. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBWHOLE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  118. rgfpu:=Trgx86fpu.create;
  119. end;
  120. procedure tcg8086.do_register_allocation(list:TAsmList;headertai:tai);
  121. begin
  122. if (pi_needs_got in current_procinfo.flags) then
  123. begin
  124. if getsupreg(current_procinfo.got) < first_int_imreg then
  125. include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
  126. end;
  127. inherited do_register_allocation(list,headertai);
  128. end;
  129. procedure tcg8086.a_call_name(list: TAsmList; const s: string; weak: boolean);
  130. begin
  131. if current_settings.x86memorymodel in x86_far_code_models then
  132. a_call_name_far(list,s,weak)
  133. else
  134. a_call_name_near(list,s,weak);
  135. end;
  136. procedure tcg8086.a_call_name_far(list: TAsmList; const s: string;
  137. weak: boolean);
  138. var
  139. sym : tasmsymbol;
  140. begin
  141. if not(weak) then
  142. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION)
  143. else
  144. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION);
  145. list.concat(taicpu.op_sym(A_CALL,S_FAR,sym));
  146. end;
  147. procedure tcg8086.a_call_name_static(list: TAsmList; const s: string);
  148. begin
  149. if current_settings.x86memorymodel in x86_far_code_models then
  150. a_call_name_static_far(list,s)
  151. else
  152. a_call_name_static_near(list,s);
  153. end;
  154. procedure tcg8086.a_call_name_static_far(list: TAsmList; const s: string);
  155. var
  156. sym : tasmsymbol;
  157. begin
  158. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  159. list.concat(taicpu.op_sym(A_CALL,S_FAR,sym));
  160. end;
  161. procedure tcg8086.a_call_reg(list: TAsmList; reg: tregister);
  162. begin
  163. if current_settings.x86memorymodel in x86_far_code_models then
  164. a_call_reg_far(list,reg)
  165. else
  166. a_call_reg_near(list,reg);
  167. end;
  168. procedure tcg8086.a_call_reg_far(list: TAsmList; reg: tregister);
  169. var
  170. href: treference;
  171. begin
  172. { unfortunately, x86 doesn't have a 'call far reg:reg' instruction, so }
  173. { we have to use a temp }
  174. tg.gettemp(list,4,2,tt_normal,href);
  175. { HACK!!! at this point all registers are allocated, due to the fact that
  176. in the pascal calling convention, all registers are caller saved. This
  177. causes the register allocator to fail on the next move instruction, so we
  178. temporarily deallocate 2 registers.
  179. TODO: figure out a better way to do this. }
  180. cg.ungetcpuregister(list,NR_BX);
  181. cg.ungetcpuregister(list,NR_SI);
  182. a_load_reg_ref(list,OS_32,OS_32,reg,href);
  183. cg.getcpuregister(list,NR_BX);
  184. cg.getcpuregister(list,NR_SI);
  185. href.segment:=NR_NO;
  186. list.concat(taicpu.op_ref(A_CALL,S_FAR,href));
  187. tg.ungettemp(list,href);
  188. end;
  189. procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  190. a: tcgint; reg: TRegister);
  191. type
  192. trox32method=(rm_unspecified,rm_unrolledleftloop,rm_unrolledrightloop,
  193. rm_loopleft,rm_loopright,rm_fast_386);
  194. var
  195. tmpreg: tregister;
  196. op1, op2: TAsmOp;
  197. ax_subreg: tregister;
  198. hl_loop_start: tasmlabel;
  199. ai: taicpu;
  200. use_loop, use_186_fast_shift, use_8086_fast_shift,
  201. use_386_fast_shift: Boolean;
  202. rox32method: trox32method=rm_unspecified;
  203. i: Integer;
  204. rol_amount, ror_amount: TCGInt;
  205. begin
  206. optimize_op_const(size, op, a);
  207. check_register_size(size,reg);
  208. if size in [OS_64, OS_S64] then
  209. internalerror(2013030904);
  210. if size in [OS_32, OS_S32] then
  211. begin
  212. case op of
  213. OP_NONE:
  214. begin
  215. { Opcode is optimized away }
  216. end;
  217. OP_MOVE:
  218. begin
  219. { Optimized, replaced with a simple load }
  220. a_load_const_reg(list,size,a,reg);
  221. end;
  222. OP_ADD, OP_SUB:
  223. begin
  224. get_32bit_ops(op, op1, op2);
  225. { Optimization when the low 16-bits of the constant are 0 }
  226. if aint(a and $FFFF) = 0 then
  227. begin
  228. { use a_op_const_reg to allow the use of inc/dec }
  229. a_op_const_reg(list,op,OS_16,aint(a shr 16),GetNextReg(reg));
  230. end
  231. else
  232. begin
  233. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  234. list.concat(taicpu.op_const_reg(op1,S_W,aint(a and $FFFF),reg));
  235. list.concat(taicpu.op_const_reg(op2,S_W,aint(a shr 16),GetNextReg(reg)));
  236. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  237. end;
  238. end;
  239. OP_AND, OP_OR, OP_XOR:
  240. begin
  241. { low word operation }
  242. if aint(a and $FFFF) = aint(0) then
  243. begin
  244. case op of
  245. OP_AND:
  246. a_load_const_reg(list,OS_16,aint(0),reg);
  247. OP_OR,OP_XOR:
  248. {do nothing};
  249. else
  250. InternalError(2013100701);
  251. end;
  252. end
  253. else if aint(a and $FFFF) = aint($FFFF) then
  254. begin
  255. case op of
  256. OP_AND:
  257. {do nothing};
  258. OP_OR:
  259. a_load_const_reg(list,OS_16,aint($FFFF),reg);
  260. OP_XOR:
  261. list.concat(taicpu.op_reg(A_NOT,S_W,reg));
  262. else
  263. InternalError(2013100701);
  264. end;
  265. end
  266. else
  267. a_op_const_reg(list,op,OS_16,aint(a and $FFFF),reg);
  268. { high word operation }
  269. if aint(a shr 16) = aint(0) then
  270. begin
  271. case op of
  272. OP_AND:
  273. a_load_const_reg(list,OS_16,aint(0),GetNextReg(reg));
  274. OP_OR,OP_XOR:
  275. {do nothing};
  276. else
  277. InternalError(2013100701);
  278. end;
  279. end
  280. else if aint(a shr 16) = aint($FFFF) then
  281. begin
  282. case op of
  283. OP_AND:
  284. {do nothing};
  285. OP_OR:
  286. a_load_const_reg(list,OS_16,aint($FFFF),GetNextReg(reg));
  287. OP_XOR:
  288. list.concat(taicpu.op_reg(A_NOT,S_W,GetNextReg(reg)));
  289. else
  290. InternalError(2013100701);
  291. end;
  292. end
  293. else
  294. a_op_const_reg(list,op,OS_16,aint(a shr 16),GetNextReg(reg));
  295. end;
  296. OP_SHR,OP_SHL,OP_SAR:
  297. begin
  298. a:=a and 31;
  299. { for shl with const >= 16, we can just move the low register
  300. to the high reg, then zero the low register, then do the
  301. remaining part of the shift (by const-16) in 16 bit on the
  302. high register. the same thing applies to shr with low and high
  303. reversed. sar is exactly like shr, except that instead of
  304. zeroing the high register, we sar it by 15. }
  305. if a>=16 then
  306. case op of
  307. OP_SHR:
  308. begin
  309. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  310. a_load_const_reg(list,OS_16,0,GetNextReg(reg));
  311. a_op_const_reg(list,OP_SHR,OS_16,a-16,reg);
  312. end;
  313. OP_SHL:
  314. begin
  315. a_load_reg_reg(list,OS_16,OS_16,reg,GetNextReg(reg));
  316. a_load_const_reg(list,OS_16,0,reg);
  317. a_op_const_reg(list,OP_SHL,OS_16,a-16,GetNextReg(reg));
  318. end;
  319. OP_SAR:
  320. begin
  321. if a=31 then
  322. begin
  323. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  324. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  325. end
  326. else
  327. begin
  328. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  329. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  330. a_op_const_reg(list,OP_SAR,OS_16,a-16,reg);
  331. end;
  332. end;
  333. else
  334. internalerror(2013060201);
  335. end
  336. else if a<>0 then
  337. begin
  338. use_loop:=a>2;
  339. use_386_fast_shift:=(current_settings.cputype>=cpu_386) and (a>1);
  340. use_186_fast_shift:=not use_386_fast_shift
  341. and (current_settings.cputype>=cpu_186) and (a>2)
  342. and not (cs_opt_size in current_settings.optimizerswitches);
  343. use_8086_fast_shift:=(current_settings.cputype<cpu_186) and (a>2)
  344. and not (cs_opt_size in current_settings.optimizerswitches);
  345. if use_386_fast_shift then
  346. begin
  347. case op of
  348. OP_SHR:
  349. begin
  350. list.concat(taicpu.op_const_reg_reg(A_SHRD,S_W,a,GetNextReg(reg),reg));
  351. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,GetNextReg(reg)));
  352. end;
  353. OP_SAR:
  354. begin
  355. list.concat(taicpu.op_const_reg_reg(A_SHRD,S_W,a,GetNextReg(reg),reg));
  356. list.concat(taicpu.op_const_reg(A_SAR,S_W,a,GetNextReg(reg)));
  357. end;
  358. OP_SHL:
  359. begin
  360. list.concat(taicpu.op_const_reg_reg(A_SHLD,S_W,a,reg,GetNextReg(reg)));
  361. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,reg));
  362. end;
  363. else
  364. internalerror(2017040401);
  365. end;
  366. end
  367. else if use_186_fast_shift then
  368. begin
  369. tmpreg:=getintregister(list,OS_16);
  370. case op of
  371. OP_SHR:
  372. begin
  373. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  374. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,GetNextReg(reg)));
  375. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,reg));
  376. list.concat(taicpu.op_const_reg(A_SHL,S_W,16-a,tmpreg));
  377. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  378. end;
  379. OP_SAR:
  380. begin
  381. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  382. list.concat(taicpu.op_const_reg(A_SAR,S_W,a,GetNextReg(reg)));
  383. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,reg));
  384. list.concat(taicpu.op_const_reg(A_SHL,S_W,16-a,tmpreg));
  385. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  386. end;
  387. OP_SHL:
  388. begin
  389. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  390. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,reg));
  391. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,GetNextReg(reg)));
  392. list.concat(taicpu.op_const_reg(A_SHR,S_W,16-a,tmpreg));
  393. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,GetNextReg(reg)));
  394. end;
  395. else
  396. internalerror(2017040301);
  397. end;
  398. end
  399. else if use_8086_fast_shift then
  400. begin
  401. getcpuregister(list,NR_CX);
  402. a_load_const_reg(list,OS_8,a,NR_CL);
  403. tmpreg:=getintregister(list,OS_16);
  404. case op of
  405. OP_SHR:
  406. begin
  407. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  408. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,GetNextReg(reg)));
  409. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,reg));
  410. if a<>8 then
  411. a_load_const_reg(list,OS_8,16-a,NR_CL);
  412. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,tmpreg));
  413. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  414. end;
  415. OP_SAR:
  416. begin
  417. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  418. list.concat(taicpu.op_reg_reg(A_SAR,S_W,NR_CL,GetNextReg(reg)));
  419. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,reg));
  420. if a<>8 then
  421. a_load_const_reg(list,OS_8,16-a,NR_CL);
  422. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,tmpreg));
  423. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  424. end;
  425. OP_SHL:
  426. begin
  427. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  428. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,reg));
  429. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,GetNextReg(reg)));
  430. if a<>8 then
  431. a_load_const_reg(list,OS_8,16-a,NR_CL);
  432. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,tmpreg));
  433. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,GetNextReg(reg)));
  434. end;
  435. else
  436. internalerror(2017040301);
  437. end;
  438. ungetcpuregister(list,NR_CX);
  439. end
  440. else if use_loop then
  441. begin
  442. getcpuregister(list,NR_CX);
  443. a_load_const_reg(list,OS_16,a,NR_CX);
  444. current_asmdata.getjumplabel(hl_loop_start);
  445. a_label(list,hl_loop_start);
  446. case op of
  447. OP_SHR:
  448. begin
  449. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  450. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  451. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  452. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  453. end;
  454. OP_SAR:
  455. begin
  456. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  457. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  458. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  459. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  460. end;
  461. OP_SHL:
  462. begin
  463. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  464. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  465. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  466. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  467. end;
  468. else
  469. internalerror(2013030903);
  470. end;
  471. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  472. ai.is_jmp:=true;
  473. list.concat(ai);
  474. ungetcpuregister(list,NR_CX);
  475. end
  476. else
  477. begin
  478. for i:=1 to a do
  479. begin
  480. case op of
  481. OP_SHR:
  482. begin
  483. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  484. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  485. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  486. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  487. end;
  488. OP_SAR:
  489. begin
  490. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  491. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  492. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  493. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  494. end;
  495. OP_SHL:
  496. begin
  497. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  498. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  499. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  500. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  501. end;
  502. else
  503. internalerror(2013030903);
  504. end;
  505. end;
  506. end;
  507. end;
  508. end;
  509. OP_ROL,OP_ROR:
  510. begin
  511. a:=a and 31;
  512. if a=0 then
  513. exit;
  514. if op=OP_ROL then
  515. begin
  516. rol_amount:=a;
  517. ror_amount:=32-a;
  518. end
  519. else
  520. begin
  521. rol_amount:=32-a;
  522. ror_amount:=a;
  523. end;
  524. case rol_amount of
  525. 1,17:
  526. rox32method:=rm_unrolledleftloop;
  527. 2,18:
  528. if current_settings.cputype>=cpu_386 then
  529. rox32method:=rm_fast_386
  530. else if not (cs_opt_size in current_settings.optimizerswitches) then
  531. rox32method:=rm_unrolledleftloop
  532. else
  533. rox32method:=rm_loopleft;
  534. 3..8,19..24:
  535. if current_settings.cputype>=cpu_386 then
  536. rox32method:=rm_fast_386
  537. else
  538. rox32method:=rm_loopleft;
  539. 15,31:
  540. rox32method:=rm_unrolledrightloop;
  541. 14,30:
  542. if current_settings.cputype>=cpu_386 then
  543. rox32method:=rm_fast_386
  544. else if not (cs_opt_size in current_settings.optimizerswitches) then
  545. rox32method:=rm_unrolledrightloop
  546. else
  547. { the left loop has a smaller size }
  548. rox32method:=rm_loopleft;
  549. 9..13,25..29:
  550. if current_settings.cputype>=cpu_386 then
  551. rox32method:=rm_fast_386
  552. else if not (cs_opt_size in current_settings.optimizerswitches) then
  553. rox32method:=rm_loopright
  554. else
  555. { the left loop has a smaller size }
  556. rox32method:=rm_loopleft;
  557. 16:
  558. rox32method:=rm_unrolledleftloop;
  559. else
  560. internalerror(2017040601);
  561. end;
  562. case rox32method of
  563. rm_unrolledleftloop:
  564. begin
  565. if rol_amount>=16 then
  566. begin
  567. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  568. dec(rol_amount,16);
  569. end;
  570. for i:=1 to rol_amount do
  571. begin
  572. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  573. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(reg)));
  574. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,reg));
  575. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(reg)));
  576. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  577. end;
  578. end;
  579. rm_unrolledrightloop:
  580. begin
  581. if ror_amount>=16 then
  582. begin
  583. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  584. dec(ror_amount,16);
  585. end;
  586. tmpreg:=getintregister(list,OS_16);
  587. for i:=1 to ror_amount do
  588. begin
  589. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  590. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  591. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  592. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(reg)));
  593. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  594. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  595. end;
  596. end;
  597. rm_loopleft:
  598. begin
  599. if (rol_amount>=16) and not (cs_opt_size in current_settings.optimizerswitches) then
  600. begin
  601. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  602. dec(rol_amount,16);
  603. if rol_amount=0 then
  604. exit;
  605. end;
  606. getcpuregister(list,NR_CX);
  607. a_load_const_reg(list,OS_16,rol_amount,NR_CX);
  608. current_asmdata.getjumplabel(hl_loop_start);
  609. a_label(list,hl_loop_start);
  610. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  611. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(reg)));
  612. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,reg));
  613. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(reg)));
  614. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  615. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  616. ai.is_jmp:=true;
  617. list.concat(ai);
  618. ungetcpuregister(list,NR_CX);
  619. end;
  620. rm_loopright:
  621. begin
  622. if (ror_amount>=16) and not (cs_opt_size in current_settings.optimizerswitches) then
  623. begin
  624. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  625. dec(ror_amount,16);
  626. if ror_amount=0 then
  627. exit;
  628. end;
  629. getcpuregister(list,NR_CX);
  630. a_load_const_reg(list,OS_16,ror_amount,NR_CX);
  631. current_asmdata.getjumplabel(hl_loop_start);
  632. a_label(list,hl_loop_start);
  633. tmpreg:=getintregister(list,OS_16);
  634. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  635. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  636. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  637. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(reg)));
  638. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  639. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  640. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  641. ai.is_jmp:=true;
  642. list.concat(ai);
  643. ungetcpuregister(list,NR_CX);
  644. end;
  645. rm_fast_386:
  646. begin
  647. tmpreg:=getintregister(list,OS_16);
  648. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  649. if op=OP_ROL then
  650. begin
  651. list.Concat(taicpu.op_const_reg_reg(A_SHLD,S_W,rol_amount,reg,GetNextReg(reg)));
  652. list.Concat(taicpu.op_const_reg_reg(A_SHLD,S_W,rol_amount,tmpreg,reg));
  653. end
  654. else
  655. begin
  656. list.Concat(taicpu.op_const_reg_reg(A_SHRD,S_W,ror_amount,reg,GetNextReg(reg)));
  657. list.Concat(taicpu.op_const_reg_reg(A_SHRD,S_W,ror_amount,tmpreg,reg));
  658. end;
  659. end;
  660. else
  661. internalerror(2017040602);
  662. end;
  663. end;
  664. else
  665. begin
  666. tmpreg:=getintregister(list,size);
  667. a_load_const_reg(list,size,a,tmpreg);
  668. a_op_reg_reg(list,op,size,tmpreg,reg);
  669. end;
  670. end;
  671. end
  672. else
  673. begin
  674. { size <= 16-bit }
  675. { 8086 doesn't support 'imul reg,const', so we handle it here }
  676. if (current_settings.cputype<cpu_186) and (op in [OP_MUL,OP_IMUL]) then
  677. begin
  678. if op = OP_IMUL then
  679. begin
  680. if size in [OS_16,OS_S16] then
  681. ax_subreg := NR_AX
  682. else
  683. if size in [OS_8,OS_S8] then
  684. ax_subreg := NR_AL
  685. else
  686. internalerror(2013050102);
  687. getcpuregister(list,NR_AX);
  688. a_load_const_reg(list,size,a,ax_subreg);
  689. if size in [OS_16,OS_S16] then
  690. getcpuregister(list,NR_DX);
  691. { prefer MUL over IMUL when overflow checking is off, }
  692. { because it's faster on the 8086 & 8088 }
  693. if not (cs_check_overflow in current_settings.localswitches) then
  694. list.concat(taicpu.op_reg(A_MUL,TCgSize2OpSize[size],reg))
  695. else
  696. list.concat(taicpu.op_reg(A_IMUL,TCgSize2OpSize[size],reg));
  697. if size in [OS_16,OS_S16] then
  698. ungetcpuregister(list,NR_DX);
  699. a_load_reg_reg(list,size,size,ax_subreg,reg);
  700. ungetcpuregister(list,NR_AX);
  701. exit;
  702. end
  703. else
  704. { OP_MUL should be handled specifically in the code }
  705. { generator because of the silly register usage restraints }
  706. internalerror(200109225);
  707. end
  708. else
  709. inherited a_op_const_reg(list, Op, size, a, reg);
  710. end;
  711. end;
  712. procedure tcg8086.a_op_const_ref(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  713. var
  714. tmpref: treference;
  715. op1,op2: TAsmOp;
  716. tmpreg: TRegister;
  717. begin
  718. optimize_op_const(size, op, a);
  719. tmpref:=ref;
  720. make_simple_ref(list,tmpref);
  721. if size in [OS_64, OS_S64] then
  722. internalerror(2013050801);
  723. if size in [OS_32, OS_S32] then
  724. begin
  725. case Op of
  726. OP_NONE :
  727. begin
  728. { Opcode is optimized away }
  729. end;
  730. OP_MOVE :
  731. begin
  732. { Optimized, replaced with a simple load }
  733. a_load_const_ref(list,size,a,ref);
  734. end;
  735. OP_ADD, OP_SUB:
  736. begin
  737. get_32bit_ops(op, op1, op2);
  738. { Optimization when the low 16-bits of the constant are 0 }
  739. if aint(a and $FFFF) = 0 then
  740. begin
  741. inc(tmpref.offset, 2);
  742. { use a_op_const_ref to allow the use of inc/dec }
  743. a_op_const_ref(list,op,OS_16,aint(a shr 16),tmpref);
  744. end
  745. else
  746. begin
  747. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  748. list.concat(taicpu.op_const_ref(op1,S_W,aint(a and $FFFF),tmpref));
  749. inc(tmpref.offset, 2);
  750. list.concat(taicpu.op_const_ref(op2,S_W,aint(a shr 16),tmpref));
  751. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  752. end;
  753. end;
  754. OP_AND, OP_OR, OP_XOR:
  755. begin
  756. { low word operation }
  757. if aint(a and $FFFF) = aint(0) then
  758. begin
  759. case op of
  760. OP_AND:
  761. a_load_const_ref(list,OS_16,aint(0),ref);
  762. OP_OR,OP_XOR:
  763. {do nothing};
  764. else
  765. InternalError(2013100701);
  766. end;
  767. end
  768. else if aint(a and $FFFF) = aint($FFFF) then
  769. begin
  770. case op of
  771. OP_AND:
  772. {do nothing};
  773. OP_OR:
  774. a_load_const_ref(list,OS_16,aint($FFFF),tmpref);
  775. OP_XOR:
  776. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  777. else
  778. InternalError(2013100701);
  779. end;
  780. end
  781. else
  782. a_op_const_ref(list,op,OS_16,aint(a and $FFFF),tmpref);
  783. { high word operation }
  784. inc(tmpref.offset, 2);
  785. if aint(a shr 16) = aint(0) then
  786. begin
  787. case op of
  788. OP_AND:
  789. a_load_const_ref(list,OS_16,aint(0),tmpref);
  790. OP_OR,OP_XOR:
  791. {do nothing};
  792. else
  793. InternalError(2013100701);
  794. end;
  795. end
  796. else if aint(a shr 16) = aint($FFFF) then
  797. begin
  798. case op of
  799. OP_AND:
  800. {do nothing};
  801. OP_OR:
  802. a_load_const_ref(list,OS_16,aint($FFFF),tmpref);
  803. OP_XOR:
  804. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  805. else
  806. InternalError(2013100701);
  807. end;
  808. end
  809. else
  810. a_op_const_ref(list,op,OS_16,aint(a shr 16),tmpref);
  811. end;
  812. OP_SHR,OP_SHL,OP_SAR:
  813. begin
  814. a:=a and 31;
  815. if a=1 then
  816. begin
  817. case op of
  818. OP_SHR:
  819. begin
  820. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  821. inc(tmpref.offset, 2);
  822. list.concat(taicpu.op_const_ref(A_SHR,S_W,1,tmpref));
  823. dec(tmpref.offset, 2);
  824. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  825. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  826. end;
  827. OP_SAR:
  828. begin
  829. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  830. inc(tmpref.offset, 2);
  831. list.concat(taicpu.op_const_ref(A_SAR,S_W,1,tmpref));
  832. dec(tmpref.offset, 2);
  833. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  834. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  835. end;
  836. OP_SHL:
  837. begin
  838. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  839. list.concat(taicpu.op_const_ref(A_SHL,S_W,1,tmpref));
  840. inc(tmpref.offset, 2);
  841. list.concat(taicpu.op_const_ref(A_RCL,S_W,1,tmpref));
  842. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  843. end;
  844. else
  845. internalerror(2015042501);
  846. end;
  847. end
  848. else
  849. begin
  850. tmpreg:=getintregister(list,size);
  851. a_load_ref_reg(list,size,size,ref,tmpreg);
  852. a_op_const_reg(list,Op,size,a,tmpreg);
  853. a_load_reg_ref(list,size,size,tmpreg,ref);
  854. end;
  855. end;
  856. OP_ROL,OP_ROR:
  857. begin
  858. tmpreg:=getintregister(list,size);
  859. a_load_ref_reg(list,size,size,ref,tmpreg);
  860. a_op_const_reg(list,Op,size,a,tmpreg);
  861. a_load_reg_ref(list,size,size,tmpreg,ref);
  862. end;
  863. else
  864. internalerror(2013050802);
  865. end;
  866. end
  867. else
  868. inherited a_op_const_ref(list,Op,size,a,tmpref);
  869. end;
  870. procedure tcg8086.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  871. src, dst: TRegister);
  872. var
  873. op1, op2: TAsmOp;
  874. hl_skip, hl_loop_start: TAsmLabel;
  875. ai: taicpu;
  876. tmpreg: TRegister;
  877. begin
  878. check_register_size(size,src);
  879. check_register_size(size,dst);
  880. if size in [OS_64, OS_S64] then
  881. internalerror(2013030902);
  882. if size in [OS_32, OS_S32] then
  883. begin
  884. case op of
  885. OP_NEG:
  886. begin
  887. if src<>dst then
  888. a_load_reg_reg(list,size,size,src,dst);
  889. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  890. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  891. list.concat(taicpu.op_reg(A_NEG, S_W, dst));
  892. list.concat(taicpu.op_const_reg(A_SBB, S_W,-1, GetNextReg(dst)));
  893. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  894. end;
  895. OP_NOT:
  896. begin
  897. if src<>dst then
  898. a_load_reg_reg(list,size,size,src,dst);
  899. list.concat(taicpu.op_reg(A_NOT, S_W, dst));
  900. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  901. end;
  902. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  903. begin
  904. get_32bit_ops(op, op1, op2);
  905. if op in [OP_ADD,OP_SUB] then
  906. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  907. list.concat(taicpu.op_reg_reg(op1, S_W, src, dst));
  908. list.concat(taicpu.op_reg_reg(op2, S_W, GetNextReg(src), GetNextReg(dst)));
  909. if op in [OP_ADD,OP_SUB] then
  910. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  911. end;
  912. OP_SHR,OP_SHL,OP_SAR:
  913. begin
  914. getcpuregister(list,NR_CX);
  915. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  916. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  917. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  918. current_asmdata.getjumplabel(hl_skip);
  919. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  920. ai.SetCondition(C_Z);
  921. ai.is_jmp:=true;
  922. list.concat(ai);
  923. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  924. current_asmdata.getjumplabel(hl_loop_start);
  925. a_label(list,hl_loop_start);
  926. case op of
  927. OP_SHR:
  928. begin
  929. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  930. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(dst)));
  931. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  932. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  933. end;
  934. OP_SAR:
  935. begin
  936. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  937. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(dst)));
  938. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  939. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  940. end;
  941. OP_SHL:
  942. begin
  943. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  944. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,dst));
  945. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(dst)));
  946. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  947. end;
  948. else
  949. internalerror(2013030903);
  950. end;
  951. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  952. ai.is_jmp:=true;
  953. list.concat(ai);
  954. a_label(list,hl_skip);
  955. ungetcpuregister(list,NR_CX);
  956. end;
  957. OP_ROL,OP_ROR:
  958. begin
  959. getcpuregister(list,NR_CX);
  960. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  961. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  962. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  963. current_asmdata.getjumplabel(hl_skip);
  964. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  965. ai.SetCondition(C_Z);
  966. ai.is_jmp:=true;
  967. list.concat(ai);
  968. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  969. current_asmdata.getjumplabel(hl_loop_start);
  970. a_label(list,hl_loop_start);
  971. case op of
  972. OP_ROL:
  973. begin
  974. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  975. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(dst)));
  976. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,dst));
  977. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(dst)));
  978. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  979. end;
  980. OP_ROR:
  981. begin
  982. tmpreg:=getintregister(list,OS_16);
  983. a_load_reg_reg(list,OS_16,OS_16,dst,tmpreg);
  984. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  985. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  986. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(dst)));
  987. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  988. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  989. end;
  990. else
  991. internalerror(2017042502);
  992. end;
  993. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  994. ai.is_jmp:=true;
  995. list.concat(ai);
  996. a_label(list,hl_skip);
  997. ungetcpuregister(list,NR_CX);
  998. end;
  999. else
  1000. internalerror(2013030901);
  1001. end;
  1002. end
  1003. else
  1004. inherited a_op_reg_reg(list, Op, size, src, dst);
  1005. end;
  1006. procedure tcg8086.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  1007. var
  1008. tmpref : treference;
  1009. op1, op2: TAsmOp;
  1010. begin
  1011. tmpref:=ref;
  1012. make_simple_ref(list,tmpref);
  1013. check_register_size(size,reg);
  1014. if size in [OS_64, OS_S64] then
  1015. internalerror(2013030902);
  1016. if size in [OS_32, OS_S32] then
  1017. begin
  1018. case op of
  1019. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  1020. begin
  1021. get_32bit_ops(op, op1, op2);
  1022. if op in [OP_ADD,OP_SUB] then
  1023. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1024. list.concat(taicpu.op_ref_reg(op1, S_W, tmpref, reg));
  1025. inc(tmpref.offset, 2);
  1026. list.concat(taicpu.op_ref_reg(op2, S_W, tmpref, GetNextReg(reg)));
  1027. if op in [OP_ADD,OP_SUB] then
  1028. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1029. end;
  1030. else
  1031. internalerror(2013050701);
  1032. end;
  1033. end
  1034. else
  1035. inherited a_op_ref_reg(list,Op,size,tmpref,reg);
  1036. end;
  1037. procedure tcg8086.a_op_reg_ref(list: TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference);
  1038. var
  1039. tmpref: treference;
  1040. op1,op2: TAsmOp;
  1041. hl_skip, hl_loop_start: TAsmLabel;
  1042. ai: taicpu;
  1043. tmpreg: TRegister;
  1044. begin
  1045. tmpref:=ref;
  1046. make_simple_ref(list,tmpref);
  1047. if not (op in [OP_NEG,OP_NOT,OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR]) then
  1048. check_register_size(size,reg);
  1049. if size in [OS_64, OS_S64] then
  1050. internalerror(2013050803);
  1051. if size in [OS_32, OS_S32] then
  1052. begin
  1053. case op of
  1054. OP_NEG:
  1055. begin
  1056. if reg<>NR_NO then
  1057. internalerror(200109237);
  1058. inc(tmpref.offset, 2);
  1059. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1060. dec(tmpref.offset, 2);
  1061. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1062. list.concat(taicpu.op_ref(A_NEG, S_W, tmpref));
  1063. inc(tmpref.offset, 2);
  1064. list.concat(taicpu.op_const_ref(A_SBB, S_W,-1, tmpref));
  1065. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1066. end;
  1067. OP_NOT:
  1068. begin
  1069. if reg<>NR_NO then
  1070. internalerror(200109237);
  1071. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1072. inc(tmpref.offset, 2);
  1073. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1074. end;
  1075. OP_IMUL:
  1076. begin
  1077. { this one needs a load/imul/store, which is the default }
  1078. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  1079. end;
  1080. OP_MUL,OP_DIV,OP_IDIV:
  1081. { special stuff, needs separate handling inside code }
  1082. { generator }
  1083. internalerror(200109238);
  1084. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  1085. begin
  1086. get_32bit_ops(op, op1, op2);
  1087. if op in [OP_ADD,OP_SUB] then
  1088. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1089. list.concat(taicpu.op_reg_ref(op1, S_W, reg, tmpref));
  1090. inc(tmpref.offset, 2);
  1091. list.concat(taicpu.op_reg_ref(op2, S_W, GetNextReg(reg), tmpref));
  1092. if op in [OP_ADD,OP_SUB] then
  1093. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1094. end;
  1095. OP_SHR,OP_SHL,OP_SAR:
  1096. begin
  1097. getcpuregister(list,NR_CX);
  1098. a_load_reg_reg(list,size,OS_16,reg,NR_CX);
  1099. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1100. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  1101. current_asmdata.getjumplabel(hl_skip);
  1102. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  1103. ai.SetCondition(C_Z);
  1104. ai.is_jmp:=true;
  1105. list.concat(ai);
  1106. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1107. current_asmdata.getjumplabel(hl_loop_start);
  1108. a_label(list,hl_loop_start);
  1109. case op of
  1110. OP_SHR:
  1111. begin
  1112. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1113. inc(tmpref.offset, 2);
  1114. list.concat(taicpu.op_const_ref(A_SHR,S_W,1,tmpref));
  1115. dec(tmpref.offset, 2);
  1116. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  1117. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1118. end;
  1119. OP_SAR:
  1120. begin
  1121. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1122. inc(tmpref.offset, 2);
  1123. list.concat(taicpu.op_const_ref(A_SAR,S_W,1,tmpref));
  1124. dec(tmpref.offset, 2);
  1125. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  1126. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1127. end;
  1128. OP_SHL:
  1129. begin
  1130. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1131. list.concat(taicpu.op_const_ref(A_SHL,S_W,1,tmpref));
  1132. inc(tmpref.offset, 2);
  1133. list.concat(taicpu.op_const_ref(A_RCL,S_W,1,tmpref));
  1134. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1135. end;
  1136. else
  1137. internalerror(2013030903);
  1138. end;
  1139. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  1140. ai.is_jmp:=true;
  1141. list.concat(ai);
  1142. a_label(list,hl_skip);
  1143. ungetcpuregister(list,NR_CX);
  1144. end;
  1145. OP_ROL,OP_ROR:
  1146. begin
  1147. tmpreg:=getintregister(list,size);
  1148. a_load_ref_reg(list,size,size,ref,tmpreg);
  1149. a_op_reg_reg(list,Op,size,reg,tmpreg);
  1150. a_load_reg_ref(list,size,size,tmpreg,ref);
  1151. end;
  1152. else
  1153. internalerror(2013050804);
  1154. end;
  1155. end
  1156. else
  1157. inherited a_op_reg_ref(list,Op,size,reg,tmpref);
  1158. end;
  1159. procedure tcg8086.push_const(list: TAsmList; size: tcgsize; a: tcgint);
  1160. var
  1161. tmpreg: TRegister;
  1162. begin
  1163. if not (size in [OS_16,OS_S16]) then
  1164. internalerror(2013043001);
  1165. if current_settings.cputype < cpu_186 then
  1166. begin
  1167. tmpreg:=getintregister(list,size);
  1168. a_load_const_reg(list,size,a,tmpreg);
  1169. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1170. end
  1171. else
  1172. list.concat(taicpu.op_const(A_PUSH,TCGSize2OpSize[size],a));
  1173. end;
  1174. procedure tcg8086.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  1175. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  1176. var
  1177. ref : treference;
  1178. begin
  1179. paramanager.allocparaloc(list,paraloc);
  1180. case paraloc^.loc of
  1181. LOC_REGISTER,LOC_CREGISTER:
  1182. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  1183. LOC_REFERENCE,LOC_CREFERENCE:
  1184. begin
  1185. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]);
  1186. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  1187. end;
  1188. else
  1189. internalerror(2002071004);
  1190. end;
  1191. end;
  1192. var
  1193. pushsize,pushsize2 : tcgsize;
  1194. begin
  1195. check_register_size(size,r);
  1196. if use_push(cgpara) then
  1197. begin
  1198. if tcgsize2size[cgpara.Size] > 2 then
  1199. begin
  1200. if tcgsize2size[cgpara.Size] <> 4 then
  1201. internalerror(2013031101);
  1202. if cgpara.location^.Next = nil then
  1203. begin
  1204. if tcgsize2size[cgpara.location^.size] <> 4 then
  1205. internalerror(2013031101);
  1206. end
  1207. else
  1208. begin
  1209. if tcgsize2size[cgpara.location^.size] <> 2 then
  1210. internalerror(2013031101);
  1211. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1212. internalerror(2013031101);
  1213. if cgpara.location^.Next^.Next <> nil then
  1214. internalerror(2013031101);
  1215. end;
  1216. if tcgsize2size[cgpara.size]>cgpara.alignment then
  1217. pushsize:=cgpara.size
  1218. else
  1219. pushsize:=int_cgsize(cgpara.alignment);
  1220. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  1221. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  1222. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  1223. end
  1224. else
  1225. begin
  1226. cgpara.check_simple_location;
  1227. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  1228. pushsize:=cgpara.location^.size
  1229. else
  1230. pushsize:=int_cgsize(cgpara.alignment);
  1231. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  1232. end;
  1233. end
  1234. else
  1235. begin
  1236. if tcgsize2size[cgpara.Size]=4 then
  1237. begin
  1238. if (cgpara.location^.Next=nil) or
  1239. (tcgsize2size[cgpara.location^.size]<>2) or
  1240. (tcgsize2size[cgpara.location^.Next^.size]<>2) or
  1241. (cgpara.location^.Next^.Next<>nil) or
  1242. (cgpara.location^.shiftval<>0) then
  1243. internalerror(2013031102);
  1244. load_para_loc(r,cgpara.Location);
  1245. load_para_loc(GetNextReg(r),cgpara.Location^.Next);
  1246. end
  1247. else
  1248. inherited a_load_reg_cgpara(list,size,r,cgpara);
  1249. end;
  1250. end;
  1251. procedure tcg8086.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
  1252. var
  1253. pushsize : tcgsize;
  1254. begin
  1255. if use_push(cgpara) then
  1256. begin
  1257. if tcgsize2size[cgpara.Size] > 2 then
  1258. begin
  1259. if tcgsize2size[cgpara.Size] <> 4 then
  1260. internalerror(2013031101);
  1261. if cgpara.location^.Next = nil then
  1262. begin
  1263. if tcgsize2size[cgpara.location^.size] <> 4 then
  1264. internalerror(2013031101);
  1265. end
  1266. else
  1267. begin
  1268. if tcgsize2size[cgpara.location^.size] <> 2 then
  1269. internalerror(2013031101);
  1270. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1271. internalerror(2013031101);
  1272. if cgpara.location^.Next^.Next <> nil then
  1273. internalerror(2013031101);
  1274. end;
  1275. if (cgpara.alignment <> 4) and (cgpara.alignment <> 2) then
  1276. internalerror(2013031101);
  1277. push_const(list,OS_16,a shr 16);
  1278. push_const(list,OS_16,a and $FFFF);
  1279. end
  1280. else
  1281. begin
  1282. cgpara.check_simple_location;
  1283. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  1284. pushsize:=cgpara.location^.size
  1285. else
  1286. pushsize:=int_cgsize(cgpara.alignment);
  1287. push_const(list,pushsize,a);
  1288. end;
  1289. end
  1290. else if (tcgsize2size[cgpara.Size]>2) and
  1291. (cgpara.location^.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  1292. (cgpara.location^.Next<>nil) then
  1293. begin
  1294. if (tcgsize2size[cgpara.Size]<>4) or
  1295. (tcgsize2size[cgpara.location^.Size]<>2) or
  1296. not (cgpara.location^.Next^.Loc in [LOC_REGISTER,LOC_CREGISTER]) or
  1297. (tcgsize2size[cgpara.location^.Next^.Size]<>2) or
  1298. (cgpara.location^.Next^.Next<>nil) then
  1299. internalerror(2018041801);
  1300. a_load_const_reg(list,cgpara.location^.size,a and $FFFF,cgpara.location^.register);
  1301. a_load_const_reg(list,cgpara.location^.Next^.size,a shr 16,cgpara.location^.Next^.register);
  1302. end
  1303. else
  1304. inherited a_load_const_cgpara(list,size,a,cgpara);
  1305. end;
  1306. procedure tcg8086.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
  1307. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  1308. var
  1309. pushsize : tcgsize;
  1310. opsize : topsize;
  1311. tmpreg : tregister;
  1312. href,tmpref: treference;
  1313. begin
  1314. if not assigned(paraloc) then
  1315. exit;
  1316. if (paraloc^.loc<>LOC_REFERENCE) or
  1317. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  1318. (tcgsize2size[paraloc^.size]>4) then
  1319. internalerror(200501162);
  1320. { Pushes are needed in reverse order, add the size of the
  1321. current location to the offset where to load from. This
  1322. prevents wrong calculations for the last location when
  1323. the size is not a power of 2 }
  1324. if assigned(paraloc^.next) then
  1325. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  1326. { Push the data starting at ofs }
  1327. href:=r;
  1328. inc(href.offset,ofs);
  1329. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  1330. pushsize:=paraloc^.size
  1331. else
  1332. pushsize:=int_cgsize(cgpara.alignment);
  1333. opsize:=TCgsize2opsize[pushsize];
  1334. { for go32v2 we obtain OS_F32,
  1335. but pushs is not valid, we need pushl }
  1336. if opsize=S_FS then
  1337. opsize:=S_W;
  1338. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  1339. begin
  1340. tmpreg:=getintregister(list,pushsize);
  1341. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  1342. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  1343. end
  1344. else
  1345. begin
  1346. make_simple_ref(list,href);
  1347. if tcgsize2size[pushsize] > 2 then
  1348. begin
  1349. tmpref := href;
  1350. Inc(tmpref.offset, 2);
  1351. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  1352. end;
  1353. list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  1354. end;
  1355. end;
  1356. var
  1357. len : tcgint;
  1358. href : treference;
  1359. begin
  1360. { cgpara.size=OS_NO requires a copy on the stack }
  1361. if use_push(cgpara) then
  1362. begin
  1363. { Record copy? }
  1364. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  1365. begin
  1366. cgpara.check_simple_location;
  1367. len:=align(cgpara.intsize,cgpara.alignment);
  1368. g_stackpointer_alloc(list,len);
  1369. reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
  1370. g_concatcopy(list,r,href,len);
  1371. end
  1372. else
  1373. begin
  1374. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  1375. internalerror(200501161);
  1376. { We need to push the data in reverse order,
  1377. therefor we use a recursive algorithm }
  1378. pushdata(cgpara.location,0);
  1379. end
  1380. end
  1381. else
  1382. inherited a_load_ref_cgpara(list,size,r,cgpara);
  1383. end;
  1384. procedure tcg8086.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
  1385. var
  1386. tmpreg : tregister;
  1387. tmpref : treference;
  1388. begin
  1389. with r do
  1390. begin
  1391. if use_push(cgpara) then
  1392. begin
  1393. if tcgsize2size[cgpara.Size] > 2 then
  1394. begin
  1395. if tcgsize2size[cgpara.Size] <> 4 then
  1396. internalerror(2014032401);
  1397. if cgpara.location^.Next = nil then
  1398. begin
  1399. if tcgsize2size[cgpara.location^.size] <> 4 then
  1400. internalerror(2014032401);
  1401. end
  1402. else
  1403. begin
  1404. if tcgsize2size[cgpara.location^.size] <> 2 then
  1405. internalerror(2014032401);
  1406. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1407. internalerror(2014032401);
  1408. if cgpara.location^.Next^.Next <> nil then
  1409. internalerror(2014032401);
  1410. end;
  1411. if cgpara.alignment > 4 then
  1412. internalerror(2014032401);
  1413. if segment<>NR_NO then
  1414. begin
  1415. list.concat(Taicpu.op_reg(A_PUSH,S_W,segment));
  1416. tmpref:=r;
  1417. tmpref.segment:=NR_NO;
  1418. tmpreg:=getaddressregister(list);
  1419. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1420. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1421. end
  1422. else
  1423. begin
  1424. if (base=NR_NO) and (index=NR_NO) then
  1425. begin
  1426. if assigned(symbol) then
  1427. begin
  1428. tmpref:=r;
  1429. tmpref.refaddr:=addr_seg;
  1430. tmpref.offset:=0;
  1431. if current_settings.cputype < cpu_186 then
  1432. begin
  1433. tmpreg:=getaddressregister(list);
  1434. a_load_ref_reg(list,OS_16,OS_16,tmpref,tmpreg);
  1435. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1436. end
  1437. else
  1438. list.concat(Taicpu.Op_ref(A_PUSH,S_W,tmpref));
  1439. if current_settings.cputype < cpu_186 then
  1440. begin
  1441. tmpreg:=getaddressregister(list);
  1442. a_loadaddr_ref_reg(list,r,tmpreg);
  1443. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1444. end
  1445. else
  1446. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_W,symbol,offset));
  1447. end
  1448. else
  1449. internalerror(2014032402);
  1450. end
  1451. else if assigned(symbol) then
  1452. begin
  1453. reference_reset_symbol(tmpref,r.symbol,0,r.alignment,r.volatility);
  1454. tmpref.refaddr:=addr_seg;
  1455. if current_settings.cputype < cpu_186 then
  1456. begin
  1457. tmpreg:=getaddressregister(list);
  1458. a_load_ref_reg(list,OS_16,OS_16,tmpref,tmpreg);
  1459. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1460. end
  1461. else
  1462. list.concat(Taicpu.Op_ref(A_PUSH,S_W,tmpref));
  1463. tmpreg:=getaddressregister(list);
  1464. a_loadaddr_ref_reg(list,r,tmpreg);
  1465. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1466. end
  1467. else if base=NR_BP then
  1468. begin
  1469. list.concat(Taicpu.op_reg(A_PUSH,S_W,NR_SS));
  1470. tmpreg:=getaddressregister(list);
  1471. a_loadaddr_ref_reg(list,r,tmpreg);
  1472. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1473. end
  1474. else
  1475. internalerror(2014032403);
  1476. end;
  1477. end
  1478. else
  1479. begin
  1480. cgpara.check_simple_location;
  1481. tmpref:=r;
  1482. tmpref.segment:=NR_NO;
  1483. with tmpref do
  1484. begin
  1485. if (base=NR_NO) and (index=NR_NO) then
  1486. begin
  1487. if assigned(symbol) then
  1488. begin
  1489. if current_settings.cputype < cpu_186 then
  1490. begin
  1491. tmpreg:=getaddressregister(list);
  1492. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1493. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1494. end
  1495. else
  1496. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_W,symbol,offset));
  1497. end
  1498. else
  1499. push_const(list,OS_16,offset);
  1500. end
  1501. else if (base=NR_NO) and (index<>NR_NO) and
  1502. (offset=0) and (scalefactor=0) and (symbol=nil) then
  1503. list.concat(Taicpu.Op_reg(A_PUSH,S_W,index))
  1504. else if (base<>NR_NO) and (index=NR_NO) and
  1505. (offset=0) and (symbol=nil) then
  1506. list.concat(Taicpu.Op_reg(A_PUSH,S_W,base))
  1507. else
  1508. begin
  1509. tmpreg:=getaddressregister(list);
  1510. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1511. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1512. end;
  1513. end;
  1514. end;
  1515. end
  1516. else
  1517. inherited a_loadaddr_ref_cgpara(list,r,cgpara);
  1518. end;
  1519. end;
  1520. procedure tcg8086.a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);
  1521. begin
  1522. check_register_size(tosize,reg);
  1523. if tosize in [OS_S32,OS_32] then
  1524. begin
  1525. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a and $ffff),reg));
  1526. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a shr 16),GetNextReg(reg)));
  1527. end
  1528. else
  1529. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg));
  1530. end;
  1531. procedure tcg8086.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
  1532. var
  1533. tmpref : treference;
  1534. begin
  1535. tmpref:=ref;
  1536. make_simple_ref(list,tmpref);
  1537. if tosize in [OS_S32,OS_32] then
  1538. begin
  1539. a_load_const_ref(list,OS_16,longint(a and $ffff),tmpref);
  1540. inc(tmpref.offset,2);
  1541. a_load_const_ref(list,OS_16,longint(a shr 16),tmpref);
  1542. end
  1543. else
  1544. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
  1545. end;
  1546. procedure tcg8086.a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);
  1547. var
  1548. tmpreg : tregister;
  1549. tmpref : treference;
  1550. begin
  1551. tmpref:=ref;
  1552. make_simple_ref(list,tmpref);
  1553. check_register_size(fromsize,reg);
  1554. case tosize of
  1555. OS_8,OS_S8:
  1556. if fromsize in [OS_8,OS_S8] then
  1557. list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
  1558. else
  1559. internalerror(2013030310);
  1560. OS_16,OS_S16:
  1561. case fromsize of
  1562. OS_8,OS_S8:
  1563. begin
  1564. tmpreg:=getintregister(list,tosize);
  1565. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  1566. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  1567. end;
  1568. OS_16,OS_S16:
  1569. begin
  1570. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1571. end;
  1572. else
  1573. internalerror(2013030312);
  1574. end;
  1575. OS_32,OS_S32:
  1576. case fromsize of
  1577. OS_8,OS_S8,OS_S16:
  1578. begin
  1579. tmpreg:=getintregister(list,tosize);
  1580. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  1581. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  1582. end;
  1583. OS_16:
  1584. begin
  1585. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1586. inc(tmpref.offset, 2);
  1587. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  1588. end;
  1589. OS_32,OS_S32:
  1590. begin
  1591. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1592. inc(tmpref.offset, 2);
  1593. list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
  1594. end;
  1595. else
  1596. internalerror(2013030313);
  1597. end;
  1598. else
  1599. internalerror(2013030311);
  1600. end;
  1601. end;
  1602. procedure tcg8086.a_load_ref_reg_internal(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister;isdirect:boolean);
  1603. procedure add_mov(instr: Taicpu);
  1604. begin
  1605. { Notify the register allocator that we have written a move instruction so
  1606. it can try to eliminate it. }
  1607. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1608. add_move_instruction(instr);
  1609. list.concat(instr);
  1610. end;
  1611. var
  1612. tmpref : treference;
  1613. begin
  1614. tmpref:=ref;
  1615. make_simple_ref(list,tmpref,isdirect);
  1616. check_register_size(tosize,reg);
  1617. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1618. internalerror(2011021307);
  1619. { if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1620. fromsize:=tosize;}
  1621. case tosize of
  1622. OS_8,OS_S8:
  1623. if fromsize in [OS_8,OS_S8] then
  1624. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
  1625. else
  1626. internalerror(2013030210);
  1627. OS_16,OS_S16:
  1628. case fromsize of
  1629. OS_8:
  1630. begin
  1631. if current_settings.cputype>=cpu_386 then
  1632. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1633. else
  1634. begin
  1635. reg := makeregsize(list, reg, OS_8);
  1636. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1637. setsubreg(reg, R_SUBH);
  1638. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1639. makeregsize(list, reg, OS_16);
  1640. end;
  1641. end;
  1642. OS_S8:
  1643. begin
  1644. if current_settings.cputype>=cpu_386 then
  1645. list.concat(taicpu.op_ref_reg(A_MOVSX, S_BW, tmpref, reg))
  1646. else
  1647. begin
  1648. getcpuregister(list, NR_AX);
  1649. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1650. list.concat(taicpu.op_none(A_CBW));
  1651. ungetcpuregister(list, NR_AX);
  1652. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1653. end;
  1654. end;
  1655. OS_16,OS_S16:
  1656. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1657. else
  1658. internalerror(2013030212);
  1659. end;
  1660. OS_32,OS_S32:
  1661. case fromsize of
  1662. OS_8:
  1663. begin
  1664. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1665. if current_settings.cputype>=cpu_386 then
  1666. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1667. else
  1668. begin
  1669. reg := makeregsize(list, reg, OS_8);
  1670. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1671. setsubreg(reg, R_SUBH);
  1672. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1673. makeregsize(list, reg, OS_16);
  1674. end;
  1675. end;
  1676. OS_S8:
  1677. begin
  1678. getcpuregister(list, NR_AX);
  1679. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1680. getcpuregister(list, NR_DX);
  1681. list.concat(taicpu.op_none(A_CBW));
  1682. list.concat(taicpu.op_none(A_CWD));
  1683. ungetcpuregister(list, NR_AX);
  1684. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1685. ungetcpuregister(list, NR_DX);
  1686. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1687. end;
  1688. OS_16:
  1689. begin
  1690. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1691. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1692. end;
  1693. OS_S16:
  1694. begin
  1695. getcpuregister(list, NR_AX);
  1696. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  1697. getcpuregister(list, NR_DX);
  1698. list.concat(taicpu.op_none(A_CWD));
  1699. ungetcpuregister(list, NR_AX);
  1700. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1701. ungetcpuregister(list, NR_DX);
  1702. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1703. end;
  1704. OS_32,OS_S32:
  1705. begin
  1706. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1707. inc(tmpref.offset, 2);
  1708. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  1709. end;
  1710. else
  1711. internalerror(2013030213);
  1712. end;
  1713. else
  1714. internalerror(2013030211);
  1715. end;
  1716. end;
  1717. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  1718. procedure add_mov(instr: Taicpu);
  1719. begin
  1720. { Notify the register allocator that we have written a move instruction so
  1721. it can try to eliminate it. }
  1722. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1723. add_move_instruction(instr);
  1724. list.concat(instr);
  1725. end;
  1726. begin
  1727. check_register_size(fromsize,reg1);
  1728. check_register_size(tosize,reg2);
  1729. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1730. begin
  1731. if tosize in [OS_32, OS_S32] then
  1732. internalerror(2013031801);
  1733. reg1:=makeregsize(list,reg1,tosize);
  1734. fromsize:=tosize;
  1735. end;
  1736. if (reg1<>reg2) or (fromsize<>tosize) then
  1737. begin
  1738. case tosize of
  1739. OS_8,OS_S8:
  1740. if fromsize in [OS_8,OS_S8] then
  1741. begin
  1742. if reg1<>reg2 then
  1743. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1744. end
  1745. else
  1746. internalerror(2013030210);
  1747. OS_16,OS_S16:
  1748. case fromsize of
  1749. OS_8:
  1750. begin
  1751. if current_settings.cputype>=cpu_386 then
  1752. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1753. else
  1754. begin
  1755. reg2 := makeregsize(list, reg2, OS_8);
  1756. if reg1<>reg2 then
  1757. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1758. setsubreg(reg2,R_SUBH);
  1759. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1760. makeregsize(list, reg2, OS_16);
  1761. end;
  1762. end;
  1763. OS_S8:
  1764. begin
  1765. if current_settings.cputype>=cpu_386 then
  1766. add_mov(taicpu.op_reg_reg(A_MOVSX, S_BW, reg1, reg2))
  1767. else
  1768. begin
  1769. getcpuregister(list, NR_AX);
  1770. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1771. list.concat(taicpu.op_none(A_CBW));
  1772. ungetcpuregister(list, NR_AX);
  1773. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1774. end;
  1775. end;
  1776. OS_16,OS_S16:
  1777. begin
  1778. if reg1<>reg2 then
  1779. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1780. end
  1781. else
  1782. internalerror(2013030212);
  1783. end;
  1784. OS_32,OS_S32:
  1785. case fromsize of
  1786. OS_8:
  1787. begin
  1788. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
  1789. if current_settings.cputype>=cpu_386 then
  1790. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1791. else
  1792. begin
  1793. reg2 := makeregsize(list, reg2, OS_8);
  1794. if reg1<>reg2 then
  1795. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1796. setsubreg(reg2,R_SUBH);
  1797. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1798. makeregsize(list, reg2, OS_16);
  1799. end;
  1800. end;
  1801. OS_S8:
  1802. begin
  1803. getcpuregister(list, NR_AX);
  1804. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1805. getcpuregister(list, NR_DX);
  1806. list.concat(taicpu.op_none(A_CBW));
  1807. list.concat(taicpu.op_none(A_CWD));
  1808. ungetcpuregister(list, NR_AX);
  1809. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1810. ungetcpuregister(list, NR_DX);
  1811. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1812. end;
  1813. OS_16:
  1814. begin
  1815. if reg1<>reg2 then
  1816. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1817. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1818. end;
  1819. OS_S16:
  1820. begin
  1821. getcpuregister(list, NR_AX);
  1822. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1823. getcpuregister(list, NR_DX);
  1824. list.concat(taicpu.op_none(A_CWD));
  1825. ungetcpuregister(list, NR_AX);
  1826. if reg1<>reg2 then
  1827. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1828. ungetcpuregister(list, NR_DX);
  1829. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1830. end;
  1831. OS_32,OS_S32:
  1832. begin
  1833. if reg1<>reg2 then
  1834. begin
  1835. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1836. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1837. end;
  1838. end;
  1839. else
  1840. internalerror(2013030213);
  1841. end;
  1842. else
  1843. internalerror(2013030211);
  1844. end;
  1845. end;
  1846. end;
  1847. procedure tcg8086.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1848. var
  1849. hl_skip: TAsmLabel;
  1850. begin
  1851. if size in [OS_32, OS_S32] then
  1852. begin
  1853. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1854. if (longint(a shr 16) = 0) then
  1855. list.concat(taicpu.op_reg_reg(A_TEST,S_W,GetNextReg(reg),GetNextReg(reg)))
  1856. else
  1857. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a shr 16),GetNextReg(reg)));
  1858. current_asmdata.getjumplabel(hl_skip);
  1859. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1860. if (longint(a and $ffff) = 0) then
  1861. list.concat(taicpu.op_reg_reg(A_TEST,S_W,reg,reg))
  1862. else
  1863. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a and $ffff),reg));
  1864. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1865. a_label(list,hl_skip);
  1866. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1867. end
  1868. else
  1869. inherited a_cmp_const_reg_label(list, size, cmp_op, a, reg, l);
  1870. end;
  1871. procedure tcg8086.a_cmp_const_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
  1872. var
  1873. tmpref: treference;
  1874. hl_skip: TAsmLabel;
  1875. begin
  1876. if size in [OS_32, OS_S32] then
  1877. begin
  1878. tmpref:=ref;
  1879. make_simple_ref(list,tmpref);
  1880. inc(tmpref.offset,2);
  1881. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1882. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a shr 16),tmpref));
  1883. current_asmdata.getjumplabel(hl_skip);
  1884. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1885. dec(tmpref.offset,2);
  1886. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a and $ffff),tmpref));
  1887. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1888. a_label(list,hl_skip);
  1889. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1890. end
  1891. else
  1892. inherited a_cmp_const_ref_label(list, size, cmp_op, a, ref, l);
  1893. end;
  1894. procedure tcg8086.a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  1895. var
  1896. hl_skip: TAsmLabel;
  1897. begin
  1898. if size in [OS_32, OS_S32] then
  1899. begin
  1900. check_register_size(size,reg1);
  1901. check_register_size(size,reg2);
  1902. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1903. list.concat(taicpu.op_reg_reg(A_CMP,S_W,GetNextReg(reg1),GetNextReg(reg2)));
  1904. current_asmdata.getjumplabel(hl_skip);
  1905. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1906. list.concat(taicpu.op_reg_reg(A_CMP,S_W,reg1,reg2));
  1907. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1908. a_label(list,hl_skip);
  1909. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1910. end
  1911. else
  1912. inherited a_cmp_reg_reg_label(list, size, cmp_op, reg1, reg2, l);
  1913. end;
  1914. procedure tcg8086.a_cmp_ref_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
  1915. var
  1916. tmpref: treference;
  1917. hl_skip: TAsmLabel;
  1918. begin
  1919. if size in [OS_32, OS_S32] then
  1920. begin
  1921. tmpref:=ref;
  1922. make_simple_ref(list,tmpref);
  1923. check_register_size(size,reg);
  1924. inc(tmpref.offset,2);
  1925. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1926. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,GetNextReg(reg)));
  1927. current_asmdata.getjumplabel(hl_skip);
  1928. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1929. dec(tmpref.offset,2);
  1930. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,reg));
  1931. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1932. a_label(list,hl_skip);
  1933. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1934. end
  1935. else
  1936. inherited a_cmp_ref_reg_label(list, size, cmp_op, ref, reg, l);
  1937. end;
  1938. procedure tcg8086.a_cmp_reg_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
  1939. var
  1940. tmpref: treference;
  1941. hl_skip: TAsmLabel;
  1942. begin
  1943. if size in [OS_32, OS_S32] then
  1944. begin
  1945. tmpref:=ref;
  1946. make_simple_ref(list,tmpref);
  1947. check_register_size(size,reg);
  1948. inc(tmpref.offset,2);
  1949. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1950. list.concat(taicpu.op_reg_ref(A_CMP,S_W,GetNextReg(reg),tmpref));
  1951. current_asmdata.getjumplabel(hl_skip);
  1952. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1953. dec(tmpref.offset,2);
  1954. list.concat(taicpu.op_reg_ref(A_CMP,S_W,reg,tmpref));
  1955. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1956. a_label(list,hl_skip);
  1957. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1958. end
  1959. else
  1960. inherited a_cmp_reg_ref_label(list, size, cmp_op, reg, ref, l);
  1961. end;
  1962. procedure tcg8086.gen_cmp32_jmp1(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1963. begin
  1964. case cmp_op of
  1965. OC_EQ:
  1966. a_jmp_cond(list, OC_NE, l_skip);
  1967. OC_NE:
  1968. a_jmp_cond(list, OC_NE, l_target);
  1969. OC_GT,OC_GTE:
  1970. begin
  1971. a_jmp_cond(list, OC_GT, l_target);
  1972. a_jmp_cond(list, OC_LT, l_skip);
  1973. end;
  1974. OC_LT,OC_LTE:
  1975. begin
  1976. a_jmp_cond(list, OC_LT, l_target);
  1977. a_jmp_cond(list, OC_GT, l_skip);
  1978. end;
  1979. OC_B,OC_BE:
  1980. begin
  1981. a_jmp_cond(list, OC_B, l_target);
  1982. a_jmp_cond(list, OC_A, l_skip);
  1983. end;
  1984. OC_A,OC_AE:
  1985. begin
  1986. a_jmp_cond(list, OC_A, l_target);
  1987. a_jmp_cond(list, OC_B, l_skip);
  1988. end;
  1989. else
  1990. internalerror(2014010305);
  1991. end;
  1992. end;
  1993. procedure tcg8086.gen_cmp32_jmp2(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1994. begin
  1995. case cmp_op of
  1996. OC_EQ:
  1997. a_jmp_cond(list, OC_EQ, l_target);
  1998. OC_GT:
  1999. a_jmp_cond(list, OC_A, l_target);
  2000. OC_LT:
  2001. a_jmp_cond(list, OC_B, l_target);
  2002. OC_GTE:
  2003. a_jmp_cond(list, OC_AE, l_target);
  2004. OC_LTE:
  2005. a_jmp_cond(list, OC_BE, l_target);
  2006. OC_NE:
  2007. a_jmp_cond(list, OC_NE, l_target);
  2008. OC_BE:
  2009. a_jmp_cond(list, OC_BE, l_target);
  2010. OC_B:
  2011. a_jmp_cond(list, OC_B, l_target);
  2012. OC_AE:
  2013. a_jmp_cond(list, OC_AE, l_target);
  2014. OC_A:
  2015. a_jmp_cond(list, OC_A, l_target);
  2016. else
  2017. internalerror(2014010306);
  2018. end;
  2019. end;
  2020. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  2021. var
  2022. ai : taicpu;
  2023. hreg16 : tregister;
  2024. hl_skip: TAsmLabel;
  2025. invf: TResFlags;
  2026. tmpsize: TCgSize;
  2027. tmpopsize: topsize;
  2028. begin
  2029. { optimized case for the carry flag, using ADC/RCL }
  2030. if f in [F_C,F_B,F_FB] then
  2031. begin
  2032. case size of
  2033. OS_8,OS_S8:
  2034. begin
  2035. tmpsize:=OS_8;
  2036. tmpopsize:=S_B;
  2037. end;
  2038. OS_16,OS_S16,OS_32,OS_S32:
  2039. begin
  2040. tmpsize:=OS_16;
  2041. tmpopsize:=S_W;
  2042. end;
  2043. else
  2044. internalerror(2013123101);
  2045. end;
  2046. list.concat(Taicpu.op_const_reg(A_MOV, tmpopsize, 0, reg));
  2047. hl_skip:=nil;
  2048. if f=F_FB then
  2049. begin
  2050. current_asmdata.getjumplabel(hl_skip);
  2051. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  2052. ai.SetCondition(C_P);
  2053. ai.is_jmp:=true;
  2054. list.concat(ai);
  2055. end;
  2056. { RCL is faster than ADC on 8086/8088. On the 80286, it is
  2057. equally fast and it also has the same size. In these cases,
  2058. we still prefer it over ADC, because it's a better choice in
  2059. case the register is spilled. }
  2060. if (cs_opt_size in current_settings.optimizerswitches) or
  2061. (current_settings.optimizecputype<=cpu_286) then
  2062. list.concat(Taicpu.op_const_reg(A_RCL, tmpopsize, 1, reg))
  2063. else
  2064. { ADC is much faster on the 386. }
  2065. list.concat(Taicpu.op_reg_reg(A_ADC, tmpopsize, reg, reg));
  2066. if f=F_FB then
  2067. a_label(list,hl_skip);
  2068. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2069. end
  2070. { optimized case for the inverted carry flag, using SBB }
  2071. else if f in [F_NC,F_AE,F_FAE] then
  2072. begin
  2073. case size of
  2074. OS_8,OS_S8:
  2075. begin
  2076. tmpsize:=OS_8;
  2077. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 1, reg));
  2078. list.concat(Taicpu.op_const_reg(A_SBB, S_B, 0, reg));
  2079. end;
  2080. OS_16,OS_S16,OS_32,OS_S32:
  2081. begin
  2082. tmpsize:=OS_16;
  2083. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 1, reg));
  2084. list.concat(Taicpu.op_const_reg(A_SBB, S_W, 0, reg));
  2085. end;
  2086. else
  2087. internalerror(2013123101);
  2088. end;
  2089. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2090. end
  2091. else
  2092. begin
  2093. invf := f;
  2094. inverse_flags(invf);
  2095. case size of
  2096. OS_8,OS_S8:
  2097. begin
  2098. tmpsize:=OS_8;
  2099. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  2100. end;
  2101. OS_16,OS_S16,OS_32,OS_S32:
  2102. begin
  2103. tmpsize:=OS_16;
  2104. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  2105. end;
  2106. else
  2107. internalerror(2013123101);
  2108. end;
  2109. current_asmdata.getjumplabel(hl_skip);
  2110. { we can't just forward invf to a_jmp_flags for FA,FAE,FB and FBE, because
  2111. in the case of NaNs:
  2112. not(F_FA )<>F_FBE
  2113. not(F_FAE)<>F_FB
  2114. not(F_FB )<>F_FAE
  2115. not(F_FBE)<>F_FA
  2116. }
  2117. case f of
  2118. F_FA:
  2119. invf:=FPUFlags2Flags[invf];
  2120. F_FAE,F_FB:
  2121. { F_FAE and F_FB are handled above, using ADC/RCL/SBB }
  2122. internalerror(2015102101);
  2123. F_FBE:
  2124. begin
  2125. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  2126. ai.SetCondition(C_P);
  2127. ai.is_jmp:=true;
  2128. list.concat(ai);
  2129. invf:=FPUFlags2Flags[invf];
  2130. end;
  2131. end;
  2132. a_jmp_flags(list,invf,hl_skip);
  2133. { 16-bit INC is shorter than 8-bit }
  2134. hreg16:=makeregsize(list,reg,OS_16);
  2135. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  2136. makeregsize(list,hreg16,tmpsize);
  2137. a_label(list,hl_skip);
  2138. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2139. end;
  2140. end;
  2141. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  2142. var
  2143. tmpreg : tregister;
  2144. tmpregsize: TCgSize;
  2145. tmpref: treference;
  2146. begin
  2147. if size in [OS_8,OS_S8,OS_16,OS_S16] then
  2148. tmpregsize:=size
  2149. else
  2150. tmpregsize:=OS_16;
  2151. tmpreg:=getintregister(list,tmpregsize);
  2152. g_flags2reg(list,tmpregsize,f,tmpreg);
  2153. tmpref:=ref;
  2154. make_simple_ref(list,tmpref);
  2155. if size in [OS_64,OS_S64] then
  2156. begin
  2157. a_load_reg_ref(list,tmpregsize,OS_32,tmpreg,tmpref);
  2158. inc(tmpref.offset,4);
  2159. a_load_const_ref(list,OS_32,0,tmpref);
  2160. end
  2161. else
  2162. a_load_reg_ref(list,tmpregsize,size,tmpreg,tmpref);
  2163. end;
  2164. procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
  2165. begin
  2166. if cs_check_stack in current_settings.localswitches then
  2167. begin
  2168. cg.getcpuregister(list,NR_AX);
  2169. cg.a_load_const_reg(list,OS_16, localsize,NR_AX);
  2170. cg.a_call_name(list,'FPC_STACKCHECK_I8086',false);
  2171. cg.ungetcpuregister(list, NR_AX);
  2172. end;
  2173. if localsize>0 then
  2174. list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
  2175. end;
  2176. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  2177. var
  2178. stacksize : longint;
  2179. ret_instr: TAsmOp;
  2180. sp_moved : boolean;
  2181. procedure maybe_move_sp;
  2182. var
  2183. ref : treference;
  2184. begin
  2185. if sp_moved then
  2186. exit;
  2187. if not(pi_has_open_array_parameter in current_procinfo.flags) then
  2188. exit;
  2189. { Restore SP position before SP change }
  2190. if current_settings.x86memorymodel=mm_huge then
  2191. stacksize:=stacksize + 2;
  2192. reference_reset_base(ref,NR_BP,-stacksize,ctempposinvalid,2,[]);
  2193. list.concat(Taicpu.op_ref_reg(A_LEA,S_W,ref,NR_SP));
  2194. sp_moved:=true;
  2195. end;
  2196. begin
  2197. if is_proc_far(current_procinfo.procdef) then
  2198. ret_instr:=A_RETF
  2199. else
  2200. ret_instr:=A_RET;
  2201. { MMX needs to call EMMS }
  2202. if assigned(rg[R_MMXREGISTER]) and
  2203. (rg[R_MMXREGISTER].uses_registers) then
  2204. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  2205. sp_moved:=false;
  2206. { remove stackframe }
  2207. if not nostackframe then
  2208. begin
  2209. stacksize:=current_procinfo.calc_stackframe_size;
  2210. if (target_info.stackalign>4) and
  2211. ((stacksize <> 0) or
  2212. (pi_do_call in current_procinfo.flags) or
  2213. { can't detect if a call in this case -> use nostackframe }
  2214. { if you (think you) know what you are doing }
  2215. (po_assembler in current_procinfo.procdef.procoptions)) then
  2216. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  2217. if (po_exports in current_procinfo.procdef.procoptions) and
  2218. (target_info.system=system_i8086_win16) then
  2219. begin
  2220. maybe_move_sp;
  2221. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  2222. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  2223. end;
  2224. if ((current_settings.x86memorymodel=mm_huge) and
  2225. not (po_interrupt in current_procinfo.procdef.procoptions)) or
  2226. ((po_exports in current_procinfo.procdef.procoptions) and
  2227. (target_info.system=system_i8086_win16)) then
  2228. begin
  2229. maybe_move_sp;
  2230. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  2231. end;
  2232. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  2233. begin
  2234. if (stacksize<>0) then
  2235. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  2236. end
  2237. else
  2238. begin
  2239. generate_leave(list);
  2240. if ((ts_x86_far_procs_push_odd_bp in current_settings.targetswitches) or
  2241. ((po_exports in current_procinfo.procdef.procoptions) and
  2242. (target_info.system=system_i8086_win16))) and
  2243. is_proc_far(current_procinfo.procdef) then
  2244. cg.a_op_const_reg(list,OP_SUB,OS_ADDR,1,current_procinfo.framepointer);
  2245. end;
  2246. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  2247. end;
  2248. { return from interrupt }
  2249. if po_interrupt in current_procinfo.procdef.procoptions then
  2250. begin
  2251. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  2252. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  2253. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  2254. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  2255. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DX));
  2256. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_CX));
  2257. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_BX));
  2258. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_AX));
  2259. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  2260. end
  2261. { Routines with the poclearstack flag set use only a ret }
  2262. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  2263. (not paramanager.use_fixed_stack) then
  2264. begin
  2265. { complex return values are removed from stack in C code PM }
  2266. { but not on win32 }
  2267. { and not for safecall with hidden exceptions, because the result }
  2268. { wich contains the exception is passed in EAX }
  2269. if (target_info.system <> system_i386_win32) and
  2270. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  2271. (tf_safecall_exceptions in target_info.flags)) and
  2272. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  2273. current_procinfo.procdef) then
  2274. list.concat(Taicpu.Op_const(ret_instr,S_W,sizeof(aint)))
  2275. else
  2276. list.concat(Taicpu.Op_none(ret_instr,S_NO));
  2277. end
  2278. { ... also routines with parasize=0 }
  2279. else if (parasize=0) then
  2280. list.concat(Taicpu.Op_none(ret_instr,S_NO))
  2281. else
  2282. begin
  2283. { parameters are limited to 65535 bytes because ret allows only imm16 }
  2284. if (parasize>65535) then
  2285. CGMessage(cg_e_parasize_too_big);
  2286. list.concat(Taicpu.Op_const(ret_instr,S_W,parasize));
  2287. end;
  2288. end;
  2289. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  2290. var
  2291. power : longint;
  2292. opsize : topsize;
  2293. saved_ds: Boolean;
  2294. begin
  2295. { get stack space }
  2296. getcpuregister(list,NR_DI);
  2297. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  2298. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  2299. { Now DI contains (high+1). }
  2300. include(current_procinfo.flags, pi_has_open_array_parameter);
  2301. { special case handling for elesize=2:
  2302. set CX = (high+1) instead of CX = (high+1)*elesize.
  2303. This allows us to avoid the SHR later. }
  2304. if elesize=2 then
  2305. begin
  2306. { Now DI contains (high+1). Copy it to CX for later use. }
  2307. getcpuregister(list,NR_CX);
  2308. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  2309. end;
  2310. { DI := DI * elesize }
  2311. if (elesize<>1) then
  2312. begin
  2313. if ispowerof2(elesize, power) then
  2314. a_op_const_reg(list,OP_SHL,OS_16,power,NR_DI)
  2315. else
  2316. a_op_const_reg(list,OP_IMUL,OS_16,elesize,NR_DI);
  2317. end;
  2318. if elesize<>2 then
  2319. begin
  2320. { Now DI contains (high+1)*elesize. Copy it to CX for later use. }
  2321. getcpuregister(list,NR_CX);
  2322. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  2323. end;
  2324. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  2325. by (size div pagesize)*pagesize, otherwise EDI=size.
  2326. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  2327. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  2328. { align stack on 2 bytes }
  2329. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  2330. { load destination, don't use a_load_reg_reg, that will add a move instruction
  2331. that can confuse the reg allocator }
  2332. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  2333. {$ifdef volatile_es}
  2334. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS));
  2335. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  2336. {$endif volatile_es}
  2337. { Allocate SI and load it with source }
  2338. getcpuregister(list,NR_SI);
  2339. if ((ref.segment=NR_NO) and (segment_regs_equal(NR_SS,NR_DS) or (ref.base<>NR_BP))) or
  2340. (is_segment_reg(ref.segment) and segment_regs_equal(ref.segment,NR_DS)) then
  2341. begin
  2342. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  2343. saved_ds:=false;
  2344. end
  2345. else
  2346. begin
  2347. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  2348. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  2349. saved_ds:=true;
  2350. if ref.segment<>NR_NO then
  2351. list.concat(taicpu.op_reg(A_PUSH,S_W,ref.segment))
  2352. else if ref.base=NR_BP then
  2353. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS))
  2354. else
  2355. internalerror(2014040403);
  2356. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  2357. end;
  2358. { calculate size }
  2359. opsize:=S_B;
  2360. if elesize=2 then
  2361. begin
  2362. opsize:=S_W;
  2363. { CX is already number of words, so no need to SHL/SHR }
  2364. end
  2365. else if (elesize and 1)=0 then
  2366. begin
  2367. opsize:=S_W;
  2368. { CX is number of bytes, convert to words }
  2369. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX))
  2370. end;
  2371. if ts_cld in current_settings.targetswitches then
  2372. list.concat(Taicpu.op_none(A_CLD,S_NO));
  2373. if (opsize=S_B) and not (cs_opt_size in current_settings.optimizerswitches) then
  2374. begin
  2375. { SHR CX,1 moves the lowest (odd/even) bit to the carry flag }
  2376. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2377. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX));
  2378. list.concat(Taicpu.op_none(A_REP,S_NO));
  2379. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  2380. { ADC CX,CX will set CX to 1 if the number of bytes was odd }
  2381. list.concat(Taicpu.op_reg_reg(A_ADC,S_W,NR_CX,NR_CX));
  2382. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2383. list.concat(Taicpu.op_none(A_REP,S_NO));
  2384. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  2385. end
  2386. else
  2387. begin
  2388. list.concat(Taicpu.op_none(A_REP,S_NO));
  2389. case opsize of
  2390. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  2391. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  2392. end;
  2393. end;
  2394. ungetcpuregister(list,NR_DI);
  2395. ungetcpuregister(list,NR_CX);
  2396. ungetcpuregister(list,NR_SI);
  2397. if saved_ds then
  2398. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  2399. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  2400. that can confuse the reg allocator }
  2401. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  2402. if current_settings.x86memorymodel in x86_far_data_models then
  2403. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SS,GetNextReg(destreg)));
  2404. end;
  2405. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  2406. begin
  2407. { Nothing to do }
  2408. end;
  2409. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  2410. begin
  2411. case op of
  2412. OP_ADD :
  2413. begin
  2414. op1:=A_ADD;
  2415. op2:=A_ADC;
  2416. end;
  2417. OP_SUB :
  2418. begin
  2419. op1:=A_SUB;
  2420. op2:=A_SBB;
  2421. end;
  2422. OP_XOR :
  2423. begin
  2424. op1:=A_XOR;
  2425. op2:=A_XOR;
  2426. end;
  2427. OP_OR :
  2428. begin
  2429. op1:=A_OR;
  2430. op2:=A_OR;
  2431. end;
  2432. OP_AND :
  2433. begin
  2434. op1:=A_AND;
  2435. op2:=A_AND;
  2436. end;
  2437. else
  2438. internalerror(200203241);
  2439. end;
  2440. end;
  2441. procedure tcg8086.add_move_instruction(instr: Taicpu);
  2442. begin
  2443. { HACK: when regvars are on, don't notify the register allocator of any
  2444. direct moves to BX, so it doesn't try to coalesce them. Currently,
  2445. direct moves to BX are only used when returning an int64 value in
  2446. AX:BX:CX:DX. This hack fixes a common issue with functions, returning
  2447. int64, for example:
  2448. function RandomFrom(const AValues: array of Int64): Int64;
  2449. begin
  2450. result:=AValues[random(High(AValues)+1)];
  2451. end;
  2452. push bp
  2453. mov bp,sp
  2454. ; Var AValues located in register ireg20w
  2455. ; Var $highAVALUES located in register ireg21w
  2456. ; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
  2457. mov ireg20w,word [bp+6]
  2458. mov ireg21w,word [bp+4]
  2459. ; [3] result:=AValues[random(High(AValues)+1)];
  2460. mov ireg22w,ireg21w
  2461. inc ireg22w
  2462. mov ax,ireg22w
  2463. cwd
  2464. mov ireg23w,ax
  2465. mov ireg24w,dx
  2466. push ireg24w
  2467. push ireg23w
  2468. call SYSTEM_$$_RANDOM$LONGINT$$LONGINT
  2469. mov ireg25w,ax
  2470. mov ireg26w,dx
  2471. mov ireg27w,ireg25w
  2472. mov ireg28w,ireg27w
  2473. mov ireg29w,ireg28w
  2474. mov cl,3
  2475. shl ireg29w,cl
  2476. ; Var $result located in register ireg32w:ireg30w
  2477. mov ireg30w,word [ireg20w+ireg29w]
  2478. mov ireg31w,word [ireg20w+ireg29w+2]
  2479. mov ireg32w,word [ireg20w+ireg29w+4] ; problematic section start
  2480. mov ireg33w,word [ireg20w+ireg29w+6]
  2481. ; [4] end;
  2482. mov bx,ireg32w ; problematic section end
  2483. mov ax,ireg33w
  2484. mov dx,ireg30w
  2485. mov cx,ireg31w
  2486. mov sp,bp
  2487. pop bp
  2488. ret 4
  2489. the problem arises, because the register allocator tries to coalesce
  2490. mov bx,ireg32w
  2491. however, in the references [ireg20w+ireg29w+const], due to the
  2492. constraints of i8086, ireg20w can only be BX (or BP, which isn't available
  2493. to the register allocator, because it's used as a base pointer) }
  2494. if (cs_opt_regvar in current_settings.optimizerswitches) and
  2495. (instr.opcode=A_MOV) and (instr.ops=2) and
  2496. (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
  2497. exit
  2498. else
  2499. inherited add_move_instruction(instr);
  2500. end;
  2501. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2502. var
  2503. hsym : tsym;
  2504. href : treference;
  2505. paraloc : Pcgparalocation;
  2506. return_address_size: Integer;
  2507. begin
  2508. if current_settings.x86memorymodel in x86_far_code_models then
  2509. return_address_size:=4
  2510. else
  2511. return_address_size:=2;
  2512. { calculate the parameter info for the procdef }
  2513. procdef.init_paraloc_info(callerside);
  2514. hsym:=tsym(procdef.parast.Find('self'));
  2515. if not(assigned(hsym) and
  2516. (hsym.typ=paravarsym)) then
  2517. internalerror(200305251);
  2518. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2519. with paraloc^ do
  2520. begin
  2521. case loc of
  2522. LOC_REGISTER:
  2523. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  2524. LOC_REFERENCE:
  2525. begin
  2526. { offset in the wrapper needs to be adjusted for the stored
  2527. return address }
  2528. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  2529. and (reference.index<>NR_SI) then
  2530. begin
  2531. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  2532. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  2533. if reference.index=NR_SP then
  2534. reference_reset_base(href,NR_DI,reference.offset+return_address_size+2,ctempposinvalid,sizeof(pint),[])
  2535. else
  2536. reference_reset_base(href,NR_DI,reference.offset+return_address_size,ctempposinvalid,sizeof(pint),[]);
  2537. href.segment:=NR_SS;
  2538. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2539. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  2540. end
  2541. else
  2542. begin
  2543. reference_reset_base(href,reference.index,reference.offset+return_address_size,ctempposinvalid,sizeof(pint),[]);
  2544. href.segment:=NR_SS;
  2545. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2546. end;
  2547. end
  2548. else
  2549. internalerror(200309189);
  2550. end;
  2551. paraloc:=next;
  2552. end;
  2553. end;
  2554. { ************* 64bit operations ************ }
  2555. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  2556. begin
  2557. case op of
  2558. OP_ADD :
  2559. begin
  2560. op1:=A_ADD;
  2561. op2:=A_ADC;
  2562. end;
  2563. OP_SUB :
  2564. begin
  2565. op1:=A_SUB;
  2566. op2:=A_SBB;
  2567. end;
  2568. OP_XOR :
  2569. begin
  2570. op1:=A_XOR;
  2571. op2:=A_XOR;
  2572. end;
  2573. OP_OR :
  2574. begin
  2575. op1:=A_OR;
  2576. op2:=A_OR;
  2577. end;
  2578. OP_AND :
  2579. begin
  2580. op1:=A_AND;
  2581. op2:=A_AND;
  2582. end;
  2583. else
  2584. internalerror(200203241);
  2585. end;
  2586. end;
  2587. procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  2588. var
  2589. op1,op2 : TAsmOp;
  2590. tempref : treference;
  2591. begin
  2592. if not(op in [OP_NEG,OP_NOT]) then
  2593. begin
  2594. get_64bit_ops(op,op1,op2);
  2595. tempref:=ref;
  2596. tcgx86(cg).make_simple_ref(list,tempref);
  2597. if op in [OP_ADD,OP_SUB] then
  2598. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2599. list.concat(taicpu.op_ref_reg(op1,S_W,tempref,reg.reglo));
  2600. inc(tempref.offset,2);
  2601. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,cg.GetNextReg(reg.reglo)));
  2602. inc(tempref.offset,2);
  2603. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,reg.reghi));
  2604. inc(tempref.offset,2);
  2605. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,cg.GetNextReg(reg.reghi)));
  2606. if op in [OP_ADD,OP_SUB] then
  2607. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2608. end
  2609. else
  2610. begin
  2611. a_load64_ref_reg(list,ref,reg);
  2612. a_op64_reg_reg(list,op,size,reg,reg);
  2613. end;
  2614. end;
  2615. procedure tcg64f8086.a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);
  2616. var
  2617. op1,op2 : TAsmOp;
  2618. tempref : treference;
  2619. begin
  2620. case op of
  2621. OP_NOT:
  2622. begin
  2623. tempref:=ref;
  2624. tcgx86(cg).make_simple_ref(list,tempref);
  2625. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2626. inc(tempref.offset,2);
  2627. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2628. inc(tempref.offset,2);
  2629. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2630. inc(tempref.offset,2);
  2631. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2632. end;
  2633. OP_NEG:
  2634. begin
  2635. tempref:=ref;
  2636. tcgx86(cg).make_simple_ref(list,tempref);
  2637. inc(tempref.offset,6);
  2638. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2639. dec(tempref.offset,2);
  2640. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2641. dec(tempref.offset,2);
  2642. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2643. dec(tempref.offset,2);
  2644. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2645. list.concat(taicpu.op_ref(A_NEG,S_W,tempref));
  2646. inc(tempref.offset,2);
  2647. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2648. inc(tempref.offset,2);
  2649. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2650. inc(tempref.offset,2);
  2651. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2652. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2653. end;
  2654. else
  2655. begin
  2656. get_64bit_ops(op,op1,op2);
  2657. tempref:=ref;
  2658. tcgx86(cg).make_simple_ref(list,tempref);
  2659. if op in [OP_ADD,OP_SUB] then
  2660. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2661. list.concat(taicpu.op_reg_ref(op1,S_W,reg.reglo,tempref));
  2662. inc(tempref.offset,2);
  2663. list.concat(taicpu.op_reg_ref(op2,S_W,cg.GetNextReg(reg.reglo),tempref));
  2664. inc(tempref.offset,2);
  2665. list.concat(taicpu.op_reg_ref(op2,S_W,reg.reghi,tempref));
  2666. inc(tempref.offset,2);
  2667. list.concat(taicpu.op_reg_ref(op2,S_W,cg.GetNextReg(reg.reghi),tempref));
  2668. if op in [OP_ADD,OP_SUB] then
  2669. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2670. end;
  2671. end;
  2672. end;
  2673. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2674. var
  2675. op1,op2 : TAsmOp;
  2676. l2, l3: TAsmLabel;
  2677. ai: taicpu;
  2678. begin
  2679. case op of
  2680. OP_NEG :
  2681. begin
  2682. if (regsrc.reglo<>regdst.reglo) then
  2683. a_load64_reg_reg(list,regsrc,regdst);
  2684. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2685. list.concat(taicpu.op_reg(A_NOT,S_W,cg.GetNextReg(regdst.reglo)));
  2686. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2687. list.concat(taicpu.op_reg(A_NEG,S_W,regdst.reglo));
  2688. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,cg.GetNextReg(regdst.reglo)));
  2689. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  2690. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,cg.GetNextReg(regdst.reghi)));
  2691. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2692. exit;
  2693. end;
  2694. OP_NOT :
  2695. begin
  2696. if (regsrc.reglo<>regdst.reglo) then
  2697. a_load64_reg_reg(list,regsrc,regdst);
  2698. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  2699. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2700. exit;
  2701. end;
  2702. OP_SHR,OP_SHL,OP_SAR:
  2703. begin
  2704. { load right operators in a register }
  2705. cg.getcpuregister(list,NR_CX);
  2706. cg.a_load_reg_reg(list,OS_16,OS_16,regsrc.reglo,NR_CX);
  2707. current_asmdata.getjumplabel(l2);
  2708. current_asmdata.getjumplabel(l3);
  2709. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2710. list.concat(taicpu.op_const_reg(A_AND,S_W,63,NR_CX));
  2711. cg.a_jmp_flags(list,F_E,l3);
  2712. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2713. cg.a_label(list,l2);
  2714. case op of
  2715. OP_SHL:
  2716. begin
  2717. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2718. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,regdst.reglo));
  2719. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(regdst.reglo)));
  2720. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,regdst.reghi));
  2721. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(regdst.reghi)));
  2722. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2723. end;
  2724. OP_SHR,OP_SAR:
  2725. begin
  2726. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2727. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(regdst.reghi));
  2728. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,regdst.reghi));
  2729. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(regdst.reglo)));
  2730. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,regdst.reglo));
  2731. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2732. end;
  2733. end;
  2734. ai:=Taicpu.Op_Sym(A_LOOP,S_W,l2);
  2735. ai.is_jmp := True;
  2736. list.Concat(ai);
  2737. cg.a_label(list,l3);
  2738. cg.ungetcpuregister(list,NR_CX);
  2739. exit;
  2740. end;
  2741. end;
  2742. get_64bit_ops(op,op1,op2);
  2743. if op in [OP_ADD,OP_SUB] then
  2744. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2745. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  2746. list.concat(taicpu.op_reg_reg(op2,S_W,cg.GetNextReg(regsrc.reglo),cg.GetNextReg(regdst.reglo)));
  2747. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  2748. list.concat(taicpu.op_reg_reg(op2,S_W,cg.GetNextReg(regsrc.reghi),cg.GetNextReg(regdst.reghi)));
  2749. if op in [OP_ADD,OP_SUB] then
  2750. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2751. end;
  2752. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2753. var
  2754. op1,op2 : TAsmOp;
  2755. loop_start: TAsmLabel;
  2756. ai: taicpu;
  2757. begin
  2758. case op of
  2759. OP_AND,OP_OR,OP_XOR:
  2760. begin
  2761. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  2762. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  2763. end;
  2764. OP_ADD, OP_SUB:
  2765. begin
  2766. get_64bit_ops(op,op1,op2);
  2767. if (value and $ffffffffffff) = 0 then
  2768. begin
  2769. { use a_op_const_reg to allow the use of inc/dec }
  2770. cg.a_op_const_reg(list,op,OS_16,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi));
  2771. end
  2772. // can't use a_op_const_ref because this may use dec/inc
  2773. else if (value and $ffffffff) = 0 then
  2774. begin
  2775. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2776. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2777. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2778. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2779. end
  2780. else if (value and $ffff) = 0 then
  2781. begin
  2782. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2783. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 16) and $ffff),cg.GetNextReg(reg.reglo)));
  2784. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2785. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2786. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2787. end
  2788. else
  2789. begin
  2790. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2791. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  2792. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),cg.GetNextReg(reg.reglo)));
  2793. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2794. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2795. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2796. end;
  2797. end;
  2798. OP_SHR,OP_SHL,OP_SAR:
  2799. begin
  2800. value:=value and 63;
  2801. case value of
  2802. 0:
  2803. { ultra hyper fast shift by 0 };
  2804. 1:
  2805. case op of
  2806. OP_SHL:
  2807. begin
  2808. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2809. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg.reglo));
  2810. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reglo)));
  2811. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2812. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2813. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2814. end;
  2815. OP_SHR,OP_SAR:
  2816. begin
  2817. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2818. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(reg.reghi));
  2819. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reghi));
  2820. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2821. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2822. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2823. end;
  2824. end;
  2825. 2..15:
  2826. begin
  2827. cg.getcpuregister(list,NR_CX);
  2828. cg.a_load_const_reg(list,OS_16,value,NR_CX);
  2829. current_asmdata.getjumplabel(loop_start);
  2830. cg.a_label(list,loop_start);
  2831. case op of
  2832. OP_SHL:
  2833. begin
  2834. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2835. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg.reglo));
  2836. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reglo)));
  2837. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2838. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2839. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2840. end;
  2841. OP_SHR,OP_SAR:
  2842. begin
  2843. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2844. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(reg.reghi));
  2845. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reghi));
  2846. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2847. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2848. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2849. end;
  2850. end;
  2851. ai:=Taicpu.Op_Sym(A_LOOP,S_W,loop_start);
  2852. ai.is_jmp := True;
  2853. list.Concat(ai);
  2854. cg.ungetcpuregister(list,NR_CX);
  2855. end;
  2856. 16,17:
  2857. begin
  2858. case op of
  2859. OP_SHL:
  2860. begin
  2861. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2862. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  2863. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reglo));
  2864. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2865. end;
  2866. OP_SHR:
  2867. begin
  2868. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2869. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2870. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2871. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2872. end;
  2873. OP_SAR:
  2874. begin
  2875. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2876. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2877. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2878. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2879. end;
  2880. end;
  2881. if value=17 then
  2882. case op of
  2883. OP_SHL:
  2884. begin
  2885. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2886. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,cg.GetNextReg(reg.reglo)));
  2887. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2888. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2889. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2890. end;
  2891. OP_SHR,OP_SAR:
  2892. begin
  2893. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2894. cg.a_op_const_reg(list,op,OS_16,1,reg.reghi);
  2895. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2896. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2897. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2898. end;
  2899. end;
  2900. end;
  2901. 18..31:
  2902. begin
  2903. case op of
  2904. OP_SHL:
  2905. begin
  2906. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2907. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  2908. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reglo));
  2909. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2910. end;
  2911. OP_SHR:
  2912. begin
  2913. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2914. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2915. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2916. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2917. end;
  2918. OP_SAR:
  2919. begin
  2920. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2921. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2922. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2923. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2924. end;
  2925. end;
  2926. cg.getcpuregister(list,NR_CX);
  2927. cg.a_load_const_reg(list,OS_16,value-16,NR_CX);
  2928. current_asmdata.getjumplabel(loop_start);
  2929. cg.a_label(list,loop_start);
  2930. case op of
  2931. OP_SHL:
  2932. begin
  2933. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2934. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,cg.GetNextReg(reg.reglo)));
  2935. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2936. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2937. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2938. end;
  2939. OP_SHR,OP_SAR:
  2940. begin
  2941. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2942. cg.a_op_const_reg(list,op,OS_16,1,reg.reghi);
  2943. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2944. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2945. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2946. end;
  2947. end;
  2948. ai:=Taicpu.Op_Sym(A_LOOP,S_W,loop_start);
  2949. ai.is_jmp := True;
  2950. list.Concat(ai);
  2951. cg.ungetcpuregister(list,NR_CX);
  2952. end;
  2953. 32..47:
  2954. case op of
  2955. OP_SHL:
  2956. begin
  2957. cg.a_op_const_reg_reg(list,OP_SHL,OS_32,value-32,reg.reglo,reg.reghi);
  2958. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2959. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2960. end;
  2961. OP_SHR:
  2962. begin
  2963. cg.a_op_const_reg_reg(list,OP_SHR,OS_32,value-32,reg.reghi,reg.reglo);
  2964. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2965. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2966. end;
  2967. OP_SAR:
  2968. begin
  2969. cg.a_op_const_reg_reg(list,OP_SAR,OS_32,value-32,reg.reghi,reg.reglo);
  2970. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,15-(value-32),cg.GetNextReg(reg.reglo),reg.reghi);
  2971. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2972. end;
  2973. end;
  2974. 48..63:
  2975. case op of
  2976. OP_SHL:
  2977. begin
  2978. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reghi));
  2979. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2980. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2981. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2982. cg.a_op_const_reg(list,OP_SHL,OS_16,value-48,cg.GetNextReg(reg.reghi));
  2983. end;
  2984. OP_SHR:
  2985. begin
  2986. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reglo);
  2987. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2988. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2989. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2990. cg.a_op_const_reg(list,OP_SHR,OS_16,value-48,reg.reglo);
  2991. end;
  2992. OP_SAR:
  2993. if value=63 then
  2994. begin
  2995. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2996. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2997. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reglo));
  2998. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reglo);
  2999. end
  3000. else
  3001. begin
  3002. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,value-48,cg.GetNextReg(reg.reghi),reg.reglo);
  3003. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,15-(value-48),reg.reglo,cg.GetNextReg(reg.reglo));
  3004. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  3005. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reghi));
  3006. end;
  3007. end;
  3008. end;
  3009. end;
  3010. else
  3011. internalerror(200204021);
  3012. end;
  3013. end;
  3014. procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  3015. var
  3016. op1,op2 : TAsmOp;
  3017. tempref : treference;
  3018. begin
  3019. tempref:=ref;
  3020. tcgx86(cg).make_simple_ref(list,tempref);
  3021. case op of
  3022. OP_AND,OP_OR,OP_XOR:
  3023. begin
  3024. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  3025. inc(tempref.offset,4);
  3026. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  3027. end;
  3028. OP_ADD, OP_SUB:
  3029. begin
  3030. get_64bit_ops(op,op1,op2);
  3031. if (value and $ffffffffffff) = 0 then
  3032. begin
  3033. inc(tempref.offset,6);
  3034. { use a_op_const_ref to allow the use of inc/dec }
  3035. cg.a_op_const_ref(list,op,OS_16,aint((value shr 48) and $ffff),tempref);
  3036. end
  3037. // can't use a_op_const_ref because this may use dec/inc
  3038. else if (value and $ffffffff) = 0 then
  3039. begin
  3040. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3041. inc(tempref.offset,4);
  3042. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 32) and $ffff),tempref));
  3043. inc(tempref.offset,2);
  3044. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3045. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3046. end
  3047. else if (value and $ffff) = 0 then
  3048. begin
  3049. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3050. inc(tempref.offset,2);
  3051. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 16) and $ffff),tempref));
  3052. inc(tempref.offset,2);
  3053. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  3054. inc(tempref.offset,2);
  3055. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3056. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3057. end
  3058. else
  3059. begin
  3060. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3061. list.concat(taicpu.op_const_ref(op1,S_W,aint(value and $ffff),tempref));
  3062. inc(tempref.offset,2);
  3063. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 16) and $ffff),tempref));
  3064. inc(tempref.offset,2);
  3065. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  3066. inc(tempref.offset,2);
  3067. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3068. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3069. end;
  3070. end;
  3071. else
  3072. internalerror(200204022);
  3073. end;
  3074. end;
  3075. procedure create_codegen;
  3076. begin
  3077. cg := tcg8086.create;
  3078. cg64 := tcg64f8086.create;
  3079. end;
  3080. end.