cgcpu.pas 94 KB

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