cgcpu.pas 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. {******************************************************************************
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This program is free software;you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation;either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY;without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program;if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *****************************************************************************}
  16. UNIT cgcpu;
  17. {This unit implements the code generator for the SPARC architecture}
  18. {$INCLUDE fpcdefs.inc}
  19. INTERFACE
  20. USES
  21. cginfo,cgbase,cgobj,cg64f32,
  22. aasmbase,aasmtai,aasmcpu,
  23. cpubase,cpuinfo,cpupara,
  24. node,symconst;
  25. TYPE
  26. TCgSparc=CLASS(tcg)
  27. {This method is used to pass a parameter, which is located in a register, to a
  28. routine. It should give the parameter to the routine, as required by the
  29. specific processor ABI. It is overriden for each CPU target.
  30. Size : is the size of the operand in the register
  31. r : is the register source of the operand
  32. LocPara : is the location where the parameter will be stored}
  33. procedure a_param_reg(list:TAasmOutput;size:tcgsize;r:tregister;const LocPara:TParaLocation);override;
  34. {passes a parameter which is a constant to a function}
  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_ref(list:TAasmOutput;CONST ref:TReference);override;
  40. procedure a_call_reg(list:TAasmOutput;Reg:TRegister);override;
  41. {Branch Instruction}
  42. procedure a_jmp_always(List:TAasmOutput;l:TAsmLabel);override;
  43. {General purpose instyructions}
  44. procedure a_op_const_reg(list:TAasmOutput;Op:TOpCG;a:AWord;reg:TRegister);override;
  45. procedure a_op_const_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;a:AWord;CONST ref:TReference);override;
  46. procedure a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);override;
  47. procedure a_op_ref_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;CONST ref:TReference;reg:TRegister);override;
  48. procedure a_op_reg_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;reg:TRegister;CONST ref:TReference);override;
  49. procedure a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);override;
  50. procedure a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override;
  51. { move instructions }
  52. procedure a_load_const_reg(list:TAasmOutput;size:tcgsize;a:aword;reg:tregister);override;
  53. procedure a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;CONST ref:TReference);override;
  54. procedure a_load_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;CONST ref:TReference);override;
  55. procedure a_load_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);override;
  56. procedure a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);override;
  57. procedure a_loadaddr_ref_reg(list:TAasmOutput;CONST ref:TReference;r:tregister);override;
  58. { fpu move instructions }
  59. procedure a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);override;
  60. procedure a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);override;
  61. procedure a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;CONST ref:TReference);override;
  62. { vector register move instructions }
  63. procedure a_loadmm_reg_reg(list:TAasmOutput;reg1, reg2:tregister);override;
  64. procedure a_loadmm_ref_reg(list:TAasmOutput;CONST ref:TReference;reg:tregister);override;
  65. procedure a_loadmm_reg_ref(list:TAasmOutput;reg:tregister;CONST ref:TReference);override;
  66. procedure a_parammm_reg(list:TAasmOutput;reg:tregister);override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);override;
  69. procedure a_cmp_const_ref_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;CONST ref:TReference;l:tasmlabel);override;
  70. procedure a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override;
  71. procedure a_cmp_ref_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;CONST ref:TReference;reg:tregister;l:tasmlabel);override;
  72. procedure a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);{ override;}
  73. procedure a_jmp_flags(list:TAasmOutput;CONST f:TResFlags;l:tasmlabel);override;
  74. procedure g_flags2reg(list:TAasmOutput;Size:TCgSize;CONST f:tresflags;reg:TRegister);override;
  75. procedure g_overflowCheck(List:TAasmOutput;const p:TNode);override;
  76. procedure g_stackframe_entry(list:TAasmOutput;localsize:LongInt);override;
  77. procedure g_restore_all_registers(list:TAasmOutput;selfused,accused,acchiused:boolean);override;
  78. procedure g_restore_frame_pointer(list:TAasmOutput);override;
  79. procedure g_return_from_proc(list:TAasmOutput;parasize:aword);override;
  80. procedure g_save_all_registers(list : taasmoutput);override;
  81. procedure g_save_standard_registers(list : taasmoutput; usedinproc : tregisterset);override;
  82. procedure g_concatcopy(list:TAasmOutput;CONST source,dest:TReference;len:aword;delsource,loadref:boolean);override;
  83. class function reg_cgsize(CONST reg:tregister):tcgsize;override;
  84. PRIVATE
  85. function IsSimpleRef(const ref:treference):boolean;
  86. procedure sizes2load(s1:tcgsize;s2:topsize;var op:tasmop;var s3:topsize);
  87. procedure floatload(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  88. procedure floatstore(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  89. procedure floatloadops(t:tcgsize;var op:tasmop;var s:topsize);
  90. procedure floatstoreops(t:tcgsize;var op:tasmop;var s:topsize);
  91. END;
  92. TCg64fSPARC=class(tcg64f32)
  93. procedure a_op64_ref_reg(list:TAasmOutput;op:TOpCG;CONST ref:TReference;reg:TRegister64);override;
  94. procedure a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);override;
  95. procedure a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);override;
  96. procedure a_op64_const_ref(list:TAasmOutput;op:TOpCG;value:qWord;CONST ref:TReference);override;
  97. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  98. END;
  99. CONST
  100. TOpCG2AsmOp:ARRAY[topcg]OF TAsmOp=(A_NONE,A_ADD,A_AND,A_UDIV,A_SDIV,A_UMUL, A_SMUL, A_NEG,A_NOT,A_OR,A_not,A_not,A_not,A_SUB,A_XOR);
  101. TOpCmp2AsmCond:ARRAY[topcmp]OF TAsmCond=(C_NONE,C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  102. TCGSize2OpSize:ARRAY[tcgsize]OF TOpSize=(S_NO,S_B,S_W,S_SW,S_SW,S_B,S_W,S_SW,S_SW,S_FS,S_FD,S_FQ,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  103. IMPLEMENTATION
  104. USES
  105. globtype,globals,verbose,systems,cutils,
  106. symdef,symsym,defutil,paramgr,
  107. rgobj,tgobj,rgcpu,cpupi;
  108. { we implement the following routines because otherwise we can't }
  109. { instantiate the class since it's abstract }
  110. procedure TCgSparc.a_param_reg(list:TAasmOutput;size:tcgsize;r:tregister;const LocPara:TParaLocation);
  111. var r2:Tregister;
  112. begin
  113. r2.enum:=R_G0;
  114. if(Size<>OS_32)and(Size<>OS_S32)
  115. then
  116. InternalError(2002032212);
  117. with list,LocPara do
  118. case Loc of
  119. LOC_REGISTER:
  120. if r.enum<>Register.enum then
  121. Concat(taicpu.op_Reg_Reg_Reg(A_OR,r,r2,Register));
  122. else
  123. InternalError(2002101002);
  124. end;
  125. end;
  126. procedure TCgSparc.a_param_const(list:TAasmOutput;size:tcgsize;a:aword;CONST LocPara:TParaLocation);
  127. var
  128. Ref:TReference;
  129. begin
  130. with List do
  131. case locpara.loc of
  132. LOC_REGISTER,LOC_CREGISTER:
  133. a_load_const_reg(list,size,a,locpara.register);
  134. LOC_REFERENCE:
  135. begin
  136. reference_reset(ref);
  137. ref.base:=locpara.reference.index;
  138. ref.offset:=locpara.reference.offset;
  139. a_load_const_ref(list,size,a,ref);
  140. end;
  141. else
  142. InternalError(2002122200);
  143. end;
  144. if locpara.sp_fixup<>0
  145. then
  146. InternalError(2002122201);
  147. end;
  148. procedure TCgSparc.a_param_ref(list:TAasmOutput;sz:TCgSize;const r:TReference;const LocPara:TParaLocation);
  149. var
  150. ref: treference;
  151. tmpreg:TRegister;
  152. begin
  153. with LocPara do
  154. case locpara.loc of
  155. LOC_REGISTER,LOC_CREGISTER:
  156. a_load_ref_reg(list,sz,r,Register);
  157. LOC_REFERENCE:
  158. begin
  159. {Code conventions need the parameters being allocated in %o6+92. See
  160. comment on g_stack_frame}
  161. if locpara.sp_fixup<92
  162. then
  163. InternalError(2002081104);
  164. reference_reset(ref);
  165. ref.base:=locpara.reference.index;
  166. ref.offset:=locpara.reference.offset;
  167. tmpreg := get_scratch_reg_int(list);
  168. a_load_ref_reg(list,sz,r,tmpreg);
  169. a_load_reg_ref(list,sz,tmpreg,ref);
  170. free_scratch_reg(list,tmpreg);
  171. end;
  172. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  173. case sz of
  174. OS_32:
  175. a_loadfpu_ref_reg(list,OS_F32,r,locpara.register);
  176. OS_64:
  177. a_loadfpu_ref_reg(list,OS_F64,r,locpara.register);
  178. else
  179. internalerror(2002072801);
  180. end;
  181. else
  182. internalerror(2002081103);
  183. end;
  184. end;
  185. procedure TCgSparc.a_paramaddr_ref(list:TAasmOutput;CONST r:TReference;CONST LocPara:TParaLocation);
  186. VAR
  187. tmpreg:TRegister;
  188. BEGIN
  189. IF r.segment.enum<>R_NO
  190. THEN
  191. CGMessage(cg_e_cant_use_far_pointer_there);
  192. IF(r.base.enum=R_NO)AND(r.index.enum=R_NO)
  193. THEN
  194. list.concat(Taicpu.Op_sym_ofs(A_LD,S_SW,r.symbol,r.offset))
  195. ELSE IF(r.base.enum=R_NO)AND(r.index.enum<>R_NO)AND
  196. (r.offset=0)AND(r.scalefactor=0)AND(r.symbol=nil)
  197. THEN
  198. list.concat(Taicpu.Op_reg(A_LD,r.index))
  199. ELSE IF(r.base.enum<>R_NO)AND(r.index.enum=R_NO)AND
  200. (r.offset=0)AND(r.symbol=nil)
  201. THEN
  202. list.concat(Taicpu.Op_reg(A_LD,r.base))
  203. ELSE
  204. BEGIN
  205. tmpreg:=get_scratch_reg_address(list);
  206. a_loadaddr_ref_reg(list,r,tmpreg);
  207. list.concat(taicpu.op_reg(A_LD,tmpreg));
  208. free_scratch_reg(list,tmpreg);
  209. END;
  210. END;
  211. procedure TCgSparc.a_call_name(list:TAasmOutput;CONST s:string);
  212. BEGIN
  213. WITH List,objectlibrary DO
  214. BEGIN
  215. concat(taicpu.op_sym(A_CALL,S_SW,newasmsymbol(s)));
  216. concat(taicpu.op_none(A_NOP));
  217. END;
  218. END;
  219. procedure TCgSparc.a_call_ref(list:TAasmOutput;CONST ref:TReference);
  220. begin
  221. list.concat(taicpu.op_ref(A_CALL,ref));
  222. list.concat(taicpu.op_none(A_NOP));
  223. end;
  224. procedure TCgSparc.a_call_reg(list:TAasmOutput;Reg:TRegister);
  225. begin
  226. list.concat(taicpu.op_reg(A_JMPL,reg));
  227. if target_info.system=system_sparc_linux
  228. then
  229. list.concat(taicpu.op_none(A_NOP));
  230. procinfo.flags:=procinfo.flags or pi_do_call;
  231. end;
  232. {********************** branch instructions ********************}
  233. procedure TCgSparc.a_jmp_always(List:TAasmOutput;l:TAsmLabel);
  234. begin
  235. List.Concat(TAiCpu.op_sym(A_BA,S_NO,objectlibrary.newasmsymbol(l.name)));
  236. end;
  237. {********************** load instructions ********************}
  238. procedure TCgSparc.a_load_const_reg(list:TAasmOutput;size:TCGSize;a:aword;reg:TRegister);
  239. var r:Tregister;
  240. BEGIN
  241. r.enum:=R_G0;
  242. WITH List DO
  243. IF a<>0
  244. THEN{R_G0 is usually set to zero, so we use it}
  245. Concat(taicpu.op_reg_const_reg(A_OR,r,a,reg))
  246. ELSE{The is no A_MOV in sparc, that's why we use A_OR with help of R_G0}
  247. Concat(taicpu.op_reg_reg_reg(A_OR,r,r,reg));
  248. END;
  249. procedure TCgSparc.a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;CONST ref:TReference);
  250. var r:Tregister;
  251. BEGIN
  252. r.enum:=R_G0;
  253. WITH List DO
  254. IF a=0
  255. THEN
  256. Concat(taicpu.op_reg_ref(A_ST,r,Ref))
  257. ELSE
  258. BEGIN
  259. r.enum:=R_G1;
  260. a_load_const_reg(list,size,a,r);
  261. a_load_reg_ref(list,size,r,Ref);
  262. END;
  263. END;
  264. procedure TCgSparc.a_load_reg_ref(list:TAasmOutput;size:TCGSize;reg:tregister;const Ref:TReference);
  265. var
  266. op:tasmop;
  267. begin
  268. case size of
  269. { signed integer registers }
  270. OS_S8:
  271. Op:=A_STB;{Store Signed Byte}
  272. OS_S16:
  273. Op:=A_STH;{Store Signed Halfword}
  274. OS_S32:
  275. Op:=A_ST;{Store Word}
  276. OS_S64:
  277. Op:=A_STD;{Store Double Word}
  278. { unsigned integer registers }
  279. //A_STSTUB;{Store-Store Unsigned Byte}
  280. OS_8:
  281. Op:=A_STB;{Store Unsigned Bye}
  282. OS_16:
  283. Op:=A_STH;{Store Unsigned Halfword}
  284. OS_32:
  285. Op:=A_ST;{Store Word}
  286. OS_64:
  287. Op:=A_STD;{Store Double Word}
  288. { floating-point real registers }
  289. OS_F32:
  290. Op:=A_STF;{Store Floating-point word}
  291. //A_STFSR
  292. OS_F64:
  293. Op:=A_STDF;{Store Double Floating-point word}
  294. //A_STC;{Store Coprocessor}
  295. //A_STCSR;
  296. //A_STDC;{Store Double Coprocessor}
  297. else
  298. InternalError(2002122100);
  299. end;
  300. with list do
  301. concat(taicpu.op_reg_ref(op,reg,ref));
  302. end;
  303. procedure TCgSparc.a_load_ref_reg(list:TAasmOutput;size:TCgSize;const ref:TReference;reg:tregister);
  304. var
  305. op:tasmop;
  306. begin
  307. case size of
  308. { signed integer registers }
  309. OS_S8:
  310. Op:=A_LDSB;{Load Signed Byte}
  311. OS_S16:
  312. Op:=A_LDSH;{Load Signed Halfword}
  313. OS_S32:
  314. Op:=A_LD;{Load Word}
  315. OS_S64:
  316. Op:=A_LDD;{Load Double Word}
  317. { unsigned integer registers }
  318. //A_LDSTUB;{Load-Store Unsigned Byte}
  319. OS_8:
  320. Op:=A_LDUB;{Load Unsigned Bye}
  321. OS_16:
  322. Op:=A_LDUH;{Load Unsigned Halfword}
  323. OS_32:
  324. Op:=A_LD;{Load Word}
  325. OS_64:
  326. Op:=A_LDD;{Load Double Word}
  327. { floating-point real registers }
  328. OS_F32:
  329. Op:=A_LDF;{Load Floating-point word}
  330. //A_LDFSR
  331. OS_F64:
  332. Op:=A_LDDF;{Load Double Floating-point word}
  333. //A_LDC;{Load Coprocessor}
  334. //A_LDCSR;
  335. //A_LDDC;{Load Double Coprocessor}
  336. else
  337. InternalError(2002122100);
  338. end;
  339. with list do
  340. concat(taicpu.op_ref_reg(op,ref,reg));
  341. end;
  342. procedure TCgSparc.a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);
  343. var
  344. op:tasmop;
  345. s:topsize;
  346. r:Tregister;
  347. begin
  348. r.enum:=R_G0;
  349. if(reg1.enum<>reg2.enum)or
  350. (tcgsize2size[tosize]<tcgsize2size[fromsize])or
  351. ((tcgsize2size[tosize] = tcgsize2size[fromsize])and
  352. (tosize <> fromsize)and
  353. not(fromsize in [OS_32,OS_S32]))
  354. then
  355. with list do
  356. case fromsize of
  357. OS_8:
  358. InternalError(2002100800);{concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,reg2,reg1,0,31-8+1,31));}
  359. OS_S8:
  360. InternalError(2002100801);{concat(taicpu.op_reg_reg(A_EXTSB,reg2,reg1));}
  361. OS_16:
  362. InternalError(2002100802);{concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,reg2,reg1,0,31-16+1,31));}
  363. OS_S16:
  364. InternalError(2002100803);{concat(taicpu.op_reg_reg(A_EXTSH,reg2,reg1));}
  365. OS_32,OS_S32:
  366. concat(taicpu.op_reg_reg_reg(A_OR,r,reg1,reg2));
  367. else internalerror(2002090901);
  368. end;
  369. end;
  370. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  371. { R_ST means "the current value at the top of the fpu stack" (JM) }
  372. procedure TCgSparc.a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);
  373. begin
  374. { if NOT (reg1 IN [R_F0..R_F31]) then
  375. begin
  376. list.concat(taicpu.op_reg(A_NONE,S_NO,
  377. trgcpu(rg).correct_fpuregister(reg1,trgcpu(rg).fpuvaroffset)));
  378. inc(trgcpu(rg).fpuvaroffset);
  379. end;
  380. if NOT (reg2 IN [R_F0..R_F31]) then
  381. begin
  382. list.concat(taicpu.op_reg(A_JMPL,S_NO,
  383. trgcpu(rg).correct_fpuregister(reg2,trgcpu(rg).fpuvaroffset)));
  384. dec(trgcpu(rg).fpuvaroffset);
  385. end;}
  386. end;
  387. procedure TCgSparc.a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);
  388. begin
  389. floatload(list,size,ref);
  390. { if (reg <> R_ST) then
  391. a_loadfpu_reg_reg(list,R_ST,reg);}
  392. end;
  393. procedure TCgSparc.a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;CONST ref:TReference);
  394. begin
  395. { if reg <> R_ST then
  396. a_loadfpu_reg_reg(list,reg,R_ST);}
  397. floatstore(list,size,ref);
  398. end;
  399. procedure TCgSparc.a_loadmm_reg_reg(list:TAasmOutput;reg1, reg2:tregister);
  400. begin
  401. // list.concat(taicpu.op_reg_reg(A_NONEQ,S_NO,reg1,reg2));
  402. end;
  403. procedure TCgSparc.a_loadmm_ref_reg(list:TAasmOutput;CONST ref:TReference;reg:tregister);
  404. begin
  405. // list.concat(taicpu.op_ref_reg(A_NONEQ,S_NO,ref,reg));
  406. end;
  407. procedure TCgSparc.a_loadmm_reg_ref(list:TAasmOutput;reg:tregister;CONST ref:TReference);
  408. begin
  409. // list.concat(taicpu.op_reg_ref(A_NONEQ,S_NO,reg,ref));
  410. end;
  411. procedure TCgSparc.a_parammm_reg(list:TAasmOutput;reg:tregister);
  412. VAR
  413. href:TReference;
  414. BEGIN
  415. // list.concat(taicpu.op_const_reg(A_SUB,S_SW,8,R_RSP));
  416. // reference_reset_base(href,R_ESP,0);
  417. // list.concat(taicpu.op_reg_ref(A_NONEQ,S_NO,reg,href));
  418. END;
  419. procedure TCgSparc.a_op_const_reg(list:TAasmOutput;Op:TOpCG;a:AWord;reg:TRegister);
  420. var
  421. opcode:tasmop;
  422. power:LongInt;
  423. begin
  424. (* Case Op of
  425. OP_DIV, OP_IDIV:
  426. Begin
  427. if ispowerof2(a,power) then
  428. begin
  429. case op of
  430. OP_DIV:
  431. opcode := A_SHR;
  432. OP_IDIV:
  433. opcode := A_SAR;
  434. end;
  435. list.concat(taicpu.op_const_reg(opcode,S_SW,power,
  436. reg));
  437. exit;
  438. end;
  439. { the rest should be handled specifically in the code }
  440. { generator because of the silly register usage restraints }
  441. internalerror(200109224);
  442. End;
  443. OP_MUL,OP_IMUL:
  444. begin
  445. if not(cs_check_overflow in aktlocalswitches) and
  446. ispowerof2(a,power) then
  447. begin
  448. list.concat(taicpu.op_const_reg(A_SHL,S_SW,power,
  449. reg));
  450. exit;
  451. end;
  452. if op = OP_IMUL then
  453. list.concat(taicpu.op_const_reg(A_IMUL,S_SW,
  454. a,reg))
  455. else
  456. { OP_MUL should be handled specifically in the code }
  457. { generator because of the silly register usage restraints }
  458. internalerror(200109225);
  459. end;
  460. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  461. if not(cs_check_overflow in aktlocalswitches) and
  462. (a = 1) and
  463. (op in [OP_ADD,OP_SUB]) then
  464. if op = OP_ADD then
  465. list.concat(taicpu.op_reg(A_INC,S_SW,reg))
  466. else
  467. list.concat(taicpu.op_reg(A_DEC,S_SW,reg))
  468. else if (a = 0) then
  469. if (op <> OP_AND) then
  470. exit
  471. else
  472. list.concat(taicpu.op_const_reg(A_NONE,S_SW,0,reg))
  473. else if (a = high(aword)) and
  474. (op in [OP_AND,OP_OR,OP_XOR]) then
  475. begin
  476. case op of
  477. OP_AND:
  478. exit;
  479. OP_OR:
  480. list.concat(taicpu.op_const_reg(A_NONE,S_SW,high(aword),reg));
  481. OP_XOR:
  482. list.concat(taicpu.op_reg(A_NOT,S_SW,reg));
  483. end
  484. end
  485. else
  486. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],S_SW,
  487. a,reg));
  488. OP_SHL,OP_SHR,OP_SAR:
  489. begin
  490. if (a and 31) <> 0 Then
  491. list.concat(taicpu.op_const_reg(
  492. TOpCG2AsmOp[op],S_SW,a and 31,reg));
  493. if (a shr 5) <> 0 Then
  494. internalerror(68991);
  495. end
  496. else internalerror(68992);
  497. end;*)
  498. end;
  499. procedure TCgSparc.a_op_const_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;a:AWord;CONST ref:TReference);
  500. var
  501. opcode:tasmop;
  502. power:LongInt;
  503. begin
  504. (* Case Op of
  505. OP_DIV, OP_IDIV:
  506. Begin
  507. if ispowerof2(a,power) then
  508. begin
  509. case op of
  510. OP_DIV:
  511. opcode := A_SHR;
  512. OP_IDIV:
  513. opcode := A_SAR;
  514. end;
  515. list.concat(taicpu.op_const_ref(opcode,
  516. TCgSize2OpSize[size],power,ref));
  517. exit;
  518. end;
  519. { the rest should be handled specifically in the code }
  520. { generator because of the silly register usage restraints }
  521. internalerror(200109231);
  522. End;
  523. OP_MUL,OP_IMUL:
  524. begin
  525. if not(cs_check_overflow in aktlocalswitches) and
  526. ispowerof2(a,power) then
  527. begin
  528. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  529. power,ref));
  530. exit;
  531. end;
  532. { can't multiply a memory location directly with a CONSTant }
  533. if op = OP_IMUL then
  534. inherited a_op_const_ref(list,op,size,a,ref)
  535. else
  536. { OP_MUL should be handled specifically in the code }
  537. { generator because of the silly register usage restraints }
  538. internalerror(200109232);
  539. end;
  540. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  541. if not(cs_check_overflow in aktlocalswitches) and
  542. (a = 1) and
  543. (op in [OP_ADD,OP_SUB]) then
  544. if op = OP_ADD then
  545. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  546. else
  547. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  548. else if (a = 0) then
  549. if (op <> OP_AND) then
  550. exit
  551. else
  552. a_load_const_ref(list,size,0,ref)
  553. else if (a = high(aword)) and
  554. (op in [OP_AND,OP_OR,OP_XOR]) then
  555. begin
  556. case op of
  557. OP_AND:
  558. exit;
  559. OP_OR:
  560. list.concat(taicpu.op_const_ref(A_NONE,TCgSize2OpSize[size],high(aword),ref));
  561. OP_XOR:
  562. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  563. end
  564. end
  565. else
  566. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  567. TCgSize2OpSize[size],a,ref));
  568. OP_SHL,OP_SHR,OP_SAR:
  569. begin
  570. if (a and 31) <> 0 Then
  571. list.concat(taicpu.op_const_ref(
  572. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  573. if (a shr 5) <> 0 Then
  574. internalerror(68991);
  575. end
  576. else internalerror(68992);
  577. end;*)
  578. end;
  579. procedure TCgSparc.a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);
  580. var
  581. regloadsize:tcgsize;
  582. dstsize:topsize;
  583. tmpreg:tregister;
  584. popecx:boolean;
  585. begin
  586. (* dstsize := S_Q{makeregsize(dst,size)};
  587. case op of
  588. OP_NEG,OP_NOT:
  589. begin
  590. if src <> R_NO then
  591. internalerror(200112291);
  592. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  593. end;
  594. OP_MUL,OP_DIV,OP_IDIV:
  595. { special stuff, needs separate handling inside code }
  596. { generator }
  597. internalerror(200109233);
  598. OP_SHR,OP_SHL,OP_SAR:
  599. begin
  600. tmpreg := R_NO;
  601. { we need cl to hold the shift count, so if the destination }
  602. { is ecx, save it to a temp for now }
  603. if dst in [R_ECX,R_CX,R_CL] then
  604. begin
  605. case S_SW of
  606. S_B:regloadsize := OS_8;
  607. S_W:regloadsize := OS_16;
  608. else regloadsize := OS_32;
  609. end;
  610. tmpreg := get_scratch_reg(list);
  611. a_load_reg_reg(list,regloadsize,OS_32,src,tmpreg);
  612. end;
  613. if not(src in [R_ECX,R_CX,R_CL]) then
  614. begin
  615. { is ecx still free (it's also free if it was allocated }
  616. { to dst, since we've moved dst somewhere else already) }
  617. if not((dst = R_ECX) or
  618. ((R_ECX in rg.unusedregsint) and
  619. { this will always be true, it's just here to }
  620. { allocate ecx }
  621. (rg.getexplicitregisterint(list,R_ECX) = R_ECX))) then
  622. begin
  623. list.concat(taicpu.op_reg(A_NONE,S_SW,R_ECX));
  624. popecx := true;
  625. end;
  626. a_load_reg_reg(list,OS_8,OS_8,(src),R_CL);
  627. end
  628. else
  629. src := R_CL;
  630. { do the shift }
  631. if tmpreg = R_NO then
  632. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  633. R_CL,dst))
  634. else
  635. begin
  636. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_SW,
  637. R_CL,tmpreg));
  638. { move result back to the destination }
  639. a_load_reg_reg(list,OS_32,OS_32,tmpreg,R_ECX);
  640. free_scratch_reg(list,tmpreg);
  641. end;
  642. if popecx then
  643. list.concat(taicpu.op_reg(A_POP,S_SW,R_ECX))
  644. else if not (dst in [R_ECX,R_CX,R_CL]) then
  645. rg.ungetregisterint(list,R_ECX);
  646. end;
  647. else
  648. begin
  649. if S_SW <> dstsize then
  650. internalerror(200109226);
  651. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  652. src,dst));
  653. end;
  654. end;*)
  655. end;
  656. procedure TCgSparc.a_op_ref_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;CONST ref:TReference;reg:TRegister);
  657. var
  658. opsize:topsize;
  659. begin
  660. (* case op of
  661. OP_NEG,OP_NOT,OP_IMUL:
  662. begin
  663. inherited a_op_ref_reg(list,op,size,ref,reg);
  664. end;
  665. OP_MUL,OP_DIV,OP_IDIV:
  666. { special stuff, needs separate handling inside code }
  667. { generator }
  668. internalerror(200109239);
  669. else
  670. begin
  671. opsize := S_Q{makeregsize(reg,size)};
  672. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],opsize,ref,reg));
  673. end;
  674. end;*)
  675. end;
  676. procedure TCgSparc.a_op_reg_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;reg:TRegister;CONST ref:TReference);
  677. var
  678. opsize:topsize;
  679. begin
  680. (* case op of
  681. OP_NEG,OP_NOT:
  682. begin
  683. if reg <> R_NO then
  684. internalerror(200109237);
  685. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  686. end;
  687. OP_IMUL:
  688. begin
  689. { this one needs a load/imul/store, which is the default }
  690. inherited a_op_ref_reg(list,op,size,ref,reg);
  691. end;
  692. OP_MUL,OP_DIV,OP_IDIV:
  693. { special stuff, needs separate handling inside code }
  694. { generator }
  695. internalerror(200109238);
  696. else
  697. begin
  698. opsize := tcgsize2opsize[size];
  699. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,ref));
  700. end;
  701. end;*)
  702. end;
  703. procedure TCgSparc.a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;
  704. size:tcgsize;a:aword;src, dst:tregister);
  705. var
  706. tmpref:TReference;
  707. power:LongInt;
  708. opsize:topsize;
  709. begin
  710. opsize := S_SW;
  711. if (opsize <> S_SW) or
  712. not (size in [OS_32,OS_S32]) then
  713. begin
  714. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  715. exit;
  716. end;
  717. { if we get here, we have to do a 32 bit calculation, guaranteed }
  718. Case Op of
  719. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  720. OP_SAR:
  721. { can't do anything special for these }
  722. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  723. OP_IMUL:
  724. begin
  725. if not(cs_check_overflow in aktlocalswitches) and
  726. ispowerof2(a,power) then
  727. { can be done with a shift }
  728. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  729. list.concat(taicpu.op_reg_const_reg(A_SMUL,src,a,dst));
  730. end;
  731. OP_ADD, OP_SUB:
  732. if (a = 0) then
  733. a_load_reg_reg(list,size,size,src,dst)
  734. else
  735. begin
  736. reference_reset(tmpref);
  737. tmpref.base := src;
  738. tmpref.offset := LongInt(a);
  739. if op = OP_SUB then
  740. tmpref.offset := -tmpref.offset;
  741. list.concat(taicpu.op_ref_reg(A_NONE,tmpref,dst));
  742. end
  743. else internalerror(200112302);
  744. end;
  745. end;
  746. procedure TCgSparc.a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;
  747. size:tcgsize;src1, src2, dst:tregister);
  748. var
  749. tmpref:TReference;
  750. opsize:topsize;
  751. begin
  752. opsize := S_SW;
  753. if (opsize <> S_SW) or
  754. (S_SW <> S_SW) or
  755. not (size in [OS_32,OS_S32]) then
  756. begin
  757. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  758. exit;
  759. end;
  760. { if we get here, we have to do a 32 bit calculation, guaranteed }
  761. Case Op of
  762. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  763. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  764. { can't do anything special for these }
  765. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  766. OP_IMUL:
  767. list.concat(taicpu.op_reg_reg_reg(A_SMUL,src1,src2,dst));
  768. OP_ADD:
  769. begin
  770. reference_reset(tmpref);
  771. tmpref.base := src1;
  772. tmpref.index := src2;
  773. tmpref.scalefactor := 1;
  774. list.concat(taicpu.op_ref_reg(A_NONE,tmpref,dst));
  775. end
  776. else internalerror(200112303);
  777. end;
  778. end;
  779. {*************** compare instructructions ****************}
  780. procedure TCgSparc.a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;
  781. l:tasmlabel);
  782. begin
  783. if (a = 0) then
  784. list.concat(taicpu.op_reg_reg(A_CMP,reg,reg))
  785. else
  786. list.concat(taicpu.op_const_reg(A_CMP,a,reg));
  787. a_jmp_cond(list,cmp_op,l);
  788. end;
  789. procedure TCgSparc.a_cmp_const_ref_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;const ref:TReference;l:tasmlabel);
  790. begin
  791. with List do
  792. begin
  793. Concat(taicpu.op_const(A_LD,a));
  794. Concat(taicpu.op_ref(A_CMP,ref));
  795. end;
  796. a_jmp_cond(list,cmp_op,l);
  797. end;
  798. procedure TCgSparc.a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;
  799. reg1,reg2:tregister;l:tasmlabel);
  800. begin
  801. { if regsize(reg1) <> S_SW then
  802. internalerror(200109226);
  803. list.concat(taicpu.op_reg_reg(A_CMP,regsize(reg1),reg1,reg2));
  804. a_jmp_cond(list,cmp_op,l);}
  805. end;
  806. procedure TCgSparc.a_cmp_ref_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;CONST ref:TReference;reg:tregister;l:tasmlabel);
  807. var
  808. TempReg:TRegister;
  809. begin
  810. TempReg:=cg.get_scratch_reg_int(List);
  811. a_load_ref_reg(list,OS_32,Ref,TempReg);
  812. list.concat(taicpu.op_reg_reg(A_SUBcc,TempReg,Reg));
  813. a_jmp_cond(list,cmp_op,l);
  814. cg.free_scratch_reg(exprasmlist,TempReg);
  815. end;
  816. procedure TCgSparc.a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);
  817. var
  818. ai:taicpu;
  819. begin
  820. if cond=OC_None then
  821. ai := Taicpu.Op_sym(A_JMPL,S_NO,l)
  822. else
  823. begin
  824. ai:=Taicpu.Op_sym(A_JMPL,S_NO,l);
  825. ai.SetCondition(TOpCmp2AsmCond[cond]);
  826. end;
  827. ai.is_jmp:=true;
  828. list.concat(ai);
  829. end;
  830. procedure TCgSparc.a_jmp_flags(list:TAasmOutput;CONST f:TResFlags;l:tasmlabel);
  831. var
  832. ai:taicpu;
  833. begin
  834. ai := Taicpu.op_sym(A_JMPL,S_NO,l);
  835. ai.SetCondition(flags_to_cond(f));
  836. ai.is_jmp := true;
  837. list.concat(ai);
  838. end;
  839. procedure TCgSparc.g_flags2reg(list:TAasmOutput;Size:TCgSize;CONST f:tresflags;reg:TRegister);
  840. VAR
  841. ai:taicpu;
  842. r,hreg:tregister;
  843. BEGIN
  844. r.enum:=R_PSR;
  845. hreg := rg.makeregsize(reg,OS_8);
  846. ai:=Taicpu.Op_reg_reg(A_RDPSR,r,hreg);
  847. ai.SetCondition(flags_to_cond(f));
  848. list.concat(ai);
  849. IF hreg.enum<>reg.enum
  850. THEN
  851. a_load_reg_reg(list,OS_32,OS_32,hreg,reg);
  852. END;
  853. procedure TCgSparc.g_overflowCheck(List:TAasmOutput;const p:TNode);
  854. var
  855. hl:TAsmLabel;
  856. r:Tregister;
  857. begin
  858. r.enum:=R_NONE;
  859. if not(cs_check_overflow in aktlocalswitches)
  860. then
  861. exit;
  862. objectlibrary.getlabel(hl);
  863. if not((p.resulttype.def.deftype=pointerdef) or
  864. ((p.resulttype.def.deftype=orddef) and
  865. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  866. bool8bit,bool16bit,bool32bit])))
  867. then
  868. begin
  869. list.concat(taicpu.op_reg(A_NONE,r));
  870. a_jmp_always(list,hl)
  871. end
  872. else
  873. a_jmp_cond(list,OC_NONE,hl);
  874. a_call_name(list,'FPC_OVERFLOW');
  875. a_label(list,hl);
  876. end;
  877. { *********** entry/exit code and address loading ************ }
  878. procedure TCgSparc.g_stackframe_entry(list:TAasmOutput;LocalSize:LongInt);
  879. var
  880. href:TReference;
  881. r:Tregister;
  882. i:integer;
  883. again:tasmlabel;
  884. begin
  885. {Althogh the SPARC architecture require only word alignment, software
  886. convention and the operating system require every stack frame to be double word
  887. aligned}
  888. LocalSize:=(LocalSize+7)and $FFFFFFF8;
  889. {Execute the SAVE instruction to get a new register window and create a new
  890. stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state
  891. before execution of the SAVE instrucion so it is the caller %i6, when the %i6
  892. after execution of that instruction is the called function stack pointer}
  893. r.enum:=stack_pointer_reg;
  894. with list do
  895. concat(Taicpu.Op_reg_const_reg(A_SAVE,r,-LocalSize,r));
  896. end;
  897. procedure TCgSparc.g_restore_all_registers(list:TaasmOutput;selfused,accused,acchiused:boolean);
  898. begin
  899. {$warning FIX ME TCgSparc.g_restore_all_registers}
  900. end;
  901. procedure TCgSparc.g_restore_frame_pointer(list:TAasmOutput);
  902. begin
  903. {This function intontionally does nothing as frame pointer is restored in the
  904. delay slot of the return instrucion done in g_return_from_proc}
  905. end;
  906. procedure TCgSparc.g_return_from_proc(list:TAasmOutput;parasize:aword);
  907. var r,r2:Tregister;
  908. begin
  909. {According to the SPARC ABI, the stack is cleared using the RESTORE instruction
  910. which is genereted in the g_restore_frame_pointer. Notice that SPARC has no
  911. RETURN instruction and that JMPL is used instead. The JMPL instrucion have one
  912. delay slot, so an inversion is possible such as
  913. JMPL %i7+8,%g0
  914. RESTORE %g0,0,%g0
  915. If no inversion we can use just
  916. RESTORE %g0,0,%g0
  917. JMPL %i7+8,%g0
  918. NOP}
  919. with list do
  920. begin
  921. {Return address is computed by adding 8 to the CALL address saved onto %i6}
  922. r.enum:=R_G0;
  923. r2.enum:=R_I7;
  924. concat(Taicpu.Op_caddr_reg(A_JMPL,r,8,r));
  925. {We use trivial restore in the delay slot of the JMPL instruction, as we
  926. already set result onto %i0}
  927. concat(Taicpu.Op_reg_const_reg(A_RESTORE,r,0,r));
  928. end
  929. end;
  930. procedure TCgSparc.g_save_all_registers(list : taasmoutput);
  931. begin
  932. {$warning FIX ME TCgSparc.g_save_all_registers}
  933. end;
  934. procedure TCgSparc.g_save_standard_registers(list : taasmoutput; usedinproc : tregisterset);
  935. begin
  936. {$warning FIX ME tcgppc.g_save_standard_registers}
  937. end;
  938. procedure TCgSparc.a_loadaddr_ref_reg(list:TAasmOutput;CONST ref:TReference;r:tregister);
  939. begin
  940. // list.concat(taicpu.op_ref_reg(A_LEA,S_SW,ref,r));
  941. end;
  942. { ************* 64bit operations ************ }
  943. procedure TCg64fSPARC.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  944. begin
  945. case op of
  946. OP_ADD :
  947. begin
  948. op1:=A_ADD;
  949. op2:=A_ADD;
  950. end;
  951. OP_SUB :
  952. begin
  953. op1:=A_SUB;
  954. op2:=A_SUB;
  955. end;
  956. OP_XOR :
  957. begin
  958. op1:=A_XOR;
  959. op2:=A_XOR;
  960. end;
  961. OP_OR :
  962. begin
  963. op1:=A_OR;
  964. op2:=A_OR;
  965. end;
  966. OP_AND :
  967. begin
  968. op1:=A_AND;
  969. op2:=A_AND;
  970. end;
  971. else
  972. internalerror(200203241);
  973. end;
  974. end;
  975. procedure TCg64fSPARC.a_op64_ref_reg(list:TAasmOutput;op:TOpCG;CONST ref:TReference;reg:TRegister64);
  976. var
  977. op1,op2:TAsmOp;
  978. tempref:TReference;
  979. begin
  980. get_64bit_ops(op,op1,op2);
  981. list.concat(taicpu.op_ref_reg(op1,ref,reg.reglo));
  982. tempref:=ref;
  983. inc(tempref.offset,4);
  984. list.concat(taicpu.op_ref_reg(op2,tempref,reg.reghi));
  985. end;
  986. procedure TCg64fSPARC.a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);
  987. var
  988. op1,op2:TAsmOp;
  989. begin
  990. get_64bit_ops(op,op1,op2);
  991. list.concat(taicpu.op_reg_reg(op1,regsrc.reglo,regdst.reglo));
  992. list.concat(taicpu.op_reg_reg(op2,regsrc.reghi,regdst.reghi));
  993. end;
  994. procedure TCg64fSPARC.a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);
  995. var
  996. op1,op2:TAsmOp;
  997. begin
  998. case op of
  999. OP_AND,OP_OR,OP_XOR:
  1000. WITH cg DO
  1001. begin
  1002. a_op_const_reg(list,op,Lo(Value),regdst.reglo);
  1003. a_op_const_reg(list,op,Hi(Value),regdst.reghi);
  1004. end;
  1005. OP_ADD, OP_SUB:
  1006. begin
  1007. {can't use a_op_const_ref because this may use dec/inc}
  1008. get_64bit_ops(op,op1,op2);
  1009. list.concat(taicpu.op_const_reg(op1,Lo(Value),regdst.reglo));
  1010. list.concat(taicpu.op_const_reg(op2,Hi(Value),regdst.reghi));
  1011. end;
  1012. else
  1013. internalerror(200204021);
  1014. end;
  1015. end;
  1016. procedure TCg64fSPARC.a_op64_const_ref(list:TAasmOutput;op:TOpCG;value:qWord;const ref:TReference);
  1017. var
  1018. op1,op2:TAsmOp;
  1019. tempref:TReference;
  1020. begin
  1021. case op of
  1022. OP_AND,OP_OR,OP_XOR:
  1023. with cg do
  1024. begin
  1025. a_op_const_ref(list,op,OS_32,Lo(Value),ref);
  1026. tempref:=ref;
  1027. inc(tempref.offset,4);
  1028. a_op_const_ref(list,op,OS_32,Hi(Value),tempref);
  1029. end;
  1030. OP_ADD, OP_SUB:
  1031. begin
  1032. get_64bit_ops(op,op1,op2);
  1033. { can't use a_op_const_ref because this may use dec/inc}
  1034. { list.concat(taicpu.op_const_ref(op1,Lo(Value),ref));
  1035. tempref:=ref;
  1036. inc(tempref.offset,4);
  1037. list.concat(taicpu.op_const_ref(op2,S_SW,Hi(Value),tempref));}
  1038. InternalError(2002102101);
  1039. end;
  1040. else
  1041. internalerror(200204022);
  1042. end;
  1043. end;
  1044. { ************* concatcopy ************ }
  1045. procedure TCgSparc.g_concatcopy(list:taasmoutput;const source,dest:treference;len:aword;delsource,loadref:boolean);
  1046. var
  1047. countreg: TRegister;
  1048. src, dst: TReference;
  1049. lab: tasmlabel;
  1050. count, count2: aword;
  1051. orgsrc, orgdst: boolean;
  1052. r:Tregister;
  1053. begin
  1054. {$ifdef extdebug}
  1055. if len > high(longint)
  1056. then
  1057. internalerror(2002072704);
  1058. {$endif extdebug}
  1059. { make sure short loads are handled as optimally as possible }
  1060. if not loadref then
  1061. if (len <= 8) and
  1062. (byte(len) in [1,2,4,8]) then
  1063. begin
  1064. if len < 8 then
  1065. begin
  1066. a_load_ref_ref(list,int_cgsize(len),source,dest);
  1067. if delsource then
  1068. reference_release(list,source);
  1069. end
  1070. else
  1071. begin
  1072. r.enum:=R_F0;
  1073. a_reg_alloc(list,r);
  1074. a_loadfpu_ref_reg(list,OS_F64,source,r);
  1075. if delsource then
  1076. reference_release(list,source);
  1077. a_loadfpu_reg_ref(list,OS_F64,r,dest);
  1078. a_reg_dealloc(list,r);
  1079. end;
  1080. exit;
  1081. end;
  1082. reference_reset(src);
  1083. reference_reset(dst);
  1084. { load the address of source into src.base }
  1085. if loadref then
  1086. begin
  1087. src.base := get_scratch_reg_address(list);
  1088. a_load_ref_reg(list,OS_32,source,src.base);
  1089. orgsrc := false;
  1090. end
  1091. else if not issimpleref(source) or
  1092. ((source.index.enum <> R_NO) and
  1093. ((source.offset + longint(len)) > high(smallint))) then
  1094. begin
  1095. src.base := get_scratch_reg_address(list);
  1096. a_loadaddr_ref_reg(list,source,src.base);
  1097. orgsrc := false;
  1098. end
  1099. else
  1100. begin
  1101. src := source;
  1102. orgsrc := true;
  1103. end;
  1104. if not orgsrc and delsource then
  1105. reference_release(list,source);
  1106. { load the address of dest into dst.base }
  1107. if not issimpleref(dest) or
  1108. ((dest.index.enum <> R_NO) and
  1109. ((dest.offset + longint(len)) > high(smallint))) then
  1110. begin
  1111. dst.base := get_scratch_reg_address(list);
  1112. a_loadaddr_ref_reg(list,dest,dst.base);
  1113. orgdst := false;
  1114. end
  1115. else
  1116. begin
  1117. dst := dest;
  1118. orgdst := true;
  1119. end;
  1120. count := len div 8;
  1121. if count > 4 then
  1122. { generate a loop }
  1123. begin
  1124. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1125. { have to be set to 8. I put an Inc there so debugging may be }
  1126. { easier (should offset be different from zero here, it will be }
  1127. { easy to notice in the generated assembler }
  1128. inc(dst.offset,8);
  1129. inc(src.offset,8);
  1130. list.concat(taicpu.op_reg_const_reg(A_SUB,src.base,8,src.base));
  1131. list.concat(taicpu.op_reg_const_reg(A_SUB,dst.base,8,dst.base));
  1132. countreg := get_scratch_reg_int(list);
  1133. a_load_const_reg(list,OS_32,count,countreg);
  1134. { explicitely allocate R_O0 since it can be used safely here }
  1135. { (for holding date that's being copied) }
  1136. r.enum:=R_F0;
  1137. a_reg_alloc(list,r);
  1138. objectlibrary.getlabel(lab);
  1139. a_label(list, lab);
  1140. list.concat(taicpu.op_reg_const_reg(A_SUB,countreg,1,countreg));
  1141. list.concat(taicpu.op_reg_ref(A_LDF,r,src));
  1142. list.concat(taicpu.op_reg_ref(A_STD,r,dst));
  1143. //a_jmp(list,A_BC,C_NE,0,lab);
  1144. free_scratch_reg(list,countreg);
  1145. a_reg_dealloc(list,r);
  1146. len := len mod 8;
  1147. end;
  1148. count := len div 8;
  1149. if count > 0 then
  1150. { unrolled loop }
  1151. begin
  1152. r.enum:=R_F0;
  1153. a_reg_alloc(list,r);
  1154. for count2 := 1 to count do
  1155. begin
  1156. a_loadfpu_ref_reg(list,OS_F64,src,r);
  1157. a_loadfpu_reg_ref(list,OS_F64,r,dst);
  1158. inc(src.offset,8);
  1159. inc(dst.offset,8);
  1160. end;
  1161. a_reg_dealloc(list,r);
  1162. len := len mod 8;
  1163. end;
  1164. if (len and 4) <> 0 then
  1165. begin
  1166. r.enum:=R_O0;
  1167. a_reg_alloc(list,r);
  1168. a_load_ref_reg(list,OS_32,src,r);
  1169. a_load_reg_ref(list,OS_32,r,dst);
  1170. inc(src.offset,4);
  1171. inc(dst.offset,4);
  1172. a_reg_dealloc(list,r);
  1173. end;
  1174. { copy the leftovers }
  1175. if (len and 2) <> 0 then
  1176. begin
  1177. r.enum:=R_O0;
  1178. a_reg_alloc(list,r);
  1179. a_load_ref_reg(list,OS_16,src,r);
  1180. a_load_reg_ref(list,OS_16,r,dst);
  1181. inc(src.offset,2);
  1182. inc(dst.offset,2);
  1183. a_reg_dealloc(list,r);
  1184. end;
  1185. if (len and 1) <> 0 then
  1186. begin
  1187. r.enum:=R_O0;
  1188. a_reg_alloc(list,r);
  1189. a_load_ref_reg(list,OS_8,src,r);
  1190. a_load_reg_ref(list,OS_8,r,dst);
  1191. a_reg_dealloc(list,r);
  1192. end;
  1193. if orgsrc then
  1194. begin
  1195. if delsource then
  1196. reference_release(list,source);
  1197. end
  1198. else
  1199. free_scratch_reg(list,src.base);
  1200. if not orgdst then
  1201. free_scratch_reg(list,dst.base);
  1202. end;
  1203. function TCgSparc.reg_cgsize(CONST reg:tregister):tcgsize;
  1204. begin
  1205. result:=OS_32;
  1206. end;
  1207. {***************** This is private property, keep out! :) *****************}
  1208. function TCgSparc.IsSimpleRef(const ref:treference):boolean;
  1209. begin
  1210. if(ref.base.enum=R_NONE)and(ref.index.enum <> R_NO)
  1211. then
  1212. InternalError(2002100804);
  1213. result :=not(assigned(ref.symbol))and
  1214. (((ref.index.enum = R_NO) and
  1215. (ref.offset >= low(smallint)) and
  1216. (ref.offset <= high(smallint))) or
  1217. ((ref.index.enum <> R_NO) and
  1218. (ref.offset = 0)));
  1219. end;
  1220. procedure TCgSparc.sizes2load(s1:tcgsize;s2:topsize;var op:tasmop;var s3:topsize);
  1221. begin
  1222. case s2 of
  1223. S_B:
  1224. if S1 in [OS_8,OS_S8]
  1225. then
  1226. s3 := S_B
  1227. else
  1228. internalerror(200109221);
  1229. S_W:
  1230. case s1 of
  1231. OS_8,OS_S8:
  1232. s3 := S_B;
  1233. OS_16,OS_S16:
  1234. s3 := S_H;
  1235. else
  1236. internalerror(200109222);
  1237. end;
  1238. S_SW:
  1239. case s1 of
  1240. OS_8,OS_S8:
  1241. s3 := S_B;
  1242. OS_16,OS_S16:
  1243. s3 := S_H;
  1244. OS_32,OS_S32:
  1245. s3 := S_W;
  1246. else
  1247. internalerror(200109223);
  1248. end;
  1249. else internalerror(200109227);
  1250. end;
  1251. if s3 in [S_B,S_W,S_SW]
  1252. then
  1253. op := A_LD
  1254. { else if s3=S_DW
  1255. then
  1256. op:=A_LDD
  1257. else if s3 in [OS_8,OS_16,OS_32]
  1258. then
  1259. op := A_NONE}
  1260. else
  1261. op := A_NONE;
  1262. end;
  1263. procedure TCgSparc.floatloadops(t:tcgsize;VAR op:tasmop;VAR s:topsize);
  1264. BEGIN
  1265. (* case t of
  1266. OS_F32:begin
  1267. op:=A_FLD;
  1268. s:=S_FS;
  1269. end;
  1270. OS_F64:begin
  1271. op:=A_FLD;
  1272. { ???? }
  1273. s:=S_FL;
  1274. end;
  1275. OS_F80:begin
  1276. op:=A_FLD;
  1277. s:=S_FX;
  1278. end;
  1279. OS_C64:begin
  1280. op:=A_FILD;
  1281. s:=S_IQ;
  1282. end;
  1283. else internalerror(17);
  1284. end;*)
  1285. END;
  1286. procedure TCgSparc.floatload(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  1287. VAR
  1288. op:tasmop;
  1289. s:topsize;
  1290. BEGIN
  1291. floatloadops(t,op,s);
  1292. list.concat(Taicpu.Op_ref(op,ref));
  1293. { inc(trgcpu(rg).fpuvaroffset);}
  1294. END;
  1295. procedure TCgSparc.floatstoreops(t:tcgsize;var op:tasmop;var s:topsize);
  1296. BEGIN
  1297. { case t of
  1298. OS_F32:begin
  1299. op:=A_FSTP;
  1300. s:=S_FS;
  1301. end;
  1302. OS_F64:begin
  1303. op:=A_FSTP;
  1304. s:=S_FL;
  1305. end;
  1306. OS_F80:begin
  1307. op:=A_FSTP;
  1308. s:=S_FX;
  1309. end;
  1310. OS_C64:begin
  1311. op:=A_FISTP;
  1312. s:=S_IQ;
  1313. end;
  1314. else
  1315. internalerror(17);
  1316. end;}
  1317. end;
  1318. procedure TCgSparc.floatstore(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  1319. VAR
  1320. op:tasmop;
  1321. s:topsize;
  1322. BEGIN
  1323. floatstoreops(t,op,s);
  1324. list.concat(Taicpu.Op_ref(op,ref));
  1325. { dec(trgcpu(rg).fpuvaroffset);}
  1326. END;
  1327. BEGIN
  1328. cg:=TCgSparc.create;
  1329. END.
  1330. {
  1331. $Log$
  1332. Revision 1.34 2003-01-08 18:43:58 daniel
  1333. * Tregister changed into a record
  1334. Revision 1.33 2003/01/07 22:03:40 mazen
  1335. * adding unequaln node support to sparc compiler
  1336. Revision 1.32 2003/01/06 22:51:47 mazen
  1337. * fixing bugs related to load_reg_ref
  1338. Revision 1.31 2003/01/05 21:32:35 mazen
  1339. * fixing several bugs compiling the RTL
  1340. Revision 1.30 2003/01/05 13:36:53 florian
  1341. * x86-64 compiles
  1342. + very basic support for float128 type (x86-64 only)
  1343. Revision 1.29 2002/12/25 20:59:49 mazen
  1344. - many emitXXX removed from cga.pas in order to remove that file.
  1345. Revision 1.28 2002/12/22 19:26:31 mazen
  1346. * many internal errors related to unimplemented nodes are fixed
  1347. Revision 1.27 2002/12/21 23:21:47 mazen
  1348. + added support for the shift nodes
  1349. + added debug output on screen with -an command line option
  1350. Revision 1.26 2002/11/25 19:21:49 mazen
  1351. * fixed support of nSparcInline
  1352. Revision 1.25 2002/11/25 17:43:28 peter
  1353. * splitted defbase in defutil,symutil,defcmp
  1354. * merged isconvertable and is_equal into compare_defs(_ext)
  1355. * made operator search faster by walking the list only once
  1356. Revision 1.24 2002/11/17 17:49:09 mazen
  1357. + 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
  1358. Revision 1.23 2002/11/10 19:07:46 mazen
  1359. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  1360. Revision 1.22 2002/11/06 11:31:24 mazen
  1361. * op_reg_reg_reg don't need any more a TOpSize parameter
  1362. Revision 1.21 2002/11/05 16:15:00 mazen
  1363. *** empty log message ***
  1364. Revision 1.20 2002/11/03 20:22:40 mazen
  1365. * parameter handling updated
  1366. Revision 1.19 2002/10/28 20:59:17 mazen
  1367. * TOpSize values changed S_L --> S_SW
  1368. Revision 1.18 2002/10/22 13:43:01 mazen
  1369. - cga.pas redueced to an empty unit
  1370. Revision 1.17 2002/10/20 19:01:38 mazen
  1371. + op_raddr_reg and op_caddr_reg added to fix functions prologue
  1372. Revision 1.16 2002/10/13 21:46:07 mazen
  1373. * assembler output format fixed
  1374. Revision 1.15 2002/10/11 13:35:14 mazen
  1375. *** empty log message ***
  1376. Revision 1.14 2002/10/10 19:57:51 mazen
  1377. * Just to update repsitory
  1378. Revision 1.13 2002/10/10 15:10:39 mazen
  1379. * Internal error fixed, but usually i386 parameter model used
  1380. Revision 1.12 2002/10/08 17:17:03 mazen
  1381. *** empty log message ***
  1382. Revision 1.11 2002/10/07 20:33:04 mazen
  1383. word alignement modified in g_stack_frame
  1384. Revision 1.10 2002/10/04 21:57:42 mazen
  1385. * 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
  1386. Revision 1.9 2002/10/02 22:20:28 mazen
  1387. + out registers allocator for the first 6 scalar parameters which must be passed into %o0..%o5
  1388. Revision 1.8 2002/10/01 21:35:58 mazen
  1389. + procedures exiting prologue added and stack frame now restored in the delay slot of the return (JMPL) instruction
  1390. Revision 1.7 2002/10/01 21:06:29 mazen
  1391. attinst.inc --> strinst.inc
  1392. Revision 1.6 2002/10/01 17:41:50 florian
  1393. * fixed log and id
  1394. }