cgcpu.pas 79 KB

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