rgx86.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the x86 specific class for the register
  5. allocator
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit rgx86;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cpubase,
  24. cpuinfo,
  25. aasmbase,aasmtai,aasmcpu,
  26. cclasses,globtype,cgbase,rgobj;
  27. type
  28. trgx86 = class(trgobj)
  29. function instr_spill_register(list:Taasmoutput;
  30. instr:taicpu;
  31. const r:Tsuperregisterset;
  32. const spilltemplist:Tspill_temp_list): boolean;override;
  33. end;
  34. tpushedsavedloc = record
  35. case byte of
  36. 0: (pushed: boolean);
  37. 1: (ofs: longint);
  38. end;
  39. tpushedsavedfpu = array[tsuperregister] of tpushedsavedloc;
  40. trgx86fpu = class
  41. { The "usableregsxxx" contain all registers of type "xxx" that }
  42. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  43. { contain all registers of type "xxx" that aren't currently }
  44. { allocated }
  45. unusedregsfpu,usableregsfpu : Tsuperregisterset;
  46. { these counters contain the number of elements in the }
  47. { unusedregsxxx/usableregsxxx sets }
  48. countunusedregsfpu : byte;
  49. { Contains the registers which are really used by the proc itself.
  50. It doesn't take care of registers used by called procedures
  51. }
  52. used_in_proc : tcpuregisterset;
  53. {reg_pushes_other : regvarother_longintarray;
  54. is_reg_var_other : regvarother_booleanarray;
  55. regvar_loaded_other : regvarother_booleanarray;}
  56. { tries to hold the amount of times which the current tree is processed }
  57. t_times: longint;
  58. fpuvaroffset : byte;
  59. constructor create;
  60. function getregisterfpu(list: taasmoutput) : tregister;
  61. procedure ungetregisterfpu(list: taasmoutput; r : tregister);
  62. { pushes and restores registers }
  63. procedure saveusedfpuregisters(list:Taasmoutput;
  64. var saved:Tpushedsavedfpu;
  65. const s:Tcpuregisterset);
  66. procedure restoreusedfpuregisters(list:Taasmoutput;
  67. const saved:Tpushedsavedfpu);
  68. { corrects the fpu stack register by ofs }
  69. function correct_fpuregister(r : tregister;ofs : byte) : tregister;
  70. end;
  71. implementation
  72. uses
  73. systems,
  74. verbose;
  75. const
  76. { This value is used in tsaved. If the array value is equal
  77. to this, then this means that this register is not used.}
  78. reg_not_saved = $7fffffff;
  79. {******************************************************************************
  80. Trgcpu
  81. ******************************************************************************}
  82. function trgx86.instr_spill_register(list:Taasmoutput;
  83. instr:taicpu;
  84. const r:Tsuperregisterset;
  85. const spilltemplist:Tspill_temp_list): boolean;
  86. {
  87. Spill the registers in r in this instruction. Returns true if any help
  88. registers are used. This procedure has become one big hack party, because
  89. of the huge amount of situations you can have. The irregularity of the i386
  90. instruction set doesn't help either. (DM)
  91. }
  92. var i:byte;
  93. supreg:Tsuperregister;
  94. subreg:Tsubregister;
  95. helpreg:Tregister;
  96. helpins:Taicpu;
  97. op:Tasmop;
  98. hopsize:Topsize;
  99. pos:Tai;
  100. begin
  101. {Situation examples are in intel notation, so operand order:
  102. mov eax , ebx
  103. ^^^ ^^^
  104. oper[1] oper[0]
  105. (DM)}
  106. result:=false;
  107. with taicpu(instr) do
  108. begin
  109. case ops of
  110. 0:
  111. ;
  112. 1:
  113. begin
  114. if (oper[0]^.typ=top_reg) and
  115. (getregtype(oper[0]^.reg)=regtype) then
  116. begin
  117. supreg:=getsupreg(oper[0]^.reg);
  118. if supregset_in(r,supreg) then
  119. begin
  120. {Situation example:
  121. push r20d ; r20d must be spilled into [ebp-12]
  122. Change into:
  123. push [ebp-12] ; Replace register by reference }
  124. { hopsize:=reg2opsize(oper[0].reg);}
  125. oper[0]^.typ:=top_ref;
  126. new(oper[0]^.ref);
  127. oper[0]^.ref^:=spilltemplist[supreg];
  128. { oper[0]^.ref^.size:=hopsize;}
  129. end;
  130. end;
  131. if oper[0]^.typ=top_ref then
  132. begin
  133. supreg:=getsupreg(oper[0]^.ref^.base);
  134. if supregset_in(r,supreg) then
  135. begin
  136. {Situation example:
  137. push [r21d+4*r22d] ; r21d must be spilled into [ebp-12]
  138. Change into:
  139. mov r23d,[ebp-12] ; Use a help register
  140. push [r23d+4*r22d] ; Replace register by helpregister }
  141. subreg:=getsubreg(oper[0]^.ref^.base);
  142. if oper[0]^.ref^.index=NR_NO then
  143. pos:=Tai(previous)
  144. else
  145. pos:=get_insert_pos(Tai(previous),getsupreg(oper[0]^.ref^.index),RS_INVALID,RS_INVALID);
  146. getregisterinline(list,pos,subreg,helpreg);
  147. result:=true;
  148. helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.ref^.base),spilltemplist[supreg],helpreg);
  149. if pos=nil then
  150. list.insertafter(helpins,list.first)
  151. else
  152. list.insertafter(helpins,pos.next);
  153. ungetregisterinline(list,helpins,helpreg);
  154. forward_allocation(Tai(helpins.next),instr);
  155. oper[0]^.ref^.base:=helpreg;
  156. end;
  157. supreg:=getsupreg(oper[0]^.ref^.index);
  158. if supregset_in(r,supreg) then
  159. begin
  160. {Situation example:
  161. push [r21d+4*r22d] ; r22d must be spilled into [ebp-12]
  162. Change into:
  163. mov r23d,[ebp-12] ; Use a help register
  164. push [r21d+4*r23d] ; Replace register by helpregister }
  165. subreg:=getsubreg(oper[0]^.ref^.index);
  166. if oper[0]^.ref^.base=NR_NO then
  167. pos:=Tai(instr.previous)
  168. else
  169. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.ref^.base),RS_INVALID,RS_INVALID);
  170. getregisterinline(list,pos,subreg,helpreg);
  171. result:=true;
  172. helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.ref^.index),spilltemplist[supreg],helpreg);
  173. if pos=nil then
  174. list.insertafter(helpins,list.first)
  175. else
  176. list.insertafter(helpins,pos.next);
  177. ungetregisterinline(list,helpins,helpreg);
  178. forward_allocation(Tai(helpins.next),instr);
  179. oper[0]^.ref^.index:=helpreg;
  180. end;
  181. end;
  182. end;
  183. 2,
  184. 3 :
  185. begin
  186. { Opcodes with 3 registers are shrd/shld, where the 3rd operand is const or CL,
  187. that doesn't need spilling }
  188. { First spill the registers from the references. This is
  189. required because the reference can be moved from this instruction
  190. to a MOV instruction when spilling of the register operand is done }
  191. for i:=0 to 1 do
  192. if oper[i]^.typ=top_ref then
  193. begin
  194. supreg:=getsupreg(oper[i]^.ref^.base);
  195. if supregset_in(r,supreg) then
  196. begin
  197. {Situation example:
  198. add r20d,[r21d+4*r22d] ; r21d must be spilled into [ebp-12]
  199. Change into:
  200. mov r23d,[ebp-12] ; Use a help register
  201. add r20d,[r23d+4*r22d] ; Replace register by helpregister }
  202. subreg:=getsubreg(oper[i]^.ref^.base);
  203. if i=1 then
  204. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.index),getsupreg(oper[0]^.reg),RS_INVALID)
  205. else
  206. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.index),RS_INVALID,RS_INVALID);
  207. getregisterinline(list,pos,subreg,helpreg);
  208. result:=true;
  209. helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[i]^.ref^.base),spilltemplist[supreg],helpreg);
  210. if pos=nil then
  211. list.insertafter(helpins,list.first)
  212. else
  213. list.insertafter(helpins,pos.next);
  214. oper[i]^.ref^.base:=helpreg;
  215. ungetregisterinline(list,helpins,helpreg);
  216. forward_allocation(Tai(helpins.next),instr);
  217. end;
  218. supreg:=getsupreg(oper[i]^.ref^.index);
  219. if supregset_in(r,supreg) then
  220. begin
  221. {Situation example:
  222. add r20d,[r21d+4*r22d] ; r22d must be spilled into [ebp-12]
  223. Change into:
  224. mov r23d,[ebp-12] ; Use a help register
  225. add r20d,[r21d+4*r23d] ; Replace register by helpregister }
  226. subreg:=getsubreg(oper[i]^.ref^.index);
  227. if i=1 then
  228. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.base),
  229. getsupreg(oper[0]^.reg),RS_INVALID)
  230. else
  231. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.base),RS_INVALID,RS_INVALID);
  232. getregisterinline(list,pos,subreg,helpreg);
  233. result:=true;
  234. helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[i]^.ref^.index),spilltemplist[supreg],helpreg);
  235. if pos=nil then
  236. list.insertafter(helpins,list.first)
  237. else
  238. list.insertafter(helpins,pos.next);
  239. oper[i]^.ref^.index:=helpreg;
  240. ungetregisterinline(list,helpins,helpreg);
  241. forward_allocation(Tai(helpins.next),instr);
  242. end;
  243. end;
  244. if (oper[0]^.typ=top_reg) and
  245. (getregtype(oper[0]^.reg)=regtype) then
  246. begin
  247. supreg:=getsupreg(oper[0]^.reg);
  248. subreg:=getsubreg(oper[0]^.reg);
  249. if supregset_in(r,supreg) then
  250. if oper[1]^.typ=top_ref then
  251. begin
  252. {Situation example:
  253. add [r20d],r21d ; r21d must be spilled into [ebp-12]
  254. Change into:
  255. mov r22d,[ebp-12] ; Use a help register
  256. add [r20d],r22d ; Replace register by helpregister }
  257. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.reg),
  258. getsupreg(oper[1]^.ref^.base),getsupreg(oper[1]^.ref^.index));
  259. getregisterinline(list,pos,subreg,helpreg);
  260. result:=true;
  261. helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.reg),spilltemplist[supreg],helpreg);
  262. if pos=nil then
  263. list.insertafter(helpins,list.first)
  264. else
  265. list.insertafter(helpins,pos.next);
  266. oper[0]^.reg:=helpreg;
  267. ungetregisterinline(list,helpins,helpreg);
  268. forward_allocation(Tai(helpins.next),instr);
  269. end
  270. else
  271. begin
  272. {Situation example:
  273. add r20d,r21d ; r21d must be spilled into [ebp-12]
  274. Change into:
  275. add r20d,[ebp-12] ; Replace register by reference }
  276. oper[0]^.typ:=top_ref;
  277. new(oper[0]^.ref);
  278. oper[0]^.ref^:=spilltemplist[supreg];
  279. end;
  280. end;
  281. if (oper[1]^.typ=top_reg) and
  282. (getregtype(oper[1]^.reg)=regtype) then
  283. begin
  284. supreg:=getsupreg(oper[1]^.reg);
  285. subreg:=getsubreg(oper[1]^.reg);
  286. if supregset_in(r,supreg) then
  287. begin
  288. if oper[0]^.typ=top_ref then
  289. begin
  290. {Situation example:
  291. add r20d,[r21d] ; r20d must be spilled into [ebp-12]
  292. Change into:
  293. mov r22d,[r21d] ; Use a help register
  294. add [ebp-12],r22d ; Replace register by helpregister }
  295. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.ref^.base),
  296. getsupreg(oper[0]^.ref^.index),RS_INVALID);
  297. getregisterinline(list,pos,subreg,helpreg);
  298. result:=true;
  299. op:=A_MOV;
  300. hopsize:=opsize; {Save old value...}
  301. if (opcode=A_MOVZX) or (opcode=A_MOVSX) or (opcode=A_LEA) then
  302. begin
  303. {Because 'movzx memory,register' does not exist...}
  304. op:=opcode;
  305. opcode:=A_MOV;
  306. opsize:=reg2opsize(oper[1]^.reg);
  307. end;
  308. helpins:=Taicpu.op_ref_reg(op,hopsize,oper[0]^.ref^,helpreg);
  309. if pos=nil then
  310. list.insertafter(helpins,list.first)
  311. else
  312. list.insertafter(helpins,pos.next);
  313. dispose(oper[0]^.ref);
  314. oper[0]^.typ:=top_reg;
  315. oper[0]^.reg:=helpreg;
  316. oper[1]^.typ:=top_ref;
  317. new(oper[1]^.ref);
  318. oper[1]^.ref^:=spilltemplist[supreg];
  319. ungetregisterinline(list,helpins,helpreg);
  320. forward_allocation(Tai(helpins.next),instr);
  321. end
  322. else
  323. begin
  324. {Situation example:
  325. add r20d,r21d ; r20d must be spilled into [ebp-12]
  326. Change into:
  327. add [ebp-12],r21d ; Replace register by reference }
  328. if (opcode=A_MOVZX) or (opcode=A_MOVSX) then
  329. begin
  330. {Because 'movzx memory,register' does not exist...}
  331. result:=true;
  332. op:=opcode;
  333. hopsize:=opsize;
  334. opcode:=A_MOV;
  335. opsize:=reg2opsize(oper[1]^.reg);
  336. pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.reg),RS_INVALID,RS_INVALID);
  337. getregisterinline(list,pos,subreg,helpreg);
  338. helpins:=Taicpu.op_reg_reg(op,hopsize,oper[0]^.reg,helpreg);
  339. if pos=nil then
  340. list.insertafter(helpins,list.first)
  341. else
  342. list.insertafter(helpins,pos.next);
  343. oper[0]^.reg:=helpreg;
  344. ungetregisterinline(list,helpins,helpreg);
  345. forward_allocation(Tai(helpins.next),instr);
  346. end;
  347. oper[1]^.typ:=top_ref;
  348. new(oper[1]^.ref);
  349. oper[1]^.ref^:=spilltemplist[supreg];
  350. end;
  351. end;
  352. end;
  353. { The i386 instruction set never gets boring...
  354. some opcodes do not support a memory location as destination }
  355. if (oper[1]^.typ=top_ref) and
  356. (
  357. (oper[0]^.typ=top_const) or
  358. ((oper[0]^.typ=top_reg) and
  359. (getregtype(oper[0]^.reg)=regtype))
  360. ) then
  361. begin
  362. case opcode of
  363. A_SHLD,A_SHRD,
  364. A_IMUL :
  365. begin
  366. {Yikes! We just changed the destination register into
  367. a memory location above here.
  368. Situation examples:
  369. imul [ebp-12],r21d ; We need a help register
  370. imul [ebp-12],<const> ; We need a help register
  371. Change into:
  372. mov r22d,[ebp-12] ; Use a help instruction (only for IMUL)
  373. imul r22d,r21d ; Replace reference by helpregister
  374. mov [ebp-12],r22d ; Use another help instruction}
  375. getregisterinline(list,Tai(previous),subreg,helpreg);
  376. result:=true;
  377. {First help instruction.}
  378. helpins:=Taicpu.op_ref_reg(A_MOV,opsize,oper[1]^.ref^,helpreg);
  379. if previous=nil then
  380. list.insert(helpins)
  381. else
  382. list.insertafter(helpins,previous);
  383. {Second help instruction.}
  384. helpins:=Taicpu.op_reg_ref(A_MOV,opsize,helpreg,oper[1]^.ref^);
  385. dispose(oper[1]^.ref);
  386. oper[1]^.typ:=top_reg;
  387. oper[1]^.reg:=helpreg;
  388. list.insertafter(helpins,instr);
  389. ungetregisterinline(list,instr,helpreg);
  390. end;
  391. end;
  392. end;
  393. { The i386 instruction set never gets boring...
  394. some opcodes do not support a memory location as source }
  395. if (oper[0]^.typ=top_ref) and
  396. (oper[1]^.typ=top_reg) and
  397. (getregtype(oper[1]^.reg)=regtype) then
  398. begin
  399. case opcode of
  400. A_BT,A_BTS,
  401. A_BTC,A_BTR :
  402. begin
  403. {Yikes! We just changed the source register into
  404. a memory location above here.
  405. Situation example:
  406. bt r21d,[ebp-12] ; We need a help register
  407. Change into:
  408. mov r22d,[ebp-12] ; Use a help instruction (only for IMUL)
  409. bt r21d,r22d ; Replace reference by helpregister}
  410. getregisterinline(list,Tai(previous),subreg,helpreg);
  411. result:=true;
  412. {First help instruction.}
  413. helpins:=Taicpu.op_ref_reg(A_MOV,opsize,oper[0]^.ref^,helpreg);
  414. if previous=nil then
  415. list.insert(helpins)
  416. else
  417. list.insertafter(helpins,previous);
  418. dispose(oper[0]^.ref);
  419. oper[0]^.typ:=top_reg;
  420. oper[0]^.reg:=helpreg;
  421. ungetregisterinline(list,helpins,helpreg);
  422. end;
  423. end;
  424. end;
  425. end;
  426. else
  427. internalerror(200409202);
  428. end;
  429. end;
  430. end;
  431. {******************************************************************************
  432. Trgx86fpu
  433. ******************************************************************************}
  434. constructor Trgx86fpu.create;
  435. var i:Tsuperregister;
  436. begin
  437. used_in_proc:=[];
  438. t_times := 0;
  439. unusedregsfpu:=usableregsfpu;
  440. end;
  441. function trgx86fpu.getregisterfpu(list: taasmoutput) : tregister;
  442. begin
  443. { note: don't return R_ST0, see comments above implementation of }
  444. { a_loadfpu_* methods in cgcpu (JM) }
  445. result:=NR_ST;
  446. end;
  447. procedure trgx86fpu.ungetregisterfpu(list : taasmoutput; r : tregister);
  448. begin
  449. { nothing to do, fpu stack management is handled by the load/ }
  450. { store operations in cgcpu (JM) }
  451. end;
  452. function trgx86fpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
  453. begin
  454. correct_fpuregister:=r;
  455. setsupreg(correct_fpuregister,ofs);
  456. end;
  457. procedure trgx86fpu.saveusedfpuregisters(list: taasmoutput;
  458. var saved : tpushedsavedfpu;
  459. const s: tcpuregisterset);
  460. var
  461. r : tregister;
  462. hr : treference;
  463. begin
  464. used_in_proc:=used_in_proc+s;
  465. {$warning TODO firstsavefpureg}
  466. (*
  467. { don't try to save the fpu registers if not desired (e.g. for }
  468. { the 80x86) }
  469. if firstsavefpureg <> R_NO then
  470. for r.enum:=firstsavefpureg to lastsavefpureg do
  471. begin
  472. saved[r.enum].ofs:=reg_not_saved;
  473. { if the register is used by the calling subroutine and if }
  474. { it's not a regvar (those are handled separately) }
  475. if not is_reg_var_other[r.enum] and
  476. (r.enum in s) and
  477. { and is present in use }
  478. not(r.enum in unusedregsfpu) then
  479. begin
  480. { then save it }
  481. tg.GetTemp(list,extended_size,tt_persistent,hr);
  482. saved[r.enum].ofs:=hr.offset;
  483. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  484. cg.a_reg_dealloc(list,r);
  485. include(unusedregsfpu,r.enum);
  486. inc(countunusedregsfpu);
  487. end;
  488. end;
  489. *)
  490. end;
  491. procedure trgx86fpu.restoreusedfpuregisters(list : taasmoutput;
  492. const saved : tpushedsavedfpu);
  493. var
  494. r,r2 : tregister;
  495. hr : treference;
  496. begin
  497. {$warning TODO firstsavefpureg}
  498. (*
  499. if firstsavefpureg <> R_NO then
  500. for r.enum:=lastsavefpureg downto firstsavefpureg do
  501. begin
  502. if saved[r.enum].ofs <> reg_not_saved then
  503. begin
  504. r2.enum:=R_INTREGISTER;
  505. r2.number:=NR_FRAME_POINTER_REG;
  506. reference_reset_base(hr,r2,saved[r.enum].ofs);
  507. cg.a_reg_alloc(list,r);
  508. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  509. if not (r.enum in unusedregsfpu) then
  510. { internalerror(10)
  511. in n386cal we always save/restore the reg *state*
  512. using save/restoreunusedstate -> the current state
  513. may not be real (JM) }
  514. else
  515. begin
  516. dec(countunusedregsfpu);
  517. exclude(unusedregsfpu,r.enum);
  518. end;
  519. tg.UnGetTemp(list,hr);
  520. end;
  521. end;
  522. *)
  523. end;
  524. (*
  525. procedure Trgx86fpu.saveotherregvars(list: taasmoutput; const s: totherregisterset);
  526. var
  527. r: Tregister;
  528. begin
  529. if not(cs_regvars in aktglobalswitches) then
  530. exit;
  531. if firstsavefpureg <> NR_NO then
  532. for r.enum := firstsavefpureg to lastsavefpureg do
  533. if is_reg_var_other[r.enum] and
  534. (r.enum in s) then
  535. store_regvar(list,r);
  536. end;
  537. *)
  538. end.
  539. {
  540. $Log$
  541. Revision 1.6 2004-09-27 14:49:45 peter
  542. * handle 3 operand opcodes the same as 2 operand opcodes, the
  543. third operand can only be a const or register CL, so it doesn't
  544. affect spilling
  545. * support shrd/shld that don't allow memory operands
  546. Revision 1.5 2004/09/26 07:15:07 florian
  547. * ie checking in spilling code improved
  548. Revision 1.4 2004/06/20 08:55:32 florian
  549. * logs truncated
  550. Revision 1.3 2004/06/16 20:07:11 florian
  551. * dwarf branch merged
  552. Revision 1.2.2.1 2004/04/10 12:36:42 peter
  553. * fixed alignment issues
  554. Revision 1.2 2004/01/12 16:37:59 peter
  555. * moved spilling code from taicpu to rg
  556. }