cgcpu.pas 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460
  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,AT_FUNCTION)
  156. else
  157. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION);
  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,AT_FUNCTION);
  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. if current_settings.cputype>=cpu_386 then
  1174. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1175. else
  1176. begin
  1177. reg := makeregsize(list, reg, OS_8);
  1178. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1179. setsubreg(reg, R_SUBH);
  1180. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1181. makeregsize(list, reg, OS_16);
  1182. end;
  1183. end;
  1184. OS_S8:
  1185. begin
  1186. if current_settings.cputype>=cpu_386 then
  1187. list.concat(taicpu.op_ref_reg(A_MOVSX, S_BW, tmpref, reg))
  1188. else
  1189. begin
  1190. getcpuregister(list, NR_AX);
  1191. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1192. list.concat(taicpu.op_none(A_CBW));
  1193. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1194. ungetcpuregister(list, NR_AX);
  1195. end;
  1196. end;
  1197. OS_16,OS_S16:
  1198. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1199. else
  1200. internalerror(2013030212);
  1201. end;
  1202. OS_32,OS_S32:
  1203. case fromsize of
  1204. OS_8:
  1205. begin
  1206. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1207. if current_settings.cputype>=cpu_386 then
  1208. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1209. else
  1210. begin
  1211. reg := makeregsize(list, reg, OS_8);
  1212. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1213. setsubreg(reg, R_SUBH);
  1214. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1215. makeregsize(list, reg, OS_16);
  1216. end;
  1217. end;
  1218. OS_S8:
  1219. begin
  1220. getcpuregister(list, NR_AX);
  1221. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1222. getcpuregister(list, NR_DX);
  1223. list.concat(taicpu.op_none(A_CBW));
  1224. list.concat(taicpu.op_none(A_CWD));
  1225. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1226. ungetcpuregister(list, NR_AX);
  1227. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1228. ungetcpuregister(list, NR_DX);
  1229. end;
  1230. OS_16:
  1231. begin
  1232. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1233. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1234. end;
  1235. OS_S16:
  1236. begin
  1237. getcpuregister(list, NR_AX);
  1238. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  1239. getcpuregister(list, NR_DX);
  1240. list.concat(taicpu.op_none(A_CWD));
  1241. ungetcpuregister(list, NR_AX);
  1242. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1243. ungetcpuregister(list, NR_DX);
  1244. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1245. end;
  1246. OS_32,OS_S32:
  1247. begin
  1248. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1249. inc(tmpref.offset, 2);
  1250. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  1251. end;
  1252. else
  1253. internalerror(2013030213);
  1254. end;
  1255. else
  1256. internalerror(2013030211);
  1257. end;
  1258. end;
  1259. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  1260. procedure add_mov(instr: Taicpu);
  1261. begin
  1262. { Notify the register allocator that we have written a move instruction so
  1263. it can try to eliminate it. }
  1264. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1265. add_move_instruction(instr);
  1266. list.concat(instr);
  1267. end;
  1268. begin
  1269. check_register_size(fromsize,reg1);
  1270. check_register_size(tosize,reg2);
  1271. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1272. begin
  1273. if tosize in [OS_32, OS_S32] then
  1274. internalerror(2013031801);
  1275. reg1:=makeregsize(list,reg1,tosize);
  1276. fromsize:=tosize;
  1277. end;
  1278. if (reg1<>reg2) or (fromsize<>tosize) then
  1279. begin
  1280. case tosize of
  1281. OS_8,OS_S8:
  1282. if fromsize in [OS_8,OS_S8] then
  1283. begin
  1284. if reg1<>reg2 then
  1285. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1286. end
  1287. else
  1288. internalerror(2013030210);
  1289. OS_16,OS_S16:
  1290. case fromsize of
  1291. OS_8:
  1292. begin
  1293. if current_settings.cputype>=cpu_386 then
  1294. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1295. else
  1296. begin
  1297. reg2 := makeregsize(list, reg2, OS_8);
  1298. if reg1<>reg2 then
  1299. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1300. setsubreg(reg2,R_SUBH);
  1301. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1302. makeregsize(list, reg2, OS_16);
  1303. end;
  1304. end;
  1305. OS_S8:
  1306. begin
  1307. if current_settings.cputype>=cpu_386 then
  1308. add_mov(taicpu.op_reg_reg(A_MOVSX, S_BW, reg1, reg2))
  1309. else
  1310. begin
  1311. getcpuregister(list, NR_AX);
  1312. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1313. list.concat(taicpu.op_none(A_CBW));
  1314. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1315. ungetcpuregister(list, NR_AX);
  1316. end;
  1317. end;
  1318. OS_16,OS_S16:
  1319. begin
  1320. if reg1<>reg2 then
  1321. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1322. end
  1323. else
  1324. internalerror(2013030212);
  1325. end;
  1326. OS_32,OS_S32:
  1327. case fromsize of
  1328. OS_8:
  1329. begin
  1330. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
  1331. if current_settings.cputype>=cpu_386 then
  1332. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1333. else
  1334. begin
  1335. reg2 := makeregsize(list, reg2, OS_8);
  1336. if reg1<>reg2 then
  1337. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1338. setsubreg(reg2,R_SUBH);
  1339. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1340. makeregsize(list, reg2, OS_16);
  1341. end;
  1342. end;
  1343. OS_S8:
  1344. begin
  1345. getcpuregister(list, NR_AX);
  1346. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1347. getcpuregister(list, NR_DX);
  1348. list.concat(taicpu.op_none(A_CBW));
  1349. list.concat(taicpu.op_none(A_CWD));
  1350. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1351. ungetcpuregister(list, NR_AX);
  1352. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1353. ungetcpuregister(list, NR_DX);
  1354. end;
  1355. OS_16:
  1356. begin
  1357. if reg1<>reg2 then
  1358. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1359. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1360. end;
  1361. OS_S16:
  1362. begin
  1363. getcpuregister(list, NR_AX);
  1364. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1365. getcpuregister(list, NR_DX);
  1366. list.concat(taicpu.op_none(A_CWD));
  1367. if reg1<>reg2 then
  1368. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1369. ungetcpuregister(list, NR_AX);
  1370. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1371. ungetcpuregister(list, NR_DX);
  1372. end;
  1373. OS_32,OS_S32:
  1374. begin
  1375. if reg1<>reg2 then
  1376. begin
  1377. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1378. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1379. end;
  1380. end;
  1381. else
  1382. internalerror(2013030213);
  1383. end;
  1384. else
  1385. internalerror(2013030211);
  1386. end;
  1387. end;
  1388. end;
  1389. procedure tcg8086.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1390. var
  1391. hl_skip: TAsmLabel;
  1392. begin
  1393. if size in [OS_32, OS_S32] then
  1394. begin
  1395. if (longint(a shr 16) = 0) then
  1396. list.concat(taicpu.op_reg_reg(A_TEST,S_W,GetNextReg(reg),GetNextReg(reg)))
  1397. else
  1398. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a shr 16),GetNextReg(reg)));
  1399. current_asmdata.getjumplabel(hl_skip);
  1400. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1401. if (longint(a and $ffff) = 0) then
  1402. list.concat(taicpu.op_reg_reg(A_TEST,S_W,reg,reg))
  1403. else
  1404. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a and $ffff),reg));
  1405. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1406. a_label(list,hl_skip);
  1407. end
  1408. else
  1409. inherited a_cmp_const_reg_label(list, size, cmp_op, a, reg, l);
  1410. end;
  1411. procedure tcg8086.a_cmp_const_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
  1412. var
  1413. tmpref: treference;
  1414. hl_skip: TAsmLabel;
  1415. begin
  1416. if size in [OS_32, OS_S32] then
  1417. begin
  1418. tmpref:=ref;
  1419. make_simple_ref(list,tmpref);
  1420. inc(tmpref.offset,2);
  1421. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a shr 16),tmpref));
  1422. current_asmdata.getjumplabel(hl_skip);
  1423. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1424. dec(tmpref.offset,2);
  1425. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a and $ffff),tmpref));
  1426. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1427. a_label(list,hl_skip);
  1428. end
  1429. else
  1430. inherited a_cmp_const_ref_label(list, size, cmp_op, a, ref, l);
  1431. end;
  1432. procedure tcg8086.a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  1433. var
  1434. hl_skip: TAsmLabel;
  1435. begin
  1436. if size in [OS_32, OS_S32] then
  1437. begin
  1438. check_register_size(size,reg1);
  1439. check_register_size(size,reg2);
  1440. list.concat(taicpu.op_reg_reg(A_CMP,S_W,GetNextReg(reg1),GetNextReg(reg2)));
  1441. current_asmdata.getjumplabel(hl_skip);
  1442. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1443. list.concat(taicpu.op_reg_reg(A_CMP,S_W,reg1,reg2));
  1444. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1445. a_label(list,hl_skip);
  1446. end
  1447. else
  1448. inherited a_cmp_reg_reg_label(list, size, cmp_op, reg1, reg2, l);
  1449. end;
  1450. procedure tcg8086.a_cmp_ref_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
  1451. var
  1452. tmpref: treference;
  1453. hl_skip: TAsmLabel;
  1454. begin
  1455. if size in [OS_32, OS_S32] then
  1456. begin
  1457. tmpref:=ref;
  1458. make_simple_ref(list,tmpref);
  1459. check_register_size(size,reg);
  1460. inc(tmpref.offset,2);
  1461. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,GetNextReg(reg)));
  1462. current_asmdata.getjumplabel(hl_skip);
  1463. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1464. dec(tmpref.offset,2);
  1465. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,reg));
  1466. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1467. a_label(list,hl_skip);
  1468. end
  1469. else
  1470. inherited a_cmp_ref_reg_label(list, size, cmp_op, ref, reg, l);
  1471. end;
  1472. procedure tcg8086.a_cmp_reg_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
  1473. var
  1474. tmpref: treference;
  1475. hl_skip: TAsmLabel;
  1476. begin
  1477. if size in [OS_32, OS_S32] then
  1478. begin
  1479. tmpref:=ref;
  1480. make_simple_ref(list,tmpref);
  1481. check_register_size(size,reg);
  1482. inc(tmpref.offset,2);
  1483. list.concat(taicpu.op_reg_ref(A_CMP,S_W,GetNextReg(reg),tmpref));
  1484. current_asmdata.getjumplabel(hl_skip);
  1485. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1486. dec(tmpref.offset,2);
  1487. list.concat(taicpu.op_reg_ref(A_CMP,S_W,reg,tmpref));
  1488. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1489. a_label(list,hl_skip);
  1490. end
  1491. else
  1492. inherited a_cmp_reg_ref_label(list, size, cmp_op, reg, ref, l);
  1493. end;
  1494. procedure tcg8086.gen_cmp32_jmp1(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1495. begin
  1496. case cmp_op of
  1497. OC_EQ:
  1498. a_jmp_cond(list, OC_NE, l_skip);
  1499. OC_NE:
  1500. a_jmp_cond(list, OC_NE, l_target);
  1501. OC_GT,OC_GTE:
  1502. begin
  1503. a_jmp_cond(list, OC_GT, l_target);
  1504. a_jmp_cond(list, OC_LT, l_skip);
  1505. end;
  1506. OC_LT,OC_LTE:
  1507. begin
  1508. a_jmp_cond(list, OC_LT, l_target);
  1509. a_jmp_cond(list, OC_GT, l_skip);
  1510. end;
  1511. OC_B,OC_BE:
  1512. begin
  1513. a_jmp_cond(list, OC_B, l_target);
  1514. a_jmp_cond(list, OC_A, l_skip);
  1515. end;
  1516. OC_A,OC_AE:
  1517. begin
  1518. a_jmp_cond(list, OC_A, l_target);
  1519. a_jmp_cond(list, OC_B, l_skip);
  1520. end;
  1521. else
  1522. internalerror(2014010305);
  1523. end;
  1524. end;
  1525. procedure tcg8086.gen_cmp32_jmp2(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1526. begin
  1527. case cmp_op of
  1528. OC_EQ:
  1529. a_jmp_cond(list, OC_EQ, l_target);
  1530. OC_GT:
  1531. a_jmp_cond(list, OC_A, l_target);
  1532. OC_LT:
  1533. a_jmp_cond(list, OC_B, l_target);
  1534. OC_GTE:
  1535. a_jmp_cond(list, OC_AE, l_target);
  1536. OC_LTE:
  1537. a_jmp_cond(list, OC_BE, l_target);
  1538. OC_NE:
  1539. a_jmp_cond(list, OC_NE, l_target);
  1540. OC_BE:
  1541. a_jmp_cond(list, OC_BE, l_target);
  1542. OC_B:
  1543. a_jmp_cond(list, OC_B, l_target);
  1544. OC_AE:
  1545. a_jmp_cond(list, OC_AE, l_target);
  1546. OC_A:
  1547. a_jmp_cond(list, OC_A, l_target);
  1548. else
  1549. internalerror(2014010306);
  1550. end;
  1551. end;
  1552. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  1553. var
  1554. ai : taicpu;
  1555. hreg16 : tregister;
  1556. hl_skip: TAsmLabel;
  1557. invf: TResFlags;
  1558. tmpsize: TCgSize;
  1559. tmpopsize: topsize;
  1560. begin
  1561. { optimized case for the carry flag, using ADC/RCL }
  1562. if f in [F_C,F_B,F_FB] then
  1563. begin
  1564. case size of
  1565. OS_8,OS_S8:
  1566. begin
  1567. tmpsize:=OS_8;
  1568. tmpopsize:=S_B;
  1569. end;
  1570. OS_16,OS_S16,OS_32,OS_S32:
  1571. begin
  1572. tmpsize:=OS_16;
  1573. tmpopsize:=S_W;
  1574. end;
  1575. else
  1576. internalerror(2013123101);
  1577. end;
  1578. list.concat(Taicpu.op_const_reg(A_MOV, tmpopsize, 0, reg));
  1579. hl_skip:=nil;
  1580. if f=F_FB then
  1581. begin
  1582. current_asmdata.getjumplabel(hl_skip);
  1583. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  1584. ai.SetCondition(C_P);
  1585. ai.is_jmp:=true;
  1586. list.concat(ai);
  1587. end;
  1588. { RCL is faster than ADC on 8086/8088. On the 80286, it is
  1589. equally fast and it also has the same size. In these cases,
  1590. we still prefer it over ADC, because it's a better choice in
  1591. case the register is spilled. }
  1592. if (cs_opt_size in current_settings.optimizerswitches) or
  1593. (current_settings.optimizecputype<=cpu_286) then
  1594. list.concat(Taicpu.op_const_reg(A_RCL, tmpopsize, 1, reg))
  1595. else
  1596. { ADC is much faster on the 386. }
  1597. list.concat(Taicpu.op_reg_reg(A_ADC, tmpopsize, reg, reg));
  1598. if f=F_FB then
  1599. a_label(list,hl_skip);
  1600. a_load_reg_reg(list,tmpsize,size,reg,reg);
  1601. end
  1602. { optimized case for the inverted carry flag, using SBB }
  1603. else if f in [F_NC,F_AE,F_FAE] then
  1604. begin
  1605. case size of
  1606. OS_8,OS_S8:
  1607. begin
  1608. tmpsize:=OS_8;
  1609. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 1, reg));
  1610. list.concat(Taicpu.op_const_reg(A_SBB, S_B, 0, reg));
  1611. end;
  1612. OS_16,OS_S16,OS_32,OS_S32:
  1613. begin
  1614. tmpsize:=OS_16;
  1615. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 1, reg));
  1616. list.concat(Taicpu.op_const_reg(A_SBB, S_W, 0, reg));
  1617. end;
  1618. else
  1619. internalerror(2013123101);
  1620. end;
  1621. a_load_reg_reg(list,tmpsize,size,reg,reg);
  1622. end
  1623. else
  1624. begin
  1625. invf := f;
  1626. inverse_flags(invf);
  1627. case size of
  1628. OS_8,OS_S8:
  1629. begin
  1630. tmpsize:=OS_8;
  1631. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1632. end;
  1633. OS_16,OS_S16,OS_32,OS_S32:
  1634. begin
  1635. tmpsize:=OS_16;
  1636. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  1637. end;
  1638. else
  1639. internalerror(2013123101);
  1640. end;
  1641. current_asmdata.getjumplabel(hl_skip);
  1642. { we can't just forward invf to a_jmp_flags for FA,FAE,FB and FBE, because
  1643. in the case of NaNs:
  1644. not(F_FA )<>F_FBE
  1645. not(F_FAE)<>F_FB
  1646. not(F_FB )<>F_FAE
  1647. not(F_FBE)<>F_FA
  1648. }
  1649. case f of
  1650. F_FA:
  1651. invf:=FPUFlags2Flags[invf];
  1652. F_FAE,F_FB:
  1653. { F_FAE and F_FB are handled above, using ADC/RCL/SBB }
  1654. internalerror(2015102101);
  1655. F_FBE:
  1656. begin
  1657. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  1658. ai.SetCondition(C_P);
  1659. ai.is_jmp:=true;
  1660. list.concat(ai);
  1661. invf:=FPUFlags2Flags[invf];
  1662. end;
  1663. end;
  1664. a_jmp_flags(list,invf,hl_skip);
  1665. { 16-bit INC is shorter than 8-bit }
  1666. hreg16:=makeregsize(list,reg,OS_16);
  1667. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  1668. makeregsize(list,hreg16,tmpsize);
  1669. a_label(list,hl_skip);
  1670. a_load_reg_reg(list,tmpsize,size,reg,reg);
  1671. end;
  1672. end;
  1673. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  1674. var
  1675. tmpreg : tregister;
  1676. tmpregsize: TCgSize;
  1677. tmpref: treference;
  1678. begin
  1679. if size in [OS_8,OS_S8,OS_16,OS_S16] then
  1680. tmpregsize:=size
  1681. else
  1682. tmpregsize:=OS_16;
  1683. tmpreg:=getintregister(list,tmpregsize);
  1684. g_flags2reg(list,tmpregsize,f,tmpreg);
  1685. tmpref:=ref;
  1686. make_simple_ref(list,tmpref);
  1687. if size in [OS_64,OS_S64] then
  1688. begin
  1689. a_load_reg_ref(list,tmpregsize,OS_32,tmpreg,tmpref);
  1690. inc(tmpref.offset,4);
  1691. a_load_const_ref(list,OS_32,0,tmpref);
  1692. end
  1693. else
  1694. a_load_reg_ref(list,tmpregsize,size,tmpreg,tmpref);
  1695. end;
  1696. procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
  1697. begin
  1698. if cs_check_stack in current_settings.localswitches then
  1699. begin
  1700. cg.getcpuregister(list,NR_AX);
  1701. cg.a_load_const_reg(list,OS_16, localsize,NR_AX);
  1702. cg.a_call_name(list,'FPC_STACKCHECK_I8086',false);
  1703. cg.ungetcpuregister(list, NR_AX);
  1704. end;
  1705. if localsize>0 then
  1706. list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
  1707. end;
  1708. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  1709. var
  1710. stacksize : longint;
  1711. ret_instr: TAsmOp;
  1712. sp_moved : boolean;
  1713. procedure maybe_move_sp;
  1714. var
  1715. ref : treference;
  1716. begin
  1717. if sp_moved then
  1718. exit;
  1719. if not(pi_has_open_array_parameter in current_procinfo.flags) then
  1720. exit;
  1721. { Restore SP position before SP change }
  1722. if current_settings.x86memorymodel=mm_huge then
  1723. stacksize:=stacksize + 2;
  1724. reference_reset_base(ref,NR_BP,-stacksize,2);
  1725. list.concat(Taicpu.op_ref_reg(A_LEA,S_W,ref,NR_SP));
  1726. sp_moved:=true;
  1727. end;
  1728. begin
  1729. if is_proc_far(current_procinfo.procdef) then
  1730. ret_instr:=A_RETF
  1731. else
  1732. ret_instr:=A_RET;
  1733. { MMX needs to call EMMS }
  1734. if assigned(rg[R_MMXREGISTER]) and
  1735. (rg[R_MMXREGISTER].uses_registers) then
  1736. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1737. sp_moved:=false;
  1738. { remove stackframe }
  1739. if not nostackframe then
  1740. begin
  1741. stacksize:=current_procinfo.calc_stackframe_size;
  1742. if (target_info.stackalign>4) and
  1743. ((stacksize <> 0) or
  1744. (pi_do_call in current_procinfo.flags) or
  1745. { can't detect if a call in this case -> use nostackframe }
  1746. { if you (think you) know what you are doing }
  1747. (po_assembler in current_procinfo.procdef.procoptions)) then
  1748. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1749. if (po_exports in current_procinfo.procdef.procoptions) and
  1750. (target_info.system=system_i8086_win16) then
  1751. begin
  1752. maybe_move_sp;
  1753. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  1754. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  1755. end;
  1756. if ((current_settings.x86memorymodel=mm_huge) and
  1757. not (po_interrupt in current_procinfo.procdef.procoptions)) or
  1758. ((po_exports in current_procinfo.procdef.procoptions) and
  1759. (target_info.system=system_i8086_win16)) then
  1760. begin
  1761. maybe_move_sp;
  1762. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1763. end;
  1764. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1765. begin
  1766. if (stacksize<>0) then
  1767. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  1768. end
  1769. else
  1770. begin
  1771. generate_leave(list);
  1772. if ((ts_x86_far_procs_push_odd_bp in current_settings.targetswitches) or
  1773. ((po_exports in current_procinfo.procdef.procoptions) and
  1774. (target_info.system=system_i8086_win16))) and
  1775. is_proc_far(current_procinfo.procdef) then
  1776. cg.a_op_const_reg(list,OP_SUB,OS_ADDR,1,current_procinfo.framepointer);
  1777. end;
  1778. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1779. end;
  1780. { return from interrupt }
  1781. if po_interrupt in current_procinfo.procdef.procoptions then
  1782. begin
  1783. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1784. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1785. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  1786. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  1787. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DX));
  1788. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_CX));
  1789. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_BX));
  1790. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_AX));
  1791. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1792. end
  1793. { Routines with the poclearstack flag set use only a ret }
  1794. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  1795. (not paramanager.use_fixed_stack) then
  1796. begin
  1797. { complex return values are removed from stack in C code PM }
  1798. { but not on win32 }
  1799. { and not for safecall with hidden exceptions, because the result }
  1800. { wich contains the exception is passed in EAX }
  1801. if (target_info.system <> system_i386_win32) and
  1802. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  1803. (tf_safecall_exceptions in target_info.flags)) and
  1804. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  1805. current_procinfo.procdef) then
  1806. list.concat(Taicpu.Op_const(ret_instr,S_W,sizeof(aint)))
  1807. else
  1808. list.concat(Taicpu.Op_none(ret_instr,S_NO));
  1809. end
  1810. { ... also routines with parasize=0 }
  1811. else if (parasize=0) then
  1812. list.concat(Taicpu.Op_none(ret_instr,S_NO))
  1813. else
  1814. begin
  1815. { parameters are limited to 65535 bytes because ret allows only imm16 }
  1816. if (parasize>65535) then
  1817. CGMessage(cg_e_parasize_too_big);
  1818. list.concat(Taicpu.Op_const(ret_instr,S_W,parasize));
  1819. end;
  1820. end;
  1821. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  1822. var
  1823. power : longint;
  1824. opsize : topsize;
  1825. saved_ds: Boolean;
  1826. begin
  1827. { get stack space }
  1828. getcpuregister(list,NR_DI);
  1829. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  1830. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  1831. { Now DI contains (high+1). }
  1832. include(current_procinfo.flags, pi_has_open_array_parameter);
  1833. { special case handling for elesize=2:
  1834. set CX = (high+1) instead of CX = (high+1)*elesize.
  1835. This allows us to avoid the SHR later. }
  1836. if elesize=2 then
  1837. begin
  1838. { Now DI contains (high+1). Copy it to CX for later use. }
  1839. getcpuregister(list,NR_CX);
  1840. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1841. end;
  1842. { DI := DI * elesize }
  1843. if (elesize<>1) then
  1844. begin
  1845. if ispowerof2(elesize, power) then
  1846. a_op_const_reg(list,OP_SHL,OS_16,power,NR_DI)
  1847. else
  1848. a_op_const_reg(list,OP_IMUL,OS_16,elesize,NR_DI);
  1849. end;
  1850. if elesize<>2 then
  1851. begin
  1852. { Now DI contains (high+1)*elesize. Copy it to CX for later use. }
  1853. getcpuregister(list,NR_CX);
  1854. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1855. end;
  1856. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  1857. by (size div pagesize)*pagesize, otherwise EDI=size.
  1858. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  1859. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  1860. { align stack on 2 bytes }
  1861. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  1862. { load destination, don't use a_load_reg_reg, that will add a move instruction
  1863. that can confuse the reg allocator }
  1864. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1865. {$ifdef volatile_es}
  1866. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS));
  1867. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  1868. {$endif volatile_es}
  1869. { Allocate SI and load it with source }
  1870. getcpuregister(list,NR_SI);
  1871. if ((ref.segment=NR_NO) and (segment_regs_equal(NR_SS,NR_DS) or (ref.base<>NR_BP))) or
  1872. (is_segment_reg(ref.segment) and segment_regs_equal(ref.segment,NR_DS)) then
  1873. begin
  1874. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  1875. saved_ds:=false;
  1876. end
  1877. else
  1878. begin
  1879. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  1880. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  1881. saved_ds:=true;
  1882. if ref.segment<>NR_NO then
  1883. list.concat(taicpu.op_reg(A_PUSH,S_W,ref.segment))
  1884. else if ref.base=NR_BP then
  1885. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS))
  1886. else
  1887. internalerror(2014040403);
  1888. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  1889. end;
  1890. { calculate size }
  1891. opsize:=S_B;
  1892. if elesize=2 then
  1893. begin
  1894. opsize:=S_W;
  1895. { CX is already number of words, so no need to SHL/SHR }
  1896. end
  1897. else if (elesize and 1)=0 then
  1898. begin
  1899. opsize:=S_W;
  1900. { CX is number of bytes, convert to words }
  1901. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX))
  1902. end;
  1903. if ts_cld in current_settings.targetswitches then
  1904. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1905. if (opsize=S_B) and not (cs_opt_size in current_settings.optimizerswitches) then
  1906. begin
  1907. { SHR CX,1 moves the lowest (odd/even) bit to the carry flag }
  1908. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX));
  1909. list.concat(Taicpu.op_none(A_REP,S_NO));
  1910. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1911. { ADC CX,CX will set CX to 1 if the number of bytes was odd }
  1912. list.concat(Taicpu.op_reg_reg(A_ADC,S_W,NR_CX,NR_CX));
  1913. list.concat(Taicpu.op_none(A_REP,S_NO));
  1914. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1915. end
  1916. else
  1917. begin
  1918. list.concat(Taicpu.op_none(A_REP,S_NO));
  1919. case opsize of
  1920. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1921. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1922. end;
  1923. end;
  1924. ungetcpuregister(list,NR_DI);
  1925. ungetcpuregister(list,NR_CX);
  1926. ungetcpuregister(list,NR_SI);
  1927. if saved_ds then
  1928. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  1929. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  1930. that can confuse the reg allocator }
  1931. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  1932. if current_settings.x86memorymodel in x86_far_data_models then
  1933. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SS,GetNextReg(destreg)));
  1934. end;
  1935. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  1936. begin
  1937. { Nothing to do }
  1938. end;
  1939. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  1940. begin
  1941. case op of
  1942. OP_ADD :
  1943. begin
  1944. op1:=A_ADD;
  1945. op2:=A_ADC;
  1946. end;
  1947. OP_SUB :
  1948. begin
  1949. op1:=A_SUB;
  1950. op2:=A_SBB;
  1951. end;
  1952. OP_XOR :
  1953. begin
  1954. op1:=A_XOR;
  1955. op2:=A_XOR;
  1956. end;
  1957. OP_OR :
  1958. begin
  1959. op1:=A_OR;
  1960. op2:=A_OR;
  1961. end;
  1962. OP_AND :
  1963. begin
  1964. op1:=A_AND;
  1965. op2:=A_AND;
  1966. end;
  1967. else
  1968. internalerror(200203241);
  1969. end;
  1970. end;
  1971. procedure tcg8086.add_move_instruction(instr: Taicpu);
  1972. begin
  1973. { HACK: when regvars are on, don't notify the register allocator of any
  1974. direct moves to BX, so it doesn't try to coalesce them. Currently,
  1975. direct moves to BX are only used when returning an int64 value in
  1976. AX:BX:CX:DX. This hack fixes a common issue with functions, returning
  1977. int64, for example:
  1978. function RandomFrom(const AValues: array of Int64): Int64;
  1979. begin
  1980. result:=AValues[random(High(AValues)+1)];
  1981. end;
  1982. push bp
  1983. mov bp,sp
  1984. ; Var AValues located in register ireg20w
  1985. ; Var $highAVALUES located in register ireg21w
  1986. ; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
  1987. mov ireg20w,word [bp+6]
  1988. mov ireg21w,word [bp+4]
  1989. ; [3] result:=AValues[random(High(AValues)+1)];
  1990. mov ireg22w,ireg21w
  1991. inc ireg22w
  1992. mov ax,ireg22w
  1993. cwd
  1994. mov ireg23w,ax
  1995. mov ireg24w,dx
  1996. push ireg24w
  1997. push ireg23w
  1998. call SYSTEM_$$_RANDOM$LONGINT$$LONGINT
  1999. mov ireg25w,ax
  2000. mov ireg26w,dx
  2001. mov ireg27w,ireg25w
  2002. mov ireg28w,ireg27w
  2003. mov ireg29w,ireg28w
  2004. mov cl,3
  2005. shl ireg29w,cl
  2006. ; Var $result located in register ireg32w:ireg30w
  2007. mov ireg30w,word [ireg20w+ireg29w]
  2008. mov ireg31w,word [ireg20w+ireg29w+2]
  2009. mov ireg32w,word [ireg20w+ireg29w+4] ; problematic section start
  2010. mov ireg33w,word [ireg20w+ireg29w+6]
  2011. ; [4] end;
  2012. mov bx,ireg32w ; problematic section end
  2013. mov ax,ireg33w
  2014. mov dx,ireg30w
  2015. mov cx,ireg31w
  2016. mov sp,bp
  2017. pop bp
  2018. ret 4
  2019. the problem arises, because the register allocator tries to coalesce
  2020. mov bx,ireg32w
  2021. however, in the references [ireg20w+ireg29w+const], due to the
  2022. constraints of i8086, ireg20w can only be BX (or BP, which isn't available
  2023. to the register allocator, because it's used as a base pointer) }
  2024. if (cs_opt_regvar in current_settings.optimizerswitches) and
  2025. (instr.opcode=A_MOV) and (instr.ops=2) and
  2026. (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
  2027. exit
  2028. else
  2029. inherited add_move_instruction(instr);
  2030. end;
  2031. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2032. var
  2033. hsym : tsym;
  2034. href : treference;
  2035. paraloc : Pcgparalocation;
  2036. return_address_size: Integer;
  2037. begin
  2038. if current_settings.x86memorymodel in x86_far_code_models then
  2039. return_address_size:=4
  2040. else
  2041. return_address_size:=2;
  2042. { calculate the parameter info for the procdef }
  2043. procdef.init_paraloc_info(callerside);
  2044. hsym:=tsym(procdef.parast.Find('self'));
  2045. if not(assigned(hsym) and
  2046. (hsym.typ=paravarsym)) then
  2047. internalerror(200305251);
  2048. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2049. with paraloc^ do
  2050. begin
  2051. case loc of
  2052. LOC_REGISTER:
  2053. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  2054. LOC_REFERENCE:
  2055. begin
  2056. { offset in the wrapper needs to be adjusted for the stored
  2057. return address }
  2058. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  2059. and (reference.index<>NR_SI) then
  2060. begin
  2061. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  2062. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  2063. if reference.index=NR_SP then
  2064. reference_reset_base(href,NR_DI,reference.offset+return_address_size+2,sizeof(pint))
  2065. else
  2066. reference_reset_base(href,NR_DI,reference.offset+return_address_size,sizeof(pint));
  2067. href.segment:=NR_SS;
  2068. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2069. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  2070. end
  2071. else
  2072. begin
  2073. reference_reset_base(href,reference.index,reference.offset+return_address_size,sizeof(pint));
  2074. href.segment:=NR_SS;
  2075. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2076. end;
  2077. end
  2078. else
  2079. internalerror(200309189);
  2080. end;
  2081. paraloc:=next;
  2082. end;
  2083. end;
  2084. { ************* 64bit operations ************ }
  2085. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  2086. begin
  2087. case op of
  2088. OP_ADD :
  2089. begin
  2090. op1:=A_ADD;
  2091. op2:=A_ADC;
  2092. end;
  2093. OP_SUB :
  2094. begin
  2095. op1:=A_SUB;
  2096. op2:=A_SBB;
  2097. end;
  2098. OP_XOR :
  2099. begin
  2100. op1:=A_XOR;
  2101. op2:=A_XOR;
  2102. end;
  2103. OP_OR :
  2104. begin
  2105. op1:=A_OR;
  2106. op2:=A_OR;
  2107. end;
  2108. OP_AND :
  2109. begin
  2110. op1:=A_AND;
  2111. op2:=A_AND;
  2112. end;
  2113. else
  2114. internalerror(200203241);
  2115. end;
  2116. end;
  2117. procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  2118. var
  2119. op1,op2 : TAsmOp;
  2120. tempref : treference;
  2121. begin
  2122. if not(op in [OP_NEG,OP_NOT]) then
  2123. begin
  2124. get_64bit_ops(op,op1,op2);
  2125. tempref:=ref;
  2126. tcgx86(cg).make_simple_ref(list,tempref);
  2127. list.concat(taicpu.op_ref_reg(op1,S_W,tempref,reg.reglo));
  2128. inc(tempref.offset,2);
  2129. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reglo)));
  2130. inc(tempref.offset,2);
  2131. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,reg.reghi));
  2132. inc(tempref.offset,2);
  2133. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reghi)));
  2134. end
  2135. else
  2136. begin
  2137. a_load64_ref_reg(list,ref,reg);
  2138. a_op64_reg_reg(list,op,size,reg,reg);
  2139. end;
  2140. end;
  2141. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2142. var
  2143. op1,op2 : TAsmOp;
  2144. begin
  2145. case op of
  2146. OP_NEG :
  2147. begin
  2148. if (regsrc.reglo<>regdst.reglo) then
  2149. a_load64_reg_reg(list,regsrc,regdst);
  2150. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2151. cg.a_op_reg_reg(list,OP_NEG,OS_32,regdst.reglo,regdst.reglo);
  2152. { there's no OP_SBB, so do it directly }
  2153. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  2154. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,GetNextReg(regdst.reghi)));
  2155. exit;
  2156. end;
  2157. OP_NOT :
  2158. begin
  2159. if (regsrc.reglo<>regdst.reglo) then
  2160. a_load64_reg_reg(list,regsrc,regdst);
  2161. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  2162. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2163. exit;
  2164. end;
  2165. end;
  2166. get_64bit_ops(op,op1,op2);
  2167. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  2168. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reglo),GetNextReg(regdst.reglo)));
  2169. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  2170. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reghi),GetNextReg(regdst.reghi)));
  2171. end;
  2172. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2173. var
  2174. op1,op2 : TAsmOp;
  2175. begin
  2176. case op of
  2177. OP_AND,OP_OR,OP_XOR:
  2178. begin
  2179. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  2180. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  2181. end;
  2182. OP_ADD, OP_SUB:
  2183. begin
  2184. get_64bit_ops(op,op1,op2);
  2185. if (value and $ffffffffffff) = 0 then
  2186. begin
  2187. { use a_op_const_reg to allow the use of inc/dec }
  2188. cg.a_op_const_reg(list,op,OS_16,aint((value shr 48) and $ffff),GetNextReg(reg.reghi));
  2189. end
  2190. // can't use a_op_const_ref because this may use dec/inc
  2191. else if (value and $ffffffff) = 0 then
  2192. begin
  2193. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2194. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  2195. end
  2196. else if (value and $ffff) = 0 then
  2197. begin
  2198. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  2199. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2200. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  2201. end
  2202. else
  2203. begin
  2204. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  2205. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  2206. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2207. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  2208. end;
  2209. end;
  2210. else
  2211. internalerror(200204021);
  2212. end;
  2213. end;
  2214. procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  2215. var
  2216. op1,op2 : TAsmOp;
  2217. tempref : treference;
  2218. begin
  2219. tempref:=ref;
  2220. tcgx86(cg).make_simple_ref(list,tempref);
  2221. case op of
  2222. OP_AND,OP_OR,OP_XOR:
  2223. begin
  2224. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  2225. inc(tempref.offset,4);
  2226. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  2227. end;
  2228. OP_ADD, OP_SUB:
  2229. begin
  2230. get_64bit_ops(op,op1,op2);
  2231. if (value and $ffffffffffff) = 0 then
  2232. begin
  2233. inc(tempref.offset,6);
  2234. { use a_op_const_ref to allow the use of inc/dec }
  2235. cg.a_op_const_ref(list,op,OS_16,aint((value shr 48) and $ffff),tempref);
  2236. end
  2237. // can't use a_op_const_ref because this may use dec/inc
  2238. else if (value and $ffffffff) = 0 then
  2239. begin
  2240. inc(tempref.offset,4);
  2241. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 32) and $ffff),tempref));
  2242. inc(tempref.offset,2);
  2243. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  2244. end
  2245. else if (value and $ffff) = 0 then
  2246. begin
  2247. inc(tempref.offset,2);
  2248. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 16) and $ffff),tempref));
  2249. inc(tempref.offset,2);
  2250. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  2251. inc(tempref.offset,2);
  2252. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  2253. end
  2254. else
  2255. begin
  2256. list.concat(taicpu.op_const_ref(op1,S_W,aint(value and $ffff),tempref));
  2257. inc(tempref.offset,2);
  2258. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 16) and $ffff),tempref));
  2259. inc(tempref.offset,2);
  2260. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  2261. inc(tempref.offset,2);
  2262. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  2263. end;
  2264. end;
  2265. else
  2266. internalerror(200204022);
  2267. end;
  2268. end;
  2269. procedure create_codegen;
  2270. begin
  2271. cg := tcg8086.create;
  2272. cg64 := tcg64f8086.create;
  2273. end;
  2274. end.