cgcpu.pas 79 KB

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