cgcpu.pas 53 KB

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