cgcpu.pas 96 KB

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