cgcpu.pas 77 KB

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