cga68k.pas 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl, Carl Eric Codere
  4. This unit generates 68000 (or better) assembler from the parse tree
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cga68k;
  19. interface
  20. uses
  21. globtype,cobjects,tree,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.38 1999-11-17 17:04:58 pierre
  1247. * Notes/hints changes
  1248. Revision 1.37 1999/11/09 23:06:44 peter
  1249. * esi_offset -> selfpointer_offset to be newcg compatible
  1250. * hcogegen -> cgbase fixes for newcg
  1251. Revision 1.36 1999/11/06 14:34:18 peter
  1252. * truncated log to 20 revs
  1253. Revision 1.35 1999/09/27 23:44:48 peter
  1254. * procinfo is now a pointer
  1255. * support for result setting in sub procedure
  1256. Revision 1.34 1999/09/16 23:05:51 florian
  1257. * m68k compiler is again compilable (only gas writer, no assembler reader)
  1258. Revision 1.33 1999/09/16 11:34:54 pierre
  1259. * typo correction
  1260. Revision 1.32 1999/08/25 11:59:54 jonas
  1261. * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
  1262. Revision 1.31 1998/12/11 00:03:09 peter
  1263. + globtype,tokens,version unit splitted from globals
  1264. Revision 1.30 1998/11/30 09:43:05 pierre
  1265. * some range check bugs fixed (still not working !)
  1266. + added DLL writing support for win32 (also accepts variables)
  1267. + TempAnsi for code that could be used for Temporary ansi strings
  1268. handling
  1269. Revision 1.29 1998/11/13 15:40:16 pierre
  1270. + added -Se in Makefile cvstest target
  1271. + lexlevel cleanup
  1272. normal_function_level main_program_level and unit_init_level defined
  1273. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1274. (test added in code !)
  1275. * -Un option was wrong
  1276. * _FAIL and _SELF only keyword inside
  1277. constructors and methods respectively
  1278. Revision 1.28 1998/11/12 11:19:42 pierre
  1279. * fix for first line of function break
  1280. Revision 1.27 1998/11/12 09:46:17 pierre
  1281. + break main stops before calls to unit inits
  1282. + break at constructors stops before call to FPC_NEW_CLASS
  1283. or FPC_HELP_CONSTRUCTOR
  1284. Revision 1.26 1998/10/20 08:06:46 pierre
  1285. * several memory corruptions due to double freemem solved
  1286. => never use p^.loc.location:=p^.left^.loc.location;
  1287. + finally I added now by default
  1288. that ra386dir translates global and unit symbols
  1289. + added a first field in tsymtable and
  1290. a nextsym field in tsym
  1291. (this allows to obtain ordered type info for
  1292. records and objects in gdb !)
  1293. Revision 1.25 1998/10/16 13:12:48 pierre
  1294. * added vmt_offsets in destructors code also !!!
  1295. * vmt_offset code for m68k
  1296. Revision 1.24 1998/10/15 12:37:42 pierre
  1297. + passes vmt offset to HELP_CONSTRUCTOR for objects
  1298. Revision 1.23 1998/10/14 11:28:22 florian
  1299. * emitpushreferenceaddress gets now the asmlist as parameter
  1300. * m68k version compiles with -duseansistrings
  1301. Revision 1.22 1998/10/13 16:50:12 pierre
  1302. * undid some changes of Peter that made the compiler wrong
  1303. for m68k (I had to reinsert some ifdefs)
  1304. * removed several memory leaks under m68k
  1305. * removed the meory leaks for assembler readers
  1306. * cross compiling shoud work again better
  1307. ( crosscompiling sysamiga works
  1308. but as68k still complain about some code !)
  1309. Revision 1.21 1998/10/13 13:10:12 peter
  1310. * new style for m68k/i386 infos and enums
  1311. Revision 1.20 1998/10/13 08:19:29 pierre
  1312. + source_os is now set correctly for cross-processor compilers
  1313. (tos contains all target_infos and
  1314. we use CPU86 and CPU68 conditionals to
  1315. get the source operating system
  1316. this only works if you do not undefine
  1317. the source target !!)
  1318. * several cg68k memory leaks fixed
  1319. + started to change the code so that it should be possible to have
  1320. a complete compiler (both for m68k and i386 !!)
  1321. Revision 1.19 1998/10/08 13:48:40 peter
  1322. * fixed memory leaks for do nothing source
  1323. * fixed unit interdependency
  1324. Revision 1.18 1998/09/28 16:57:17 pierre
  1325. * changed all length(p^.value_str^) into str_length(p)
  1326. to get it work with and without ansistrings
  1327. * changed sourcefiles field of tmodule to a pointer
  1328. Revision 1.17 1998/09/17 09:42:30 peter
  1329. + pass_2 for cg386
  1330. * Message() -> CGMessage() for pass_1/pass_2
  1331. Revision 1.16 1998/09/14 10:44:04 peter
  1332. * all internal RTL functions start with FPC_
  1333. }