cga68k.pas 57 KB

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