cgcpu.pas 97 KB

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