cgx86.pas 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the common parts of the code generator for the i386 and the x86-64.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { This unit implements the common parts of the code generator for the i386 and the x86-64.
  19. }
  20. unit cgx86;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cgbase,cgobj,
  25. aasmbase,aasmtai,aasmcpu,
  26. cpubase,cpuinfo,rgobj,rgx86,rgcpu,
  27. symconst,symtype;
  28. type
  29. tcgx86 = class(tcg)
  30. rgfpu : Trgx86fpu;
  31. procedure done_register_allocators;override;
  32. function getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  33. function getmmxregister(list:Taasmoutput):Tregister;
  34. procedure getexplicitregister(list:Taasmoutput;r:Tregister);override;
  35. procedure ungetregister(list:Taasmoutput;r:Tregister);override;
  36. procedure allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  37. procedure deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  38. function uses_registers(rt:Tregistertype):boolean;override;
  39. procedure add_reg_instruction(instr:Tai;r:tregister);override;
  40. procedure dec_fpu_stack;
  41. procedure inc_fpu_stack;
  42. { passing parameters, per default the parameter is pushed }
  43. { nr gives the number of the parameter (enumerated from }
  44. { left to right), this allows to move the parameter to }
  45. { register, if the cpu supports register calling }
  46. { conventions }
  47. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);override;
  48. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  49. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  50. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  51. procedure a_call_name(list : taasmoutput;const s : string);override;
  52. procedure a_call_reg(list : taasmoutput;reg : tregister);override;
  53. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  54. procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference); override;
  55. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  56. procedure a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  57. procedure a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  58. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  59. size: tcgsize; a: aword; src, dst: tregister); override;
  60. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  61. size: tcgsize; src1, src2, dst: tregister); override;
  62. { move instructions }
  63. procedure a_load_const_reg(list : taasmoutput; tosize: tcgsize; a : aword;reg : tregister);override;
  64. procedure a_load_const_ref(list : taasmoutput; tosize: tcgsize; a : aword;const ref : treference);override;
  65. procedure a_load_reg_ref(list : taasmoutput;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  66. procedure a_load_ref_reg(list : taasmoutput;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  67. procedure a_load_reg_reg(list : taasmoutput;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  68. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  69. { fpu move instructions }
  70. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  71. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  72. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  73. { vector register move instructions }
  74. procedure a_loadmm_reg_reg(list: taasmoutput; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  75. procedure a_loadmm_ref_reg(list: taasmoutput; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  76. procedure a_loadmm_reg_ref(list: taasmoutput; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  77. procedure a_opmm_ref_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  78. procedure a_opmm_reg_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);override;
  79. { comparison operations }
  80. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  81. l : tasmlabel);override;
  82. procedure a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  83. l : tasmlabel);override;
  84. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  85. procedure a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  86. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  87. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  88. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister); override;
  89. procedure g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference); override;
  90. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  91. procedure g_exception_reason_save(list : taasmoutput; const href : treference);override;
  92. procedure g_exception_reason_save_const(list : taasmoutput; const href : treference; a: aword);override;
  93. procedure g_exception_reason_load(list : taasmoutput; const href : treference);override;
  94. { entry/exit code helpers }
  95. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);override;
  96. procedure g_releasevaluepara_openarray(list : taasmoutput;const ref:treference);override;
  97. procedure g_interrupt_stackframe_entry(list : taasmoutput);override;
  98. procedure g_interrupt_stackframe_exit(list : taasmoutput;accused,acchiused:boolean);override;
  99. procedure g_profilecode(list : taasmoutput);override;
  100. procedure g_stackpointer_alloc(list : taasmoutput;localsize : longint);override;
  101. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  102. procedure g_restore_frame_pointer(list : taasmoutput);override;
  103. procedure g_return_from_proc(list : taasmoutput;parasize : aword);override;
  104. procedure g_save_standard_registers(list:Taasmoutput);override;
  105. procedure g_restore_standard_registers(list:Taasmoutput);override;
  106. procedure g_overflowcheck(list: taasmoutput; const l:tlocation;def:tdef);override;
  107. protected
  108. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  109. procedure check_register_size(size:tcgsize;reg:tregister);
  110. procedure opmm_loc_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  111. private
  112. procedure sizes2load(s1,s2 : tcgsize;var op: tasmop; var s3: topsize);
  113. procedure floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  114. procedure floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  115. procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  116. procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  117. end;
  118. function use_sse(def : tdef) : boolean;
  119. const
  120. {$ifdef x86_64}
  121. TCGSize2OpSize: Array[tcgsize] of topsize =
  122. (S_NO,S_B,S_W,S_L,S_Q,S_B,S_W,S_L,S_Q,
  123. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  124. S_NO,S_NO,S_NO,S_MD,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  125. {$else x86_64}
  126. TCGSize2OpSize: Array[tcgsize] of topsize =
  127. (S_NO,S_B,S_W,S_L,S_L,S_B,S_W,S_L,S_L,
  128. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  129. S_NO,S_NO,S_NO,S_MD,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  130. {$endif x86_64}
  131. implementation
  132. uses
  133. globtype,globals,verbose,systems,cutils,
  134. symdef,defutil,paramgr,tgobj,procinfo;
  135. {$ifndef NOTARGETWIN32}
  136. const
  137. winstackpagesize = 4096;
  138. {$endif NOTARGETWIN32}
  139. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIV,
  140. A_IDIV,A_MUL, A_IMUL, A_NEG,A_NOT,A_OR,
  141. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR);
  142. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,
  143. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  144. function use_sse(def : tdef) : boolean;
  145. begin
  146. use_sse:=(is_single(def) and (aktfputype in sse_singlescalar)) or
  147. (is_double(def) and (aktfputype in sse_doublescalar));
  148. end;
  149. procedure Tcgx86.done_register_allocators;
  150. begin
  151. rg[R_INTREGISTER].free;
  152. rg[R_MMREGISTER].free;
  153. rg[R_MMXREGISTER].free;
  154. rgfpu.free;
  155. inherited done_register_allocators;
  156. end;
  157. function Tcgx86.getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;
  158. begin
  159. result:=rgfpu.getregisterfpu(list);
  160. end;
  161. function Tcgx86.getmmxregister(list:Taasmoutput):Tregister;
  162. begin
  163. if not assigned(rg[R_MMXREGISTER]) then
  164. internalerror(200312124);
  165. result:=rg[R_MMXREGISTER].getregister(list,R_SUBNONE);
  166. end;
  167. procedure Tcgx86.getexplicitregister(list:Taasmoutput;r:Tregister);
  168. begin
  169. if getregtype(r)=R_FPUREGISTER then
  170. internalerror(2003121210)
  171. else
  172. inherited getexplicitregister(list,r);
  173. end;
  174. procedure tcgx86.ungetregister(list:Taasmoutput;r:Tregister);
  175. begin
  176. if getregtype(r)=R_FPUREGISTER then
  177. rgfpu.ungetregisterfpu(list,r)
  178. else
  179. inherited ungetregister(list,r);
  180. end;
  181. procedure Tcgx86.allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  182. begin
  183. if rt<>R_FPUREGISTER then
  184. inherited allocexplicitregisters(list,rt,r);
  185. end;
  186. procedure Tcgx86.deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  187. begin
  188. if rt<>R_FPUREGISTER then
  189. inherited deallocexplicitregisters(list,rt,r);
  190. end;
  191. function Tcgx86.uses_registers(rt:Tregistertype):boolean;
  192. begin
  193. if rt=R_FPUREGISTER then
  194. result:=false
  195. else
  196. result:=inherited uses_registers(rt);
  197. end;
  198. procedure tcgx86.add_reg_instruction(instr:Tai;r:tregister);
  199. begin
  200. if getregtype(r)<>R_FPUREGISTER then
  201. inherited add_reg_instruction(instr,r);
  202. end;
  203. procedure tcgx86.dec_fpu_stack;
  204. begin
  205. dec(rgfpu.fpuvaroffset);
  206. end;
  207. procedure tcgx86.inc_fpu_stack;
  208. begin
  209. inc(rgfpu.fpuvaroffset);
  210. end;
  211. {****************************************************************************
  212. This is private property, keep out! :)
  213. ****************************************************************************}
  214. procedure tcgx86.sizes2load(s1,s2 : tcgsize; var op: tasmop; var s3: topsize);
  215. begin
  216. case s2 of
  217. OS_8,OS_S8 :
  218. if S1 in [OS_8,OS_S8] then
  219. s3 := S_B
  220. else
  221. internalerror(200109221);
  222. OS_16,OS_S16:
  223. case s1 of
  224. OS_8,OS_S8:
  225. s3 := S_BW;
  226. OS_16,OS_S16:
  227. s3 := S_W;
  228. else
  229. internalerror(200109222);
  230. end;
  231. OS_32,OS_S32:
  232. case s1 of
  233. OS_8,OS_S8:
  234. s3 := S_BL;
  235. OS_16,OS_S16:
  236. s3 := S_WL;
  237. OS_32,OS_S32:
  238. s3 := S_L;
  239. else
  240. internalerror(200109223);
  241. end;
  242. {$ifdef x86_64}
  243. OS_64,OS_S64:
  244. case s1 of
  245. OS_8,OS_S8:
  246. s3 := S_BL;
  247. OS_16,OS_S16:
  248. s3 := S_WL;
  249. OS_32,OS_S32:
  250. s3 := S_L;
  251. OS_64,OS_S64:
  252. s3 := S_Q;
  253. else
  254. internalerror(200304302);
  255. end;
  256. {$endif x86_64}
  257. else
  258. internalerror(200109227);
  259. end;
  260. if s3 in [S_B,S_W,S_L,S_Q] then
  261. op := A_MOV
  262. else if s1 in [OS_8,OS_16,OS_32,OS_64] then
  263. op := A_MOVZX
  264. else
  265. op := A_MOVSX;
  266. end;
  267. procedure tcgx86.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  268. begin
  269. case t of
  270. OS_F32 :
  271. begin
  272. op:=A_FLD;
  273. s:=S_FS;
  274. end;
  275. OS_F64 :
  276. begin
  277. op:=A_FLD;
  278. { ???? }
  279. s:=S_FL;
  280. end;
  281. OS_F80 :
  282. begin
  283. op:=A_FLD;
  284. s:=S_FX;
  285. end;
  286. OS_C64 :
  287. begin
  288. op:=A_FILD;
  289. s:=S_IQ;
  290. end;
  291. else
  292. internalerror(200204041);
  293. end;
  294. end;
  295. procedure tcgx86.floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  296. var
  297. op : tasmop;
  298. s : topsize;
  299. begin
  300. floatloadops(t,op,s);
  301. list.concat(Taicpu.Op_ref(op,s,ref));
  302. inc_fpu_stack;
  303. end;
  304. procedure tcgx86.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  305. begin
  306. case t of
  307. OS_F32 :
  308. begin
  309. op:=A_FSTP;
  310. s:=S_FS;
  311. end;
  312. OS_F64 :
  313. begin
  314. op:=A_FSTP;
  315. s:=S_FL;
  316. end;
  317. OS_F80 :
  318. begin
  319. op:=A_FSTP;
  320. s:=S_FX;
  321. end;
  322. OS_C64 :
  323. begin
  324. op:=A_FISTP;
  325. s:=S_IQ;
  326. end;
  327. else
  328. internalerror(200204042);
  329. end;
  330. end;
  331. procedure tcgx86.floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  332. var
  333. op : tasmop;
  334. s : topsize;
  335. begin
  336. floatstoreops(t,op,s);
  337. list.concat(Taicpu.Op_ref(op,s,ref));
  338. dec_fpu_stack;
  339. end;
  340. procedure tcgx86.check_register_size(size:tcgsize;reg:tregister);
  341. begin
  342. if TCGSize2OpSize[size]<>TCGSize2OpSize[reg_cgsize(reg)] then
  343. internalerror(200306031);
  344. end;
  345. {****************************************************************************
  346. Assembler code
  347. ****************************************************************************}
  348. { currently does nothing }
  349. procedure tcgx86.a_jmp_always(list : taasmoutput;l: tasmlabel);
  350. begin
  351. a_jmp_cond(list, OC_NONE, l);
  352. end;
  353. { we implement the following routines because otherwise we can't }
  354. { instantiate the class since it's abstract }
  355. procedure tcgx86.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);
  356. var
  357. pushsize : tcgsize;
  358. begin
  359. check_register_size(size,r);
  360. if (locpara.loc=LOC_REFERENCE) and
  361. (locpara.reference.index=NR_STACK_POINTER_REG) then
  362. begin
  363. pushsize:=int_cgsize(locpara.alignment);
  364. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(r,pushsize)));
  365. end
  366. else
  367. inherited a_param_reg(list,size,r,locpara);
  368. end;
  369. procedure tcgx86.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  370. var
  371. pushsize : tcgsize;
  372. begin
  373. if (locpara.loc=LOC_REFERENCE) and
  374. (locpara.reference.index=NR_STACK_POINTER_REG) then
  375. begin
  376. pushsize:=int_cgsize(locpara.alignment);
  377. list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
  378. end
  379. else
  380. inherited a_param_const(list,size,a,locpara);
  381. end;
  382. procedure tcgx86.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  383. var
  384. pushsize : tcgsize;
  385. tmpreg : tregister;
  386. begin
  387. if (locpara.loc=LOC_REFERENCE) and
  388. (locpara.reference.index=NR_STACK_POINTER_REG) then
  389. begin
  390. pushsize:=int_cgsize(locpara.alignment);
  391. if tcgsize2size[size]<locpara.alignment then
  392. begin
  393. tmpreg:=getintregister(list,pushsize);
  394. a_load_ref_reg(list,size,pushsize,r,tmpreg);
  395. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],tmpreg));
  396. ungetregister(list,tmpreg);
  397. end
  398. else
  399. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[pushsize],r));
  400. end
  401. else
  402. inherited a_param_ref(list,size,r,locpara);
  403. end;
  404. procedure tcgx86.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  405. var
  406. tmpreg : tregister;
  407. opsize : topsize;
  408. begin
  409. if (r.segment<>NR_NO) then
  410. CGMessage(cg_e_cant_use_far_pointer_there);
  411. if (locpara.loc=LOC_REFERENCE) and
  412. (locpara.reference.index=NR_STACK_POINTER_REG) then
  413. begin
  414. opsize:=tcgsize2opsize[OS_ADDR];
  415. if (r.base=NR_NO) and (r.index=NR_NO) then
  416. begin
  417. if assigned(r.symbol) then
  418. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,r.symbol,r.offset))
  419. else
  420. list.concat(Taicpu.Op_const(A_PUSH,opsize,r.offset));
  421. end
  422. else if (r.base=NR_NO) and (r.index<>NR_NO) and
  423. (r.offset=0) and (r.scalefactor=0) and (r.symbol=nil) then
  424. list.concat(Taicpu.Op_reg(A_PUSH,opsize,r.index))
  425. else if (r.base<>NR_NO) and (r.index=NR_NO) and
  426. (r.offset=0) and (r.symbol=nil) then
  427. list.concat(Taicpu.Op_reg(A_PUSH,opsize,r.base))
  428. else
  429. begin
  430. tmpreg:=getaddressregister(list);
  431. a_loadaddr_ref_reg(list,r,tmpreg);
  432. ungetregister(list,tmpreg);
  433. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  434. end;
  435. end
  436. else
  437. inherited a_paramaddr_ref(list,r,locpara);
  438. end;
  439. procedure tcgx86.a_call_name(list : taasmoutput;const s : string);
  440. begin
  441. list.concat(taicpu.op_sym(A_CALL,S_NO,objectlibrary.newasmsymbol(s)));
  442. end;
  443. procedure tcgx86.a_call_reg(list : taasmoutput;reg : tregister);
  444. begin
  445. list.concat(taicpu.op_reg(A_CALL,S_NO,reg));
  446. end;
  447. {********************** load instructions ********************}
  448. procedure tcgx86.a_load_const_reg(list : taasmoutput; tosize: TCGSize; a : aword; reg : TRegister);
  449. begin
  450. check_register_size(tosize,reg);
  451. { the optimizer will change it to "xor reg,reg" when loading zero, }
  452. { no need to do it here too (JM) }
  453. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg))
  454. end;
  455. procedure tcgx86.a_load_const_ref(list : taasmoutput; tosize: tcgsize; a : aword;const ref : treference);
  456. begin
  457. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,ref));
  458. end;
  459. procedure tcgx86.a_load_reg_ref(list : taasmoutput; fromsize,tosize: TCGSize; reg : tregister;const ref : treference);
  460. var
  461. op: tasmop;
  462. s: topsize;
  463. tmpreg : tregister;
  464. begin
  465. check_register_size(fromsize,reg);
  466. sizes2load(fromsize,tosize,op,s);
  467. case s of
  468. {$ifdef x86_64}
  469. S_BQ,S_WQ,S_LQ,
  470. {$endif x86_64}
  471. S_BW,S_BL,S_WL :
  472. begin
  473. tmpreg:=getintregister(list,tosize);
  474. {$ifdef x86_64}
  475. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  476. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  477. 64 bit (FK) }
  478. if s in [S_BL,S_WL,S_L] then
  479. tmpreg:=makeregsize(tmpreg,OS_32);
  480. {$endif x86_64}
  481. list.concat(taicpu.op_reg_reg(op,s,reg,tmpreg));
  482. a_load_reg_ref(list,tosize,tosize,tmpreg,ref);
  483. ungetregister(list,tmpreg);
  484. end;
  485. else
  486. list.concat(taicpu.op_reg_ref(op,s,reg,ref));
  487. end;
  488. end;
  489. procedure tcgx86.a_load_ref_reg(list : taasmoutput;fromsize,tosize : tcgsize;const ref: treference;reg : tregister);
  490. var
  491. op: tasmop;
  492. s: topsize;
  493. begin
  494. check_register_size(tosize,reg);
  495. sizes2load(fromsize,tosize,op,s);
  496. {$ifdef x86_64}
  497. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  498. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  499. 64 bit (FK) }
  500. if s in [S_BL,S_WL,S_L] then
  501. reg:=makeregsize(reg,OS_32);
  502. {$endif x86_64}
  503. list.concat(taicpu.op_ref_reg(op,s,ref,reg));
  504. end;
  505. procedure tcgx86.a_load_reg_reg(list : taasmoutput;fromsize,tosize : tcgsize;reg1,reg2 : tregister);
  506. var
  507. op: tasmop;
  508. s: topsize;
  509. instr:Taicpu;
  510. begin
  511. check_register_size(fromsize,reg1);
  512. check_register_size(tosize,reg2);
  513. sizes2load(fromsize,tosize,op,s);
  514. {$ifdef x86_64}
  515. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  516. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  517. 64 bit (FK) }
  518. if s in [S_BL,S_WL,S_L] then
  519. reg2:=makeregsize(reg2,OS_32);
  520. {$endif x86_64}
  521. instr:=taicpu.op_reg_reg(op,s,reg1,reg2);
  522. { Notify the register allocator that we have written a move instruction so
  523. it can try to eliminate it. }
  524. add_move_instruction(instr);
  525. list.concat(instr);
  526. end;
  527. procedure tcgx86.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  528. begin
  529. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  530. begin
  531. if assigned(ref.symbol) then
  532. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,tcgsize2opsize[OS_ADDR],ref.symbol,ref.offset,r))
  533. else
  534. a_load_const_reg(list,OS_ADDR,ref.offset,r);
  535. end
  536. else if (ref.base=NR_NO) and (ref.index<>NR_NO) and
  537. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  538. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.index,r)
  539. else if (ref.base<>NR_NO) and (ref.index=NR_NO) and
  540. (ref.offset=0) and (ref.symbol=nil) then
  541. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.base,r)
  542. else
  543. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],ref,r));
  544. end;
  545. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  546. { R_ST means "the current value at the top of the fpu stack" (JM) }
  547. procedure tcgx86.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  548. begin
  549. if (reg1<>NR_ST) then
  550. begin
  551. list.concat(taicpu.op_reg(A_FLD,S_NO,rgfpu.correct_fpuregister(reg1,rgfpu.fpuvaroffset)));
  552. inc_fpu_stack;
  553. end;
  554. if (reg2<>NR_ST) then
  555. begin
  556. list.concat(taicpu.op_reg(A_FSTP,S_NO,rgfpu.correct_fpuregister(reg2,rgfpu.fpuvaroffset)));
  557. dec_fpu_stack;
  558. end;
  559. end;
  560. procedure tcgx86.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  561. begin
  562. floatload(list,size,ref);
  563. if (reg<>NR_ST) then
  564. a_loadfpu_reg_reg(list,size,NR_ST,reg);
  565. end;
  566. procedure tcgx86.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  567. begin
  568. if reg<>NR_ST then
  569. a_loadfpu_reg_reg(list,size,reg,NR_ST);
  570. floatstore(list,size,ref);
  571. end;
  572. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  573. begin
  574. case fromsize of
  575. OS_F32:
  576. case tosize of
  577. OS_F64:
  578. result:=A_CVTSS2SD;
  579. OS_F32:
  580. result:=A_MOVSS;
  581. else
  582. internalerror(200312205);
  583. end;
  584. OS_F64:
  585. case tosize of
  586. OS_F64:
  587. result:=A_MOVSD;
  588. OS_F32:
  589. result:=A_CVTSD2SS;
  590. else
  591. internalerror(200312204);
  592. end;
  593. else
  594. internalerror(200312203);
  595. end;
  596. end;
  597. procedure tcgx86.a_loadmm_reg_reg(list: taasmoutput; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle);
  598. begin
  599. if shuffle=nil then
  600. begin
  601. if fromsize=tosize then
  602. list.concat(taicpu.op_reg_reg(A_MOVAPS,S_NO,reg1,reg2))
  603. else
  604. internalerror(200312202);
  605. end
  606. else if shufflescalar(shuffle) then
  607. list.concat(taicpu.op_reg_reg(get_scalar_mm_op(fromsize,tosize),S_NO,reg1,reg2))
  608. else
  609. internalerror(200312201);
  610. end;
  611. procedure tcgx86.a_loadmm_ref_reg(list: taasmoutput; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  612. begin
  613. if shuffle=nil then
  614. begin
  615. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  616. end
  617. else if shufflescalar(shuffle) then
  618. list.concat(taicpu.op_ref_reg(get_scalar_mm_op(fromsize,tosize),S_NO,ref,reg))
  619. else
  620. internalerror(200312252);
  621. end;
  622. procedure tcgx86.a_loadmm_reg_ref(list: taasmoutput; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle);
  623. begin
  624. if shuffle=nil then
  625. begin
  626. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  627. end
  628. else if shufflescalar(shuffle) then
  629. list.concat(taicpu.op_reg_ref(get_scalar_mm_op(fromsize,tosize),S_NO,reg,ref))
  630. else
  631. internalerror(200312252);
  632. end;
  633. procedure tcgx86.a_opmm_ref_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  634. var
  635. l : tlocation;
  636. begin
  637. l.loc:=LOC_REFERENCE;
  638. l.reference:=ref;
  639. l.size:=size;
  640. opmm_loc_reg(list,op,size,l,reg,shuffle);
  641. end;
  642. procedure tcgx86.a_opmm_reg_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);
  643. var
  644. l : tlocation;
  645. begin
  646. l.loc:=LOC_MMREGISTER;
  647. l.register:=src;
  648. l.size:=size;
  649. opmm_loc_reg(list,op,size,l,dst,shuffle);
  650. end;
  651. procedure tcgx86.opmm_loc_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  652. const
  653. opmm2asmop : array[0..1,OS_F32..OS_F64,topcg] of tasmop = (
  654. ( { scalar }
  655. ( { OS_F32 }
  656. A_NOP,A_ADDSS,A_NOP,A_DIVSS,A_NOP,A_NOP,A_MULSS,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBSS,A_NOP
  657. ),
  658. ( { OS_F64 }
  659. A_NOP,A_ADDSD,A_NOP,A_DIVSD,A_NOP,A_NOP,A_MULSD,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBSD,A_NOP
  660. )
  661. ),
  662. ( { vectorized/packed }
  663. { because the logical packed single instructions have shorter op codes, we use always
  664. these
  665. }
  666. ( { OS_F32 }
  667. A_NOP,A_ADDPS,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_XORPS
  668. ),
  669. ( { OS_F64 }
  670. A_NOP,A_ADDPD,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_XORPS
  671. )
  672. )
  673. );
  674. var
  675. resultreg : tregister;
  676. asmop : tasmop;
  677. begin
  678. { this is an internally used procedure so the parameters have
  679. some constrains
  680. }
  681. if loc.size<>size then
  682. internalerror(200312213);
  683. resultreg:=dst;
  684. { deshuffle }
  685. //!!!
  686. if (shuffle<>nil) and not(shufflescalar(shuffle)) then
  687. begin
  688. end
  689. else if (shuffle=nil) then
  690. asmop:=opmm2asmop[1,size,op]
  691. else if shufflescalar(shuffle) then
  692. begin
  693. asmop:=opmm2asmop[0,size,op];
  694. { no scalar operation available? }
  695. if asmop=A_NOP then
  696. begin
  697. { do vectorized and shuffle finally }
  698. //!!!
  699. end;
  700. end
  701. else
  702. internalerror(200312211);
  703. if asmop=A_NOP then
  704. internalerror(200312215);
  705. case loc.loc of
  706. LOC_CREFERENCE,LOC_REFERENCE:
  707. list.concat(taicpu.op_ref_reg(asmop,S_NO,loc.reference,resultreg));
  708. LOC_CMMREGISTER,LOC_MMREGISTER:
  709. list.concat(taicpu.op_reg_reg(asmop,S_NO,loc.register,resultreg));
  710. else
  711. internalerror(200312214);
  712. end;
  713. { shuffle }
  714. if resultreg<>dst then
  715. begin
  716. internalerror(200312212);
  717. end;
  718. end;
  719. procedure tcgx86.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  720. var
  721. opcode: tasmop;
  722. power: longint;
  723. begin
  724. check_register_size(size,reg);
  725. case op of
  726. OP_DIV, OP_IDIV:
  727. begin
  728. if ispowerof2(a,power) then
  729. begin
  730. case op of
  731. OP_DIV:
  732. opcode := A_SHR;
  733. OP_IDIV:
  734. opcode := A_SAR;
  735. end;
  736. list.concat(taicpu.op_const_reg(opcode,TCgSize2OpSize[size],power,reg));
  737. exit;
  738. end;
  739. { the rest should be handled specifically in the code }
  740. { generator because of the silly register usage restraints }
  741. internalerror(200109224);
  742. end;
  743. OP_MUL,OP_IMUL:
  744. begin
  745. if not(cs_check_overflow in aktlocalswitches) and
  746. ispowerof2(a,power) then
  747. begin
  748. list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
  749. exit;
  750. end;
  751. if op = OP_IMUL then
  752. list.concat(taicpu.op_const_reg(A_IMUL,TCgSize2OpSize[size],a,reg))
  753. else
  754. { OP_MUL should be handled specifically in the code }
  755. { generator because of the silly register usage restraints }
  756. internalerror(200109225);
  757. end;
  758. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  759. if not(cs_check_overflow in aktlocalswitches) and
  760. (a = 1) and
  761. (op in [OP_ADD,OP_SUB]) then
  762. if op = OP_ADD then
  763. list.concat(taicpu.op_reg(A_INC,TCgSize2OpSize[size],reg))
  764. else
  765. list.concat(taicpu.op_reg(A_DEC,TCgSize2OpSize[size],reg))
  766. else if (a = 0) then
  767. if (op <> OP_AND) then
  768. exit
  769. else
  770. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],0,reg))
  771. else if (a = high(aword)) and
  772. (op in [OP_AND,OP_OR,OP_XOR]) then
  773. begin
  774. case op of
  775. OP_AND:
  776. exit;
  777. OP_OR:
  778. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],high(aword),reg));
  779. OP_XOR:
  780. list.concat(taicpu.op_reg(A_NOT,TCgSize2OpSize[size],reg));
  781. end
  782. end
  783. else
  784. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a,reg));
  785. OP_SHL,OP_SHR,OP_SAR:
  786. begin
  787. if (a and 31) <> 0 Then
  788. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,reg));
  789. if (a shr 5) <> 0 Then
  790. internalerror(68991);
  791. end
  792. else internalerror(68992);
  793. end;
  794. end;
  795. procedure tcgx86.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  796. var
  797. opcode: tasmop;
  798. power: longint;
  799. begin
  800. Case Op of
  801. OP_DIV, OP_IDIV:
  802. Begin
  803. if ispowerof2(a,power) then
  804. begin
  805. case op of
  806. OP_DIV:
  807. opcode := A_SHR;
  808. OP_IDIV:
  809. opcode := A_SAR;
  810. end;
  811. list.concat(taicpu.op_const_ref(opcode,
  812. TCgSize2OpSize[size],power,ref));
  813. exit;
  814. end;
  815. { the rest should be handled specifically in the code }
  816. { generator because of the silly register usage restraints }
  817. internalerror(200109231);
  818. End;
  819. OP_MUL,OP_IMUL:
  820. begin
  821. if not(cs_check_overflow in aktlocalswitches) and
  822. ispowerof2(a,power) then
  823. begin
  824. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  825. power,ref));
  826. exit;
  827. end;
  828. { can't multiply a memory location directly with a constant }
  829. if op = OP_IMUL then
  830. inherited a_op_const_ref(list,op,size,a,ref)
  831. else
  832. { OP_MUL should be handled specifically in the code }
  833. { generator because of the silly register usage restraints }
  834. internalerror(200109232);
  835. end;
  836. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  837. if not(cs_check_overflow in aktlocalswitches) and
  838. (a = 1) and
  839. (op in [OP_ADD,OP_SUB]) then
  840. if op = OP_ADD then
  841. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  842. else
  843. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  844. else if (a = 0) then
  845. if (op <> OP_AND) then
  846. exit
  847. else
  848. a_load_const_ref(list,size,0,ref)
  849. else if (a = high(aword)) and
  850. (op in [OP_AND,OP_OR,OP_XOR]) then
  851. begin
  852. case op of
  853. OP_AND:
  854. exit;
  855. OP_OR:
  856. list.concat(taicpu.op_const_ref(A_MOV,TCgSize2OpSize[size],high(aword),ref));
  857. OP_XOR:
  858. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  859. end
  860. end
  861. else
  862. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  863. TCgSize2OpSize[size],a,ref));
  864. OP_SHL,OP_SHR,OP_SAR:
  865. begin
  866. if (a and 31) <> 0 then
  867. list.concat(taicpu.op_const_ref(
  868. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  869. if (a shr 5) <> 0 Then
  870. internalerror(68991);
  871. end
  872. else internalerror(68992);
  873. end;
  874. end;
  875. procedure tcgx86.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  876. var
  877. dstsize: topsize;
  878. instr:Taicpu;
  879. begin
  880. check_register_size(size,src);
  881. check_register_size(size,dst);
  882. dstsize := tcgsize2opsize[size];
  883. case op of
  884. OP_NEG,OP_NOT:
  885. begin
  886. if src<>dst then
  887. a_load_reg_reg(list,size,size,src,dst);
  888. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  889. end;
  890. OP_MUL,OP_DIV,OP_IDIV:
  891. { special stuff, needs separate handling inside code }
  892. { generator }
  893. internalerror(200109233);
  894. OP_SHR,OP_SHL,OP_SAR:
  895. begin
  896. getexplicitregister(list,NR_CL);
  897. a_load_reg_reg(list,size,OS_8,dst,NR_CL);
  898. list.concat(taicpu.op_reg_reg(Topcg2asmop[op],S_B,src,NR_CL));
  899. ungetregister(list,NR_CL);
  900. end;
  901. else
  902. begin
  903. if reg2opsize(src) <> dstsize then
  904. internalerror(200109226);
  905. instr:=taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,src,dst);
  906. list.concat(instr);
  907. end;
  908. end;
  909. end;
  910. procedure tcgx86.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  911. begin
  912. check_register_size(size,reg);
  913. case op of
  914. OP_NEG,OP_NOT,OP_IMUL:
  915. begin
  916. inherited a_op_ref_reg(list,op,size,ref,reg);
  917. end;
  918. OP_MUL,OP_DIV,OP_IDIV:
  919. { special stuff, needs separate handling inside code }
  920. { generator }
  921. internalerror(200109239);
  922. else
  923. begin
  924. reg := makeregsize(reg,size);
  925. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],tcgsize2opsize[size],ref,reg));
  926. end;
  927. end;
  928. end;
  929. procedure tcgx86.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  930. begin
  931. check_register_size(size,reg);
  932. case op of
  933. OP_NEG,OP_NOT:
  934. begin
  935. if reg<>NR_NO then
  936. internalerror(200109237);
  937. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  938. end;
  939. OP_IMUL:
  940. begin
  941. { this one needs a load/imul/store, which is the default }
  942. inherited a_op_ref_reg(list,op,size,ref,reg);
  943. end;
  944. OP_MUL,OP_DIV,OP_IDIV:
  945. { special stuff, needs separate handling inside code }
  946. { generator }
  947. internalerror(200109238);
  948. else
  949. begin
  950. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],reg,ref));
  951. end;
  952. end;
  953. end;
  954. procedure tcgx86.a_op_const_reg_reg(list: taasmoutput; op: TOpCg; size: tcgsize; a: aword; src, dst: tregister);
  955. var
  956. tmpref: treference;
  957. power: longint;
  958. begin
  959. check_register_size(size,src);
  960. check_register_size(size,dst);
  961. if tcgsize2size[size]<>tcgsize2size[OS_INT] then
  962. begin
  963. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  964. exit;
  965. end;
  966. { if we get here, we have to do a 32 bit calculation, guaranteed }
  967. case op of
  968. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  969. OP_SAR:
  970. { can't do anything special for these }
  971. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  972. OP_IMUL:
  973. begin
  974. if not(cs_check_overflow in aktlocalswitches) and
  975. ispowerof2(a,power) then
  976. { can be done with a shift }
  977. begin
  978. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  979. exit;
  980. end;
  981. list.concat(taicpu.op_const_reg_reg(A_IMUL,tcgsize2opsize[size],a,src,dst));
  982. end;
  983. OP_ADD, OP_SUB:
  984. if (a = 0) then
  985. a_load_reg_reg(list,size,size,src,dst)
  986. else
  987. begin
  988. reference_reset(tmpref);
  989. tmpref.base := src;
  990. tmpref.offset := longint(a);
  991. if op = OP_SUB then
  992. tmpref.offset := -tmpref.offset;
  993. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[size],tmpref,dst));
  994. end
  995. else internalerror(200112302);
  996. end;
  997. end;
  998. procedure tcgx86.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;size: tcgsize; src1, src2, dst: tregister);
  999. var
  1000. tmpref: treference;
  1001. begin
  1002. check_register_size(size,src1);
  1003. check_register_size(size,src2);
  1004. check_register_size(size,dst);
  1005. if tcgsize2size[size]<>tcgsize2size[OS_INT] then
  1006. begin
  1007. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1008. exit;
  1009. end;
  1010. { if we get here, we have to do a 32 bit calculation, guaranteed }
  1011. Case Op of
  1012. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  1013. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  1014. { can't do anything special for these }
  1015. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1016. OP_IMUL:
  1017. list.concat(taicpu.op_reg_reg_reg(A_IMUL,tcgsize2opsize[size],src1,src2,dst));
  1018. OP_ADD:
  1019. begin
  1020. reference_reset(tmpref);
  1021. tmpref.base := src1;
  1022. tmpref.index := src2;
  1023. tmpref.scalefactor := 1;
  1024. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[size],tmpref,dst));
  1025. end
  1026. else internalerror(200112303);
  1027. end;
  1028. end;
  1029. {*************** compare instructructions ****************}
  1030. procedure tcgx86.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  1031. l : tasmlabel);
  1032. begin
  1033. if (a = 0) then
  1034. list.concat(taicpu.op_reg_reg(A_TEST,tcgsize2opsize[size],reg,reg))
  1035. else
  1036. list.concat(taicpu.op_const_reg(A_CMP,tcgsize2opsize[size],a,reg));
  1037. a_jmp_cond(list,cmp_op,l);
  1038. end;
  1039. procedure tcgx86.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  1040. l : tasmlabel);
  1041. begin
  1042. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],a,ref));
  1043. a_jmp_cond(list,cmp_op,l);
  1044. end;
  1045. procedure tcgx86.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  1046. reg1,reg2 : tregister;l : tasmlabel);
  1047. begin
  1048. check_register_size(size,reg1);
  1049. check_register_size(size,reg2);
  1050. list.concat(taicpu.op_reg_reg(A_CMP,TCgSize2OpSize[size],reg1,reg2));
  1051. a_jmp_cond(list,cmp_op,l);
  1052. end;
  1053. procedure tcgx86.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  1054. begin
  1055. check_register_size(size,reg);
  1056. list.concat(taicpu.op_ref_reg(A_CMP,TCgSize2OpSize[size],ref,reg));
  1057. a_jmp_cond(list,cmp_op,l);
  1058. end;
  1059. procedure tcgx86.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1060. var
  1061. ai : taicpu;
  1062. begin
  1063. if cond=OC_None then
  1064. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  1065. else
  1066. begin
  1067. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  1068. ai.SetCondition(TOpCmp2AsmCond[cond]);
  1069. end;
  1070. ai.is_jmp:=true;
  1071. list.concat(ai);
  1072. end;
  1073. procedure tcgx86.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  1074. var
  1075. ai : taicpu;
  1076. begin
  1077. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  1078. ai.SetCondition(flags_to_cond(f));
  1079. ai.is_jmp := true;
  1080. list.concat(ai);
  1081. end;
  1082. procedure tcgx86.g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister);
  1083. var
  1084. ai : taicpu;
  1085. hreg : tregister;
  1086. begin
  1087. hreg:=makeregsize(reg,OS_8);
  1088. ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
  1089. ai.setcondition(flags_to_cond(f));
  1090. list.concat(ai);
  1091. if (reg<>hreg) then
  1092. a_load_reg_reg(list,OS_8,size,hreg,reg);
  1093. end;
  1094. procedure tcgx86.g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference);
  1095. var
  1096. ai : taicpu;
  1097. begin
  1098. if not(size in [OS_8,OS_S8]) then
  1099. a_load_const_ref(list,size,0,ref);
  1100. ai:=Taicpu.op_ref(A_SETcc,S_B,ref);
  1101. ai.setcondition(flags_to_cond(f));
  1102. list.concat(ai);
  1103. end;
  1104. { ************* concatcopy ************ }
  1105. procedure Tcgx86.g_concatcopy(list:Taasmoutput;const source,dest:Treference;
  1106. len:aword;delsource,loadref:boolean);
  1107. type copymode=(copy_move,copy_mmx,copy_string);
  1108. var srcref,dstref:Treference;
  1109. r,r0,r1,r2,r3:Tregister;
  1110. helpsize:aword;
  1111. copysize:byte;
  1112. cgsize:Tcgsize;
  1113. cm:copymode;
  1114. begin
  1115. cm:=copy_move;
  1116. helpsize:=12;
  1117. if cs_littlesize in aktglobalswitches then
  1118. helpsize:=8;
  1119. if (cs_mmx in aktlocalswitches) and
  1120. not(pi_uses_fpu in current_procinfo.flags) and
  1121. ((len=8) or (len=16) or (len=24) or (len=32)) then
  1122. cm:=copy_mmx;
  1123. if (len>helpsize) then
  1124. cm:=copy_string;
  1125. if (cs_littlesize in aktglobalswitches) and
  1126. not((len<=16) and (cm=copy_mmx)) then
  1127. cm:=copy_string;
  1128. if loadref then
  1129. cm:=copy_string;
  1130. case cm of
  1131. copy_move:
  1132. begin
  1133. dstref:=dest;
  1134. srcref:=source;
  1135. copysize:=4;
  1136. cgsize:=OS_32;
  1137. while len<>0 do
  1138. begin
  1139. if len<2 then
  1140. begin
  1141. copysize:=1;
  1142. cgsize:=OS_8;
  1143. end
  1144. else if len<4 then
  1145. begin
  1146. copysize:=2;
  1147. cgsize:=OS_16;
  1148. end;
  1149. dec(len,copysize);
  1150. if (len=0) and delsource then
  1151. reference_release(list,source);
  1152. r:=getintregister(list,cgsize);
  1153. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1154. ungetregister(list,r);
  1155. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1156. inc(srcref.offset,copysize);
  1157. inc(dstref.offset,copysize);
  1158. end;
  1159. end;
  1160. copy_mmx:
  1161. begin
  1162. dstref:=dest;
  1163. srcref:=source;
  1164. r0:=getmmxregister(list);
  1165. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r0,nil);
  1166. if len>=16 then
  1167. begin
  1168. inc(srcref.offset,8);
  1169. r1:=getmmxregister(list);
  1170. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r1,nil);
  1171. end;
  1172. if len>=24 then
  1173. begin
  1174. inc(srcref.offset,8);
  1175. r2:=getmmxregister(list);
  1176. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r2,nil);
  1177. end;
  1178. if len>=32 then
  1179. begin
  1180. inc(srcref.offset,8);
  1181. r3:=getmmxregister(list);
  1182. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r3,nil);
  1183. end;
  1184. a_loadmm_reg_ref(list,OS_M64,OS_M64,r0,dstref,nil);
  1185. ungetregister(list,r0);
  1186. if len>=16 then
  1187. begin
  1188. inc(dstref.offset,8);
  1189. a_loadmm_reg_ref(list,OS_M64,OS_M64,r1,dstref,nil);
  1190. ungetregister(list,r1);
  1191. end;
  1192. if len>=24 then
  1193. begin
  1194. inc(dstref.offset,8);
  1195. a_loadmm_reg_ref(list,OS_M64,OS_M64,r2,dstref,nil);
  1196. ungetregister(list,r2);
  1197. end;
  1198. if len>=32 then
  1199. begin
  1200. inc(dstref.offset,8);
  1201. a_loadmm_reg_ref(list,OS_M64,OS_M64,r3,dstref,nil);
  1202. ungetregister(list,r3);
  1203. end;
  1204. end
  1205. else {copy_string, should be a good fallback in case of unhandled}
  1206. begin
  1207. getexplicitregister(list,NR_EDI);
  1208. a_loadaddr_ref_reg(list,dest,NR_EDI);
  1209. getexplicitregister(list,NR_ESI);
  1210. if loadref then
  1211. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,NR_ESI)
  1212. else
  1213. begin
  1214. a_loadaddr_ref_reg(list,source,NR_ESI);
  1215. if delsource then
  1216. begin
  1217. srcref:=source;
  1218. { Don't release ESI register yet, it's needed
  1219. by the movsl }
  1220. if (srcref.base=NR_ESI) then
  1221. srcref.base:=NR_NO
  1222. else if (srcref.index=NR_ESI) then
  1223. srcref.index:=NR_NO;
  1224. reference_release(list,srcref);
  1225. end;
  1226. end;
  1227. getexplicitregister(list,NR_ECX);
  1228. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1229. if cs_littlesize in aktglobalswitches then
  1230. begin
  1231. a_load_const_reg(list,OS_INT,len,NR_ECX);
  1232. list.concat(Taicpu.op_none(A_REP,S_NO));
  1233. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1234. end
  1235. else
  1236. begin
  1237. helpsize:=len shr 2;
  1238. len:=len and 3;
  1239. if helpsize>1 then
  1240. begin
  1241. a_load_const_reg(list,OS_INT,helpsize,NR_ECX);
  1242. list.concat(Taicpu.op_none(A_REP,S_NO));
  1243. end;
  1244. if helpsize>0 then
  1245. list.concat(Taicpu.op_none(A_MOVSL,S_NO));
  1246. if len>1 then
  1247. begin
  1248. dec(len,2);
  1249. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1250. end;
  1251. if len=1 then
  1252. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1253. end;
  1254. ungetregister(list,NR_ECX);
  1255. ungetregister(list,NR_ESI);
  1256. ungetregister(list,NR_EDI);
  1257. end;
  1258. end;
  1259. if delsource then
  1260. tg.ungetiftemp(list,source);
  1261. end;
  1262. procedure tcgx86.g_exception_reason_save(list : taasmoutput; const href : treference);
  1263. begin
  1264. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],NR_FUNCTION_RESULT_REG));
  1265. end;
  1266. procedure tcgx86.g_exception_reason_save_const(list : taasmoutput;const href : treference; a: aword);
  1267. begin
  1268. list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_ADDR],a));
  1269. end;
  1270. procedure tcgx86.g_exception_reason_load(list : taasmoutput; const href : treference);
  1271. begin
  1272. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],NR_FUNCTION_RESULT_REG));
  1273. end;
  1274. {****************************************************************************
  1275. Entry/Exit Code Helpers
  1276. ****************************************************************************}
  1277. procedure tcgx86.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);
  1278. var
  1279. power,len : longint;
  1280. opsize : topsize;
  1281. {$ifndef __NOWINPECOFF__}
  1282. again,ok : tasmlabel;
  1283. {$endif}
  1284. begin
  1285. { get stack space }
  1286. getexplicitregister(list,NR_EDI);
  1287. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,NR_EDI));
  1288. list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
  1289. if (elesize<>1) then
  1290. begin
  1291. if ispowerof2(elesize, power) then
  1292. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
  1293. else
  1294. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
  1295. end;
  1296. {$ifndef __NOWINPECOFF__}
  1297. { windows guards only a few pages for stack growing, }
  1298. { so we have to access every page first }
  1299. if target_info.system=system_i386_win32 then
  1300. begin
  1301. objectlibrary.getlabel(again);
  1302. objectlibrary.getlabel(ok);
  1303. a_label(list,again);
  1304. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
  1305. a_jmp_cond(list,OC_B,ok);
  1306. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  1307. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
  1308. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
  1309. a_jmp_always(list,again);
  1310. a_label(list,ok);
  1311. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  1312. ungetregister(list,NR_EDI);
  1313. { now reload EDI }
  1314. getexplicitregister(list,NR_EDI);
  1315. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,NR_EDI));
  1316. list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
  1317. if (elesize<>1) then
  1318. begin
  1319. if ispowerof2(elesize, power) then
  1320. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
  1321. else
  1322. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
  1323. end;
  1324. end
  1325. else
  1326. {$endif __NOWINPECOFF__}
  1327. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  1328. { align stack on 4 bytes }
  1329. list.concat(Taicpu.op_const_reg(A_AND,S_L,$fffffff4,NR_ESP));
  1330. { load destination }
  1331. a_load_reg_reg(list,OS_INT,OS_INT,NR_ESP,NR_EDI);
  1332. { Allocate other registers }
  1333. getexplicitregister(list,NR_ECX);
  1334. getexplicitregister(list,NR_ESI);
  1335. { load count }
  1336. a_load_ref_reg(list,OS_INT,OS_INT,lenref,NR_ECX);
  1337. { load source }
  1338. a_load_ref_reg(list,OS_INT,OS_INT,ref,NR_ESI);
  1339. { scheduled .... }
  1340. list.concat(Taicpu.op_reg(A_INC,S_L,NR_ECX));
  1341. { calculate size }
  1342. len:=elesize;
  1343. opsize:=S_B;
  1344. if (len and 3)=0 then
  1345. begin
  1346. opsize:=S_L;
  1347. len:=len shr 2;
  1348. end
  1349. else
  1350. if (len and 1)=0 then
  1351. begin
  1352. opsize:=S_W;
  1353. len:=len shr 1;
  1354. end;
  1355. if ispowerof2(len, power) then
  1356. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_ECX))
  1357. else
  1358. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,NR_ECX));
  1359. list.concat(Taicpu.op_none(A_REP,S_NO));
  1360. case opsize of
  1361. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1362. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1363. S_L : list.concat(Taicpu.Op_none(A_MOVSL,S_NO));
  1364. end;
  1365. ungetregister(list,NR_EDI);
  1366. ungetregister(list,NR_ECX);
  1367. ungetregister(list,NR_ESI);
  1368. { patch the new address }
  1369. a_load_reg_ref(list,OS_INT,OS_INT,NR_ESP,ref);
  1370. end;
  1371. procedure tcgx86.g_releasevaluepara_openarray(list : taasmoutput;const ref:treference);
  1372. begin
  1373. { Nothing to release }
  1374. end;
  1375. procedure tcgx86.g_interrupt_stackframe_entry(list : taasmoutput);
  1376. begin
  1377. {$ifdef i386}
  1378. { .... also the segment registers }
  1379. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_GS));
  1380. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_FS));
  1381. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_ES));
  1382. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_DS));
  1383. { save the registers of an interrupt procedure }
  1384. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDI));
  1385. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ESI));
  1386. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDX));
  1387. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ECX));
  1388. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EBX));
  1389. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EAX));
  1390. {$endif i386}
  1391. end;
  1392. procedure tcgx86.g_interrupt_stackframe_exit(list : taasmoutput;accused,acchiused:boolean);
  1393. begin
  1394. {$ifdef i386}
  1395. if accused then
  1396. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1397. else
  1398. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
  1399. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
  1400. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
  1401. if acchiused then
  1402. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1403. else
  1404. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
  1405. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
  1406. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
  1407. { .... also the segment registers }
  1408. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1409. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1410. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
  1411. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
  1412. { this restores the flags }
  1413. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1414. {$endif i386}
  1415. end;
  1416. procedure tcgx86.g_profilecode(list : taasmoutput);
  1417. var
  1418. pl : tasmlabel;
  1419. mcountprefix : String[4];
  1420. begin
  1421. case target_info.system of
  1422. {$ifndef NOTARGETWIN32}
  1423. system_i386_win32,
  1424. {$endif}
  1425. system_i386_freebsd,
  1426. system_i386_netbsd,
  1427. // system_i386_openbsd,
  1428. system_i386_wdosx,
  1429. system_i386_linux:
  1430. begin
  1431. Case target_info.system Of
  1432. system_i386_freebsd : mcountprefix:='.';
  1433. system_i386_netbsd : mcountprefix:='__';
  1434. // system_i386_openbsd : mcountprefix:='.';
  1435. else
  1436. mcountPrefix:='';
  1437. end;
  1438. objectlibrary.getaddrlabel(pl);
  1439. list.concat(Tai_section.Create(sec_data));
  1440. list.concat(Tai_align.Create(4));
  1441. list.concat(Tai_label.Create(pl));
  1442. list.concat(Tai_const.Create_32bit(0));
  1443. list.concat(Tai_section.Create(sec_code));
  1444. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,NR_EDX));
  1445. a_call_name(list,target_info.Cprefix+mcountprefix+'mcount');
  1446. include(rg[R_INTREGISTER].used_in_proc,RS_EDX);
  1447. end;
  1448. system_i386_go32v2,system_i386_watcom:
  1449. begin
  1450. a_call_name(list,'MCOUNT');
  1451. end;
  1452. end;
  1453. end;
  1454. procedure tcgx86.g_stackpointer_alloc(list : taasmoutput;localsize : longint);
  1455. {$ifdef i386}
  1456. {$ifndef NOTARGETWIN32}
  1457. var
  1458. href : treference;
  1459. i : integer;
  1460. again : tasmlabel;
  1461. {$endif NOTARGETWIN32}
  1462. {$endif i386}
  1463. begin
  1464. if localsize>0 then
  1465. begin
  1466. {$ifdef i386}
  1467. {$ifndef NOTARGETWIN32}
  1468. { windows guards only a few pages for stack growing, }
  1469. { so we have to access every page first }
  1470. if (target_info.system=system_i386_win32) and
  1471. (localsize>=winstackpagesize) then
  1472. begin
  1473. if localsize div winstackpagesize<=5 then
  1474. begin
  1475. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize-4,NR_ESP));
  1476. for i:=1 to localsize div winstackpagesize do
  1477. begin
  1478. reference_reset_base(href,NR_ESP,localsize-i*winstackpagesize);
  1479. list.concat(Taicpu.op_const_ref(A_MOV,S_L,0,href));
  1480. end;
  1481. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1482. end
  1483. else
  1484. begin
  1485. objectlibrary.getlabel(again);
  1486. getexplicitregister(list,NR_EDI);
  1487. list.concat(Taicpu.op_const_reg(A_MOV,S_L,localsize div winstackpagesize,NR_EDI));
  1488. a_label(list,again);
  1489. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  1490. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1491. list.concat(Taicpu.op_reg(A_DEC,S_L,NR_EDI));
  1492. a_jmp_cond(list,OC_NE,again);
  1493. ungetregister(list,NR_EDI);
  1494. list.concat(Taicpu.op_const_reg(A_SUB,S_L,localsize mod winstackpagesize,NR_ESP));
  1495. end
  1496. end
  1497. else
  1498. {$endif NOTARGETWIN32}
  1499. {$endif i386}
  1500. list.concat(Taicpu.Op_const_reg(A_SUB,tcgsize2opsize[OS_ADDR],localsize,NR_STACK_POINTER_REG));
  1501. end;
  1502. end;
  1503. procedure tcgx86.g_stackframe_entry(list : taasmoutput;localsize : longint);
  1504. begin
  1505. list.concat(tai_regalloc.alloc(NR_FRAME_POINTER_REG));
  1506. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1507. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
  1508. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  1509. if localsize>0 then
  1510. g_stackpointer_alloc(list,localsize);
  1511. if cs_create_pic in aktmoduleswitches then
  1512. begin
  1513. a_call_name(list,'FPC_GETEIPINEBX');
  1514. list.concat(taicpu.op_sym_ofs_reg(A_ADD,tcgsize2opsize[OS_ADDR],objectlibrary.newasmsymboldata('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
  1515. list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG));
  1516. end;
  1517. end;
  1518. procedure tcgx86.g_restore_frame_pointer(list : taasmoutput);
  1519. begin
  1520. if cs_create_pic in aktmoduleswitches then
  1521. list.concat(tai_regalloc.dealloc(NR_PIC_OFFSET_REG));
  1522. list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG));
  1523. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  1524. if assigned(rg[R_MMXREGISTER]) and
  1525. (rg[R_MMXREGISTER].uses_registers) then
  1526. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1527. end;
  1528. procedure tcgx86.g_return_from_proc(list : taasmoutput;parasize : aword);
  1529. begin
  1530. { Routines with the poclearstack flag set use only a ret }
  1531. { also routines with parasize=0 }
  1532. if current_procinfo.procdef.proccalloption in clearstack_pocalls then
  1533. begin
  1534. { complex return values are removed from stack in C code PM }
  1535. if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,
  1536. current_procinfo.procdef.proccalloption) then
  1537. list.concat(Taicpu.Op_const(A_RET,S_NO,4))
  1538. else
  1539. list.concat(Taicpu.Op_none(A_RET,S_NO));
  1540. end
  1541. else if (parasize=0) then
  1542. list.concat(Taicpu.Op_none(A_RET,S_NO))
  1543. else
  1544. begin
  1545. { parameters are limited to 65535 bytes because }
  1546. { ret allows only imm16 }
  1547. if (parasize>65535) then
  1548. CGMessage(cg_e_parasize_too_big);
  1549. list.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  1550. end;
  1551. end;
  1552. procedure tcgx86.g_save_standard_registers(list:Taasmoutput);
  1553. var
  1554. href : treference;
  1555. size : longint;
  1556. r : integer;
  1557. begin
  1558. { Get temp }
  1559. size:=0;
  1560. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1561. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1562. inc(size,POINTER_SIZE);
  1563. if size>0 then
  1564. begin
  1565. tg.GetTemp(list,size,tt_noreuse,current_procinfo.save_regs_ref);
  1566. { Copy registers to temp }
  1567. href:=current_procinfo.save_regs_ref;
  1568. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1569. begin
  1570. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1571. begin
  1572. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE),href);
  1573. inc(href.offset,POINTER_SIZE);
  1574. end;
  1575. include(rg[R_INTREGISTER].preserved_by_proc,saved_standard_registers[r]);
  1576. end;
  1577. end;
  1578. end;
  1579. procedure tcgx86.g_restore_standard_registers(list:Taasmoutput);
  1580. var
  1581. href : treference;
  1582. r : integer;
  1583. begin
  1584. { Copy registers from temp }
  1585. href:=current_procinfo.save_regs_ref;
  1586. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1587. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1588. begin
  1589. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE));
  1590. inc(href.offset,POINTER_SIZE);
  1591. end;
  1592. tg.UnGetTemp(list,current_procinfo.save_regs_ref);
  1593. end;
  1594. { produces if necessary overflowcode }
  1595. procedure tcgx86.g_overflowcheck(list: taasmoutput; const l:tlocation;def:tdef);
  1596. var
  1597. hl : tasmlabel;
  1598. ai : taicpu;
  1599. cond : TAsmCond;
  1600. begin
  1601. if not(cs_check_overflow in aktlocalswitches) then
  1602. exit;
  1603. objectlibrary.getlabel(hl);
  1604. if not ((def.deftype=pointerdef) or
  1605. ((def.deftype=orddef) and
  1606. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1607. bool8bit,bool16bit,bool32bit]))) then
  1608. cond:=C_NO
  1609. else
  1610. cond:=C_NB;
  1611. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl);
  1612. ai.SetCondition(cond);
  1613. ai.is_jmp:=true;
  1614. list.concat(ai);
  1615. a_call_name(list,'FPC_OVERFLOW');
  1616. a_label(list,hl);
  1617. end;
  1618. end.
  1619. {
  1620. $Log$
  1621. Revision 1.108 2004-02-06 14:37:48 florian
  1622. * movz*q fixed
  1623. Revision 1.107 2004/02/05 18:28:37 peter
  1624. * x86_64 fixes for opsize
  1625. Revision 1.106 2004/02/04 22:01:13 peter
  1626. * first try to get cpupara working for x86_64
  1627. Revision 1.105 2004/02/04 19:22:27 peter
  1628. *** empty log message ***
  1629. Revision 1.104 2004/02/03 19:46:48 jonas
  1630. - removed "mov reg,reg" optimization (those instructions are removed by
  1631. the register allocator, and may be necessary to indicate a register
  1632. may not be released before some point)
  1633. Revision 1.103 2004/01/15 23:16:33 daniel
  1634. + Cleanup of stabstring generation code. Cleaner, faster, and compiler
  1635. executable reduced by 50 kb,
  1636. Revision 1.102 2004/01/14 23:39:05 florian
  1637. * another bunch of x86-64 fixes mainly calling convention and
  1638. assembler reader related
  1639. Revision 1.101 2004/01/14 21:43:54 peter
  1640. * add release_openarrayvalue
  1641. Revision 1.100 2003/12/26 14:02:30 peter
  1642. * sparc updates
  1643. * use registertype in spill_register
  1644. Revision 1.99 2003/12/26 13:19:16 florian
  1645. * rtl and compiler compile with -Cfsse2
  1646. Revision 1.98 2003/12/26 00:32:22 florian
  1647. + fpu<->mm register conversion
  1648. Revision 1.97 2003/12/25 12:01:35 florian
  1649. + possible sse2 unit usage for double calculations
  1650. * some sse2 assembler issues fixed
  1651. Revision 1.96 2003/12/25 01:07:09 florian
  1652. + $fputype directive support
  1653. + single data type operations with sse unit
  1654. * fixed more x86-64 stuff
  1655. Revision 1.95 2003/12/24 01:47:23 florian
  1656. * first fixes to compile the x86-64 system unit
  1657. Revision 1.94 2003/12/24 00:10:03 florian
  1658. - delete parameter in cg64 methods removed
  1659. Revision 1.93 2003/12/21 19:42:43 florian
  1660. * fixed ppc inlining stuff
  1661. * fixed wrong unit writing
  1662. + added some sse stuff
  1663. Revision 1.92 2003/12/19 22:08:44 daniel
  1664. * Some work to restore the MMX capabilities
  1665. Revision 1.91 2003/12/15 21:25:49 peter
  1666. * reg allocations for imaginary register are now inserted just
  1667. before reg allocation
  1668. * tregister changed to enum to allow compile time check
  1669. * fixed several tregister-tsuperregister errors
  1670. Revision 1.90 2003/12/12 17:16:18 peter
  1671. * rg[tregistertype] added in tcg
  1672. Revision 1.89 2003/12/06 01:15:23 florian
  1673. * reverted Peter's alloctemp patch; hopefully properly
  1674. Revision 1.88 2003/12/03 23:13:20 peter
  1675. * delayed paraloc allocation, a_param_*() gets extra parameter
  1676. if it needs to allocate temp or real paralocation
  1677. * optimized/simplified int-real loading
  1678. Revision 1.87 2003/11/05 23:06:03 florian
  1679. * elesize of g_copyvaluepara_openarray changed
  1680. Revision 1.86 2003/10/30 18:53:53 marco
  1681. * profiling fix
  1682. Revision 1.85 2003/10/30 16:22:40 peter
  1683. * call firstpass before allocation and codegeneration is started
  1684. * move leftover code from pass_2.generatecode() to psub
  1685. Revision 1.84 2003/10/29 21:24:14 jonas
  1686. + support for fpu temp parameters
  1687. + saving/restoring of fpu register before/after a procedure call
  1688. Revision 1.83 2003/10/20 19:30:08 peter
  1689. * remove memdebug code for rg
  1690. Revision 1.82 2003/10/18 15:41:26 peter
  1691. * made worklists dynamic in size
  1692. Revision 1.81 2003/10/17 15:25:18 florian
  1693. * fixed more ppc stuff
  1694. Revision 1.80 2003/10/17 14:38:32 peter
  1695. * 64k registers supported
  1696. * fixed some memory leaks
  1697. Revision 1.79 2003/10/14 00:30:48 florian
  1698. + some code for PIC support added
  1699. Revision 1.78 2003/10/13 01:23:13 florian
  1700. * some ideas for mm support implemented
  1701. Revision 1.77 2003/10/11 16:06:42 florian
  1702. * fixed some MMX<->SSE
  1703. * started to fix ppc, needs an overhaul
  1704. + stabs info improve for spilling, not sure if it works correctly/completly
  1705. - MMX_SUPPORT removed from Makefile.fpc
  1706. Revision 1.76 2003/10/10 17:48:14 peter
  1707. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  1708. * tregisteralloctor renamed to trgobj
  1709. * removed rgobj from a lot of units
  1710. * moved location_* and reference_* to cgobj
  1711. * first things for mmx register allocation
  1712. Revision 1.75 2003/10/09 21:31:37 daniel
  1713. * Register allocator splitted, ans abstract now
  1714. Revision 1.74 2003/10/07 16:09:03 florian
  1715. * x86 supports only mem/reg to reg for movsx and movzx
  1716. Revision 1.73 2003/10/07 15:17:07 peter
  1717. * inline supported again, LOC_REFERENCEs are used to pass the
  1718. parameters
  1719. * inlineparasymtable,inlinelocalsymtable removed
  1720. * exitlabel inserting fixed
  1721. Revision 1.72 2003/10/03 22:00:33 peter
  1722. * parameter alignment fixes
  1723. Revision 1.71 2003/10/03 14:45:37 peter
  1724. * save ESP after pusha and restore before popa for save all registers
  1725. Revision 1.70 2003/10/01 20:34:51 peter
  1726. * procinfo unit contains tprocinfo
  1727. * cginfo renamed to cgbase
  1728. * moved cgmessage to verbose
  1729. * fixed ppc and sparc compiles
  1730. Revision 1.69 2003/09/30 19:53:47 peter
  1731. * fix pushw reg
  1732. Revision 1.68 2003/09/29 20:58:56 peter
  1733. * optimized releasing of registers
  1734. Revision 1.67 2003/09/28 13:37:19 peter
  1735. * a_call_ref removed
  1736. Revision 1.66 2003/09/25 21:29:16 peter
  1737. * change push/pop in getreg/ungetreg
  1738. Revision 1.65 2003/09/25 13:13:32 florian
  1739. * more x86-64 fixes
  1740. Revision 1.64 2003/09/11 11:55:00 florian
  1741. * improved arm code generation
  1742. * move some protected and private field around
  1743. * the temp. register for register parameters/arguments are now released
  1744. before the move to the parameter register is done. This improves
  1745. the code in a lot of cases.
  1746. Revision 1.63 2003/09/09 21:03:17 peter
  1747. * basics for x86 register calling
  1748. Revision 1.62 2003/09/09 20:59:27 daniel
  1749. * Adding register allocation order
  1750. Revision 1.61 2003/09/07 22:09:35 peter
  1751. * preparations for different default calling conventions
  1752. * various RA fixes
  1753. Revision 1.60 2003/09/05 17:41:13 florian
  1754. * merged Wiktor's Watcom patches in 1.1
  1755. Revision 1.59 2003/09/03 15:55:02 peter
  1756. * NEWRA branch merged
  1757. Revision 1.58.2.5 2003/08/31 20:40:50 daniel
  1758. * Fixed add_edges_used
  1759. Revision 1.58.2.4 2003/08/31 15:46:26 peter
  1760. * more updates for tregister
  1761. Revision 1.58.2.3 2003/08/29 17:29:00 peter
  1762. * next batch of updates
  1763. Revision 1.58.2.2 2003/08/28 18:35:08 peter
  1764. * tregister changed to cardinal
  1765. Revision 1.58.2.1 2003/08/27 21:06:34 peter
  1766. * more updates
  1767. Revision 1.58 2003/08/20 19:28:21 daniel
  1768. * Small NOTARGETWIN32 conditional tweak
  1769. Revision 1.57 2003/07/03 18:59:25 peter
  1770. * loadfpu_reg_reg size specifier
  1771. Revision 1.56 2003/06/14 14:53:50 jonas
  1772. * fixed newra cycle for x86
  1773. * added constants for indicating source and destination operands of the
  1774. "move reg,reg" instruction to aasmcpu (and use those in rgobj)
  1775. Revision 1.55 2003/06/13 21:19:32 peter
  1776. * current_procdef removed, use current_procinfo.procdef instead
  1777. Revision 1.54 2003/06/12 18:31:18 peter
  1778. * fix newra cycle for i386
  1779. Revision 1.53 2003/06/07 10:24:10 peter
  1780. * fixed copyvaluepara for left-to-right pushing
  1781. Revision 1.52 2003/06/07 10:06:55 jonas
  1782. * fixed cycling problem
  1783. Revision 1.51 2003/06/03 21:11:09 peter
  1784. * cg.a_load_* get a from and to size specifier
  1785. * makeregsize only accepts newregister
  1786. * i386 uses generic tcgnotnode,tcgunaryminus
  1787. Revision 1.50 2003/06/03 13:01:59 daniel
  1788. * Register allocator finished
  1789. Revision 1.49 2003/06/01 21:38:07 peter
  1790. * getregisterfpu size parameter added
  1791. * op_const_reg size parameter added
  1792. * sparc updates
  1793. Revision 1.48 2003/05/30 23:57:08 peter
  1794. * more sparc cleanup
  1795. * accumulator removed, splitted in function_return_reg (called) and
  1796. function_result_reg (caller)
  1797. Revision 1.47 2003/05/22 21:33:31 peter
  1798. * removed some unit dependencies
  1799. Revision 1.46 2003/05/16 14:33:31 peter
  1800. * regvar fixes
  1801. Revision 1.45 2003/05/15 18:58:54 peter
  1802. * removed selfpointer_offset, vmtpointer_offset
  1803. * tvarsym.adjusted_address
  1804. * address in localsymtable is now in the real direction
  1805. * removed some obsolete globals
  1806. Revision 1.44 2003/04/30 20:53:32 florian
  1807. * error when address of an abstract method is taken
  1808. * fixed some x86-64 problems
  1809. * merged some more x86-64 and i386 code
  1810. Revision 1.43 2003/04/27 11:21:36 peter
  1811. * aktprocdef renamed to current_procinfo.procdef
  1812. * procinfo renamed to current_procinfo
  1813. * procinfo will now be stored in current_module so it can be
  1814. cleaned up properly
  1815. * gen_main_procsym changed to create_main_proc and release_main_proc
  1816. to also generate a tprocinfo structure
  1817. * fixed unit implicit initfinal
  1818. Revision 1.42 2003/04/23 14:42:08 daniel
  1819. * Further register allocator work. Compiler now smaller with new
  1820. allocator than without.
  1821. * Somebody forgot to adjust ppu version number
  1822. Revision 1.41 2003/04/23 09:51:16 daniel
  1823. * Removed usage of edi in a lot of places when new register allocator used
  1824. + Added newra versions of g_concatcopy and secondadd_float
  1825. Revision 1.40 2003/04/22 13:47:08 peter
  1826. * fixed C style array of const
  1827. * fixed C array passing
  1828. * fixed left to right with high parameters
  1829. Revision 1.39 2003/04/22 10:09:35 daniel
  1830. + Implemented the actual register allocator
  1831. + Scratch registers unavailable when new register allocator used
  1832. + maybe_save/maybe_restore unavailable when new register allocator used
  1833. Revision 1.38 2003/04/17 16:48:21 daniel
  1834. * Added some code to keep track of move instructions in register
  1835. allocator
  1836. Revision 1.37 2003/03/28 19:16:57 peter
  1837. * generic constructor working for i386
  1838. * remove fixed self register
  1839. * esi added as address register for i386
  1840. Revision 1.36 2003/03/18 18:17:46 peter
  1841. * reg2opsize()
  1842. Revision 1.35 2003/03/13 19:52:23 jonas
  1843. * and more new register allocator fixes (in the i386 code generator this
  1844. time). At least now the ppc cross compiler can compile the linux
  1845. system unit again, but I haven't tested it.
  1846. Revision 1.34 2003/02/27 16:40:32 daniel
  1847. * Fixed ie 200301234 problem on Win32 target
  1848. Revision 1.33 2003/02/26 21:15:43 daniel
  1849. * Fixed the optimizer
  1850. Revision 1.32 2003/02/19 22:00:17 daniel
  1851. * Code generator converted to new register notation
  1852. - Horribily outdated todo.txt removed
  1853. Revision 1.31 2003/01/21 10:41:13 daniel
  1854. * Fixed another 200301081
  1855. Revision 1.30 2003/01/13 23:00:18 daniel
  1856. * Fixed internalerror
  1857. Revision 1.29 2003/01/13 14:54:34 daniel
  1858. * Further work to convert codegenerator register convention;
  1859. internalerror bug fixed.
  1860. Revision 1.28 2003/01/09 20:41:00 daniel
  1861. * Converted some code in cgx86.pas to new register numbering
  1862. Revision 1.27 2003/01/08 18:43:58 daniel
  1863. * Tregister changed into a record
  1864. Revision 1.26 2003/01/05 13:36:53 florian
  1865. * x86-64 compiles
  1866. + very basic support for float128 type (x86-64 only)
  1867. Revision 1.25 2003/01/02 16:17:50 peter
  1868. * align stack on 4 bytes in copyvalueopenarray
  1869. Revision 1.24 2002/12/24 15:56:50 peter
  1870. * stackpointer_alloc added for adjusting ESP. Win32 needs
  1871. this for the pageprotection
  1872. Revision 1.23 2002/11/25 18:43:34 carl
  1873. - removed the invalid if <> checking (Delphi is strange on this)
  1874. + implemented abstract warning on instance creation of class with
  1875. abstract methods.
  1876. * some error message cleanups
  1877. Revision 1.22 2002/11/25 17:43:29 peter
  1878. * splitted defbase in defutil,symutil,defcmp
  1879. * merged isconvertable and is_equal into compare_defs(_ext)
  1880. * made operator search faster by walking the list only once
  1881. Revision 1.21 2002/11/18 17:32:01 peter
  1882. * pass proccalloption to ret_in_xxx and push_xxx functions
  1883. Revision 1.20 2002/11/09 21:18:31 carl
  1884. * flags2reg() was not extending the byte register to the correct result size
  1885. Revision 1.19 2002/10/16 19:01:43 peter
  1886. + $IMPLICITEXCEPTIONS switch to turn on/off generation of the
  1887. implicit exception frames for procedures with initialized variables
  1888. and for constructors. The default is on for compatibility
  1889. Revision 1.18 2002/10/05 12:43:30 carl
  1890. * fixes for Delphi 6 compilation
  1891. (warning : Some features do not work under Delphi)
  1892. Revision 1.17 2002/09/17 18:54:06 jonas
  1893. * a_load_reg_reg() now has two size parameters: source and dest. This
  1894. allows some optimizations on architectures that don't encode the
  1895. register size in the register name.
  1896. Revision 1.16 2002/09/16 19:08:47 peter
  1897. * support references without registers and symbol in paramref_addr. It
  1898. pushes only the offset
  1899. Revision 1.15 2002/09/16 18:06:29 peter
  1900. * move CGSize2Opsize to interface
  1901. Revision 1.14 2002/09/01 14:42:41 peter
  1902. * removevaluepara added to fix the stackpointer so restoring of
  1903. saved registers works
  1904. Revision 1.13 2002/09/01 12:09:27 peter
  1905. + a_call_reg, a_call_loc added
  1906. * removed exprasmlist references
  1907. Revision 1.12 2002/08/17 09:23:50 florian
  1908. * first part of procinfo rewrite
  1909. Revision 1.11 2002/08/16 14:25:00 carl
  1910. * issameref() to test if two references are the same (then emit no opcodes)
  1911. + ret_in_reg to replace ret_in_acc
  1912. (fix some register allocation bugs at the same time)
  1913. + save_std_register now has an extra parameter which is the
  1914. usedinproc registers
  1915. Revision 1.10 2002/08/15 08:13:54 carl
  1916. - a_load_sym_ofs_reg removed
  1917. * loadvmt now calls loadaddr_ref_reg instead
  1918. Revision 1.9 2002/08/11 14:32:33 peter
  1919. * renamed current_library to objectlibrary
  1920. Revision 1.8 2002/08/11 13:24:20 peter
  1921. * saving of asmsymbols in ppu supported
  1922. * asmsymbollist global is removed and moved into a new class
  1923. tasmlibrarydata that will hold the info of a .a file which
  1924. corresponds with a single module. Added librarydata to tmodule
  1925. to keep the library info stored for the module. In the future the
  1926. objectfiles will also be stored to the tasmlibrarydata class
  1927. * all getlabel/newasmsymbol and friends are moved to the new class
  1928. Revision 1.7 2002/08/10 10:06:04 jonas
  1929. * fixed stupid bug of mine in g_flags2reg() when optimizations are on
  1930. Revision 1.6 2002/08/09 19:18:27 carl
  1931. * fix generic exception handling
  1932. Revision 1.5 2002/08/04 19:52:04 carl
  1933. + updated exception routines
  1934. Revision 1.4 2002/07/27 19:53:51 jonas
  1935. + generic implementation of tcg.g_flags2ref()
  1936. * tcg.flags2xxx() now also needs a size parameter
  1937. Revision 1.3 2002/07/26 21:15:46 florian
  1938. * rewrote the system handling
  1939. Revision 1.2 2002/07/21 16:55:34 jonas
  1940. * fixed bug in op_const_reg_reg() for imul
  1941. Revision 1.1 2002/07/20 19:28:47 florian
  1942. * splitting of i386\cgcpu.pas into x86\cgx86.pas and i386\cgcpu.pas
  1943. cgx86.pas will contain the common code for i386 and x86_64
  1944. }