cgrv.pas 43 KB

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