cgcpu.pas 105 KB

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