cga68k.pas 51 KB

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