cga68k.pas 60 KB

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