cgcpu.pas 92 KB

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