cgcpu.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the code generator for the SPARC
  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 cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cginfo,cgbase,cgobj,cg64f32,
  23. aasmbase,aasmtai,aasmcpu,
  24. cpubase,cpuinfo,
  25. node,symconst,SymType;
  26. type
  27. TCgSparc=class(tcg)
  28. protected
  29. function IsSimpleRef(const ref:treference):boolean;
  30. public
  31. { sparc special, needed by cg64 }
  32. procedure handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  33. procedure handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aword;dst:tregister);
  34. { parameter }
  35. procedure a_param_const(list:TAasmOutput;size:tcgsize;a:aword;const LocPara:TParaLocation);override;
  36. procedure a_param_ref(list:TAasmOutput;sz:tcgsize;const r:TReference;const LocPara:TParaLocation);override;
  37. procedure a_paramaddr_ref(list:TAasmOutput;const r:TReference;const LocPara:TParaLocation);override;
  38. procedure a_call_name(list:TAasmOutput;const s:string);override;
  39. procedure a_call_reg(list:TAasmOutput;Reg:TRegister);override;
  40. { General purpose instructions }
  41. procedure a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:AWord;reg:TRegister);override;
  42. procedure a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);override;
  43. procedure a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);override;
  44. procedure a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override;
  45. { move instructions }
  46. procedure a_load_const_reg(list:TAasmOutput;size:tcgsize;a:aword;reg:tregister);override;
  47. procedure a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;const ref:TReference);override;
  48. procedure a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCgSize;reg:TRegister;const ref:TReference);override;
  49. procedure a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);override;
  50. procedure a_load_reg_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;reg1,reg2:tregister);override;
  51. procedure a_loadaddr_ref_reg(list:TAasmOutput;const ref:TReference;r:tregister);override;
  52. { fpu move instructions }
  53. procedure a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);override;
  54. procedure a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister);override;
  55. procedure a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);override;
  56. { comparison operations }
  57. procedure a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);override;
  58. procedure a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override;
  59. procedure a_jmp_always(List:TAasmOutput;l:TAsmLabel);override;
  60. procedure a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);{ override;}
  61. procedure a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel);override;
  62. procedure g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister);override;
  63. procedure g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef);override;
  64. procedure g_stackframe_entry(list:TAasmOutput;localsize:LongInt);override;
  65. procedure g_restore_all_registers(list:TAasmOutput;accused,acchiused:boolean);override;
  66. procedure g_restore_frame_pointer(list:TAasmOutput);override;
  67. procedure g_restore_standard_registers(list:taasmoutput;usedinproc:Tsupregset);override;
  68. procedure g_return_from_proc(list:TAasmOutput;parasize:aword);override;
  69. procedure g_save_all_registers(list : taasmoutput);override;
  70. procedure g_save_standard_registers(list : taasmoutput; usedinproc : Tsupregset);override;
  71. procedure g_concatcopy(list:TAasmOutput;const source,dest:TReference;len:aword;delsource,loadref:boolean);override;
  72. class function reg_cgsize(const reg:tregister):tcgsize;override;
  73. end;
  74. TCg64Sparc=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;regdst:TRegister64);override;
  77. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  78. end;
  79. const
  80. TOpCG2AsmOp : array[topcg] of TAsmOp=(
  81. A_NONE,A_ADD,A_AND,A_UDIV,A_SDIV,A_UMUL,A_SMUL,A_NEG,A_NOT,A_OR,A_SRA,A_SRL,A_SLL,A_SUB,A_XOR
  82. );
  83. TOpCmp2AsmCond : array[topcmp] of TAsmCond=(
  84. C_NONE,C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A
  85. );
  86. implementation
  87. uses
  88. globtype,globals,verbose,systems,cutils,
  89. symdef,symsym,defutil,paramgr,
  90. rgobj,tgobj,rgcpu,cpupi;
  91. {****************************************************************************
  92. This is private property, keep out! :)
  93. ****************************************************************************}
  94. function TCgSparc.IsSimpleRef(const ref:treference):boolean;
  95. begin
  96. if (ref.base.number=NR_NO) and (ref.index.number<>NR_NO) then
  97. InternalError(2002100804);
  98. result :=not(assigned(ref.symbol))and
  99. (((ref.index.number = NR_NO) and
  100. (ref.offset >= low(smallint)) and
  101. (ref.offset <= high(smallint))) or
  102. ((ref.index.number <> NR_NO) and
  103. (ref.offset = 0)));
  104. end;
  105. procedure tcgsparc.handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  106. var
  107. tmpreg : tregister;
  108. tmpref : treference;
  109. begin
  110. tmpreg.enum:=R_INTREGISTER;
  111. tmpreg.number:=NR_NO;
  112. { Be sure to have a base register }
  113. if (ref.base.number=NR_NO) then
  114. begin
  115. ref.base:=ref.index;
  116. ref.index.number:=NR_NO;
  117. end;
  118. { When need to use SETHI, do it first }
  119. if assigned(ref.symbol) or
  120. (ref.offset<simm13lo) or
  121. (ref.offset>simm13hi) then
  122. begin
  123. tmpreg:=get_scratch_reg_int(list,OS_INT);
  124. reference_reset(tmpref);
  125. tmpref.symbol:=ref.symbol;
  126. tmpref.offset:=ref.offset;
  127. tmpref.symaddr:=refs_hi;
  128. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg));
  129. { Load the low part is left }
  130. {$warning TODO Maybe not needed to load symbol}
  131. tmpref.symaddr:=refs_lo;
  132. list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg));
  133. { The offset and symbol are loaded, reset in reference }
  134. ref.offset:=0;
  135. ref.symbol:=nil;
  136. { Only an index register or offset is allowed }
  137. if tmpreg.number<>NR_NO then
  138. begin
  139. if (ref.index.number<>NR_NO) then
  140. begin
  141. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
  142. ref.index:=tmpreg;
  143. end
  144. else
  145. begin
  146. if ref.base.number<>NR_NO then
  147. ref.index:=tmpreg
  148. else
  149. ref.base:=tmpreg;
  150. end;
  151. end;
  152. end;
  153. if (ref.base.number<>NR_NO) then
  154. begin
  155. if (ref.index.number<>NR_NO) and
  156. ((ref.offset<>0) or assigned(ref.symbol)) then
  157. begin
  158. if tmpreg.number=NR_NO then
  159. tmpreg:=get_scratch_reg_int(list,OS_INT);
  160. if (ref.index.number<>NR_NO) then
  161. begin
  162. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
  163. ref.index.number:=NR_NO;
  164. end;
  165. end;
  166. end;
  167. if isstore then
  168. list.concat(taicpu.op_reg_ref(op,reg,ref))
  169. else
  170. list.concat(taicpu.op_ref_reg(op,ref,reg));
  171. if (tmpreg.number<>NR_NO) then
  172. free_scratch_reg(list,tmpreg);
  173. end;
  174. procedure tcgsparc.handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aword;dst:tregister);
  175. var
  176. tmpreg : tregister;
  177. begin
  178. if (longint(a)<simm13lo) or
  179. (longint(a)>simm13hi) then
  180. begin
  181. tmpreg:=get_scratch_reg_int(list,OS_INT);
  182. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,tmpreg));
  183. list.concat(taicpu.op_reg_const_reg(A_OR,tmpreg,a and aword($3ff),tmpreg));
  184. list.concat(taicpu.op_reg_reg_reg(op,src,tmpreg,dst));
  185. free_scratch_reg(list,tmpreg);
  186. end
  187. else
  188. list.concat(taicpu.op_reg_const_reg(op,src,a,dst));
  189. end;
  190. {****************************************************************************
  191. Assembler code
  192. ****************************************************************************}
  193. function TCgSparc.reg_cgsize(const reg:tregister):tcgsize;
  194. begin
  195. result:=OS_32;
  196. end;
  197. procedure TCgSparc.a_param_const(list:TAasmOutput;size:tcgsize;a:aword;const LocPara:TParaLocation);
  198. var
  199. Ref:TReference;
  200. begin
  201. case locpara.loc of
  202. LOC_REGISTER,LOC_CREGISTER:
  203. a_load_const_reg(list,size,a,locpara.register);
  204. LOC_REFERENCE:
  205. begin
  206. reference_reset(ref);
  207. ref.base:=locpara.reference.index;
  208. ref.offset:=locpara.reference.offset;
  209. a_load_const_ref(list,size,a,ref);
  210. end;
  211. else
  212. InternalError(2002122200);
  213. end;
  214. if locpara.sp_fixup<>0 then
  215. InternalError(2002122201);
  216. end;
  217. procedure TCgSparc.a_param_ref(list:TAasmOutput;sz:TCgSize;const r:TReference;const LocPara:TParaLocation);
  218. var
  219. ref: treference;
  220. tmpreg:TRegister;
  221. begin
  222. with LocPara do
  223. case loc of
  224. LOC_REGISTER,LOC_CREGISTER:
  225. a_load_ref_reg(list,sz,sz,r,Register);
  226. LOC_REFERENCE:
  227. begin
  228. { Code conventions need the parameters being allocated in %o6+92. See
  229. comment on g_stack_frame }
  230. if locpara.sp_fixup<92 then
  231. InternalError(2002081104);
  232. reference_reset(ref);
  233. ref.base:=locpara.reference.index;
  234. ref.offset:=locpara.reference.offset;
  235. tmpreg := get_scratch_reg_int(list,sz);
  236. a_load_ref_reg(list,sz,sz,r,tmpreg);
  237. a_load_reg_ref(list,sz,sz,tmpreg,ref);
  238. free_scratch_reg(list,tmpreg);
  239. end;
  240. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  241. begin
  242. case sz of
  243. OS_32:
  244. a_loadfpu_ref_reg(list,OS_F32,r,locpara.register);
  245. OS_64:
  246. a_loadfpu_ref_reg(list,OS_F64,r,locpara.register);
  247. else
  248. internalerror(2002072801);
  249. end;
  250. end;
  251. else
  252. internalerror(2002081103);
  253. end;
  254. end;
  255. procedure TCgSparc.a_paramaddr_ref(list:TAasmOutput;const r:TReference;const LocPara:TParaLocation);
  256. var
  257. Ref:TReference;
  258. TmpReg:TRegister;
  259. begin
  260. case locpara.loc of
  261. LOC_REGISTER,LOC_CREGISTER:
  262. a_loadaddr_ref_reg(list,r,locpara.register);
  263. LOC_REFERENCE:
  264. begin
  265. reference_reset(ref);
  266. ref.base := locpara.reference.index;
  267. ref.offset := locpara.reference.offset;
  268. tmpreg := get_scratch_reg_address(list);
  269. a_loadaddr_ref_reg(list,r,tmpreg);
  270. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  271. free_scratch_reg(list,tmpreg);
  272. end;
  273. else
  274. internalerror(2002080701);
  275. end;
  276. end;
  277. procedure TCgSparc.a_call_name(list:TAasmOutput;const s:string);
  278. begin
  279. list.concat(taicpu.op_sym(A_CALL,objectlibrary.newasmsymbol(s)));
  280. list.concat(taicpu.op_none(A_NOP));
  281. end;
  282. procedure TCgSparc.a_call_reg(list:TAasmOutput;Reg:TRegister);
  283. begin
  284. list.concat(taicpu.op_reg(A_CALL,reg));
  285. end;
  286. {********************** load instructions ********************}
  287. procedure TCgSparc.a_load_const_reg(list : TAasmOutput;size : TCGSize;a : aword;reg : TRegister);
  288. var
  289. zeroreg : tregister;
  290. begin
  291. zeroreg.enum:=R_INTREGISTER;
  292. zeroreg.number:=NR_G0;
  293. { we don't use the set instruction here because it could be evalutated to two
  294. instructions which would cause problems with the delay slot (FK) }
  295. { sethi allows to set the upper 22 bit, so we'll take full advantage of it }
  296. if (a and aword($1fff))=0 then
  297. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg))
  298. else if (longint(a)>=simm13lo) and (longint(a)<=simm13hi) then
  299. list.concat(taicpu.op_reg_const_reg(A_OR,zeroreg,a,reg))
  300. else
  301. begin
  302. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg));
  303. list.concat(taicpu.op_reg_const_reg(A_OR,reg,a and aword($3ff),reg));
  304. end;
  305. end;
  306. procedure TCgSparc.a_load_const_ref(list : TAasmOutput;size : tcgsize;a : aword;const ref : TReference);
  307. var
  308. zeroreg : Tregister;
  309. begin
  310. if a=0 then
  311. begin
  312. zeroreg.enum:=R_INTREGISTER;
  313. zeroreg.number:=NR_G0;
  314. a_load_reg_ref(list,size,size,zeroreg,ref);
  315. end
  316. else
  317. inherited a_load_const_ref(list,size,a,ref);
  318. end;
  319. procedure TCgSparc.a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCGSize;reg:tregister;const Ref:TReference);
  320. var
  321. op:tasmop;
  322. begin
  323. case ToSize of
  324. { signed integer registers }
  325. OS_8,
  326. OS_S8:
  327. Op:=A_STB;
  328. OS_16,
  329. OS_S16:
  330. Op:=A_STH;
  331. OS_32,
  332. OS_S32:
  333. Op:=A_ST;
  334. else
  335. InternalError(2002122100);
  336. end;
  337. handle_load_store(list,true,op,reg,ref);
  338. end;
  339. procedure TCgSparc.a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);
  340. var
  341. op:tasmop;
  342. begin
  343. case Fromsize of
  344. { signed integer registers }
  345. OS_S8:
  346. Op:=A_LDSB;{Load Signed Byte}
  347. OS_8:
  348. Op:=A_LDUB;{Load Unsigned Bye}
  349. OS_S16:
  350. Op:=A_LDSH;{Load Signed Halfword}
  351. OS_16:
  352. Op:=A_LDUH;{Load Unsigned Halfword}
  353. OS_S32,
  354. OS_32:
  355. Op:=A_LD;{Load Word}
  356. else
  357. InternalError(2002122101);
  358. end;
  359. handle_load_store(list,false,op,reg,ref);
  360. end;
  361. procedure TCgSparc.a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);
  362. begin
  363. if(reg1.enum<>R_INTREGISTER)or(reg1.number=NR_NO) then
  364. InternalError(200303101);
  365. if(reg2.enum<>R_INTREGISTER)or(reg2.number=NR_NO) then
  366. InternalError(200303102);
  367. if (reg1.Number<>reg2.Number) or
  368. (tcgsize2size[tosize]<tcgsize2size[fromsize]) or
  369. (
  370. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  371. (tosize <> fromsize) and
  372. not(fromsize in [OS_32,OS_S32])
  373. ) then
  374. begin
  375. {$warning TODO Sign extension}
  376. case tosize of
  377. OS_8,OS_S8:
  378. a_op_const_reg_reg(list,OP_AND,tosize,$ff,reg1,reg2);
  379. OS_16,OS_S16:
  380. a_op_const_reg_reg(list,OP_AND,tosize,$ffff,reg1,reg2);
  381. OS_32,OS_S32:
  382. begin
  383. if reg1.number<>reg2.number then
  384. list.Concat(taicpu.op_reg_reg(A_MOV,reg1,reg2));
  385. end;
  386. else
  387. internalerror(2002090901);
  388. end;
  389. end;
  390. end;
  391. procedure TCgSparc.a_loadaddr_ref_reg(list : TAasmOutput;const ref : TReference;r : tregister);
  392. var
  393. tmpref : treference;
  394. hreg : tregister;
  395. begin
  396. if (r.number=ref.index.number) or (r.number=ref.base.number) then
  397. begin
  398. {$ifdef newra}
  399. hreg:=rg.getaddressregister(list);
  400. {$else}
  401. hreg:=get_scratch_reg_address(list);
  402. {$endif}
  403. end
  404. else
  405. hreg:=r;
  406. { Need to use SETHI? }
  407. if assigned(ref.symbol) or
  408. (ref.offset<simm13lo) or
  409. (ref.offset>simm13hi) then
  410. begin
  411. reference_reset(tmpref);
  412. tmpref.symbol := ref.symbol;
  413. tmpref.offset := ref.offset;
  414. tmpref.symaddr := refs_hi;
  415. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg));
  416. { Only the low part is left }
  417. tmpref.symaddr:=refs_lo;
  418. list.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg));
  419. end;
  420. if ref.base.number<>NR_NO then
  421. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.base,hreg));
  422. if ref.index.number<>NR_NO then
  423. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.base,hreg));
  424. if hreg.number<>r.number then
  425. begin
  426. a_load_reg_reg(list,OS_INT,OS_INT,hreg,r);
  427. {$ifdef newra}
  428. rg.ungetaddressregister(list,hreg);
  429. {$else}
  430. free_scratch_reg(list,hreg);
  431. {$endif}
  432. end;
  433. end;
  434. procedure TCgSparc.a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);
  435. begin
  436. list.concat(taicpu.op_reg_reg(A_FMOVs,reg1,reg2));
  437. end;
  438. procedure TCgSparc.a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister);
  439. const
  440. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  441. (A_LDF,A_LDDF);
  442. begin
  443. { several functions call this procedure with OS_32 or OS_64 }
  444. { so this makes life easier (FK) }
  445. case size of
  446. OS_32,OS_F32:
  447. size:=OS_F32;
  448. OS_64,OS_F64,OS_C64:
  449. size:=OS_F64;
  450. else
  451. internalerror(200201121);
  452. end;
  453. handle_load_store(list,false,fpuloadinstr[size],reg,ref);
  454. end;
  455. procedure TCgSparc.a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);
  456. const
  457. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  458. (A_STF,A_STDF);
  459. begin
  460. { several functions call this procedure with OS_32 or OS_64 }
  461. { so this makes life easier (FK) }
  462. case size of
  463. OS_32,OS_F32:
  464. size:=OS_F32;
  465. OS_64,OS_F64,OS_C64:
  466. size:=OS_F64;
  467. else
  468. internalerror(200201121);
  469. end;
  470. handle_load_store(list,true,fpuloadinstr[size],reg,ref);
  471. end;
  472. procedure TCgSparc.a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:AWord;reg:TRegister);
  473. var
  474. zeroreg : tregister;
  475. begin
  476. if Op in [OP_NEG,OP_NOT] then
  477. internalerror(200306011);
  478. zeroreg.enum:=R_INTREGISTER;
  479. zeroreg.number:=NR_G0;
  480. if (a=0) then
  481. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],reg,zeroreg,reg))
  482. else
  483. handle_reg_const_reg(list,TOpCG2AsmOp[op],reg,a,reg);
  484. end;
  485. procedure TCgSparc.a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);
  486. begin
  487. Case Op of
  488. OP_NEG,
  489. OP_NOT:
  490. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],src,dst));
  491. else
  492. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src,dst));
  493. end;
  494. end;
  495. procedure TCgSparc.a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);
  496. var
  497. power : longInt;
  498. begin
  499. case op of
  500. OP_IMUL :
  501. begin
  502. if not(cs_check_overflow in aktlocalswitches) and
  503. ispowerof2(a,power) then
  504. begin
  505. { can be done with a shift }
  506. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  507. exit;
  508. end;
  509. end;
  510. OP_SUB,
  511. OP_ADD :
  512. begin
  513. if (a=0) then
  514. begin
  515. a_load_reg_reg(list,size,size,src,dst);
  516. exit;
  517. end;
  518. end;
  519. end;
  520. handle_reg_const_reg(list,TOpCG2AsmOp[op],src,a,dst);
  521. end;
  522. procedure TCgSparc.a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);
  523. begin
  524. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst));
  525. end;
  526. {*************** compare instructructions ****************}
  527. procedure TCgSparc.a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);
  528. var
  529. zeroreg : tregister;
  530. begin
  531. zeroreg.enum:=R_INTREGISTER;
  532. zeroreg.number:=NR_G0;
  533. if (a=0) then
  534. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg,zeroreg,zeroreg))
  535. else
  536. handle_reg_const_reg(list,A_SUBcc,reg,a,zeroreg);
  537. a_jmp_cond(list,cmp_op,l);
  538. end;
  539. procedure TCgSparc.a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);
  540. var
  541. zeroreg : tregister;
  542. begin
  543. zeroreg.enum:=R_INTREGISTER;
  544. zeroreg.number:=NR_G0;
  545. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg1,reg2,zeroreg));
  546. a_jmp_cond(list,cmp_op,l);
  547. end;
  548. procedure TCgSparc.a_jmp_always(List:TAasmOutput;l:TAsmLabel);
  549. begin
  550. List.Concat(TAiCpu.op_sym(A_BA,objectlibrary.newasmsymbol(l.name)));
  551. end;
  552. procedure TCgSparc.a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:TAsmLabel);
  553. var
  554. ai:TAiCpu;
  555. begin
  556. ai:=TAiCpu.Op_sym(A_BA,l);
  557. ai.SetCondition(TOpCmp2AsmCond[cond]);
  558. list.Concat(ai);
  559. list.Concat(TAiCpu.Op_none(A_NOP));
  560. end;
  561. procedure TCgSparc.a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel);
  562. var
  563. ai:taicpu;
  564. begin
  565. ai := Taicpu.op_sym(A_BA,l);
  566. ai.SetCondition(flags_to_cond(f));
  567. list.Concat(ai);
  568. list.Concat(TAiCpu.Op_none(A_NOP));
  569. end;
  570. procedure TCgSparc.g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister);
  571. var
  572. ai : taicpu;
  573. r : tregister;
  574. begin
  575. r.enum:=R_PSR;
  576. ai:=Taicpu.Op_reg_reg(A_RDPSR,r,reg);
  577. ai.SetCondition(flags_to_cond(f));
  578. list.Concat(ai);
  579. list.Concat(TAiCpu.Op_none(A_NOP));
  580. end;
  581. procedure TCgSparc.g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef);
  582. var
  583. hl : tasmlabel;
  584. r:Tregister;
  585. begin
  586. if not(cs_check_overflow in aktlocalswitches)
  587. then
  588. exit;
  589. objectlibrary.getlabel(hl);
  590. if not((def.deftype=pointerdef)or
  591. ((def.deftype=orddef)and
  592. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit])))
  593. then
  594. begin
  595. //r.enum:=R_CR7;
  596. //list.concat(taicpu.op_reg(A_MCRXR,r));
  597. //a_jmp_cond(list,A_BA,C_OV,hl)
  598. a_jmp_always(list,hl)
  599. end
  600. else
  601. a_jmp_cond(list,OC_AE,hl);
  602. a_call_name(list,'FPC_OVERFLOW');
  603. a_label(list,hl);
  604. end;
  605. { *********** entry/exit code and address loading ************ }
  606. procedure TCgSparc.g_stackframe_entry(list:TAasmOutput;LocalSize:LongInt);
  607. var
  608. r : tregister;
  609. begin
  610. { Althogh the SPARC architecture require only word alignment, software
  611. convention and the operating system require every stack frame to be double word
  612. aligned }
  613. LocalSize:=align(LocalSize,8);
  614. { Execute the SAVE instruction to get a new register window and create a new
  615. stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state
  616. before execution of the SAVE instrucion so it is the caller %i6, when the %i6
  617. after execution of that instruction is the called function stack pointer}
  618. r.enum:=R_INTREGISTER;
  619. r.number:=NR_STACK_POINTER_REG;
  620. list.concat(Taicpu.Op_reg_const_reg(A_SAVE,r,aword(-LocalSize),r));
  621. end;
  622. procedure TCgSparc.g_restore_all_registers(list:TaasmOutput;accused,acchiused:boolean);
  623. begin
  624. { The sparc port uses the sparc standard calling convetions so this function has no used }
  625. end;
  626. procedure TCgSparc.g_restore_frame_pointer(list:TAasmOutput);
  627. begin
  628. { This function intontionally does nothing as frame pointer is restored in the
  629. delay slot of the return instrucion done in g_return_from_proc}
  630. end;
  631. procedure TCgSparc.g_restore_standard_registers(list:taasmoutput;usedinproc:Tsupregset);
  632. begin
  633. { The sparc port uses the sparc standard calling convetions so this function has no used }
  634. end;
  635. procedure TCgSparc.g_return_from_proc(list:TAasmOutput;parasize:aword);
  636. begin
  637. { According to the SPARC ABI, the stack is cleared using the RESTORE instruction
  638. which is genereted in the g_restore_frame_pointer. Notice that SPARC has no
  639. real RETURN instruction and that JMPL is used instead. The JMPL instrucion have one
  640. delay slot, so an inversion is possible such as
  641. RET (=JMPL %i7+8,%g0)
  642. RESTORE (=RESTORE %g0,0,%g0)
  643. If no inversion we can use just
  644. RESTORE (=RESTORE %g0,0,%g0)
  645. RET (=JMPL %i7+8,%g0)
  646. NOP
  647. }
  648. list.concat(Taicpu.op_none(A_RET));
  649. { We use trivial restore in the delay slot of the JMPL instruction, as we
  650. already set result onto %i0 }
  651. list.concat(Taicpu.op_none(A_RESTORE));
  652. end;
  653. procedure TCgSparc.g_save_all_registers(list : taasmoutput);
  654. begin
  655. { The sparc port uses the sparc standard calling convetions so this function has no used }
  656. end;
  657. procedure TCgSparc.g_save_standard_registers(list : taasmoutput; usedinproc:Tsupregset);
  658. begin
  659. { The sparc port uses the sparc standard calling convetions so this function has no used }
  660. end;
  661. { ************* concatcopy ************ }
  662. procedure TCgSparc.g_concatcopy(list:taasmoutput;const source,dest:treference;len:aword;delsource,loadref:boolean);
  663. var
  664. countreg: TRegister;
  665. src, dst: TReference;
  666. lab: tasmlabel;
  667. count, count2: aword;
  668. orgsrc, orgdst: boolean;
  669. r:Tregister;
  670. begin
  671. if len > high(longint) then
  672. internalerror(2002072704);
  673. { make sure short loads are handled as optimally as possible }
  674. if not loadref then
  675. begin
  676. if (len <= 8) and (byte(len) in [1,2,4,8]) then
  677. begin
  678. if len < 8 then
  679. begin
  680. a_load_ref_ref(list,int_cgsize(len),int_cgsize(len),source,dest);
  681. if delsource then
  682. reference_release(list,source);
  683. end
  684. else
  685. begin
  686. r.enum:=R_F0;
  687. a_reg_alloc(list,r);
  688. a_loadfpu_ref_reg(list,OS_F64,source,r);
  689. if delsource then
  690. reference_release(list,source);
  691. a_loadfpu_reg_ref(list,OS_F64,r,dest);
  692. a_reg_dealloc(list,r);
  693. end;
  694. exit;
  695. end;
  696. end;
  697. reference_reset(src);
  698. reference_reset(dst);
  699. { load the address of source into src.base }
  700. if loadref then
  701. begin
  702. src.base := get_scratch_reg_address(list);
  703. a_load_ref_reg(list,OS_32,OS_32,source,src.base);
  704. orgsrc := false;
  705. end
  706. else
  707. if not issimpleref(source) or
  708. (
  709. (source.index.number<>NR_NO) and
  710. ((source.offset+longint(len))>high(smallint))
  711. ) then
  712. begin
  713. src.base := get_scratch_reg_address(list);
  714. a_loadaddr_ref_reg(list,source,src.base);
  715. orgsrc := false;
  716. end
  717. else
  718. begin
  719. src := source;
  720. orgsrc := true;
  721. end;
  722. if not orgsrc and delsource then
  723. reference_release(list,source);
  724. { load the address of dest into dst.base }
  725. if not issimpleref(dest) or
  726. (
  727. (dest.index.number<>NR_NO) and
  728. ((dest.offset + longint(len)) > high(smallint))
  729. ) then
  730. begin
  731. dst.base := get_scratch_reg_address(list);
  732. a_loadaddr_ref_reg(list,dest,dst.base);
  733. orgdst := false;
  734. end
  735. else
  736. begin
  737. dst := dest;
  738. orgdst := true;
  739. end;
  740. { generate a loop }
  741. count:=len div 8;
  742. if count>4 then
  743. begin
  744. { the offsets are zero after the a_loadaddress_ref_reg and just }
  745. { have to be set to 8. I put an Inc there so debugging may be }
  746. { easier (should offset be different from zero here, it will be }
  747. { easy to notice in the generated assembler }
  748. inc(dst.offset,8);
  749. inc(src.offset,8);
  750. list.concat(taicpu.op_reg_const_reg(A_SUB,src.base,8,src.base));
  751. list.concat(taicpu.op_reg_const_reg(A_SUB,dst.base,8,dst.base));
  752. countreg := get_scratch_reg_int(list,OS_32);
  753. a_load_const_reg(list,OS_32,count,countreg);
  754. { explicitely allocate R_O0 since it can be used safely here }
  755. { (for holding date that's being copied) }
  756. r.enum:=R_F0;
  757. a_reg_alloc(list,r);
  758. objectlibrary.getlabel(lab);
  759. a_label(list, lab);
  760. list.concat(taicpu.op_reg_const_reg(A_SUB,countreg,1,countreg));
  761. list.concat(taicpu.op_ref_reg(A_LDF,src,r));
  762. list.concat(taicpu.op_reg_ref(A_STD,r,dst));
  763. //a_jmp(list,A_BC,C_NE,0,lab);
  764. free_scratch_reg(list,countreg);
  765. a_reg_dealloc(list,r);
  766. len := len mod 8;
  767. end;
  768. { unrolled loop }
  769. count:=len and 7;
  770. if count>0 then
  771. begin
  772. r.enum:=R_F0;
  773. a_reg_alloc(list,r);
  774. for count2 := 1 to count do
  775. begin
  776. a_loadfpu_ref_reg(list,OS_F64,src,r);
  777. a_loadfpu_reg_ref(list,OS_F64,r,dst);
  778. inc(src.offset,8);
  779. inc(dst.offset,8);
  780. end;
  781. a_reg_dealloc(list,r);
  782. len := len mod 8;
  783. end;
  784. if (len and 4) <> 0 then
  785. begin
  786. r.enum:=R_INTREGISTER;
  787. r.number:=NR_O0;
  788. a_reg_alloc(list,r);
  789. a_load_ref_reg(list,OS_32,OS_32,src,r);
  790. a_load_reg_ref(list,OS_32,OS_32,r,dst);
  791. inc(src.offset,4);
  792. inc(dst.offset,4);
  793. a_reg_dealloc(list,r);
  794. end;
  795. { copy the leftovers }
  796. if (len and 2) <> 0 then
  797. begin
  798. r.enum:=R_INTREGISTER;
  799. r.number:=NR_O0;
  800. a_reg_alloc(list,r);
  801. a_load_ref_reg(list,OS_16,OS_16,src,r);
  802. a_load_reg_ref(list,OS_16,OS_16,r,dst);
  803. inc(src.offset,2);
  804. inc(dst.offset,2);
  805. a_reg_dealloc(list,r);
  806. end;
  807. if (len and 1) <> 0 then
  808. begin
  809. r.enum:=R_INTREGISTER;
  810. r.number:=NR_O0;
  811. a_reg_alloc(list,r);
  812. a_load_ref_reg(list,OS_8,OS_8,src,r);
  813. a_load_reg_ref(list,OS_8,OS_8,r,dst);
  814. a_reg_dealloc(list,r);
  815. end;
  816. if orgsrc then
  817. begin
  818. if delsource then
  819. reference_release(list,source);
  820. end
  821. else
  822. free_scratch_reg(list,src.base);
  823. if not orgdst then
  824. free_scratch_reg(list,dst.base);
  825. end;
  826. {****************************************************************************
  827. TCG64Sparc
  828. ****************************************************************************}
  829. procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  830. begin
  831. case op of
  832. OP_ADD :
  833. begin
  834. op1:=A_ADD;
  835. op2:=A_ADDX;
  836. end;
  837. OP_SUB :
  838. begin
  839. op1:=A_SUB;
  840. op2:=A_SUBX;
  841. end;
  842. OP_XOR :
  843. begin
  844. op1:=A_XOR;
  845. op2:=A_XOR;
  846. end;
  847. OP_OR :
  848. begin
  849. op1:=A_OR;
  850. op2:=A_OR;
  851. end;
  852. OP_AND :
  853. begin
  854. op1:=A_AND;
  855. op2:=A_AND;
  856. end;
  857. OP_NOT :
  858. begin
  859. op1:=A_NOT;
  860. op2:=A_NOT;
  861. end;
  862. else
  863. internalerror(200203241);
  864. end;
  865. end;
  866. procedure TCg64Sparc.a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);
  867. var
  868. zeroreg : tregister;
  869. op1,op2 : TAsmOp;
  870. begin
  871. case op of
  872. OP_NEG :
  873. begin
  874. zeroreg.enum:=R_INTREGISTER;
  875. zeroreg.number:=NR_G0;
  876. list.concat(taicpu.op_reg_reg_reg(A_XNOR,zeroreg,regsrc.reghi,regdst.reghi));
  877. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,zeroreg,regsrc.reglo,regdst.reglo));
  878. list.concat(taicpu.op_reg_const_reg(A_ADDX,regdst.reglo,aword(-1),regdst.reglo));
  879. exit;
  880. end;
  881. end;
  882. get_64bit_ops(op,op1,op2);
  883. list.concat(taicpu.op_reg_reg_reg(op1,regdst.reglo,regsrc.reglo,regdst.reglo));
  884. list.concat(taicpu.op_reg_reg_reg(op2,regdst.reghi,regsrc.reghi,regdst.reghi));
  885. end;
  886. procedure TCg64Sparc.a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);
  887. var
  888. op1,op2:TAsmOp;
  889. begin
  890. case op of
  891. OP_NEG,
  892. OP_NOT :
  893. internalerror(200306017);
  894. end;
  895. get_64bit_ops(op,op1,op2);
  896. tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reglo,lo(value),regdst.reglo);
  897. tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reghi,hi(value),regdst.reghi);
  898. end;
  899. begin
  900. cg:=TCgSparc.Create;
  901. cg64:=TCg64Sparc.Create;
  902. end.
  903. {
  904. $Log$
  905. Revision 1.57 2003-06-04 20:59:37 mazen
  906. + added size of destination in code gen methods
  907. + making g_overflowcheck declaration same as
  908. ancestor's method declaration
  909. Revision 1.56 2003/06/01 21:38:06 peter
  910. * getregisterfpu size parameter added
  911. * op_const_reg size parameter added
  912. * sparc updates
  913. Revision 1.55 2003/06/01 01:04:35 peter
  914. * reference fixes
  915. Revision 1.54 2003/05/31 01:00:51 peter
  916. * register fixes
  917. Revision 1.53 2003/05/30 23:57:08 peter
  918. * more sparc cleanup
  919. * accumulator removed, splitted in function_return_reg (called) and
  920. function_result_reg (caller)
  921. Revision 1.52 2003/05/28 23:18:31 florian
  922. * started to fix and clean up the sparc port
  923. Revision 1.51 2003/05/26 22:04:57 mazen
  924. * added 64 bit value support to fix a problem in RTL
  925. Revision 1.50 2003/05/23 22:33:48 florian
  926. * fix some small flaws which prevent sparc linux system unit from compiling
  927. * some reformatting done
  928. Revision 1.49 2003/05/22 16:11:22 florian
  929. * fixed sparc compilation partially
  930. Revision 1.48 2003/05/07 15:04:30 mazen
  931. * invalid genrated code for CASE statement fixed
  932. Revision 1.47 2003/05/06 20:25:20 mazen
  933. * Invalid genrated code : A_JMPL changed to A_BA
  934. Revision 1.46 2003/05/06 15:02:40 mazen
  935. * fixed a bug in a_load_const_reg related to max 13bit value limit
  936. for immediat value ==> use of A_SETHI for greater values
  937. Revision 1.45 2003/04/29 11:58:21 mazen
  938. * fixed bug of output generated assembler for a_cmp_const_ref_label
  939. Revision 1.44 2003/04/28 09:44:42 mazen
  940. + NOP after conditional jump instruction to prevent delay slot execution
  941. Revision 1.43 2003/04/27 11:21:36 peter
  942. * aktprocdef renamed to current_procdef
  943. * procinfo renamed to current_procinfo
  944. * procinfo will now be stored in current_module so it can be
  945. cleaned up properly
  946. * gen_main_procsym changed to create_main_proc and release_main_proc
  947. to also generate a tprocinfo structure
  948. * fixed unit implicit initfinal
  949. Revision 1.42 2003/03/16 20:45:45 mazen
  950. * fixing an LD operation without refernce in loading address parameters
  951. Revision 1.41 2003/03/10 21:59:54 mazen
  952. * fixing index overflow in handling new registers arrays.
  953. Revision 1.40 2003/02/25 21:41:44 mazen
  954. * code re-aligned 2 spaces
  955. Revision 1.39 2003/02/19 22:00:16 daniel
  956. * Code generator converted to new register notation
  957. - Horribily outdated todo.txt removed
  958. Revision 1.38 2003/02/18 22:00:20 mazen
  959. * asm condition generation modified by TAiCpu.SetCondition
  960. Revision 1.37 2003/02/05 21:48:34 mazen
  961. * fixing run time errors related to unimplemented abstract methods in CG
  962. + giving empty emplementations for some RTL functions
  963. Revision 1.36 2003/01/22 22:30:03 mazen
  964. - internal errors rmoved from a_loar_reg_reg when reg sizes differs from 32
  965. Revision 1.35 2003/01/20 22:21:36 mazen
  966. * many stuff related to RTL fixed
  967. Revision 1.34 2003/01/08 18:43:58 daniel
  968. * Tregister changed into a record
  969. Revision 1.33 2003/01/07 22:03:40 mazen
  970. * adding unequaln node support to sparc compiler
  971. Revision 1.32 2003/01/06 22:51:47 mazen
  972. * fixing bugs related to load_reg_ref
  973. Revision 1.31 2003/01/05 21:32:35 mazen
  974. * fixing several bugs compiling the RTL
  975. Revision 1.30 2003/01/05 13:36:53 florian
  976. * x86-64 compiles
  977. + very basic support for float128 type (x86-64 only)
  978. Revision 1.29 2002/12/25 20:59:49 mazen
  979. - many emitXXX removed from cga.pas in order to remove that file.
  980. Revision 1.28 2002/12/22 19:26:31 mazen
  981. * many internal errors related to unimplemented nodes are fixed
  982. Revision 1.27 2002/12/21 23:21:47 mazen
  983. + added support for the shift nodes
  984. + added debug output on screen with -an command line option
  985. Revision 1.26 2002/11/25 19:21:49 mazen
  986. * fixed support of nSparcInline
  987. Revision 1.25 2002/11/25 17:43:28 peter
  988. * splitted defbase in defutil,symutil,defcmp
  989. * merged isconvertable and is_equal into compare_defs(_ext)
  990. * made operator search faster by walking the list only once
  991. Revision 1.24 2002/11/17 17:49:09 mazen
  992. + return_result_reg and FUNCTION_RESULT_REG are now used, in all plateforms, to pass functions result between called function and its caller. See the explanation of each one
  993. Revision 1.23 2002/11/10 19:07:46 mazen
  994. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  995. Revision 1.22 2002/11/06 11:31:24 mazen
  996. * op_reg_reg_reg don't need any more a TOpSize parameter
  997. Revision 1.21 2002/11/05 16:15:00 mazen
  998. *** empty log message ***
  999. Revision 1.20 2002/11/03 20:22:40 mazen
  1000. * parameter handling updated
  1001. Revision 1.19 2002/10/28 20:59:17 mazen
  1002. * TOpSize values changed S_L --> S_SW
  1003. Revision 1.18 2002/10/22 13:43:01 mazen
  1004. - cga.pas redueced to an empty unit
  1005. Revision 1.17 2002/10/20 19:01:38 mazen
  1006. + op_raddr_reg and op_caddr_reg added to fix functions prologue
  1007. Revision 1.16 2002/10/13 21:46:07 mazen
  1008. * assembler output format fixed
  1009. Revision 1.15 2002/10/11 13:35:14 mazen
  1010. *** empty log message ***
  1011. Revision 1.14 2002/10/10 19:57:51 mazen
  1012. * Just to update repsitory
  1013. Revision 1.13 2002/10/10 15:10:39 mazen
  1014. * Internal error fixed, but usually i386 parameter model used
  1015. Revision 1.12 2002/10/08 17:17:03 mazen
  1016. *** empty log message ***
  1017. Revision 1.11 2002/10/07 20:33:04 mazen
  1018. word alignement modified in g_stack_frame
  1019. Revision 1.10 2002/10/04 21:57:42 mazen
  1020. * register allocation for parameters now done in cpupara, but InternalError(200109223) in cgcpu.pas:1053 is still not fixed du to location_force problem in ncgutils.pas:419
  1021. Revision 1.9 2002/10/02 22:20:28 mazen
  1022. + out registers allocator for the first 6 scalar parameters which must be passed into %o0..%o5
  1023. Revision 1.8 2002/10/01 21:35:58 mazen
  1024. + procedures exiting prologue added and stack frame now restored in the delay slot of the return (JMPL) instruction
  1025. Revision 1.7 2002/10/01 21:06:29 mazen
  1026. attinst.inc --> strinst.inc
  1027. Revision 1.6 2002/10/01 17:41:50 florian
  1028. * fixed log and id
  1029. }