cgcpu.pas 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. {
  2. $Id$
  3. Copyright (c) 2003 by Florian Klaempfl
  4. Member of the Free Pascal development team
  5. This unit implements the code generator for the ARM
  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 cgcpu;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. symtype,
  24. cgbase,cgobj,
  25. aasmbase,aasmcpu,aasmtai,
  26. cpubase,cpuinfo,node,cg64f32,cginfo;
  27. type
  28. tcgarm = class(tcg)
  29. procedure init_register_allocators;override;
  30. procedure done_register_allocators;override;
  31. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  32. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  33. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  34. procedure a_call_name(list : taasmoutput;const s : string);override;
  35. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  36. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  37. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  38. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  39. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  40. size: tcgsize; a: aword; src, dst: tregister); override;
  41. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  42. size: tcgsize; src1, src2, dst: tregister); override;
  43. { move instructions }
  44. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  45. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  46. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  47. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  48. { fpu move instructions }
  49. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  50. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  51. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  52. { comparison operations }
  53. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  54. l : tasmlabel);override;
  55. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  56. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  57. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  58. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  59. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);override;
  60. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  61. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  62. procedure g_restore_frame_pointer(list : taasmoutput);override;
  63. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  64. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  65. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  66. procedure g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
  67. procedure g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
  68. procedure g_save_all_registers(list : taasmoutput);override;
  69. procedure g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);override;
  70. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  71. procedure fixref(list : taasmoutput;var ref : treference);
  72. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  73. end;
  74. tcg64farm = class(tcg64f32)
  75. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  76. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  77. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
  78. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  79. end;
  80. const
  81. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  82. C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
  83. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  84. implementation
  85. uses
  86. globtype,globals,verbose,systems,cutils,symconst,symdef,symsym,rgobj,rgcpu,tgobj,cpupi;
  87. procedure tcgarm.init_register_allocators;
  88. begin
  89. rg:=trgcpu.create(11,#0#1#2#3#4#5#6#7#8#9#10);
  90. end;
  91. procedure tcgarm.done_register_allocators;
  92. begin
  93. rg.free;
  94. end;
  95. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  96. var
  97. ref: treference;
  98. begin
  99. case locpara.loc of
  100. LOC_REGISTER,LOC_CREGISTER:
  101. a_load_const_reg(list,size,a,locpara.register);
  102. LOC_REFERENCE:
  103. begin
  104. reference_reset(ref);
  105. ref.base:=locpara.reference.index;
  106. ref.offset:=locpara.reference.offset;
  107. a_load_const_ref(list,size,a,ref);
  108. end;
  109. else
  110. internalerror(2002081101);
  111. end;
  112. if locpara.sp_fixup<>0 then
  113. internalerror(2002081102);
  114. end;
  115. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  116. var
  117. ref: treference;
  118. tmpreg: tregister;
  119. begin
  120. case locpara.loc of
  121. LOC_REGISTER,LOC_CREGISTER:
  122. a_load_ref_reg(list,size,size,r,locpara.register);
  123. LOC_REFERENCE:
  124. begin
  125. reference_reset(ref);
  126. ref.base:=locpara.reference.index;
  127. ref.offset:=locpara.reference.offset;
  128. tmpreg := rg.getregisterint(list,size);
  129. a_load_ref_reg(list,size,size,r,tmpreg);
  130. a_load_reg_ref(list,size,size,tmpreg,ref);
  131. rg.ungetregisterint(list,tmpreg);
  132. end;
  133. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  134. case size of
  135. OS_F32, OS_F64:
  136. a_loadfpu_ref_reg(list,size,r,locpara.register);
  137. else
  138. internalerror(2002072801);
  139. end;
  140. else
  141. internalerror(2002081103);
  142. end;
  143. if locpara.sp_fixup<>0 then
  144. internalerror(2002081104);
  145. end;
  146. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  147. var
  148. ref: treference;
  149. tmpreg: tregister;
  150. begin
  151. case locpara.loc of
  152. LOC_REGISTER,LOC_CREGISTER:
  153. a_loadaddr_ref_reg(list,r,locpara.register);
  154. LOC_REFERENCE:
  155. begin
  156. reference_reset(ref);
  157. ref.base := locpara.reference.index;
  158. ref.offset := locpara.reference.offset;
  159. tmpreg := rg.getregisterint(list,OS_ADDR);
  160. a_loadaddr_ref_reg(list,r,tmpreg);
  161. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  162. rg.ungetregisterint(list,tmpreg);
  163. end;
  164. else
  165. internalerror(2002080701);
  166. end;
  167. end;
  168. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  169. begin
  170. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s)));
  171. if not(pi_do_call in current_procinfo.flags) then
  172. internalerror(2003060703);
  173. end;
  174. procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
  175. var
  176. r : tregister;
  177. begin
  178. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  179. if not(pi_do_call in current_procinfo.flags) then
  180. internalerror(2003060704);
  181. end;
  182. procedure tcgarm.a_call_ref(list : taasmoutput;const ref : treference);
  183. var
  184. r : tregister;
  185. begin
  186. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_PC);
  187. if not(pi_do_call in current_procinfo.flags) then
  188. internalerror(2003060705);
  189. end;
  190. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  191. begin
  192. a_op_const_reg_reg(list,op,size,a,reg,reg);
  193. end;
  194. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  195. begin
  196. case op of
  197. OP_NEG:
  198. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  199. OP_NOT:
  200. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  201. else
  202. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  203. end;
  204. end;
  205. const
  206. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  207. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  208. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  209. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  210. size: tcgsize; a: aword; src, dst: tregister);
  211. var
  212. shift : byte;
  213. tmpreg : tregister;
  214. so : tshifterop;
  215. begin
  216. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  217. case op of
  218. OP_NEG,OP_NOT,
  219. OP_DIV,OP_IDIV:
  220. internalerror(200308281);
  221. OP_SHL:
  222. begin
  223. if a>32 then
  224. internalerror(200308291);
  225. shifterop_reset(so);
  226. so.shiftmode:=SM_LSL;
  227. so.shiftimm:=a;
  228. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  229. end;
  230. OP_SHR:
  231. begin
  232. if a>32 then
  233. internalerror(200308292);
  234. shifterop_reset(so);
  235. so.shiftmode:=SM_LSR;
  236. so.shiftimm:=a;
  237. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  238. end;
  239. OP_SAR:
  240. begin
  241. if a>32 then
  242. internalerror(200308291);
  243. shifterop_reset(so);
  244. so.shiftmode:=SM_LSL;
  245. so.shiftimm:=a;
  246. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  247. end;
  248. else
  249. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
  250. end
  251. else
  252. begin
  253. { there could be added some more sophisticated optimizations }
  254. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  255. a_load_reg_reg(list,size,size,src,dst)
  256. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  257. a_load_const_reg(list,size,0,dst)
  258. else if (op in [OP_IMUL]) and (a=-1) then
  259. a_op_reg_reg(list,OP_NEG,size,src,dst)
  260. else
  261. begin
  262. tmpreg:=rg.getregisterint(list,size);
  263. a_load_const_reg(list,size,a,tmpreg);
  264. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  265. rg.ungetregisterint(list,tmpreg);
  266. end;
  267. end;
  268. end;
  269. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  270. size: tcgsize; src1, src2, dst: tregister);
  271. var
  272. so : tshifterop;
  273. tmpreg : tregister;
  274. begin
  275. case op of
  276. OP_NEG,OP_NOT,
  277. OP_DIV,OP_IDIV:
  278. internalerror(200308281);
  279. OP_SHL:
  280. begin
  281. shifterop_reset(so);
  282. so.rs:=src1;
  283. so.shiftmode:=SM_LSL;
  284. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  285. end;
  286. OP_SHR:
  287. begin
  288. shifterop_reset(so);
  289. so.rs:=src1;
  290. so.shiftmode:=SM_LSR;
  291. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  292. end;
  293. OP_SAR:
  294. begin
  295. shifterop_reset(so);
  296. so.rs:=src1;
  297. so.shiftmode:=SM_ASR;
  298. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  299. end;
  300. OP_IMUL,
  301. OP_MUL:
  302. begin
  303. { the arm doesn't allow that rd and rm are the same }
  304. rg.add_edge(dst,src2);
  305. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  306. end;
  307. else
  308. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
  309. end;
  310. end;
  311. function rotl(d : dword;b : byte) : dword;
  312. begin
  313. result:=(d shr (32-b)) or (d shl b);
  314. end;
  315. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  316. var
  317. i : longint;
  318. begin
  319. for i:=0 to 15 do
  320. begin
  321. if (d and not(rotl($ff,i*2)))=0 then
  322. begin
  323. imm_shift:=i*2;
  324. result:=true;
  325. exit;
  326. end;
  327. end;
  328. result:=false;
  329. end;
  330. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
  331. var
  332. imm_shift : byte;
  333. l : tasmlabel;
  334. hr : treference;
  335. begin
  336. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  337. internalerror(2002090902);
  338. if is_shifter_const(a,imm_shift) then
  339. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  340. else if is_shifter_const(not(a),imm_shift) then
  341. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  342. else
  343. begin
  344. objectlibrary.getdatalabel(l);
  345. current_procinfo.aktlocaldata.concat(tai_symbol.Create(l,0));
  346. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(a));
  347. reference_reset(hr);
  348. hr.symbol:=l;
  349. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  350. end;
  351. end;
  352. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  353. var
  354. tmpreg : tregister;
  355. tmpref : treference;
  356. l : tasmlabel;
  357. begin
  358. tmpreg:=NR_NO;
  359. { Be sure to have a base register }
  360. if (ref.base=NR_NO) then
  361. begin
  362. if ref.shiftmode<>SM_None then
  363. internalerror(200308294);
  364. ref.base:=ref.index;
  365. ref.index:=NR_NO;
  366. end;
  367. { absolute symbols can't be handled directly, we've to store the symbol reference
  368. in the text segment and access it pc relative
  369. For now, we assume that references where base or index equals to PC are already
  370. relative, all other references are assumed to be absolute and thus they need
  371. to be handled extra.
  372. A proper solution would be to change refoptions to a set and store the information
  373. if the symbol is absolute or relative there.
  374. }
  375. if (assigned(ref.symbol) and
  376. not(is_pc(ref.base)) and
  377. not(is_pc(ref.index))
  378. ) or
  379. (ref.offset<-4095) or
  380. (ref.offset>4095) or
  381. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  382. ((ref.offset<-255) or
  383. (ref.offset>255)
  384. )
  385. ) then
  386. begin
  387. { check consts distance }
  388. { create consts entry }
  389. objectlibrary.getdatalabel(l);
  390. current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
  391. if assigned(ref.symbol) then
  392. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  393. else
  394. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  395. { load consts entry }
  396. tmpreg:=rg.getregisterint(list,OS_INT);
  397. reference_reset(tmpref);
  398. tmpref.symbol:=l;
  399. tmpref.base:=NR_R15;
  400. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  401. if (ref.base<>NR_NO) then
  402. begin
  403. if ref.index<>NR_NO then
  404. begin
  405. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  406. rg.ungetregister(list,ref.base);
  407. ref.base:=tmpreg;
  408. end
  409. else
  410. begin
  411. ref.index:=tmpreg;
  412. ref.shiftimm:=0;
  413. ref.signindex:=1;
  414. ref.shiftmode:=SM_None;
  415. end;
  416. end
  417. else
  418. ref.base:=tmpreg;
  419. ref.offset:=0;
  420. ref.symbol:=nil;
  421. end;
  422. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  423. if (tmpreg<>NR_NO) then
  424. rg.ungetregisterint(list,tmpreg);
  425. end;
  426. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  427. var
  428. oppostfix:toppostfix;
  429. begin
  430. case ToSize of
  431. { signed integer registers }
  432. OS_8,
  433. OS_S8:
  434. oppostfix:=PF_B;
  435. OS_16,
  436. OS_S16:
  437. oppostfix:=PF_H;
  438. OS_32,
  439. OS_S32:
  440. oppostfix:=PF_None;
  441. else
  442. InternalError(200308295);
  443. end;
  444. handle_load_store(list,A_STR,oppostfix,reg,ref);
  445. end;
  446. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  447. var
  448. oppostfix:toppostfix;
  449. begin
  450. case FromSize of
  451. { signed integer registers }
  452. OS_8:
  453. oppostfix:=PF_B;
  454. OS_S8:
  455. oppostfix:=PF_SB;
  456. OS_16:
  457. oppostfix:=PF_H;
  458. OS_S16:
  459. oppostfix:=PF_SH;
  460. OS_32,
  461. OS_S32:
  462. oppostfix:=PF_None;
  463. else
  464. InternalError(200308291);
  465. end;
  466. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  467. end;
  468. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  469. var
  470. instr: taicpu;
  471. so : tshifterop;
  472. begin
  473. shifterop_reset(so);
  474. if (reg1<>reg2) or
  475. (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  476. ((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  477. (tosize <> fromsize) and
  478. not(fromsize in [OS_32,OS_S32])) then
  479. begin
  480. case tosize of
  481. OS_8:
  482. instr := taicpu.op_reg_reg_const(A_AND,
  483. reg2,reg1,$ff);
  484. OS_S8:
  485. begin
  486. so.shiftmode:=SM_LSL;
  487. so.shiftimm:=24;
  488. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  489. so.shiftmode:=SM_ASR;
  490. so.shiftimm:=24;
  491. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  492. end;
  493. OS_16:
  494. begin
  495. so.shiftmode:=SM_LSL;
  496. so.shiftimm:=16;
  497. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  498. so.shiftmode:=SM_LSR;
  499. so.shiftimm:=16;
  500. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  501. end;
  502. OS_S16:
  503. begin
  504. so.shiftmode:=SM_LSL;
  505. so.shiftimm:=16;
  506. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  507. so.shiftmode:=SM_ASR;
  508. so.shiftimm:=16;
  509. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  510. end;
  511. OS_32,OS_S32:
  512. begin
  513. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  514. rg.add_move_instruction(instr);
  515. list.concat(instr);
  516. end;
  517. else internalerror(2002090901);
  518. end;
  519. end;
  520. end;
  521. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  522. begin
  523. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  524. end;
  525. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  526. var
  527. oppostfix:toppostfix;
  528. begin
  529. case size of
  530. OS_F32:
  531. oppostfix:=PF_S;
  532. OS_F64:
  533. oppostfix:=PF_D;
  534. OS_F80:
  535. oppostfix:=PF_E;
  536. else
  537. InternalError(200309021);
  538. end;
  539. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  540. end;
  541. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  542. var
  543. oppostfix:toppostfix;
  544. begin
  545. case size of
  546. OS_F32:
  547. oppostfix:=PF_S;
  548. OS_F64:
  549. oppostfix:=PF_D;
  550. OS_F80:
  551. oppostfix:=PF_E;
  552. else
  553. InternalError(200309021);
  554. end;
  555. handle_load_store(list,A_STF,oppostfix,reg,ref);
  556. end;
  557. { comparison operations }
  558. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  559. l : tasmlabel);
  560. var
  561. tmpreg : tregister;
  562. b : byte;
  563. begin
  564. if is_shifter_const(a,b) then
  565. list.concat(taicpu.op_reg_const(A_CMN,reg,a))
  566. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  567. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  568. else if is_shifter_const(not(a),b) and (a<>$7fffffff) and (a<>$ffffffff) then
  569. list.concat(taicpu.op_reg_const(A_CMN,reg,not(a)))
  570. else
  571. begin
  572. tmpreg:=rg.getregisterint(list,size);
  573. a_load_const_reg(list,size,a,tmpreg);
  574. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  575. rg.ungetregisterint(list,tmpreg);
  576. end;
  577. a_jmp_cond(list,cmp_op,l);
  578. end;
  579. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  580. begin
  581. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  582. a_jmp_cond(list,cmp_op,l);
  583. end;
  584. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  585. begin
  586. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name)));
  587. end;
  588. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  589. var
  590. ai : taicpu;
  591. begin
  592. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  593. ai.is_jmp:=true;
  594. list.concat(ai);
  595. end;
  596. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  597. var
  598. ai : taicpu;
  599. begin
  600. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  601. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
  602. end;
  603. procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);
  604. begin
  605. end;
  606. procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
  607. var
  608. ref : treference;
  609. begin
  610. LocalSize:=align(LocalSize,4);
  611. a_reg_alloc(list,NR_STACK_POINTER_REG);
  612. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  613. a_reg_alloc(list,NR_R12);
  614. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  615. { save int registers }
  616. reference_reset(ref);
  617. ref.index:=NR_STACK_POINTER_REG;
  618. ref.addressmode:=AM_PREINDEXED;
  619. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R12,RS_R15]),PF_FD));
  620. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  621. a_reg_alloc(list,NR_R12);
  622. { allocate necessary stack size }
  623. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  624. end;
  625. procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
  626. var
  627. ref : treference;
  628. begin
  629. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  630. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  631. else
  632. begin
  633. { restore int registers and return }
  634. reference_reset(ref);
  635. ref.index:=NR_FRAME_POINTER_REG;
  636. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R13,RS_R15]),PF_EA));
  637. end;
  638. end;
  639. procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
  640. begin
  641. { the frame pointer on the ARM is restored while the ret is executed }
  642. end;
  643. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  644. var
  645. b : byte;
  646. tmpref : treference;
  647. instr : taicpu;
  648. begin
  649. if ref.addressmode<>AM_OFFSET then
  650. internalerror(200309071);
  651. tmpref:=ref;
  652. { Be sure to have a base register }
  653. if (tmpref.base=NR_NO) then
  654. begin
  655. if tmpref.shiftmode<>SM_None then
  656. internalerror(200308294);
  657. tmpref.base:=tmpref.index;
  658. tmpref.index:=NR_NO;
  659. end;
  660. if assigned(tmpref.symbol) or
  661. not(is_shifter_const(tmpref.offset,b)) or
  662. ((tmpref.base<>NR_NO) and (tmpref.index<>NR_NO)) then
  663. fixref(list,tmpref);
  664. if tmpref.index<>NR_NO then
  665. begin
  666. {!!!!!!!}
  667. end
  668. else
  669. begin
  670. if tmpref.offset>0 then
  671. list.concat(taicpu.op_reg_reg_const(A_ADD,r,tmpref.base,tmpref.offset))
  672. else if tmpref.offset<0 then
  673. list.concat(taicpu.op_reg_reg_const(A_SUB,r,tmpref.base,-tmpref.offset))
  674. else
  675. begin
  676. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  677. rg.add_move_instruction(instr);
  678. list.concat(instr);
  679. end;
  680. end;
  681. reference_release(list,tmpref);
  682. end;
  683. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  684. var
  685. tmpreg : tregister;
  686. tmpref : treference;
  687. l : tasmlabel;
  688. begin
  689. { absolute symbols can't be handled directly, we've to store the symbol reference
  690. in the text segment and access it pc relative
  691. For now, we assume that references where base or index equals to PC are already
  692. relative, all other references are assumed to be absolute and thus they need
  693. to be handled extra.
  694. A proper solution would be to change refoptions to a set and store the information
  695. if the symbol is absolute or relative there.
  696. }
  697. { check consts distance }
  698. {!!!!!}
  699. { create consts entry }
  700. objectlibrary.getdatalabel(l);
  701. current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
  702. if assigned(ref.symbol) then
  703. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  704. else
  705. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  706. { load consts entry }
  707. reference_reset(tmpref);
  708. tmpreg:=rg.getregisterint(list,OS_INT);
  709. tmpref.symbol:=l;
  710. tmpref.base:=NR_PC;
  711. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  712. if (ref.base<>NR_NO) then
  713. begin
  714. if ref.index<>NR_NO then
  715. begin
  716. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  717. ref.base:=tmpreg;
  718. end
  719. else
  720. begin
  721. ref.index:=tmpreg;
  722. ref.shiftimm:=0;
  723. ref.signindex:=1;
  724. ref.shiftmode:=SM_None;
  725. end;
  726. end
  727. else
  728. ref.base:=tmpreg;
  729. ref.offset:=0;
  730. ref.symbol:=nil;
  731. end;
  732. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  733. var
  734. srcref,dstref:treference;
  735. srcreg,destreg,countreg,r:tregister;
  736. helpsize:aword;
  737. copysize:byte;
  738. cgsize:Tcgsize;
  739. procedure genloop(count : aword;size : byte);
  740. const
  741. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  742. var
  743. l : tasmlabel;
  744. begin
  745. objectlibrary.getdatalabel(l);
  746. a_load_const_reg(list,OS_INT,count,countreg);
  747. list.concat(Tai_symbol.Create(l,0));
  748. srcref.addressmode:=AM_POSTINDEXED;
  749. dstref.addressmode:=AM_POSTINDEXED;
  750. srcref.offset:=size;
  751. dstref.offset:=size;
  752. r:=rg.getregisterint(list,size2opsize[size]);
  753. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  754. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  755. rg.ungetregisterint(list,r);
  756. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  757. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  758. end;
  759. begin
  760. helpsize:=12;
  761. dstref:=dest;
  762. srcref:=source;
  763. if cs_littlesize in aktglobalswitches then
  764. helpsize:=8;
  765. if not loadref and (len<=helpsize) then
  766. begin
  767. copysize:=4;
  768. cgsize:=OS_32;
  769. while len<>0 do
  770. begin
  771. if len<2 then
  772. begin
  773. copysize:=1;
  774. cgsize:=OS_8;
  775. end
  776. else if len<4 then
  777. begin
  778. copysize:=2;
  779. cgsize:=OS_16;
  780. end;
  781. dec(len,copysize);
  782. r:=rg.getregisterint(list,cgsize);
  783. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  784. if (len=0) and delsource then
  785. reference_release(list,source);
  786. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  787. inc(srcref.offset,copysize);
  788. inc(dstref.offset,copysize);
  789. rg.ungetregisterint(list,r);
  790. end;
  791. end
  792. else
  793. begin
  794. destreg:=rg.getregisterint(list,OS_ADDR);
  795. a_loadaddr_ref_reg(list,dest,destreg);
  796. srcreg:=rg.getregisterint(list,OS_ADDR);
  797. if loadref then
  798. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
  799. else
  800. begin
  801. a_loadaddr_ref_reg(list,source,srcreg);
  802. if delsource then
  803. begin
  804. srcref:=source;
  805. reference_release(list,srcref);
  806. end;
  807. end;
  808. countreg:=rg.getregisterint(list,OS_32);
  809. // if cs_littlesize in aktglobalswitches then
  810. genloop(len,1);
  811. {
  812. else
  813. begin
  814. helpsize:=len shr 2;
  815. len:=len and 3;
  816. if helpsize>1 then
  817. begin
  818. a_load_const_reg(list,OS_INT,helpsize,countreg);
  819. list.concat(Taicpu.op_none(A_REP,S_NO));
  820. end;
  821. if helpsize>0 then
  822. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  823. if len>1 then
  824. begin
  825. dec(len,2);
  826. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  827. end;
  828. if len=1 then
  829. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  830. end;
  831. }
  832. rg.ungetregisterint(list,countreg);
  833. rg.ungetregisterint(list,srcreg);
  834. rg.ungetregisterint(list,destreg);
  835. end;
  836. if delsource then
  837. tg.ungetiftemp(list,source);
  838. end;
  839. procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  840. begin
  841. end;
  842. procedure tcgarm.g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
  843. begin
  844. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  845. end;
  846. procedure tcgarm.g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
  847. begin
  848. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  849. end;
  850. procedure tcgarm.g_save_all_registers(list : taasmoutput);
  851. begin
  852. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  853. end;
  854. procedure tcgarm.g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);
  855. begin
  856. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  857. end;
  858. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  859. var
  860. ai : taicpu;
  861. begin
  862. ai:=Taicpu.Op_sym(A_B,l);
  863. ai.SetCondition(OpCmp2AsmCond[cond]);
  864. ai.is_jmp:=true;
  865. list.concat(ai);
  866. end;
  867. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  868. var
  869. tmpreg : tregister;
  870. begin
  871. case op of
  872. OP_NEG:
  873. begin
  874. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  875. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  876. end;
  877. else
  878. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  879. end;
  880. end;
  881. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  882. begin
  883. a_op64_const_reg_reg(list,op,value,reg,reg);
  884. end;
  885. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  886. var
  887. tmpreg : tregister;
  888. b : byte;
  889. begin
  890. case op of
  891. OP_AND,OP_OR,OP_XOR:
  892. begin
  893. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  894. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  895. end;
  896. OP_ADD:
  897. begin
  898. if is_shifter_const(lo(value),b) then
  899. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  900. else
  901. begin
  902. tmpreg:=rg.getregisterint(list,OS_32);
  903. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  904. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  905. rg.ungetregisterint(list,tmpreg);
  906. end;
  907. if is_shifter_const(hi(value),b) then
  908. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  909. else
  910. begin
  911. tmpreg:=rg.getregisterint(list,OS_32);
  912. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  913. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  914. rg.ungetregisterint(list,tmpreg);
  915. end;
  916. end;
  917. OP_SUB:
  918. begin
  919. if is_shifter_const(lo(value),b) then
  920. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  921. else
  922. begin
  923. tmpreg:=rg.getregisterint(list,OS_32);
  924. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  925. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  926. rg.ungetregisterint(list,tmpreg);
  927. end;
  928. if is_shifter_const(hi(value),b) then
  929. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  930. else
  931. begin
  932. tmpreg:=rg.getregisterint(list,OS_32);
  933. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  934. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  935. rg.ungetregisterint(list,tmpreg);
  936. end;
  937. end;
  938. else
  939. internalerror(2003083101);
  940. end;
  941. end;
  942. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  943. begin
  944. case op of
  945. OP_AND,OP_OR,OP_XOR:
  946. begin
  947. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  948. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  949. end;
  950. OP_ADD:
  951. begin
  952. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  953. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  954. end;
  955. OP_SUB:
  956. begin
  957. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  958. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  959. end;
  960. else
  961. internalerror(2003083101);
  962. end;
  963. end;
  964. begin
  965. cg:=tcgarm.create;
  966. cg64:=tcg64farm.create;
  967. end.
  968. {
  969. $Log$
  970. Revision 1.19 2003-09-11 11:55:00 florian
  971. * improved arm code generation
  972. * move some protected and private field around
  973. * the temp. register for register parameters/arguments are now released
  974. before the move to the parameter register is done. This improves
  975. the code in a lot of cases.
  976. Revision 1.18 2003/09/09 12:53:40 florian
  977. * some assembling problems fixed
  978. * improved loadaddr_ref_reg
  979. Revision 1.17 2003/09/06 16:45:51 florian
  980. * fixed exit code (no preindexed addressing mode in LDM)
  981. Revision 1.16 2003/09/06 11:21:50 florian
  982. * fixed stm and ldm to be usable with preindex operand
  983. Revision 1.15 2003/09/05 23:57:01 florian
  984. * arm is working again as before the new register naming scheme was implemented
  985. Revision 1.14 2003/09/04 21:07:03 florian
  986. * ARM compiler compiles again
  987. Revision 1.13 2003/09/04 00:15:29 florian
  988. * first bunch of adaptions of arm compiler for new register type
  989. Revision 1.12 2003/09/03 19:10:30 florian
  990. * initial revision of new register naming
  991. Revision 1.11 2003/09/03 11:18:37 florian
  992. * fixed arm concatcopy
  993. + arm support in the common compiler sources added
  994. * moved some generic cg code around
  995. + tfputype added
  996. * ...
  997. Revision 1.10 2003/09/01 15:11:16 florian
  998. * fixed reference handling
  999. * fixed operand postfix for floating point instructions
  1000. * fixed wrong shifter constant handling
  1001. Revision 1.9 2003/09/01 09:54:57 florian
  1002. * results of work on arm port last weekend
  1003. Revision 1.8 2003/08/29 21:36:28 florian
  1004. * fixed procedure entry/exit code
  1005. * started to fix reference handling
  1006. Revision 1.7 2003/08/28 13:26:10 florian
  1007. * another couple of arm fixes
  1008. Revision 1.6 2003/08/28 00:05:29 florian
  1009. * today's arm patches
  1010. Revision 1.5 2003/08/25 23:20:38 florian
  1011. + started to implement FPU support for the ARM
  1012. * fixed a lot of other things
  1013. Revision 1.4 2003/08/24 12:27:26 florian
  1014. * continued to work on the arm port
  1015. Revision 1.3 2003/08/21 03:14:00 florian
  1016. * arm compiler can be compiled; far from being working
  1017. Revision 1.2 2003/08/20 15:50:12 florian
  1018. * more arm stuff
  1019. Revision 1.1 2003/07/21 16:35:30 florian
  1020. * very basic stuff for the arm
  1021. }