cgrv.pas 36 KB

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