cga68k.pas 58 KB

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