cga68k.pas 53 KB

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