cga68k.pas 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl, Carl Eric Codere
  4. This unit generates 68000 (or better) assembler from the parse tree
  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. unit cga68k;
  19. interface
  20. uses
  21. globtype,cobjects,tree,m68k,aasm,symtable;
  22. procedure emitl(op : tasmop;var l : plabel);
  23. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  24. procedure emitcall(const routine:string;add_to_externals : boolean);
  25. procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
  26. destreg:Tregister;delloc:boolean);
  27. procedure emit_to_reg32(var hr:tregister);
  28. procedure loadsetelement(var p : ptree);
  29. { produces jumps to true respectively false labels using boolean expressions }
  30. procedure maketojumpbool(p : ptree);
  31. procedure emitoverflowcheck(p: ptree);
  32. procedure push_int(l : longint);
  33. function maybe_push(needed : byte;p : ptree) : boolean;
  34. procedure restore(p : ptree);
  35. procedure emit_push_mem(const ref : treference);
  36. procedure emitpushreferenceaddr(list : paasmoutput;const ref : treference);
  37. procedure copystring(const dref,sref : treference;len : byte);
  38. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
  39. { see implementation }
  40. procedure maybe_loada5;
  41. procedure emit_bounds_check(hp: treference; index: tregister);
  42. procedure loadstring(p:ptree);
  43. procedure decransiref(const ref : treference);
  44. procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
  45. { return a float op_size from a floatb type }
  46. { also does some error checking for problems }
  47. function getfloatsize(t: tfloattype): topsize;
  48. procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
  49. { procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  50. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize); }
  51. procedure firstcomplex(p : ptree);
  52. { generate stackframe for interrupt procedures }
  53. procedure generate_interrupt_stackframe_entry;
  54. procedure generate_interrupt_stackframe_exit;
  55. { generate entry code for a procedure.}
  56. procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  57. stackframe:longint;
  58. var parasize:longint;var nostackframe:boolean;
  59. inlined : boolean);
  60. { generate the exit code for a procedure. }
  61. procedure genexitcode(list : paasmoutput;parasize:longint;
  62. nostackframe,inlined:boolean);
  63. procedure removetemps(list : paasmoutput;p : plinkedlist);
  64. procedure releasedata(p : plinkedlist);
  65. {$ifdef test_dest_loc}
  66. const { used to avoid temporary assignments }
  67. dest_loc_known : boolean = false;
  68. in_dest_loc : boolean = false;
  69. dest_loc_tree : ptree = nil;
  70. var dest_loc : tlocation;
  71. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  72. {$endif test_dest_loc}
  73. implementation
  74. uses
  75. systems,globals,verbose,files,types,pbase,
  76. tgen68k,hcodegen,temp_gen,ppu
  77. {$ifdef GDB}
  78. ,gdb
  79. {$endif}
  80. ;
  81. {
  82. procedure genconstadd(size : topsize;l : longint;const str : string);
  83. begin
  84. if l=0 then
  85. else if l=1 then
  86. exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
  87. else if l=-1 then
  88. exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
  89. else
  90. exprasmlist^.concat(new(pai68k,op_ADD,size,'$'+tostr(l)+','+str);
  91. end;
  92. }
  93. procedure copystring(const dref,sref : treference;len : byte);
  94. var
  95. pushed : tpushed;
  96. begin
  97. pushusedregisters(pushed,$ffff);
  98. { emitpushreferenceaddr(dref); }
  99. { emitpushreferenceaddr(sref); }
  100. { push_int(len); }
  101. { This speeds up from 116 cycles to 24 cycles on the 68000 }
  102. { when passing register parameters! }
  103. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dref),R_A1)));
  104. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(sref),R_A0)));
  105. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,len,R_D0)));
  106. emitcall('FPC_STRCOPY',true);
  107. maybe_loada5;
  108. popusedregisters(pushed);
  109. end;
  110. procedure decransiref(const ref : treference);
  111. begin
  112. emitpushreferenceaddr(exprasmlist,ref);
  113. emitcall('FPC_ANSISTR_DECR_REF',true);
  114. end;
  115. procedure loadstring(p:ptree);
  116. begin
  117. case p^.right^.resulttype^.deftype of
  118. stringdef : begin
  119. { load a string ... }
  120. { here two possible choices: }
  121. { if it is a char, then simply }
  122. { load 0 length string }
  123. if (p^.right^.treetype=stringconstn) and
  124. (str_length(p^.right)=0) then
  125. exprasmlist^.concat(new(pai68k,op_const_ref(
  126. A_MOVE,S_B,0,newreference(p^.left^.location.reference))))
  127. else
  128. copystring(p^.left^.location.reference,p^.right^.location.reference,
  129. min(pstringdef(p^.right^.resulttype)^.len,pstringdef(p^.left^.resulttype)^.len));
  130. end;
  131. orddef : begin
  132. if p^.right^.treetype=ordconstn then
  133. begin
  134. { offset 0: length of string }
  135. { offset 1: character }
  136. exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_W,1*256+p^.right^.value,
  137. newreference(p^.left^.location.reference))))
  138. end
  139. else
  140. begin
  141. { not so elegant (goes better with extra register }
  142. if (p^.right^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  143. begin
  144. exprasmlist^.concat(new(pai68k,op_reg_reg(
  145. A_MOVE,S_B,p^.right^.location.register,R_D0)));
  146. ungetregister32(p^.right^.location.register);
  147. end
  148. else
  149. begin
  150. exprasmlist^.concat(new(pai68k,op_ref_reg(
  151. A_MOVE,S_B,newreference(p^.right^.location.reference),R_D0)));
  152. del_reference(p^.right^.location.reference);
  153. end;
  154. { alignment can cause problems }
  155. { add length of string to ref }
  156. exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_B,1,
  157. newreference(p^.left^.location.reference))));
  158. (* if abs(p^.left^.location.reference.offset) >= 1 then
  159. Begin *)
  160. { temporarily decrease offset }
  161. Inc(p^.left^.location.reference.offset);
  162. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,R_D0,
  163. newreference(p^.left^.location.reference))));
  164. Dec(p^.left^.location.reference.offset);
  165. { restore offset }
  166. (* end
  167. else
  168. Begin
  169. Comment(V_Debug,'SecondChar2String() internal error.');
  170. internalerror(34);
  171. end; *)
  172. end;
  173. end;
  174. else
  175. CGMessage(type_e_mismatch);
  176. end;
  177. end;
  178. procedure restore(p : ptree);
  179. var
  180. hregister : tregister;
  181. begin
  182. if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
  183. hregister:=getregister32
  184. else
  185. hregister:=getaddressreg;
  186. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SPPULL,hregister)));
  187. if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
  188. begin
  189. p^.location.register:=hregister;
  190. end
  191. else
  192. begin
  193. reset_reference(p^.location.reference);
  194. p^.location.reference.base:=hregister;
  195. set_location(p^.left^.location,p^.location);
  196. end;
  197. end;
  198. function maybe_push(needed : byte;p : ptree) : boolean;
  199. var
  200. pushed : boolean;
  201. begin
  202. if (needed>usablereg32) or (needed > usableaddress) then
  203. begin
  204. if (p^.location.loc=LOC_REGISTER) or
  205. (p^.location.loc=LOC_CREGISTER) then
  206. begin
  207. pushed:=true;
  208. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,p^.location.register,R_SPPUSH)));
  209. ungetregister32(p^.location.register);
  210. end
  211. else
  212. if ((p^.location.loc=LOC_MEM) or(p^.location.loc=LOC_REFERENCE)) and
  213. ((p^.location.reference.base<>R_NO) or
  214. (p^.location.reference.index<>R_NO)) then
  215. begin
  216. del_reference(p^.location.reference);
  217. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  218. R_A0)));
  219. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A0,R_SPPUSH)));
  220. pushed:=true;
  221. end
  222. else pushed:=false;
  223. end
  224. else pushed:=false;
  225. maybe_push:=pushed;
  226. end;
  227. { emit out of range check for arrays and sets}
  228. procedure emit_bounds_check(hp: treference; index: tregister);
  229. { index = index of array to check }
  230. { memory of range check information for array }
  231. var
  232. hl : plabel;
  233. begin
  234. if (aktoptprocessor = MC68020) then
  235. begin
  236. exprasmlist^.concat(new(pai68k, op_ref_reg(A_CMP2,S_L,newreference(hp),index)));
  237. getlabel(hl);
  238. emitl(A_BCC, hl);
  239. exprasmlist^.concat(new(pai68k, op_const_reg(A_MOVE,S_L,201,R_D0)));
  240. emitcall('FPC_HALT_ERROR',true);
  241. emitl(A_LABEL, hl);
  242. end
  243. else
  244. begin
  245. exprasmlist^.concat(new(pai68k, op_ref_reg(A_LEA,S_L,newreference(hp), R_A1)));
  246. exprasmlist^.concat(new(pai68k, op_reg_reg(A_MOVE, S_L, index, R_D0)));
  247. emitcall('FPC_RE_BOUNDS_CHECK',true);
  248. end;
  249. end;
  250. procedure emit_to_reg32(var hr:tregister);
  251. begin
  252. (* case hr of
  253. R_AX..R_DI : begin
  254. hr:=reg16toreg32(hr);
  255. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ffff,hr)));
  256. end;
  257. R_AL..R_DL : begin
  258. hr:=reg8toreg32(hr);
  259. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff,hr)));
  260. end;
  261. R_AH..R_DH : begin
  262. hr:=reg8toreg32(hr);
  263. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff00,hr)));
  264. end;
  265. end; *)
  266. end;
  267. function getfloatsize(t: tfloattype): topsize;
  268. begin
  269. case t of
  270. s32real: getfloatsize := S_FS;
  271. s64real: getfloatsize := S_FL;
  272. s80real: getfloatsize := S_FX;
  273. {$ifdef extdebug}
  274. else {else case }
  275. begin
  276. Comment(V_Debug,' getfloatsize() trying to get unknown size.');
  277. internalerror(12);
  278. end;
  279. {$endif}
  280. end;
  281. end;
  282. procedure emitl(op : tasmop;var l : plabel);
  283. begin
  284. if op=A_LABEL then
  285. exprasmlist^.concat(new(pai_label,init(l)))
  286. else
  287. exprasmlist^.concat(new(pai_labeled,init(op,l)))
  288. end;
  289. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  290. begin
  291. if (reg1 <> reg2) or (i <> A_MOVE) then
  292. exprasmlist^.concat(new(pai68k,op_reg_reg(i,s,reg1,reg2)));
  293. end;
  294. procedure emitcall(const routine:string;add_to_externals : boolean);
  295. begin
  296. exprasmlist^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol(routine,0))));
  297. if add_to_externals and
  298. not (cs_compilesystem in aktmoduleswitches) then
  299. concat_external(routine,EXT_NEAR);
  300. end;
  301. procedure maketojumpbool(p : ptree);
  302. begin
  303. if p^.error then
  304. exit;
  305. if (p^.resulttype^.deftype=orddef) and
  306. (porddef(p^.resulttype)^.typ=bool8bit) then
  307. begin
  308. if is_constboolnode(p) then
  309. begin
  310. if p^.value<>0 then
  311. emitl(A_JMP,truelabel)
  312. else emitl(A_JMP,falselabel);
  313. end
  314. else
  315. begin
  316. case p^.location.loc of
  317. LOC_CREGISTER,LOC_REGISTER : begin
  318. exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_B,p^.location.register)));
  319. ungetregister32(p^.location.register);
  320. emitl(A_BNE,truelabel);
  321. emitl(A_JMP,falselabel);
  322. end;
  323. LOC_MEM,LOC_REFERENCE : begin
  324. exprasmlist^.concat(new(pai68k,op_ref(
  325. A_TST,S_B,newreference(p^.location.reference))));
  326. del_reference(p^.location.reference);
  327. emitl(A_BNE,truelabel);
  328. emitl(A_JMP,falselabel);
  329. end;
  330. LOC_FLAGS : begin
  331. emitl(flag_2_jmp[p^.location.resflags],truelabel);
  332. emitl(A_JMP,falselabel);
  333. end;
  334. end;
  335. end;
  336. end
  337. else
  338. CGMessage(type_e_mismatch);
  339. end;
  340. procedure emitoverflowcheck(p: ptree);
  341. var
  342. hl : plabel;
  343. begin
  344. if cs_check_overflow in aktlocalswitches then
  345. begin
  346. getlabel(hl);
  347. if not ((p^.resulttype^.deftype=pointerdef) or
  348. ((p^.resulttype^.deftype=orddef) and
  349. (porddef(p^.resulttype)^.typ in [u16bit,u32bit,u8bit,uchar,bool8bit]))) then
  350. emitl(A_BVC,hl)
  351. else
  352. emitl(A_BCC,hl);
  353. emitcall('FPC_OVERFLOW',true);
  354. emitl(A_LABEL,hl);
  355. end;
  356. end;
  357. procedure push_int(l : longint);
  358. begin
  359. if (l = 0) and (aktoptprocessor = MC68020) then
  360. begin
  361. exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_L,R_D6)));
  362. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  363. R_D6, R_SPPUSH)));
  364. end
  365. else
  366. if not(cs_littlesize in aktglobalswitches) and (l >= -128) and (l <= 127) then
  367. begin
  368. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVEQ,S_L,l,R_D6)));
  369. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_D6,R_SPPUSH)));
  370. end
  371. else
  372. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,l,R_SPPUSH)));
  373. end;
  374. procedure emit_push_mem(const ref : treference);
  375. { Push a value on to the stack }
  376. begin
  377. if ref.isintvalue then
  378. push_int(ref.offset)
  379. else
  380. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),R_SPPUSH)));
  381. end;
  382. { USES REGISTER R_A1 }
  383. procedure emitpushreferenceaddr(list : paasmoutput;const ref : treference);
  384. { Push a pointer to a value on the stack }
  385. begin
  386. if ref.isintvalue then
  387. push_int(ref.offset)
  388. else
  389. begin
  390. if (ref.base=R_NO) and (ref.index=R_NO) then
  391. list^.concat(new(pai68k,op_ref(A_PEA,S_L,
  392. newreference(ref))))
  393. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  394. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  395. list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  396. ref.index,R_SPPUSH)))
  397. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  398. (ref.offset=0) and (ref.symbol=nil) then
  399. list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,ref.base,R_SPPUSH)))
  400. else
  401. begin
  402. list^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(ref),R_A1)));
  403. list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A1,R_SPPUSH)));
  404. end;
  405. end;
  406. end;
  407. { This routine needs to be further checked to see if it works correctly }
  408. { because contrary to the intel version, all large set elements are read }
  409. { as 32-bit value_str, and then decomposed to find the correct byte. }
  410. { CHECKED : Depending on the result size, if reference, a load may be }
  411. { required on word, long or byte. }
  412. procedure loadsetelement(var p : ptree);
  413. var
  414. hr : tregister;
  415. opsize : topsize;
  416. begin
  417. { copy the element in the d0.b register, slightly complicated }
  418. case p^.location.loc of
  419. LOC_REGISTER,
  420. LOC_CREGISTER : begin
  421. hr:=p^.location.register;
  422. emit_reg_reg(A_MOVE,S_L,hr,R_D0);
  423. ungetregister32(hr);
  424. end;
  425. else
  426. begin
  427. { This is quite complicated, because of the endian on }
  428. { the m68k! }
  429. opsize:=S_NO;
  430. case integer(p^.resulttype^.savesize) of
  431. 1 : opsize:=S_B;
  432. 2 : opsize:=S_W;
  433. 4 : opsize:=S_L;
  434. else
  435. internalerror(19);
  436. end;
  437. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,opsize,
  438. newreference(p^.location.reference),R_D0)));
  439. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  440. 255,R_D0)));
  441. {
  442. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  443. newreference(p^.location.reference),R_D0))); }
  444. { exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  445. $ff,R_D0))); }
  446. del_reference(p^.location.reference);
  447. end;
  448. end;
  449. end;
  450. procedure generate_interrupt_stackframe_entry;
  451. begin
  452. { save the registers of an interrupt procedure }
  453. { .... also the segment registers }
  454. end;
  455. procedure generate_interrupt_stackframe_exit;
  456. begin
  457. { restore the registers of an interrupt procedure }
  458. end;
  459. procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  460. stackframe:longint;
  461. var parasize:longint;var nostackframe:boolean;
  462. inlined : boolean);
  463. {Generates the entry code for a procedure.}
  464. var hs:string;
  465. hp:Pused_unit;
  466. unitinits:taasmoutput;
  467. {$ifdef GDB}
  468. stab_function_name:Pai_stab_function_name;
  469. {$endif GDB}
  470. begin
  471. if (aktprocsym^.definition^.options and poproginit<>0) then
  472. begin
  473. {Init the stack checking.}
  474. if (cs_check_stack in aktlocalswitches) and
  475. (target_info.target=target_m68k_linux) then
  476. begin
  477. procinfo.aktentrycode^.insert(new(pai68k,
  478. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_INIT_STACK_CHECK',0))));
  479. end
  480. else
  481. { The main program has already allocated its stack - so we simply compare }
  482. { with a value of ZERO, and the comparison will directly check! }
  483. if (cs_check_stack in aktlocalswitches) then
  484. begin
  485. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  486. newcsymbol('FPC_STACKCHECK',0))));
  487. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  488. 0,R_D0)));
  489. concat_external('FPC_STACKCHECK',EXT_NEAR);
  490. end;
  491. unitinits.init;
  492. {Call the unit init procedures.}
  493. hp:=pused_unit(usedunits.first);
  494. while assigned(hp) do
  495. begin
  496. { call the unit init code and make it external }
  497. if (hp^.u^.flags and uf_init)<>0 then
  498. begin
  499. unitinits.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('INIT$$'+hp^.u^.modulename^,0))));
  500. concat_external('INIT$$'+hp^.u^.modulename^,EXT_NEAR);
  501. end;
  502. hp:=pused_unit(hp^.next);
  503. end;
  504. procinfo.aktentrycode^.insertlist(@unitinits);
  505. unitinits.done;
  506. end;
  507. { a constructor needs a help procedure }
  508. if (aktprocsym^.definition^.options and poconstructor)<>0 then
  509. begin
  510. if procinfo._class^.isclass then
  511. begin
  512. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  513. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  514. newcsymbol('FPC_NEW_CLASS',0))));
  515. concat_external('FPC_NEW_CLASS',EXT_NEAR);
  516. end
  517. else
  518. begin
  519. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  520. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  521. newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
  522. concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
  523. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,procinfo._class^.vmt_offset,R_D0)));
  524. end;
  525. end;
  526. { don't load ESI, does the caller }
  527. {$ifdef GDB}
  528. if (cs_debuginfo in aktmoduleswitches) then
  529. list^.insert(new(pai_force_line,init));
  530. {$endif GDB}
  531. { omit stack frame ? }
  532. if procinfo.framepointer=stack_pointer then
  533. begin
  534. CGMessage(cg_d_stackframe_omited);
  535. nostackframe:=true;
  536. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  537. parasize:=0
  538. else
  539. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset;
  540. end
  541. else
  542. begin
  543. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  544. parasize:=0
  545. else
  546. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
  547. nostackframe:=false;
  548. if stackframe<>0 then
  549. begin
  550. if cs_littlesize in aktglobalswitches then
  551. begin
  552. if (cs_check_stack in aktlocalswitches) and
  553. (target_info.target<>target_m68k_linux) then
  554. begin
  555. { If only not in main program, do we setup stack checking }
  556. if (aktprocsym^.definition^.options and poproginit=0) then
  557. Begin
  558. procinfo.aktentrycode^.insert(new(pai68k,
  559. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  560. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,stackframe,R_D0)));
  561. concat_external('FPC_STACKCHECK',EXT_NEAR);
  562. end;
  563. end;
  564. { to allocate stack space }
  565. { here we allocate space using link signed 16-bit version }
  566. { -ve offset to allocate stack space! }
  567. if (stackframe > -32767) and (stackframe < 32769) then
  568. procinfo.aktentrycode^.insert(new(pai68k,op_reg_const(A_LINK,S_W,R_A6,-stackframe)))
  569. else
  570. CGMessage(cg_e_stacklimit_in_local_routine);
  571. end
  572. else
  573. begin
  574. { Not to complicate the code generator too much, and since some }
  575. { of the systems only support this format, the stackframe cannot }
  576. { exceed 32K in size. }
  577. if (stackframe > -32767) and (stackframe < 32769) then
  578. begin
  579. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_SUB,S_L,stackframe,R_SP)));
  580. { IF only NOT in main program do we check the stack normally }
  581. if (cs_check_stack in aktlocalswitches)
  582. and (aktprocsym^.definition^.options and poproginit=0) then
  583. begin
  584. procinfo.aktentrycode^.insert(new(pai68k,
  585. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  586. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  587. stackframe,R_D0)));
  588. concat_external('FPC_STACKCHECK',EXT_NEAR);
  589. end;
  590. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  591. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  592. end
  593. else
  594. CGMessage(cg_e_stacklimit_in_local_routine);
  595. end;
  596. end {endif stackframe<>0 }
  597. else
  598. begin
  599. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  600. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  601. end;
  602. end;
  603. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  604. generate_interrupt_stackframe_entry;
  605. {proc_names.insert(aktprocsym^.definition^.mangledname);}
  606. if (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  607. ((procinfo._class<>nil) and (procinfo._class^.owner^.
  608. symtabletype=globalsymtable)) then
  609. make_global:=true;
  610. hs:=proc_names.get;
  611. {$IfDef GDB}
  612. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  613. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  614. {$EndIf GDB}
  615. while hs<>'' do
  616. begin
  617. if make_global then
  618. procinfo.aktentrycode^.insert(new(pai_symbol,init_global(hs)))
  619. else
  620. procinfo.aktentrycode^.insert(new(pai_symbol,init(hs)));
  621. {$ifdef GDB}
  622. if (cs_debuginfo in aktmoduleswitches) then
  623. begin
  624. if target_os.use_function_relative_addresses then
  625. list^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  626. { This is not a nice solution to save the name, change it and restore when done }
  627. { not only not nice but also completely wrong !!! (PM) }
  628. { aktprocsym^.setname(hs);
  629. list^.insert(new(pai_stabs,init(aktprocsym^.stabstring))); }
  630. end;
  631. {$endif GDB}
  632. hs:=proc_names.get;
  633. end;
  634. {$ifdef GDB}
  635. if (cs_debuginfo in aktmoduleswitches) then
  636. begin
  637. if target_os.use_function_relative_addresses then
  638. procinfo.aktentrycode^.insert(stab_function_name);
  639. if make_global or ((procinfo.flags and pi_is_global) <> 0) then
  640. aktprocsym^.is_global := True;
  641. aktprocsym^.isstabwritten:=true;
  642. end;
  643. {$endif GDB}
  644. { Alignment required for Motorola }
  645. procinfo.aktentrycode^.insert(new(pai_align,init(2)));
  646. end;
  647. {Generate the exit code for a procedure.}
  648. procedure genexitcode(list : paasmoutput;parasize:longint; nostackframe,inlined:boolean);
  649. var hr:Preference; {This is for function results.}
  650. op:Tasmop;
  651. s:Topsize;
  652. begin
  653. { !!!! insert there automatic destructors }
  654. procinfo.aktexitcode^.insert(new(pai_label,init(aktexitlabel)));
  655. { call the destructor help procedure }
  656. if (aktprocsym^.definition^.options and podestructor)<>0 then
  657. begin
  658. if procinfo._class^.isclass then
  659. begin
  660. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  661. newcsymbol('FPC_DISPOSE_CLASS',0))));
  662. concat_external('FPC_DISPOSE_CLASS',EXT_NEAR);
  663. end
  664. else
  665. begin
  666. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  667. newcsymbol('FPC_HELP_DESTRUCTOR',0))));
  668. procinfo.aktexitcode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,procinfo._class^.vmt_offset,R_D0)));
  669. concat_external('FPC_HELP_DESTRUCTOR',EXT_NEAR);
  670. end;
  671. end;
  672. { call __EXIT for main program }
  673. { ????????? }
  674. if ((aktprocsym^.definition^.options and poproginit)<>0) and
  675. (target_info.target<>target_m68k_PalmOS) then
  676. begin
  677. procinfo.aktexitcode^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('FPC_DO_EXIT',0))));
  678. externals^.concat(new(pai_external,init('FPC_DO_EXIT',EXT_NEAR)));
  679. end;
  680. { handle return value }
  681. if (aktprocsym^.definition^.options and poassembler)=0 then
  682. if (aktprocsym^.definition^.options and poconstructor)=0 then
  683. begin
  684. if procinfo.retdef<>pdef(voiddef) then
  685. begin
  686. if not procinfo.funcret_is_valid then
  687. CGMessage(sym_w_function_result_not_set);
  688. new(hr);
  689. reset_reference(hr^);
  690. hr^.offset:=procinfo.retoffset;
  691. hr^.base:=procinfo.framepointer;
  692. if (procinfo.retdef^.deftype in [orddef,enumdef]) then
  693. begin
  694. case procinfo.retdef^.size of
  695. 4 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  696. 2 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,hr,R_D0)));
  697. 1 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,hr,R_D0)));
  698. end;
  699. end
  700. else
  701. if (procinfo.retdef^.deftype in [pointerdef,enumdef,procvardef]) or
  702. ((procinfo.retdef^.deftype=setdef) and
  703. (psetdef(procinfo.retdef)^.settype=smallset)) then
  704. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)))
  705. else
  706. if (procinfo.retdef^.deftype=floatdef) then
  707. begin
  708. if pfloatdef(procinfo.retdef)^.typ=f32bit then
  709. begin
  710. { Isnt this missing ? }
  711. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  712. end
  713. else
  714. begin
  715. { how the return value is handled }
  716. { if single value, then return in d0, otherwise return in }
  717. { TRUE FPU register (does not apply in emulation mode) }
  718. if (pfloatdef(procinfo.retdef)^.typ = s32real) then
  719. begin
  720. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  721. S_L,hr,R_D0)))
  722. end
  723. else
  724. begin
  725. if cs_fp_emulation in aktmoduleswitches then
  726. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  727. S_L,hr,R_D0)))
  728. else
  729. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_FMOVE,
  730. getfloatsize(pfloatdef(procinfo.retdef)^.typ),hr,R_FP0)));
  731. end;
  732. end;
  733. end
  734. else
  735. dispose(hr);
  736. end
  737. end
  738. else
  739. begin
  740. { successful constructor deletes the zero flag }
  741. { and returns self in accumulator }
  742. procinfo.aktexitcode^.concat(new(pai_label,init(quickexitlabel)));
  743. { eax must be set to zero if the allocation failed !!! }
  744. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_D0)));
  745. { faster then OR on mc68000/mc68020 }
  746. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_TST,S_L,R_D0)));
  747. end;
  748. procinfo.aktexitcode^.concat(new(pai_label,init(aktexit2label)));
  749. if not(nostackframe) then
  750. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_UNLK,S_NO,R_A6)));
  751. { at last, the return is generated }
  752. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  753. generate_interrupt_stackframe_exit
  754. else
  755. if (parasize=0) or ((aktprocsym^.definition^.options and poclearstack)<>0)
  756. then
  757. {Routines with the poclearstack flag set use only a ret.}
  758. { also routines with parasize=0 }
  759. procinfo.aktexitcode^.concat(new(pai68k,op_none(A_RTS,S_NO)))
  760. else
  761. { return with immediate size possible here }
  762. { signed! }
  763. if (aktoptprocessor = MC68020) and (parasize < $7FFF) then
  764. procinfo.aktexitcode^.concat(new(pai68k,op_const(
  765. A_RTD,S_NO,parasize)))
  766. { manually restore the stack }
  767. else
  768. begin
  769. { We must pull the PC Counter from the stack, before }
  770. { restoring the stack pointer, otherwise the PC would }
  771. { point to nowhere! }
  772. { save the PC counter (pop it from the stack) }
  773. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  774. A_MOVE,S_L,R_SPPULL,R_A0)));
  775. { can we do a quick addition ... }
  776. if (parasize > 0) and (parasize < 9) then
  777. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  778. A_ADD,S_L,parasize,R_SP)))
  779. else { nope ... }
  780. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  781. A_ADD,S_L,parasize,R_SP)));
  782. { endif }
  783. { restore the PC counter (push it on the stack) }
  784. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  785. A_MOVE,S_L,R_A0,R_SPPUSH)));
  786. procinfo.aktexitcode^.concat(new(pai68k,op_none(
  787. A_RTS,S_NO)))
  788. end;
  789. {$ifdef GDB}
  790. if cs_debuginfo in aktmoduleswitches then
  791. begin
  792. aktprocsym^.concatstabto(procinfo.aktexitcode);
  793. if assigned(procinfo._class) then
  794. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  795. '"$t:v'+procinfo._class^.numberstring+'",'+
  796. tostr(N_PSYM)+',0,0,'+tostr(procinfo.esi_offset)))));
  797. if (porddef(aktprocsym^.definition^.retdef) <> voiddef) then
  798. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  799. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  800. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
  801. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  802. +aktprocsym^.definition^.mangledname))));
  803. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('224,0,0,'
  804. +lab2str(aktexit2label)))));
  805. end;
  806. {$endif GDB}
  807. end;
  808. { USES REGISTERS R_A0 AND R_A1 }
  809. { maximum size of copy is 65535 bytes }
  810. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
  811. var
  812. ecxpushed : boolean;
  813. helpsize : longint;
  814. i : byte;
  815. reg8,reg32 : tregister;
  816. swap : boolean;
  817. hregister : tregister;
  818. iregister : tregister;
  819. jregister : tregister;
  820. hp1 : treference;
  821. hp2 : treference;
  822. hl : plabel;
  823. hl2: plabel;
  824. begin
  825. { this should never occur }
  826. if size > 65535 then
  827. internalerror(0);
  828. hregister := getregister32;
  829. if delsource then
  830. del_reference(source);
  831. { from 12 bytes movs is being used }
  832. if (size<=8) or (not(cs_littlesize in aktglobalswitches) and (size<=12)) then
  833. begin
  834. helpsize:=size div 4;
  835. { move a dword x times }
  836. for i:=1 to helpsize do
  837. begin
  838. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(source),hregister)));
  839. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,hregister,newreference(dest))));
  840. inc(source.offset,4);
  841. inc(dest.offset,4);
  842. dec(size,4);
  843. end;
  844. { move a word }
  845. if size>1 then
  846. begin
  847. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,newreference(source),hregister)));
  848. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_W,hregister,newreference(dest))));
  849. inc(source.offset,2);
  850. inc(dest.offset,2);
  851. dec(size,2);
  852. end;
  853. { move a single byte }
  854. if size>0 then
  855. begin
  856. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,newreference(source),hregister)));
  857. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,hregister,newreference(dest))));
  858. end
  859. end
  860. else
  861. begin
  862. if (usableaddress > 1) then
  863. begin
  864. iregister := getaddressreg;
  865. jregister := getaddressreg;
  866. end
  867. else
  868. if (usableaddress = 1) then
  869. begin
  870. iregister := getaddressreg;
  871. jregister := R_A1;
  872. end
  873. else
  874. begin
  875. iregister := R_A0;
  876. jregister := R_A1;
  877. end;
  878. { reference for move (An)+,(An)+ }
  879. reset_reference(hp1);
  880. hp1.base := iregister; { source register }
  881. hp1.direction := dir_inc;
  882. reset_reference(hp2);
  883. hp2.base := jregister;
  884. hp2.direction := dir_inc;
  885. { iregister = source }
  886. { jregister = destination }
  887. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(source),iregister)));
  888. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dest),jregister)));
  889. { double word move only on 68020+ machines }
  890. { because of possible alignment problems }
  891. { use fast loop mode }
  892. if (aktoptprocessor=MC68020) then
  893. begin
  894. helpsize := size - size mod 4;
  895. size := size mod 4;
  896. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize div 4,hregister)));
  897. getlabel(hl2);
  898. emitl(A_BRA,hl2);
  899. getlabel(hl);
  900. emitl(A_LABEL,hl);
  901. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_L,newreference(hp1),newreference(hp2))));
  902. emitl(A_LABEL,hl2);
  903. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  904. if size > 1 then
  905. begin
  906. dec(size,2);
  907. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_W,newreference(hp1), newreference(hp2))));
  908. end;
  909. if size = 1 then
  910. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1), newreference(hp2))));
  911. end
  912. else
  913. begin
  914. { Fast 68010 loop mode with no possible alignment problems }
  915. helpsize := size;
  916. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize,hregister)));
  917. getlabel(hl2);
  918. emitl(A_BRA,hl2);
  919. getlabel(hl);
  920. emitl(A_LABEL,hl);
  921. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1),newreference(hp2))));
  922. emitl(A_LABEL,hl2);
  923. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  924. end;
  925. { restore the registers that we have just used olny if they are used! }
  926. if jregister = R_A1 then
  927. hp2.base := R_NO;
  928. if iregister = R_A0 then
  929. hp1.base := R_NO;
  930. del_reference(hp1);
  931. del_reference(hp2);
  932. end;
  933. { loading SELF-reference again }
  934. maybe_loada5;
  935. if delsource then
  936. ungetiftemp(source);
  937. ungetregister32(hregister);
  938. end;
  939. procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
  940. destreg:Tregister;delloc:boolean);
  941. {A lot smaller and less bug sensitive than the original unfolded loads.}
  942. var tai:pai68k;
  943. r:Preference;
  944. begin
  945. case location.loc of
  946. LOC_REGISTER,LOC_CREGISTER:
  947. begin
  948. case orddef^.typ of
  949. u8bit: begin
  950. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  951. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  952. end;
  953. s8bit: begin
  954. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  955. if (aktoptprocessor <> MC68020) then
  956. begin
  957. { byte to word }
  958. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  959. { word to long }
  960. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  961. end
  962. else { 68020+ and later only }
  963. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  964. end;
  965. u16bit: begin
  966. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  967. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FFFF,destreg)));
  968. end;
  969. s16bit: begin
  970. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  971. { word to long }
  972. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  973. end;
  974. u32bit:
  975. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  976. s32bit:
  977. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  978. end;
  979. if delloc then
  980. ungetregister(location.register);
  981. end;
  982. LOC_REFERENCE:
  983. begin
  984. r:=newreference(location.reference);
  985. case orddef^.typ of
  986. u8bit: begin
  987. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  988. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  989. end;
  990. s8bit: begin
  991. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  992. if (aktoptprocessor <> MC68020) then
  993. begin
  994. { byte to word }
  995. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  996. { word to long }
  997. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  998. end
  999. else { 68020+ and later only }
  1000. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  1001. end;
  1002. u16bit: begin
  1003. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  1004. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$ffff,destreg)));
  1005. end;
  1006. s16bit: begin
  1007. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  1008. { word to long }
  1009. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  1010. end;
  1011. u32bit:
  1012. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  1013. s32bit:
  1014. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  1015. end;
  1016. if delloc then
  1017. del_reference(location.reference);
  1018. end
  1019. else
  1020. internalerror(6);
  1021. end;
  1022. end;
  1023. { if necessary A5 is reloaded after a call}
  1024. procedure maybe_loada5;
  1025. var
  1026. hp : preference;
  1027. p : pprocinfo;
  1028. i : longint;
  1029. begin
  1030. if assigned(procinfo._class) then
  1031. begin
  1032. if lexlevel>normal_function_level then
  1033. begin
  1034. new(hp);
  1035. reset_reference(hp^);
  1036. hp^.offset:=procinfo.framepointer_offset;
  1037. hp^.base:=procinfo.framepointer;
  1038. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1039. p:=procinfo.parent;
  1040. for i:=3 to lexlevel-1 do
  1041. begin
  1042. new(hp);
  1043. reset_reference(hp^);
  1044. hp^.offset:=p^.framepointer_offset;
  1045. hp^.base:=R_A5;
  1046. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1047. p:=p^.parent;
  1048. end;
  1049. new(hp);
  1050. reset_reference(hp^);
  1051. hp^.offset:=p^.ESI_offset;
  1052. hp^.base:=R_A5;
  1053. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1054. end
  1055. else
  1056. begin
  1057. new(hp);
  1058. reset_reference(hp^);
  1059. hp^.offset:=procinfo.ESI_offset;
  1060. hp^.base:=procinfo.framepointer;
  1061. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1062. end;
  1063. end;
  1064. end;
  1065. (***********************************************************************)
  1066. (* PROCEDURE FLOATLOAD *)
  1067. (* Description: This routine is to be called each time a location *)
  1068. (* must be set to LOC_FPU and a value loaded into a FPU register. *)
  1069. (* *)
  1070. (* Remark: The routine sets up the register field of LOC_FPU correctly*)
  1071. (***********************************************************************)
  1072. procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
  1073. var
  1074. op : tasmop;
  1075. s : topsize;
  1076. begin
  1077. { no emulation }
  1078. case t of
  1079. s32real : s := S_FS;
  1080. s64real : s := S_FL;
  1081. s80real : s := S_FX;
  1082. else
  1083. begin
  1084. CGMessage(cg_f_unknown_float_type);
  1085. end;
  1086. end; { end case }
  1087. location.loc := LOC_FPU;
  1088. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1089. begin
  1090. location.fpureg := getfloatreg;
  1091. exprasmlist^.concat(new(pai68k,op_ref_reg(A_FMOVE,s,newreference(ref),location.fpureg)))
  1092. end
  1093. else
  1094. { handle emulation }
  1095. begin
  1096. if t = s32real then
  1097. begin
  1098. location.fpureg := getregister32;
  1099. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),location.fpureg)))
  1100. end
  1101. else
  1102. { other floating types are not supported in emulation mode }
  1103. CGMessage(sym_e_type_id_not_defined);
  1104. end;
  1105. end;
  1106. { procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1107. begin
  1108. case t of
  1109. s32real : begin
  1110. op:=A_FSTP;
  1111. s:=S_FS;
  1112. end;
  1113. s64real : begin
  1114. op:=A_FSTP;
  1115. s:=S_FL;
  1116. end;
  1117. s80real : begin
  1118. op:=A_FSTP;
  1119. s:=S_FX;
  1120. end;
  1121. s64bit : begin
  1122. op:=A_FISTP;
  1123. s:=S_IQ;
  1124. end;
  1125. else internalerror(17);
  1126. end;
  1127. end; }
  1128. { stores an FPU value to memory }
  1129. { location:tlocation used to free up FPU register }
  1130. { ref: destination of storage }
  1131. procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
  1132. var
  1133. op : tasmop;
  1134. s : topsize;
  1135. begin
  1136. if location.loc <> LOC_FPU then
  1137. InternalError(34);
  1138. { no emulation }
  1139. case t of
  1140. s32real : s := S_FS;
  1141. s64real : s := S_FL;
  1142. s80real : s := S_FX;
  1143. else
  1144. begin
  1145. CGMessage(cg_f_unknown_float_type);
  1146. end;
  1147. end; { end case }
  1148. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1149. begin
  1150. { This permits the mixing of emulation and non-emulation routines }
  1151. { only possible for REAL = SINGLE value_str }
  1152. if not (location.fpureg in [R_FP0..R_FP7]) then
  1153. Begin
  1154. if s = S_FS then
  1155. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))))
  1156. else
  1157. internalerror(255);
  1158. end
  1159. else
  1160. exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,location.fpureg,newreference(ref))));
  1161. ungetregister(location.fpureg);
  1162. end
  1163. else
  1164. { handle emulation }
  1165. begin
  1166. if t = s32real then
  1167. begin
  1168. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))));
  1169. ungetregister32(location.fpureg);
  1170. end
  1171. else
  1172. { other floating types are not supported in emulation mode }
  1173. CGMessage(sym_e_type_id_not_defined);
  1174. end;
  1175. location.fpureg:=R_NO; { no register in LOC_FPU now }
  1176. end;
  1177. procedure firstcomplex(p : ptree);
  1178. var
  1179. hp : ptree;
  1180. begin
  1181. { always calculate boolean AND and OR from left to right }
  1182. if ((p^.treetype=orn) or (p^.treetype=andn)) and
  1183. (p^.left^.resulttype^.deftype=orddef) and
  1184. (porddef(p^.left^.resulttype)^.typ=bool8bit) then
  1185. p^.swaped:=false
  1186. else if (p^.left^.registers32<p^.right^.registers32)
  1187. { the following check is appropriate, because all }
  1188. { 4 registers are rarely used and it is thereby }
  1189. { achieved that the extra code is being dropped }
  1190. { by exchanging not commutative operators }
  1191. and (p^.right^.registers32<=4) then
  1192. begin
  1193. hp:=p^.left;
  1194. p^.left:=p^.right;
  1195. p^.right:=hp;
  1196. p^.swaped:=true;
  1197. end
  1198. else p^.swaped:=false;
  1199. end;
  1200. {$ifdef test_dest_loc}
  1201. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  1202. begin
  1203. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  1204. begin
  1205. emit_reg_reg(A_MOVE,s,reg,dest_loc.register);
  1206. set_location(p^.location,dest_loc);
  1207. in_dest_loc:=true;
  1208. end
  1209. else
  1210. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  1211. begin
  1212. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,s,reg,newreference(dest_loc.reference))));
  1213. set_location(p^.location,dest_loc);
  1214. in_dest_loc:=true;
  1215. end
  1216. else
  1217. internalerror(20080);
  1218. end;
  1219. {$endif test_dest_loc}
  1220. procedure removetemps(list : paasmoutput;p : plinkedlist);
  1221. var
  1222. hp : ptemptodestroy;
  1223. begin
  1224. hp:=ptemptodestroy(p^.first);
  1225. while assigned(hp) do
  1226. begin
  1227. if is_ansistring(hp^.typ) then
  1228. begin
  1229. emitpushreferenceaddr(list,hp^.address);
  1230. list^.concat(new(pai68k,
  1231. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_ANSISTR_DECR_REF',0))));
  1232. if not (cs_compilesystem in aktmoduleswitches) then
  1233. concat_external('FPC_ANSISTR_DECR_REF',EXT_NEAR);
  1234. end;
  1235. hp:=ptemptodestroy(hp^.next);
  1236. end;
  1237. end;
  1238. procedure releasedata(p : plinkedlist);
  1239. var
  1240. hp : ptemptodestroy;
  1241. begin
  1242. hp:=ptemptodestroy(p^.first);
  1243. while assigned(hp) do
  1244. begin
  1245. ungetiftemp(hp^.address);
  1246. hp:=ptemptodestroy(hp^.next);
  1247. end;
  1248. end;
  1249. end.
  1250. {
  1251. $Log$
  1252. Revision 1.31 1998-12-11 00:03:09 peter
  1253. + globtype,tokens,version unit splitted from globals
  1254. Revision 1.30 1998/11/30 09:43:05 pierre
  1255. * some range check bugs fixed (still not working !)
  1256. + added DLL writing support for win32 (also accepts variables)
  1257. + TempAnsi for code that could be used for Temporary ansi strings
  1258. handling
  1259. Revision 1.29 1998/11/13 15:40:16 pierre
  1260. + added -Se in Makefile cvstest target
  1261. + lexlevel cleanup
  1262. normal_function_level main_program_level and unit_init_level defined
  1263. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1264. (test added in code !)
  1265. * -Un option was wrong
  1266. * _FAIL and _SELF only keyword inside
  1267. constructors and methods respectively
  1268. Revision 1.28 1998/11/12 11:19:42 pierre
  1269. * fix for first line of function break
  1270. Revision 1.27 1998/11/12 09:46:17 pierre
  1271. + break main stops before calls to unit inits
  1272. + break at constructors stops before call to FPC_NEW_CLASS
  1273. or FPC_HELP_CONSTRUCTOR
  1274. Revision 1.26 1998/10/20 08:06:46 pierre
  1275. * several memory corruptions due to double freemem solved
  1276. => never use p^.loc.location:=p^.left^.loc.location;
  1277. + finally I added now by default
  1278. that ra386dir translates global and unit symbols
  1279. + added a first field in tsymtable and
  1280. a nextsym field in tsym
  1281. (this allows to obtain ordered type info for
  1282. records and objects in gdb !)
  1283. Revision 1.25 1998/10/16 13:12:48 pierre
  1284. * added vmt_offsets in destructors code also !!!
  1285. * vmt_offset code for m68k
  1286. Revision 1.24 1998/10/15 12:37:42 pierre
  1287. + passes vmt offset to HELP_CONSTRUCTOR for objects
  1288. Revision 1.23 1998/10/14 11:28:22 florian
  1289. * emitpushreferenceaddress gets now the asmlist as parameter
  1290. * m68k version compiles with -duseansistrings
  1291. Revision 1.22 1998/10/13 16:50:12 pierre
  1292. * undid some changes of Peter that made the compiler wrong
  1293. for m68k (I had to reinsert some ifdefs)
  1294. * removed several memory leaks under m68k
  1295. * removed the meory leaks for assembler readers
  1296. * cross compiling shoud work again better
  1297. ( crosscompiling sysamiga works
  1298. but as68k still complain about some code !)
  1299. Revision 1.21 1998/10/13 13:10:12 peter
  1300. * new style for m68k/i386 infos and enums
  1301. Revision 1.20 1998/10/13 08:19:29 pierre
  1302. + source_os is now set correctly for cross-processor compilers
  1303. (tos contains all target_infos and
  1304. we use CPU86 and CPU68 conditionnals to
  1305. get the source operating system
  1306. this only works if you do not undefine
  1307. the source target !!)
  1308. * several cg68k memory leaks fixed
  1309. + started to change the code so that it should be possible to have
  1310. a complete compiler (both for m68k and i386 !!)
  1311. Revision 1.19 1998/10/08 13:48:40 peter
  1312. * fixed memory leaks for do nothing source
  1313. * fixed unit interdependency
  1314. Revision 1.18 1998/09/28 16:57:17 pierre
  1315. * changed all length(p^.value_str^) into str_length(p)
  1316. to get it work with and without ansistrings
  1317. * changed sourcefiles field of tmodule to a pointer
  1318. Revision 1.17 1998/09/17 09:42:30 peter
  1319. + pass_2 for cg386
  1320. * Message() -> CGMessage() for pass_1/pass_2
  1321. Revision 1.16 1998/09/14 10:44:04 peter
  1322. * all internal RTL functions start with FPC_
  1323. Revision 1.15 1998/09/07 18:46:00 peter
  1324. * update smartlinking, uses getdatalabel
  1325. * renamed ptree.value vars to value_str,value_real,value_set
  1326. Revision 1.14 1998/09/04 08:41:50 peter
  1327. * updated some error CGMessages
  1328. Revision 1.13 1998/09/01 12:48:02 peter
  1329. * use pdef^.size instead of orddef^.typ
  1330. Revision 1.12 1998/09/01 09:07:09 peter
  1331. * m68k fixes, splitted cg68k like cgi386
  1332. Revision 1.11 1998/08/31 12:26:24 peter
  1333. * m68k and palmos updates from surebugfixes
  1334. Revision 1.10 1998/08/21 14:08:41 pierre
  1335. + TEST_FUNCRET now default (old code removed)
  1336. works also for m68k (at least compiles)
  1337. Revision 1.9 1998/08/17 10:10:04 peter
  1338. - removed OLDPPU
  1339. Revision 1.8 1998/08/10 14:43:16 peter
  1340. * string type st_ fixed
  1341. Revision 1.7 1998/07/10 10:51:01 peter
  1342. * m68k updates
  1343. Revision 1.6 1998/06/08 13:13:39 pierre
  1344. + temporary variables now in temp_gen.pas unit
  1345. because it is processor independent
  1346. * mppc68k.bat modified to undefine i386 and support_mmx
  1347. (which are defaults for i386)
  1348. Revision 1.5 1998/06/04 23:51:36 peter
  1349. * m68k compiles
  1350. + .def file creation moved to gendef.pas so it could also be used
  1351. for win32
  1352. Revision 1.4 1998/05/07 00:17:00 peter
  1353. * smartlinking for sets
  1354. + consts labels are now concated/generated in hcodegen
  1355. * moved some cpu code to cga and some none cpu depended code from cga
  1356. to tree and hcodegen and cleanup of hcodegen
  1357. * assembling .. output reduced for smartlinking ;)
  1358. Revision 1.3 1998/04/29 10:33:46 pierre
  1359. + added some code for ansistring (not complete nor working yet)
  1360. * corrected operator overloading
  1361. * corrected nasm output
  1362. + started inline procedures
  1363. + added starstarn : use ** for exponentiation (^ gave problems)
  1364. + started UseTokenInfo cond to get accurate positions
  1365. }