cpugas.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. {
  2. Copyright (c) 1999-2003 by Florian Klaempfl
  3. This unit implements an asmoutput class for SPARC AT&T syntax
  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. }
  17. unit cpugas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,
  22. aasmtai,aasmdata,aasmcpu,assemble,aggas,
  23. cgutils,globtype;
  24. type
  25. TGasSPARC=class(TGnuAssembler)
  26. constructor create(smart: boolean); override;
  27. {# Constructs the command line for calling the assembler }
  28. function MakeCmdLine: TCmdStr; override;
  29. end;
  30. TSPARCInstrWriter=class(TCPUInstrWriter)
  31. procedure WriteInstruction(hp:Tai);override;
  32. function GetReferenceString(var ref : TReference):string;
  33. function getopstr(const Oper:TOper):string;
  34. end;
  35. implementation
  36. uses
  37. cutils,systems,globals,cpuinfo,procinfo,
  38. verbose,itcpugas,cgbase;
  39. {****************************************************************************}
  40. { GNU PPC Assembler writer }
  41. {****************************************************************************}
  42. constructor TGasSPARC.create(smart: boolean);
  43. begin
  44. inherited create(smart);
  45. InstrWriter := TSPARCInstrWriter.create(self);
  46. end;
  47. function TGasSPARC.MakeCmdLine: TCmdStr;
  48. begin
  49. result := Inherited MakeCmdLine;
  50. { ARCH selection }
  51. // Note for casual readers: gas (GNU as) uses -Av7, -Av8, -Av9 etc. on SPARC,
  52. // rather than variants of the -m option used by most other CPUs. Solaris as
  53. // uses -xarch=v7, -xarch=v8 etc., that form is not supported here since there
  54. // are probably other incompatibilties between the GNU and Solaris binutils
  55. // that need to be reviewed.
  56. //
  57. // v9 is required as the default since the RTL started using membar at 2.2.2.
  58. case current_settings.cputype of
  59. cpu_SPARC_V7: Replace(result,'$ARCH','-Av7');
  60. cpu_SPARC_V8: Replace(result,'$ARCH','-Av8')
  61. else
  62. Replace(result,'$ARCH','-Av9')
  63. end
  64. end;
  65. function TSPARCInstrWriter.GetReferenceString(var ref:TReference):string;
  66. var
  67. asm_comment : string;
  68. begin
  69. GetReferenceString:='';
  70. asm_comment:='';
  71. with ref do
  72. begin
  73. if (base=NR_NO) and (index=NR_NO) then
  74. begin
  75. if assigned(symbol) then
  76. GetReferenceString:=symbol.name;
  77. if offset>0 then
  78. GetReferenceString:=GetReferenceString+'+'+ToStr(offset)
  79. else if offset<0 then
  80. GetReferenceString:=GetReferenceString+ToStr(offset);
  81. case refaddr of
  82. addr_high:
  83. GetReferenceString:='%hi('+GetReferenceString+')';
  84. addr_low:
  85. GetReferenceString:='%lo('+GetReferenceString+')';
  86. addr_pic:
  87. begin
  88. asm_comment:='addr_pic should use %l7 register as base or index: '+GetReferenceString;
  89. Comment(V_Warning,asm_comment);
  90. GetReferenceString:='%l7+'+GetReferenceString;
  91. end;
  92. end;
  93. end
  94. else
  95. begin
  96. if (base=NR_NO) and (index<>NR_NO) then
  97. begin
  98. base:=index;
  99. index:=NR_NO;
  100. end;
  101. {$ifdef extdebug}
  102. if assigned(symbol) and
  103. not(refaddr in [addr_pic,addr_low]) then
  104. internalerror(2003052601);
  105. {$endif extdebug}
  106. GetReferenceString:=GetReferenceString+gas_regname(base);
  107. if index=NR_NO then
  108. begin
  109. { if (Offset<simm13lo) or (Offset>simm13hi) then
  110. internalerror(2003053008); }
  111. if offset>0 then
  112. GetReferenceString:=GetReferenceString+'+'+ToStr(offset)
  113. else if offset<0 then
  114. GetReferenceString:=GetReferenceString+ToStr(offset);
  115. {
  116. else if (offset=0) and not(assigned(symbol)) then
  117. GetReferenceString:=GetReferenceString+ToStr(offset);
  118. }
  119. if assigned(symbol) then
  120. begin
  121. if refaddr=addr_low then
  122. GetReferenceString:='%lo('+symbol.name+')+'+GetReferenceString
  123. else if refaddr=addr_pic then
  124. begin
  125. if assigned(current_procinfo) and (base <> current_procinfo.got) then
  126. begin
  127. asm_comment:=' pic address should use %l7 register: '+GetReferenceString;
  128. Comment(V_Warning,asm_comment);
  129. end;
  130. GetReferenceString:=GetReferenceString+'+'+symbol.name;
  131. end
  132. else
  133. GetReferenceString:=symbol.name+'+'+GetReferenceString;
  134. end;
  135. end
  136. else
  137. begin
  138. {$ifdef extdebug}
  139. if (Offset<>0) or assigned(symbol) then
  140. internalerror(2003052603);
  141. {$endif extdebug}
  142. GetReferenceString:=GetReferenceString+'+'+gas_regname(index);
  143. end;
  144. end;
  145. end;
  146. if asm_comment <> '' then
  147. begin
  148. owner.AsmWrite(target_asm.comment+' '+asm_comment);
  149. owner.AsmLn;
  150. end;
  151. end;
  152. function TSPARCInstrWriter.getopstr(const Oper:TOper):string;
  153. begin
  154. with Oper do
  155. case typ of
  156. top_reg:
  157. getopstr:=gas_regname(reg);
  158. top_const:
  159. getopstr:=tostr(longint(val));
  160. top_ref:
  161. if (oper.ref^.refaddr in [addr_no,addr_pic]) or
  162. ((oper.ref^.refaddr=addr_low) and ((oper.ref^.base<>NR_NO) or
  163. (oper.ref^.index<>NR_NO))) then
  164. getopstr:='['+getreferencestring(ref^)+']'
  165. else
  166. getopstr:=getreferencestring(ref^);
  167. else
  168. internalerror(10001);
  169. end;
  170. end;
  171. procedure TSPARCInstrWriter.WriteInstruction(hp:Tai);
  172. var
  173. Op:TAsmOp;
  174. s:String;
  175. i:Integer;
  176. begin
  177. if hp.typ<>ait_instruction then
  178. exit;
  179. op:=taicpu(hp).opcode;
  180. { translate pseudoops, this should be move to a separate pass later, so it's done before
  181. peephole optimization }
  182. case op of
  183. A_FABSd:
  184. begin
  185. if (taicpu(hp).ops<>2) or
  186. (taicpu(hp).oper[0]^.typ<>top_reg) or
  187. (taicpu(hp).oper[1]^.typ<>top_reg) then
  188. internalerror(200401045);
  189. { FABSs %f<even>,%f<even> }
  190. s:=#9+std_op2str[A_FABSs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^);
  191. owner.AsmWriteLn(s);
  192. { FMOVs %f<odd>,%f<odd> }
  193. inc(taicpu(hp).oper[0]^.reg);
  194. inc(taicpu(hp).oper[1]^.reg);
  195. s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^);
  196. dec(taicpu(hp).oper[0]^.reg);
  197. dec(taicpu(hp).oper[1]^.reg);
  198. owner.AsmWriteLn(s);
  199. end;
  200. A_FMOVd:
  201. begin
  202. if (taicpu(hp).ops<>2) or
  203. (taicpu(hp).oper[0]^.typ<>top_reg) or
  204. (taicpu(hp).oper[1]^.typ<>top_reg) then
  205. internalerror(200401045);
  206. { FMOVs %f<even>,%f<even> }
  207. s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^);
  208. owner.AsmWriteLn(s);
  209. { FMOVs %f<odd>,%f<odd> }
  210. inc(taicpu(hp).oper[0]^.reg);
  211. inc(taicpu(hp).oper[1]^.reg);
  212. s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^);
  213. dec(taicpu(hp).oper[0]^.reg);
  214. dec(taicpu(hp).oper[1]^.reg);
  215. owner.AsmWriteLn(s);
  216. end
  217. else
  218. begin
  219. { call maybe not translated to call }
  220. s:=#9+std_op2str[op]+cond2str[taicpu(hp).condition];
  221. if taicpu(hp).delayslot_annulled then
  222. s:=s+',a';
  223. if taicpu(hp).ops>0 then
  224. begin
  225. s:=s+#9+getopstr(taicpu(hp).oper[0]^);
  226. for i:=1 to taicpu(hp).ops-1 do
  227. s:=s+','+getopstr(taicpu(hp).oper[i]^);
  228. end;
  229. owner.AsmWriteLn(s);
  230. end;
  231. end;
  232. end;
  233. const
  234. as_sparc_as_info : tasminfo =
  235. (
  236. id : as_gas;
  237. idtxt : 'AS';
  238. asmbin : 'as';
  239. {$ifdef FPC_SPARC_V8_ONLY}
  240. asmcmd : '$PIC -o $OBJ $ASM';
  241. {$else}
  242. asmcmd : '$ARCH $PIC -o $OBJ $ASM';
  243. {$endif}
  244. supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
  245. flags : [af_needar,af_smartlink_sections];
  246. labelprefix : '.L';
  247. comment : '# ';
  248. dollarsign: '$';
  249. );
  250. as_sparc_gas_info : tasminfo =
  251. (
  252. id : as_ggas;
  253. idtxt : 'GAS';
  254. asmbin : 'gas';
  255. asmcmd : '$ARCH $PIC -o $OBJ $ASM';
  256. supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
  257. flags : [af_needar,af_smartlink_sections];
  258. labelprefix : '.L';
  259. comment : '# ';
  260. dollarsign: '$';
  261. );
  262. begin
  263. RegisterAssembler(as_SPARC_as_info,TGasSPARC);
  264. RegisterAssembler(as_SPARC_gas_info,TGasSPARC);
  265. end.