cga68k.pas 60 KB

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