cgrv.pas 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. {
  2. Copyright (c) 2006 by Florian Klaempfl
  3. This unit implements the common part of the code generator for the Risc-V
  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 cgrv;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,symtype,symdef,
  22. cgbase,cgobj,
  23. aasmbase,aasmcpu,aasmtai,aasmdata,
  24. cpubase,cpuinfo,cgutils,rgcpu,
  25. parabase;
  26. type
  27. tcgrv = class(tcg)
  28. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
  29. procedure a_bit_scan_reg_reg(list: TAsmList; reverse,not_zero: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
  30. procedure a_call_reg(list : TAsmList;reg: tregister); override;
  31. procedure a_call_name(list : TAsmList;const s : string; weak: boolean); override;
  32. procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override;
  33. procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize; reg: tregister; const ref: treference); override;
  34. procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  35. procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
  36. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  37. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  38. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  39. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  40. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  41. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel); override;
  42. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  43. procedure a_jmp_name(list : TAsmList;const s : string); override;
  44. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  45. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  46. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  47. procedure g_save_registers(list: TAsmList); override;
  48. procedure g_restore_registers(list: TAsmList); override;
  49. procedure g_profilecode(list: TAsmList); override;
  50. { fpu move instructions }
  51. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  52. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  53. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  54. procedure g_check_for_fpu_exception(list: TAsmList;force,clear : boolean); override;
  55. protected
  56. function fixref(list: TAsmList; var ref: treference): boolean;
  57. procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
  58. end;
  59. const
  60. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE,
  61. C_LT,C_GE,C_None,C_NE,C_NONE,C_LTU,C_GEU,C_NONE);
  62. const
  63. TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
  64. A_NONE,A_ADDI,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
  65. A_None,A_None,A_ORI,A_SRAI,A_SLLI,A_SRLI,A_NONE,A_XORI,A_None,A_None);
  66. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
  67. A_NONE,A_ADD,A_AND,A_DIVU,A_DIV,A_MUL,A_MUL,
  68. A_None,A_None,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR,A_None,A_None);
  69. {$ifdef extdebug}
  70. function ref2string(const ref : treference) : string;
  71. function cgop2string(const op : TOpCg) : String;
  72. {$endif extdebug}
  73. implementation
  74. uses
  75. {$ifdef extdebug}sysutils,{$endif}
  76. globals,verbose,systems,cutils,
  77. symconst,symsym,symtable,fmodule,
  78. rgobj,tgobj,cpupi,procinfo,paramgr;
  79. {$ifdef extdebug}
  80. function ref2string(const ref : treference) : string;
  81. begin
  82. result := 'base : ' + inttostr(ord(ref.base)) + ' index : ' + inttostr(ord(ref.index)) + ' refaddr : ' + inttostr(ord(ref.refaddr)) + ' offset : ' + inttostr(ref.offset) + ' symbol : ';
  83. if (assigned(ref.symbol)) then
  84. result := result + ref.symbol.name;
  85. end;
  86. function cgop2string(const op : TOpCg) : String;
  87. const
  88. opcg_strings : array[TOpCg] of string[6] = (
  89. 'None', 'Move', 'Add', 'And', 'Div', 'IDiv', 'IMul', 'Mul',
  90. 'Neg', 'Not', 'Or', 'Sar', 'Shl', 'Shr', 'Sub', 'Xor', 'Rol', 'Ror'
  91. );
  92. begin
  93. result := opcg_strings[op];
  94. end;
  95. {$endif extdebug}
  96. procedure tcgrv.a_call_name(list : TAsmList;const s : string; weak: boolean);
  97. var
  98. href: treference;
  99. l: TAsmLabel;
  100. ai: taicpu;
  101. begin
  102. if not(weak) then
  103. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[])
  104. else
  105. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION),0,0,[]);
  106. if cs_create_pic in current_settings.moduleswitches then
  107. begin
  108. href.refaddr:=addr_plt;
  109. list.concat(taicpu.op_ref(A_CALL,href));
  110. end
  111. else
  112. begin
  113. current_asmdata.getjumplabel(l);
  114. a_label(list,l);
  115. href.refaddr:=addr_pcrel_hi20;
  116. list.concat(taicpu.op_reg_ref(A_AUIPC,NR_RETURN_ADDRESS_REG,href));
  117. reference_reset_symbol(href,l,0,0,[]);
  118. href.refaddr:=addr_pcrel_lo12;
  119. ai:=taicpu.op_reg_reg_ref(A_JALR,NR_RETURN_ADDRESS_REG,NR_RETURN_ADDRESS_REG,href);
  120. ai.is_jmp:=true;
  121. list.concat(ai);
  122. end;
  123. { not assigned while generating external wrappers }
  124. if assigned(current_procinfo) then
  125. include(current_procinfo.flags,pi_do_call);
  126. end;
  127. procedure tcgrv.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  128. begin
  129. if a=0 then
  130. a_load_reg_ref(list,size,size,NR_X0,ref)
  131. else
  132. inherited a_load_const_ref(list, size, a, ref);
  133. end;
  134. procedure tcgrv.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  135. var
  136. ref: treference;
  137. tmpreg: tregister;
  138. begin
  139. paraloc.check_simple_location;
  140. paramanager.allocparaloc(list,paraloc.location);
  141. case paraloc.location^.loc of
  142. LOC_REGISTER,LOC_CREGISTER:
  143. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  144. LOC_REFERENCE:
  145. begin
  146. reference_reset(ref,paraloc.alignment,[]);
  147. ref.base := paraloc.location^.reference.index;
  148. ref.offset := paraloc.location^.reference.offset;
  149. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  150. a_loadaddr_ref_reg(list,r,tmpreg);
  151. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  152. end;
  153. else
  154. internalerror(2002080701);
  155. end;
  156. end;
  157. procedure tcgrv.a_bit_scan_reg_reg(list: TAsmList; reverse,not_zero: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
  158. begin
  159. internalerror(2016060401);
  160. end;
  161. procedure tcgrv.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  162. begin
  163. a_op_const_reg_reg(list,op,size,a,reg,reg);
  164. end;
  165. procedure tcgrv.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  166. begin
  167. a_op_reg_reg_reg(list,op,size,src,dst,dst);
  168. end;
  169. procedure tcgrv.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  170. var
  171. tmpreg: TRegister;
  172. begin
  173. optimize_op_const(size,op,a);
  174. if op=OP_NONE then
  175. begin
  176. a_load_reg_reg(list,size,size,src,dst);
  177. exit;
  178. end;
  179. if op=OP_SUB then
  180. begin
  181. op:=OP_ADD;
  182. a:=-a;
  183. end;
  184. {$ifdef RISCV64}
  185. if (op=OP_SHL) and
  186. (size=OS_S32) then
  187. begin
  188. list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
  189. maybeadjustresult(list,op,size,dst);
  190. end
  191. else if (op=OP_SHR) and
  192. (size=OS_S32) then
  193. begin
  194. list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
  195. maybeadjustresult(list,op,size,dst);
  196. end
  197. else if (op=OP_SAR) and
  198. (size=OS_S32) then
  199. begin
  200. list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
  201. maybeadjustresult(list,op,size,dst);
  202. end
  203. else
  204. {$endif RISCV64}
  205. if (TOpCG2AsmConstOp[op]<>A_None) and
  206. is_imm12(a) then
  207. begin
  208. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
  209. maybeadjustresult(list,op,size,dst);
  210. end
  211. else
  212. begin
  213. tmpreg:=getintregister(list,size);
  214. a_load_const_reg(list,size,a,tmpreg);
  215. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  216. end;
  217. end;
  218. procedure tcgrv.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  219. var
  220. name: String;
  221. pd: tprocdef;
  222. paraloc1, paraloc2: tcgpara;
  223. begin
  224. if op=OP_NOT then
  225. begin
  226. list.concat(taicpu.op_reg_reg_const(A_XORI,dst,src1,-1));
  227. maybeadjustresult(list,op,size,dst);
  228. end
  229. else if op=OP_NEG then
  230. begin
  231. list.concat(taicpu.op_reg_reg_reg(A_SUB,dst,NR_X0,src1));
  232. maybeadjustresult(list,op,size,dst);
  233. end
  234. else
  235. case op of
  236. OP_MOVE:
  237. a_load_reg_reg(list,size,size,src1,dst);
  238. else
  239. {$ifdef RISCV64}
  240. if (op=OP_SHL) and
  241. (size=OS_S32) then
  242. begin
  243. list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
  244. maybeadjustresult(list,op,size,dst);
  245. end
  246. else if (op=OP_SHR) and
  247. (size=OS_S32) then
  248. begin
  249. list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
  250. maybeadjustresult(list,op,size,dst);
  251. end
  252. else if (op=OP_SAR) and
  253. (size=OS_S32) then
  254. begin
  255. list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
  256. maybeadjustresult(list,op,size,dst);
  257. end
  258. else if (op=OP_SUB) and
  259. (size in [OS_32,OS_S32]) then
  260. begin
  261. list.concat(taicpu.op_reg_reg_reg(A_SUBW,dst,src2,src1));
  262. maybeadjustresult(list,op,size,dst);
  263. end
  264. else
  265. {$endif RISCV64}
  266. if (op in [OP_IMUL,OP_MUL]) and ([CPURV_HAS_MUL,CPURV_HAS_ZMMUL]*cpu_capabilities[current_settings.cputype]=[]) then
  267. begin
  268. case size of
  269. OS_8:
  270. name:='fpc_mul_byte';
  271. OS_S8:
  272. name:='fpc_mul_shortint';
  273. OS_16:
  274. name:='fpc_mul_word';
  275. OS_S16:
  276. name:='fpc_mul_integer';
  277. OS_32:
  278. name:='fpc_mul_dword';
  279. OS_S32:
  280. name:='fpc_mul_longint';
  281. else
  282. Internalerror(2021030601);
  283. end;
  284. // if check_overflow then
  285. // name:=name+'_checkoverflow';
  286. pd:=search_system_proc(name);
  287. paraloc1.init;
  288. paraloc2.init;
  289. paramanager.getcgtempparaloc(list,pd,1,paraloc1);
  290. paramanager.getcgtempparaloc(list,pd,2,paraloc2);
  291. a_load_reg_cgpara(list,OS_8,src1,paraloc2);
  292. a_load_reg_cgpara(list,OS_8,src2,paraloc1);
  293. paramanager.freecgpara(list,paraloc2);
  294. paramanager.freecgpara(list,paraloc1);
  295. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  296. a_call_name(list,upper(name),false);
  297. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  298. cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
  299. cg.a_load_reg_reg(list,size,size,NR_FUNCTION_RESULT_REG,dst);
  300. cg.a_reg_dealloc(list,NR_FUNCTION_RESULT_REG);
  301. paraloc2.done;
  302. paraloc1.done;
  303. end
  304. else
  305. begin
  306. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
  307. maybeadjustresult(list,op,size,dst);
  308. end;
  309. end;
  310. end;
  311. procedure tcgrv.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  312. var
  313. href: treference;
  314. b, tmpreg: TRegister;
  315. l: TAsmLabel;
  316. begin
  317. href:=ref;
  318. fixref(list,href);
  319. if (not assigned(href.symbol)) and
  320. (href.offset=0) then
  321. a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
  322. else if (assigned(href.symbol) or
  323. (not is_imm12(href.offset))) and
  324. (href.base<>NR_NO) then
  325. begin
  326. b:= href.base;
  327. current_asmdata.getjumplabel(l);
  328. a_label(list,l);
  329. href.base:=NR_NO;
  330. href.refaddr:=addr_pcrel_hi20;
  331. list.concat(taicpu.op_reg_ref(A_AUIPC,r,href));
  332. reference_reset_symbol(href,l,0,0,ref.volatility);
  333. href.refaddr:=addr_pcrel_lo12;
  334. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,href));
  335. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
  336. end
  337. else if is_imm12(href.offset) and
  338. (href.base<>NR_NO) then
  339. begin
  340. list.concat(taicpu.op_reg_reg_const(A_ADDI,r,href.base,href.offset));
  341. end
  342. else if (href.refaddr=addr_pcrel) then
  343. begin
  344. tmpreg:=getintregister(list,OS_ADDR);
  345. b:=href.base;
  346. href.base:=NR_NO;
  347. current_asmdata.getjumplabel(l);
  348. a_label(list,l);
  349. href.refaddr:=addr_pcrel_hi20;
  350. list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
  351. reference_reset_symbol(href,l,0,0,ref.volatility);
  352. href.refaddr:=addr_pcrel_lo12;
  353. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,tmpreg,href));
  354. if b<>NR_NO then
  355. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
  356. end
  357. else
  358. internalerror(2016060504);
  359. end;
  360. procedure tcgrv.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  361. begin
  362. if a=0 then
  363. a_cmp_reg_reg_label(list,size,cmp_op,NR_X0,reg,l)
  364. else
  365. inherited;
  366. end;
  367. procedure tcgrv.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
  368. var
  369. tmpreg: TRegister;
  370. ai: taicpu;
  371. begin
  372. if TOpCmp2AsmCond[cmp_op]=C_None then
  373. begin
  374. cmp_op:=swap_opcmp(cmp_op);
  375. tmpreg:=reg1;
  376. reg1:=reg2;
  377. reg2:=tmpreg;
  378. end;
  379. ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,reg2,reg1,l,0);
  380. ai.is_jmp:=true;
  381. ai.condition:=TOpCmp2AsmCond[cmp_op];
  382. list.concat(ai);
  383. end;
  384. procedure tcgrv.a_jmp_name(list : TAsmList;const s : string);
  385. var
  386. ai: taicpu;
  387. href: treference;
  388. tmpreg: TRegister;
  389. l: TAsmLabel;
  390. begin
  391. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
  392. tmpreg:=getintregister(list,OS_ADDR);
  393. current_asmdata.getjumplabel(l);
  394. a_label(list,l);
  395. href.refaddr:=addr_pcrel_hi20;
  396. list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
  397. reference_reset_symbol(href,l,0,0,[]);
  398. href.refaddr:=addr_pcrel_lo12;
  399. ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
  400. ai.is_jmp:=true;
  401. list.concat(ai);
  402. //ai:=taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(s));
  403. //ai.is_jmp:=true;
  404. end;
  405. procedure tcgrv.a_jmp_always(list : TAsmList;l: tasmlabel);
  406. var
  407. ai: taicpu;
  408. {href: treference;
  409. tmpreg: TRegister;}
  410. begin
  411. {reference_reset_symbol(href,l,0,0);
  412. tmpreg:=getintregister(list,OS_ADDR);
  413. current_asmdata.getjumplabel(l);
  414. a_label(list,l);
  415. href.refaddr:=addr_pcrel_hi20;
  416. list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
  417. reference_reset_symbol(href,l,0,0);
  418. href.refaddr:=addr_pcrel_lo12;
  419. ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
  420. ai.is_jmp:=true;
  421. list.concat(ai);}
  422. ai:=taicpu.op_reg_sym(A_JAL,NR_X0,l);
  423. ai.is_jmp:=true;
  424. list.concat(ai);
  425. end;
  426. procedure tcgrv.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  427. const
  428. {$ifdef cpu64bitalu}
  429. store_int_op = A_SD;
  430. {$else cpu64bitalu}
  431. store_int_op = A_SW;
  432. {$endif cpu64bitalu}
  433. var
  434. regs, fregs: tcpuregisterset;
  435. r: TSuperRegister;
  436. href: treference;
  437. stackcount, stackAdjust: longint;
  438. begin
  439. if not(nostackframe) then
  440. begin
  441. a_reg_alloc(list,NR_STACK_POINTER_REG);
  442. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  443. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  444. { Int registers }
  445. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  446. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  447. regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
  448. if (pi_do_call in current_procinfo.flags) then
  449. regs:=regs+[RS_RETURN_ADDRESS_REG];
  450. stackcount:=0;
  451. for r:=RS_X0 to RS_X31 do
  452. if r in regs then
  453. inc(stackcount,sizeof(pint));
  454. { Float registers }
  455. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  456. for r:=RS_F0 to RS_F31 do
  457. if r in fregs then
  458. inc(stackcount,8);
  459. inc(localsize,stackcount);
  460. if not is_imm12(-localsize) then
  461. begin
  462. if not (RS_RETURN_ADDRESS_REG in regs) then
  463. begin
  464. include(regs,RS_RETURN_ADDRESS_REG);
  465. inc(localsize,sizeof(pint));
  466. end;
  467. end;
  468. reference_reset_base(href,NR_STACK_POINTER_REG,stackcount,ctempposinvalid,0,[]);
  469. stackAdjust:=0;
  470. if stackcount>0 then
  471. begin
  472. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
  473. stackAdjust:=stackcount;
  474. dec(localsize,stackcount);
  475. end;
  476. for r:=RS_X0 to RS_X31 do
  477. if r in regs then
  478. begin
  479. dec(href.offset,sizeof(pint));
  480. list.concat(taicpu.op_reg_ref(store_int_op,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  481. end;
  482. { Float registers }
  483. for r:=RS_F0 to RS_F31 do
  484. if r in fregs then
  485. begin
  486. dec(href.offset,8);
  487. list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  488. end;
  489. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  490. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
  491. if localsize>0 then
  492. begin
  493. localsize:=align(localsize,sizeof(pint));
  494. if is_imm12(-localsize) then
  495. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
  496. else
  497. begin
  498. a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
  499. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
  500. end;
  501. end;
  502. end;
  503. end;
  504. procedure tcgrv.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  505. const
  506. {$ifdef cpu64bitalu}
  507. load_op = A_LD;
  508. {$else cpu64bitalu}
  509. load_op = A_LW;
  510. {$endif cpu64bitalu}
  511. var
  512. r: tsuperregister;
  513. regs, fregs: tcpuregisterset;
  514. stacksize, localsize, precompensation, postcompensation: longint;
  515. href: treference;
  516. begin
  517. if not(nostackframe) then
  518. begin
  519. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  520. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  521. regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
  522. if (pi_do_call in current_procinfo.flags) then
  523. regs:=regs+[RS_RETURN_ADDRESS_REG];
  524. stacksize:=0;
  525. for r:=RS_X31 downto RS_X0 do
  526. if r in regs then
  527. inc(stacksize,sizeof(pint));
  528. { Float registers }
  529. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  530. for r:=RS_F0 to RS_F31 do
  531. if r in fregs then
  532. inc(stacksize,8);
  533. localsize:=current_procinfo.calc_stackframe_size+stacksize;
  534. if localsize>0 then
  535. begin
  536. localsize:=align(localsize,sizeof(pint));
  537. if not is_imm12(-localsize) then
  538. begin
  539. if not (RS_RETURN_ADDRESS_REG in regs) then
  540. begin
  541. include(regs,RS_RETURN_ADDRESS_REG);
  542. inc(localsize,sizeof(pint));
  543. inc(stacksize,sizeof(pint));
  544. end;
  545. end;
  546. end;
  547. if not is_imm12(localsize) then
  548. begin
  549. precompensation:=localsize-2032;
  550. postcompensation:=localsize-precompensation;
  551. end
  552. else
  553. begin
  554. precompensation:=0;
  555. postcompensation:=localsize;
  556. end;
  557. reference_reset_base(href,NR_STACK_POINTER_REG,postcompensation-stacksize,ctempposinvalid,0,[]);
  558. if precompensation>0 then
  559. begin
  560. if is_imm12(precompensation) then
  561. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,precompensation))
  562. else
  563. begin
  564. { use X12 as temporary register as it is not callee-saved }
  565. a_load_const_reg(list,OS_INT,precompensation,NR_X12);
  566. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_X12));
  567. end;
  568. end;
  569. { Float registers }
  570. for r:=RS_F31 downto RS_F0 do
  571. if r in fregs then
  572. begin
  573. list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  574. inc(href.offset,8);
  575. end;
  576. for r:=RS_X31 downto RS_X0 do
  577. if r in regs then
  578. begin
  579. list.concat(taicpu.op_reg_ref(load_op,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  580. inc(href.offset,sizeof(pint));
  581. end;
  582. if postcompensation>0 then
  583. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,postcompensation));
  584. end;
  585. if (target_info.system in (systems_freertos+systems_embedded)) and (po_interrupt in current_procinfo.procdef.procoptions) then
  586. begin
  587. list.concat(Taicpu.Op_none(A_MRET));
  588. end
  589. else
  590. list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
  591. end;
  592. procedure tcgrv.g_save_registers(list: TAsmList);
  593. begin
  594. end;
  595. procedure tcgrv.g_restore_registers(list: TAsmList);
  596. begin
  597. end;
  598. procedure tcgrv.g_profilecode(list: TAsmList);
  599. begin
  600. if target_info.system in [system_riscv32_linux,system_riscv64_linux] then
  601. begin
  602. list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_X10,NR_RETURN_ADDRESS_REG,0));
  603. a_call_name(list,'_mcount',false);
  604. end
  605. else
  606. internalerror(2018092201);
  607. end;
  608. procedure tcgrv.a_call_reg(list : TAsmList;reg: tregister);
  609. begin
  610. list.concat(taicpu.op_reg_reg(A_JALR,NR_RETURN_ADDRESS_REG,reg));
  611. include(current_procinfo.flags,pi_do_call);
  612. end;
  613. procedure tcgrv.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  614. reg: tregister; const ref: treference);
  615. const
  616. StoreInstr: array[OS_8..OS_INT] of TAsmOp =
  617. (A_SB,A_SH,A_SW
  618. {$ifdef cpu64bitalu}
  619. ,
  620. A_SD
  621. {$endif cpu64bitalu}
  622. );
  623. var
  624. ref2: TReference;
  625. tmpreg: tregister;
  626. op: TAsmOp;
  627. begin
  628. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  629. internalerror(2002090904);
  630. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  631. internalerror(2002090905);
  632. tosize:=tcgsize2unsigned[tosize];
  633. ref2 := ref;
  634. fixref(list, ref2);
  635. op := storeinstr[tcgsize2unsigned[tosize]];
  636. list.concat(taicpu.op_reg_ref(op, reg,ref2));
  637. end;
  638. procedure tcgrv.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  639. var
  640. href: treference;
  641. op: TAsmOp;
  642. tmpreg: TRegister;
  643. begin
  644. href:=ref;
  645. fixref(list,href);
  646. if href.refaddr=addr_pcrel then
  647. begin
  648. tmpreg:=getintregister(list,OS_ADDR);
  649. a_loadaddr_ref_reg(list,href,tmpreg);
  650. reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
  651. end;
  652. case fromsize of
  653. OS_8: op:=A_LBU;
  654. OS_16: op:=A_LHU;
  655. OS_S8: op:=A_LB;
  656. OS_S16: op:=A_LH;
  657. {$ifdef RISCV64}
  658. OS_32: op:=A_LWU;
  659. OS_S32: op:=A_LW;
  660. OS_64,
  661. OS_S64: op:=A_LD;
  662. {$else}
  663. OS_64,OS_S64, { This only happens if tosize is smaller than fromsize }
  664. { We can therefore only consider the low 32-bit of the 64bit value }
  665. OS_32,
  666. OS_S32: op:=A_LW;
  667. {$endif}
  668. else
  669. internalerror(2016060502);
  670. end;
  671. list.concat(taicpu.op_reg_ref(op,reg,href));
  672. if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) then
  673. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  674. end;
  675. procedure tcgrv.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
  676. begin
  677. if a=0 then
  678. a_load_reg_reg(list,size,size,NR_X0,register)
  679. else
  680. begin
  681. if is_imm12(a) then
  682. list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
  683. else if is_lui_imm(a) then
  684. list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
  685. else
  686. begin
  687. if (a and $800)<>0 then
  688. list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
  689. else
  690. list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
  691. list.concat(taicpu.op_reg_reg_const(A_ADDI,register,register,SarSmallint(smallint(a shl 4),4)));
  692. end;
  693. end;
  694. end;
  695. procedure tcgrv.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  696. var
  697. op: TAsmOp;
  698. ai: taicpu;
  699. const
  700. convOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  701. ((A_None,A_FCVT_D_S),
  702. (A_FCVT_S_D,A_None));
  703. begin
  704. if fromsize<>tosize then
  705. begin
  706. list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1));
  707. maybe_check_for_fpu_exception(list);
  708. end
  709. else
  710. begin
  711. if tosize=OS_F32 then
  712. op:=A_FSGNJ_S
  713. else
  714. op:=A_FSGNJ_D;
  715. ai:=taicpu.op_reg_reg_reg(op,reg2,reg1,reg1);
  716. list.concat(ai);
  717. rg[R_FPUREGISTER].add_move_instruction(ai);
  718. end;
  719. end;
  720. procedure tcgrv.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  721. var
  722. href: treference;
  723. op: TAsmOp;
  724. tmpreg: TRegister;
  725. l: TAsmLabel;
  726. begin
  727. href:=ref;
  728. { can we use the fl* rd,symbol,rd pseudoinstruction? }
  729. if (assigned(href.symbol) or (href.offset<>0)) then
  730. begin
  731. if (href.base<>NR_NO) or (href.index<>NR_NO) then
  732. fixref(list,href)
  733. else
  734. href.refaddr:=addr_full;
  735. end
  736. else
  737. fixref(list,href);
  738. if fromsize=OS_F32 then
  739. op:=A_FLW
  740. else if fromsize=OS_F64 then
  741. op:=A_FLD
  742. else if fromsize=OS_F128 then
  743. op:=A_FLQ
  744. else
  745. Internalerror(2025011101);
  746. if href.refaddr in [addr_pcrel,addr_full] then
  747. begin
  748. tmpreg:=getintregister(list,OS_ADDR);
  749. list.concat(taicpu.op_reg_ref_reg(op,reg,href,tmpreg));
  750. end
  751. else
  752. list.concat(taicpu.op_reg_ref(op,reg,href));
  753. if fromsize<>tosize then
  754. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  755. end;
  756. procedure tcgrv.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  757. var
  758. href: treference;
  759. op: TAsmOp;
  760. tmpreg: TRegister;
  761. begin
  762. href:=ref;
  763. fixref(list,href);
  764. if href.refaddr=addr_pcrel then
  765. begin
  766. tmpreg:=getintregister(list,OS_ADDR);
  767. a_loadaddr_ref_reg(list,href,tmpreg);
  768. reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
  769. end;
  770. if fromsize<>tosize then
  771. begin
  772. tmpreg:=getfpuregister(list,tosize);
  773. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  774. reg:=tmpreg;
  775. end;
  776. if tosize=OS_F32 then
  777. op:=A_FSW
  778. else
  779. op:=A_FSD;
  780. list.concat(taicpu.op_reg_ref(op,reg,href));
  781. end;
  782. function tcgrv.fixref(list: TAsmList; var ref: treference): boolean;
  783. var
  784. tmpreg: TRegister;
  785. href: treference;
  786. l: TAsmLabel;
  787. begin
  788. result:=true;
  789. if ref.refaddr=addr_pcrel then
  790. exit;
  791. if assigned(ref.symbol) then
  792. begin
  793. {$ifdef unsed}
  794. { keeping the code for reference
  795. we use the pseudo instruction LA below which is expanded by the assembler, doing
  796. so results in more readable assembler and easier optimization of the assembler code
  797. }
  798. if cs_create_pic in current_settings.moduleswitches then
  799. begin
  800. reference_reset_symbol(href,ref.symbol,0,0,[]);
  801. ref.symbol:=nil;
  802. tmpreg:=getintregister(list,OS_INT);
  803. current_asmdata.getaddrlabel(l);
  804. a_label(list,l);
  805. href.refaddr:=addr_got_pcrel_hi;
  806. list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
  807. reference_reset_symbol(href,l,0,0,[]);
  808. href.refaddr:=addr_pcrel_lo12;
  809. href.base:=tmpreg;
  810. {$ifdef RISCV64}
  811. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,href));
  812. {$else}
  813. list.concat(taicpu.op_reg_ref(A_LW,tmpreg,href));
  814. {$endif}
  815. end
  816. else
  817. begin
  818. reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
  819. ref.symbol:=nil;
  820. ref.offset:=0;
  821. tmpreg:=getintregister(list,OS_INT);
  822. current_asmdata.getaddrlabel(l);
  823. a_label(list,l);
  824. href.refaddr:=addr_pcrel_hi20;
  825. list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
  826. reference_reset_symbol(href,l,0,0,ref.volatility);
  827. href.refaddr:=addr_pcrel_lo12;
  828. list.concat(taicpu.op_reg_reg_ref(A_ADDI,tmpreg,tmpreg,href));
  829. end;
  830. {$endif unsed}
  831. reference_reset_symbol(href,ref.symbol,0,0,[]);
  832. href.refaddr:=addr_full;
  833. ref.symbol:=nil;
  834. tmpreg:=getintregister(list,OS_ADDR);
  835. list.concat(taicpu.op_reg_ref(A_LA,tmpreg,href));
  836. if (ref.index<>NR_NO) and
  837. (ref.base<>NR_NO) then
  838. begin
  839. a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
  840. ref.base:=tmpreg;
  841. end
  842. else if (ref.index=NR_NO) and
  843. (ref.base<>NR_NO) then
  844. ref.index:=tmpreg
  845. else
  846. ref.base:=tmpreg;
  847. end
  848. else if (ref.index=NR_NO) and
  849. (ref.base=NR_NO) then
  850. begin
  851. tmpreg:=getintregister(list,OS_INT);
  852. a_load_const_reg(list, OS_ADDR,ref.offset,tmpreg);
  853. reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
  854. end;
  855. if (ref.index<>NR_NO) and
  856. (ref.base=NR_NO) then
  857. begin
  858. ref.base:=ref.index;
  859. ref.index:=NR_NO;
  860. end;
  861. if not is_imm12(ref.offset) then
  862. begin
  863. tmpreg:=getintregister(list,OS_INT);
  864. a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
  865. ref.offset:=0;
  866. if (ref.index<>NR_NO) and
  867. (ref.base<>NR_NO) then
  868. begin
  869. a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
  870. ref.index:=tmpreg;
  871. end
  872. else
  873. ref.index:=tmpreg;
  874. end;
  875. if (ref.index<>NR_NO) and
  876. (ref.base<>NR_NO) then
  877. begin
  878. tmpreg:=getaddressregister(list);
  879. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  880. ref.base:=tmpreg;
  881. ref.index:=NR_NO;
  882. end;
  883. end;
  884. procedure tcgrv.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
  885. const
  886. overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  887. begin
  888. if (op in overflowops) and
  889. (size in [OS_8,OS_S8,OS_16,OS_S16{$ifdef RISCV64},OS_32,OS_S32{$endif RISCV64}]) then
  890. a_load_reg_reg(list,OS_INT,size,dst,dst)
  891. end;
  892. procedure tcgrv.g_check_for_fpu_exception(list: TAsmList;force,clear : boolean);
  893. var
  894. r : TRegister;
  895. ai: taicpu;
  896. l: TAsmLabel;
  897. begin
  898. if (CPURV_HAS_F in cpu_capabilities[current_settings.cputype]) and
  899. needs_check_for_fpu_exceptions then
  900. begin
  901. r:=getintregister(list,OS_INT);
  902. list.concat(taicpu.op_reg(A_FRFLAGS,r));
  903. current_asmdata.getjumplabel(l);
  904. ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,r,NR_X0,l,0);
  905. ai.is_jmp:=true;
  906. ai.condition:=C_EQ;
  907. list.concat(ai);
  908. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  909. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_THROWFPUEXCEPTION',false);
  910. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  911. a_label(list,l);
  912. end;
  913. end;
  914. end.