cgcpu.pas 73 KB

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