cgcpu.pas 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653
  1. {
  2. Copyright (C) 2022 Loongson Technology Corporation Limited.
  3. This unit implements the code generator for the LoongArch64
  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 cgcpu;
  18. {$I fpcdefs.inc}
  19. interface
  20. uses
  21. globtype, symtype, symdef, symsym,
  22. cgbase, cgobj,
  23. aasmbase, aasmcpu, aasmtai,aasmdata,
  24. cpubase, cpuinfo, cgutils, rgcpu,
  25. parabase;
  26. type
  27. tfixref = (
  28. fr_normal, { Normal type, reg + 12i }
  29. fr_big, { Reg + 14i }
  30. fr_reg { Reg + reg }
  31. );
  32. tcgloongarch64 = class(tcg)
  33. public
  34. procedure init_register_allocators; override;
  35. procedure done_register_allocators; override;
  36. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);override;
  37. { call instructions }
  38. procedure a_call_name(list : TAsmList;const s : string; weak: boolean); override;
  39. procedure a_call_reg(list : TAsmList;reg: tregister); override;
  40. { move instructions }
  41. procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
  42. procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override;
  43. procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize; reg: tregister; const ref: treference); override;
  44. procedure a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  45. procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  46. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  47. { bit scan instructions }
  48. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
  49. { fpu move instructions }
  50. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  51. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  52. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  53. { basic arithmetic operations }
  54. procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  55. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  56. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  57. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  58. { comparison operations }
  59. procedure a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  60. procedure a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  61. { jump instructions }
  62. procedure a_jmp_name(list: TAsmList;const s : string); override;
  63. procedure a_jmp_always(list: TAsmList;l: tasmlabel); override;
  64. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  65. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  66. { mem operations }
  67. procedure g_concatcopy(list: TAsmList; const source, dest: treference; len: aint); override;
  68. { overflow check }
  69. procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
  70. { proc entry and exit }
  71. procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); override;
  72. procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
  73. protected
  74. function fixref(list: TAsmList; var ref: treference; mode : tfixref;out tmpreg : tregister): boolean;
  75. procedure ungetregister(r : tregister;list :TAsmList);
  76. procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
  77. end;
  78. procedure create_codegen;
  79. { OP_NONE,OP_MOVE,OP_ADD,OP_AND,OP_DIV,OP_IDIV,OP_IMUL,OP_MUL,OP_NEG,
  80. OP_NOT,OP_OR,OP_SAR,OP_SHL,OP_SHR,OP_SUB,OP_XOR,OP_ROL,OP_ROR }
  81. const
  82. TOpCG2AsmConstOp32: Array[topcg] of TAsmOp = (A_NONE,
  83. A_NONE,A_ADDI_W,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
  84. A_NONE,A_NONE,A_ORI,A_SRAI_W,A_SLLI_W,A_SRLI_W,
  85. A_NONE,A_XORI,A_NONE,A_ROTRI_W);
  86. TOpCG2AsmOp32: Array[topcg] of TAsmOp = (A_NONE,
  87. A_NONE,A_ADD_W,A_AND,A_DIV_WU,A_DIV_W,A_MUL_W,
  88. A_MULW_D_WU,A_NONE,A_NONE,A_OR,A_SRA_W,A_SLL_W,A_SRL_W,
  89. A_SUB_W,A_XOR,A_NONE,A_ROTR_W);
  90. TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
  91. A_NONE,A_ADDI_D,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
  92. A_NONE,A_NONE,A_ORI,A_SRAI_D,A_SLLI_D,A_SRLI_D,
  93. A_NONE,A_XORI,A_NONE,A_ROTRI_D);
  94. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
  95. A_NONE,A_ADD_D,A_AND,A_DIV_DU,A_DIV_D,A_MUL_D,
  96. A_MUL_D,A_NONE,A_NONE,A_OR,A_SRA_D,A_SLL_D,A_SRL_D,
  97. A_SUB_D,A_XOR,A_NONE,A_ROTR_D);
  98. implementation
  99. uses
  100. sysutils, cclasses,
  101. globals, verbose, systems, cutils,
  102. symconst, fmodule, symtable,
  103. rgobj, tgobj, cpupi, procinfo, paramgr, cpupara;
  104. procedure tcgloongarch64.init_register_allocators;
  105. begin
  106. inherited init_register_allocators;
  107. { From GCC REG_ALLOC_ORDER }
  108. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  109. [RS_R12,RS_R13,RS_R14,RS_R16,RS_R16,RS_R17,RS_R18,RS_R19,RS_R20,
  110. RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10,RS_R11,
  111. RS_R1,
  112. RS_R23,RS_R24,RS_R25,RS_R26,RS_R27,RS_R28,RS_R29,RS_R30,RS_R31],first_int_imreg,[]);
  113. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  114. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,RS_F8,
  115. RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,
  116. RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,RS_F24,
  117. RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],first_fpu_imreg,[]);
  118. end;
  119. procedure tcgloongarch64.done_register_allocators;
  120. begin
  121. rg[R_INTREGISTER].free;
  122. rg[R_FPUREGISTER].free;
  123. inherited done_register_allocators;
  124. end;
  125. procedure tcgloongarch64.a_call_reg(list : TAsmList;reg: tregister);
  126. begin
  127. list.concat(taicpu.op_reg_reg_const(A_JIRL,NR_RETURN_ADDRESS_REG,reg,0));
  128. include(current_procinfo.flags,pi_do_call);
  129. end;
  130. procedure tcgloongarch64.a_call_name(list : TAsmList;const s : string; weak: boolean);
  131. var
  132. href: treference;
  133. begin
  134. if not(weak) then
  135. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[])
  136. else
  137. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION),0,0,[]);
  138. if cs_create_pic in current_settings.moduleswitches then
  139. { PIC need using global symbol through GOT. }
  140. begin
  141. href.refaddr:=addr_plt;
  142. list.concat(taicpu.op_ref(A_BL,href));
  143. end
  144. else
  145. begin
  146. if not(weak) then
  147. href.refaddr:=addr_pcrel
  148. else
  149. href.refaddr:=addr_plt;
  150. list.concat(taicpu.op_ref(A_BL,href));
  151. end;
  152. { not assigned while generating external wrappers }
  153. if assigned(current_procinfo) then
  154. include(current_procinfo.flags,pi_do_call);
  155. end;
  156. procedure tcgloongarch64.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
  157. var
  158. tmpref, ref: treference;
  159. tmpreg: tregister;
  160. location: pcgparalocation;
  161. orgsizeleft,
  162. sizeleft: tcgint;
  163. usesize: tcgsize;
  164. reghasvalue: boolean;
  165. begin
  166. location:=cgpara.location;
  167. tmpref:=r;
  168. sizeleft:=cgpara.intsize;
  169. repeat
  170. paramanager.allocparaloc(list,location);
  171. case location^.loc of
  172. LOC_REGISTER,LOC_CREGISTER:
  173. begin
  174. if (size<>OS_NO) and
  175. (tcgsize2size[size]<=sizeof(aint)) then
  176. begin
  177. a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
  178. if location^.shiftval<0 then
  179. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  180. end
  181. { there's a lot more data left, and the current paraloc's
  182. register is entirely filled with part of that data }
  183. else if (sizeleft>sizeof(aint)) then
  184. begin
  185. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  186. end
  187. { we're at the end of the data, and it can be loaded into
  188. the current location's register with a single regular
  189. load }
  190. else if sizeleft in [1,2,4,8] then
  191. begin
  192. a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
  193. if location^.shiftval<0 then
  194. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  195. end
  196. { we're at the end of the data, and we need multiple loads
  197. to get it in the register because it's an irregular size }
  198. else
  199. begin
  200. { should be the last part }
  201. if assigned(location^.next) then
  202. internalerror(2022111934);
  203. { load the value piecewise to get it into the register }
  204. orgsizeleft:=sizeleft;
  205. reghasvalue:=false;
  206. {$ifdef cpu64bitalu}
  207. if sizeleft>=4 then
  208. begin
  209. a_load_ref_reg(list,OS_32,location^.size,tmpref,location^.register);
  210. dec(sizeleft,4);
  211. inc(tmpref.offset,4);
  212. reghasvalue:=true;
  213. end;
  214. {$endif cpu64bitalu}
  215. if sizeleft>=2 then
  216. begin
  217. tmpreg:=getintregister(list,location^.size);
  218. a_load_ref_reg(list,OS_16,location^.size,tmpref,tmpreg);
  219. dec(sizeleft,2);
  220. if reghasvalue then
  221. begin
  222. a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+2))*8,tmpreg);
  223. a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register);
  224. end
  225. else
  226. begin
  227. a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
  228. end;
  229. inc(tmpref.offset,2);
  230. reghasvalue:=true;
  231. end;
  232. if sizeleft=1 then
  233. begin
  234. tmpreg:=getintregister(list,location^.size);
  235. a_load_ref_reg(list,OS_8,location^.size,tmpref,tmpreg);
  236. dec(sizeleft,1);
  237. if reghasvalue then
  238. begin
  239. a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+1))*8,tmpreg);
  240. a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register)
  241. end
  242. else
  243. a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
  244. inc(tmpref.offset);
  245. end;
  246. if location^.shiftval<0 then
  247. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  248. { the loop will already adjust the offset and sizeleft }
  249. dec(tmpref.offset,orgsizeleft);
  250. sizeleft:=orgsizeleft;
  251. end;
  252. end;
  253. LOC_REFERENCE,LOC_CREFERENCE:
  254. begin
  255. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,newalignment(cgpara.alignment,cgpara.intsize-sizeleft),[]);
  256. a_load_ref_cgparalocref(list,size,sizeleft,tmpref,ref,cgpara,location);
  257. end;
  258. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  259. begin
  260. { can be not a float size in case of a record passed in fpu registers }
  261. { the size comparison is to catch F128 passed in two 64 bit floating point registers }
  262. if is_float_cgsize(size) and
  263. (tcgsize2size[location^.size]>=tcgsize2size[size]) then
  264. usesize:=size
  265. else
  266. usesize:=location^.size;
  267. a_loadfpu_ref_reg(list,usesize,location^.size,tmpref,location^.register);
  268. end
  269. else
  270. internalerror(2022111935);
  271. end;
  272. inc(tmpref.offset,tcgsize2size[location^.size]);
  273. dec(sizeleft,tcgsize2size[location^.size]);
  274. location:=location^.next;
  275. until not assigned(location);
  276. end;
  277. procedure tcgloongarch64.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  278. begin
  279. if a=0 then
  280. a_load_reg_ref(list,size,size,NR_R0,ref)
  281. else
  282. inherited a_load_const_ref(list,size,a,ref);
  283. end;
  284. procedure tcgloongarch64.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  285. reg: tregister; const ref: treference);
  286. var
  287. href: treference;
  288. op: TAsmOp;
  289. hlist: TAsmList;
  290. tmpreg : tregister;
  291. const
  292. st_ops: array[boolean,OS_8..OS_INT] of TAsmOp = (
  293. (A_ST_B,A_ST_H,A_ST_W,A_ST_D),
  294. (A_STX_B,A_STX_H,A_STX_W,A_STX_D)
  295. );
  296. stptr_ops: array[OS_8..OS_INT] of TAsmOp = (A_NONE,A_NONE,A_STPTR_W,A_STPTR_D);
  297. begin
  298. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  299. internalerror(2022111936);
  300. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  301. internalerror(2022111937);
  302. hlist:=TAsmList.create;
  303. tosize:=tcgsize2unsigned[tosize];
  304. if stptr_ops[tosize]<>A_NONE then
  305. begin
  306. href:=ref;
  307. if fixref(hlist,href,fr_big,tmpreg) then
  308. begin
  309. list.concatList(hlist);
  310. hlist.free;
  311. list.concat(taicpu.op_reg_ref(stptr_ops[tosize],reg,href));
  312. exit;
  313. end
  314. else
  315. if (tmpreg<>NR_NO) then
  316. ungetregister(tmpreg,hlist);
  317. end;
  318. hlist.Clear;
  319. hlist.free;
  320. href:=ref;
  321. op:=st_ops[fixref(list,href,fr_reg,tmpreg),tosize];
  322. list.concat(taicpu.op_reg_ref(op,reg,href));
  323. end;
  324. procedure tcgloongarch64.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  325. var
  326. href: treference;
  327. op: TAsmOp;
  328. usizef,usizet: tcgsize;
  329. have_done: boolean;
  330. hlist: TAsmList;
  331. samesign: boolean;
  332. tmpreg : tregister;
  333. const
  334. ld_ops: array[boolean,boolean,OS_8..OS_INT] of TAsmOp = (
  335. ((A_LD_B,A_LD_H,A_LD_W,A_LD_D),
  336. (A_LD_BU,A_LD_HU,A_LD_WU,A_LD_D)),
  337. ((A_LDX_B,A_LDX_H,A_LDX_W,A_LDX_D),
  338. (A_LDX_BU,A_LDX_HU,A_LDX_WU,A_LDX_D))
  339. );
  340. begin
  341. tmpreg:=NR_NO;
  342. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  343. internalerror(2022111938);
  344. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  345. internalerror(2022111939);
  346. hlist:=TAsmList.create;
  347. have_done:=false;
  348. usizef:=tcgsize2unsigned[fromsize];
  349. usizet:=tcgsize2unsigned[tosize];
  350. samesign:=((fromsize=usizef) and (tosize=usizet)) or ((fromsize<>usizef) and (tosize<>usizet));
  351. if (fromsize=OS_S32) then
  352. begin
  353. href:=ref;
  354. if fixref(hlist,href,fr_big,tmpreg) then
  355. begin
  356. hlist.concat(taicpu.op_reg_ref(A_LDPTR_W,reg,href));
  357. have_done:=true;
  358. end;
  359. end
  360. else if (fromsize=OS_S64) or (fromsize=OS_64) then
  361. begin
  362. href:=ref;
  363. if fixref(hlist,href,fr_big,tmpreg) then
  364. begin
  365. hlist.concat(taicpu.op_reg_ref(A_LDPTR_D,reg,href));
  366. have_done:=true;
  367. end;
  368. end;
  369. if not(have_done) then
  370. begin
  371. if (tmpreg<>NR_NO) then
  372. ungetregister(tmpreg,hlist);
  373. hlist.Clear;
  374. href:=ref;
  375. op:=ld_ops[fixref(list,href,fr_reg,tmpreg),fromsize=usizef,usizef];
  376. list.concat(taicpu.op_reg_ref(op,reg,href));
  377. end
  378. else
  379. list.concatList(hlist);
  380. hlist.free;
  381. { First, when load a reg to OS_(S)INT, we use signed load operations.
  382. Then, when fromsize is less or equal than tosize, we can not do
  383. a_load_reg_reg because of signed load operations. }
  384. if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) and (not((usizef<=usizet) and samesign)) then
  385. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  386. end;
  387. procedure tcgloongarch64.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
  388. begin
  389. case size of
  390. OS_S8: a:= tcgint(shortint(a));
  391. OS_S16: a:= tcgint(smallint(a));
  392. OS_S32: a:= tcgint(longint(a));
  393. else
  394. ;
  395. end;
  396. list.concat(taicpu.op_reg_const(A_LI_D,register,a));
  397. end;
  398. procedure tcgloongarch64.a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  399. const
  400. zeroextbits: array[OS_8..OS_INT] of longint=(7,15,31,63);
  401. signextop: array[OS_8..OS_INT] of TAsmOp=(A_EXT_W_B,A_EXT_W_H,A_ADDI_W,A_MOVE);
  402. var
  403. ai: taicpu;
  404. ufromsize,utosize: tcgsize;
  405. ufrom,uto : boolean;
  406. begin
  407. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  408. internalerror(2022111940);
  409. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  410. internalerror(2022111941);
  411. ufromsize:=tcgsize2unsigned[fromsize];
  412. utosize:=tcgsize2unsigned[tosize];
  413. ufrom:=ufromsize=fromsize;
  414. uto:=utosize=tosize;
  415. if (ufromsize=OS_INT) and (utosize=OS_INT) then
  416. begin
  417. ai:=taicpu.op_reg_reg(A_MOVE,reg2,reg1);
  418. list.concat(ai);
  419. rg[R_INTREGISTER].add_move_instruction(ai);
  420. end
  421. else if ufromsize>=utosize then
  422. begin
  423. if uto then
  424. list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg1,zeroextbits[utosize],0))
  425. else if utosize=OS_32 then
  426. list.concat(taicpu.op_reg_reg_const(signextop[utosize],reg2,reg1,0))
  427. else
  428. list.concat(taicpu.op_reg_reg(signextop[utosize],reg2,reg1));
  429. end
  430. else { ufromsize<utosize }
  431. begin
  432. if ufrom then
  433. list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg1,zeroextbits[ufromsize],0))
  434. else
  435. begin
  436. if ufromsize=OS_32 then
  437. list.concat(taicpu.op_reg_reg_const(signextop[ufromsize],reg2,reg1,0))
  438. else
  439. list.concat(taicpu.op_reg_reg(signextop[ufromsize],reg2,reg1));
  440. if uto then
  441. list.concat(taicpu.op_reg_reg_const_const(A_BSTRPICK_D,reg2,reg2,zeroextbits[utosize],0));
  442. end;
  443. end;
  444. end;
  445. procedure tcgloongarch64.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  446. var
  447. href: treference;
  448. l: TAsmLabel;
  449. tmpreg : tregister;
  450. begin
  451. href:=ref;
  452. fixref(list,href,fr_normal,tmpreg);
  453. { Fixref, so simplely work here. }
  454. if href.offset=0 then
  455. a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
  456. else if is_simm12(href.offset) and (href.base<>NR_NO) then
  457. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,r,href.base,href.offset))
  458. else
  459. internalerror(2022111942);
  460. end;
  461. procedure tcgloongarch64.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
  462. begin
  463. internalerror(2022111943);
  464. end;
  465. { dstreg = dstreg op imm }
  466. procedure tcgloongarch64.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  467. begin
  468. a_op_const_reg_reg(list,op,size,a,reg,reg);
  469. end;
  470. { dstreg = dstreg op srcreg }
  471. procedure tcgloongarch64.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  472. begin
  473. a_op_reg_reg_reg(list,op,size,src,dst,dst);
  474. end;
  475. procedure tcgloongarch64.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  476. var
  477. tmpreg: TRegister;
  478. usetmp: boolean;
  479. begin
  480. optimize_op_const(size,op,a);
  481. if op=OP_NONE then
  482. begin
  483. a_load_reg_reg(list,size,size,src,dst);
  484. exit;
  485. end;
  486. { Sub const to add -const }
  487. if op=OP_SUB then
  488. begin
  489. op:=OP_ADD;
  490. a:=-a;
  491. end;
  492. { Make sure shift operation const not overflow. }
  493. if op in [OP_SAR,OP_SHL,OP_SHR] then
  494. if (size in [OS_32,OS_S32]) and (a>31) then
  495. a:=31
  496. else if (size in [OS_16,OS_S16]) and (a>15) then
  497. a:=15
  498. else if (size in [OS_8,OS_S8]) and (a>7) then
  499. a:=7
  500. else if (size in [OS_64,OS_S64]) and (a>63) then
  501. a:=63;
  502. { Rotate imm bits left to rotate (size - imm) bits right. }
  503. if op=OP_ROL then
  504. begin
  505. op:=OP_ROR;
  506. if size in [OS_32,OS_S32] then
  507. a:=32-a
  508. else if size in [OS_16,OS_S16] then
  509. a:=16-a
  510. else if size in [OS_8,OS_S8] then
  511. a:=8-a
  512. else
  513. a:=64-a;
  514. end;
  515. { Only effective imm can be used by insn operation. }
  516. if ((is_simm12(a) and (op=OP_ADD)) or
  517. (is_uimm12(a) and (op<>OP_ADD))) and
  518. (TOpCG2AsmConstOp32[op]<>A_NONE)
  519. { or (TOpCG2AsmConstOp[op]<>A_NONE)} then
  520. begin
  521. usetmp:=false;
  522. tmpreg:=getintregister(list,OS_INT);
  523. { Size = 16bits or 8bits do special if rotate. }
  524. if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
  525. begin
  526. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg,src,31,16));
  527. usetmp:=true;
  528. end
  529. else if (size in [OS_8,OS_S8]) and (op=OP_ROR) then
  530. begin
  531. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg,src,15,8));
  532. usetmp:=true;
  533. end
  534. { Signext to 32bits if sra 16bits or 8bits}
  535. else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
  536. begin
  537. a_load_reg_reg(list,size,OS_S32,tmpreg,src);
  538. usetmp:=true;
  539. end;
  540. if size in [OS_64,OS_S64] then
  541. begin
  542. { Use tmp cannot be true here. }
  543. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
  544. maybeadjustresult(list,op,size,dst);
  545. end
  546. else { OS_32/S32, OS_16/S16, OS_8/S8 }
  547. begin
  548. if usetmp then
  549. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,tmpreg,a))
  550. else
  551. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,src,a));
  552. maybeadjustresult(list,op,size,dst);
  553. end;
  554. end
  555. else
  556. begin
  557. tmpreg:=getintregister(list,OS_INT);
  558. a_load_const_reg(list,size,a,tmpreg);
  559. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  560. end;
  561. end;
  562. procedure tcgloongarch64.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  563. var
  564. tmpreg1, tmpreg2: TRegister;
  565. usetmp1, usetmp2: boolean;
  566. begin
  567. usetmp1:=false;
  568. usetmp2:=false;
  569. tmpreg1:=getintregister(list,OS_INT);
  570. tmpreg2:=getintregister(list,OS_INT);
  571. if op=OP_NOT then
  572. begin
  573. list.concat(taicpu.op_reg_reg_reg(A_NOR,dst,NR_R0,src1));
  574. maybeadjustresult(list,op,size,dst);
  575. exit;
  576. end
  577. else if op=OP_NEG then
  578. begin
  579. list.concat(taicpu.op_reg_reg_reg(A_SUB_D,dst,NR_R0,src1));
  580. maybeadjustresult(list,op,size,dst);
  581. exit;
  582. end
  583. else if op=OP_MOVE then
  584. begin
  585. a_load_reg_reg(list,size,size,src1,dst);
  586. exit;
  587. end
  588. else if op=OP_ROL then
  589. begin
  590. list.concat(taicpu.op_reg_reg_reg(A_SUB_D,tmpreg1,NR_R0,src1));
  591. usetmp1:=true;
  592. op:=OP_ROR;
  593. end;
  594. if (TOpCG2AsmOp32[op]<>A_NONE) {or (TOpCG2AsmConstOp[op]<>A_NONE)} then
  595. begin
  596. { Size = 16bits or 8bits do special if rotate. }
  597. if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
  598. begin
  599. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,31,16));
  600. usetmp2:=true;
  601. end
  602. else if (size in [OS_8,OS_S8]) and (op=OP_ROR) then
  603. begin
  604. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,15,8));
  605. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,tmpreg2,31,16));
  606. usetmp2:=true;
  607. end
  608. { Signext to 32bits if sra 16bits or 8bits}
  609. else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
  610. begin
  611. a_load_reg_reg(list,size,OS_S32,src2,tmpreg2);
  612. usetmp2:=true;
  613. end;
  614. if size in [OS_64,OS_S64] then
  615. begin
  616. { usetmp2 cannot be true here. }
  617. if usetmp1 then
  618. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,tmpreg1))
  619. else
  620. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
  621. maybeadjustresult(list,op,size,dst);
  622. end
  623. else
  624. begin
  625. if usetmp1 and usetmp2 then
  626. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,tmpreg1))
  627. else if usetmp1 then
  628. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,tmpreg1))
  629. else if usetmp2 then
  630. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,src1))
  631. else
  632. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,src1));
  633. maybeadjustresult(list,op,size,dst);
  634. end;
  635. end;
  636. end;
  637. procedure tcgloongarch64.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  638. var
  639. tmpreg: tregister;
  640. begin
  641. if a = 0 then
  642. a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
  643. else
  644. begin
  645. tmpreg := GetIntRegister(list,OS_INT);
  646. a_load_const_reg(list,OS_INT,a,tmpreg);
  647. a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
  648. end;
  649. end;
  650. procedure tcgloongarch64.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
  651. const
  652. { OC_NONE,OC_EQ,OC_GT,OC_LT,OC_GTE,OC_LTE,OC_NE,OC_BE,OC_B,OC_AE,OC_A }
  653. TOpCmp2AsmCond: Array[TOpCmp] of TAsmCond = (C_NONE,
  654. C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU);
  655. TOpCmp2AsmCondZ: Array[TOpCmp] of TAsmCond = (C_NONE,
  656. C_EQZ,C_GTZ,C_LTZ,C_GEZ,C_LEZ,C_NEZ,C_NONE,C_NONE,C_NONE,C_NONE);
  657. var
  658. href: treference;
  659. ai: taicpu;
  660. begin
  661. reference_reset_symbol(href,l,0,0,[]);
  662. { It is better to use pcrel instead addr_b16 or addr_b21,
  663. because we hardly know the real op after optimizing. }
  664. href.refaddr:=addr_pcrel;
  665. if (reg1=NR_R0) or (reg2=NR_R0) then
  666. begin
  667. if (reg1=NR_R0) and (reg2=NR_R0) then
  668. begin
  669. a_jmp_always(list,l);
  670. exit;
  671. end
  672. else if reg2=NR_R0 then
  673. begin
  674. reg2:=reg1;
  675. reg1:=NR_R0;
  676. cmp_op:=swap_opcmp(cmp_op);
  677. end;
  678. if TOpCmp2AsmCondZ[cmp_op]<>C_NONE then
  679. begin
  680. ai:=taicpu.op_reg_ref(A_BXX,reg2,href);
  681. ai.is_jmp:=true;
  682. ai.condition:=TOpCmp2AsmCondZ[cmp_op];
  683. list.concat(ai);
  684. exit;
  685. end;
  686. end;
  687. ai:=taicpu.op_reg_reg_ref(A_BXX,reg2,reg1,href);
  688. ai.is_jmp:=true;
  689. ai.condition:=TOpCmp2AsmCond[cmp_op];
  690. list.concat(ai);
  691. end;
  692. procedure tcgloongarch64.a_jmp_name(list : TAsmList;const s : string);
  693. var
  694. ai: taicpu;
  695. href: treference;
  696. begin
  697. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
  698. href.refaddr:=addr_b26;
  699. ai:=taicpu.op_ref(A_B,href);
  700. ai.is_jmp:=true;
  701. list.concat(ai);
  702. end;
  703. procedure tcgloongarch64.a_jmp_always(list : TAsmList;l: tasmlabel);
  704. var
  705. ai: taicpu;
  706. href: treference;
  707. begin
  708. reference_reset_symbol(href,l,0,0,[]);
  709. href.refaddr:=addr_b26;
  710. ai:=taicpu.op_ref(A_B,href);
  711. ai.is_jmp:=true;
  712. list.concat(ai);
  713. end;
  714. procedure tcgloongarch64.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  715. var
  716. op: TAsmOp;
  717. ai: taicpu;
  718. const
  719. FpuConvOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  720. ((A_FMOV_S,A_FCVT_D_S),(A_FCVT_S_D,A_FMOV_D));
  721. begin
  722. if (reg1<>reg2) or (fromsize<>tosize) then
  723. begin
  724. ai:= taicpu.op_reg_reg(fpuconvop[fromsize,tosize],reg2,reg1);
  725. list.concat(ai);
  726. if (fromsize=tosize) then
  727. rg[R_FPUREGISTER].add_move_instruction(ai);
  728. end;
  729. end;
  730. procedure tcgloongarch64.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  731. var
  732. op: TAsmOp;
  733. href: treference;
  734. tmpreg : tregister;
  735. const
  736. fld_ops: array[boolean,boolean] of TAsmOp = (
  737. (A_FLD_D, A_FLD_S),
  738. (A_FLDX_D, A_FLDX_S)
  739. );
  740. begin
  741. href:=ref;
  742. op:=fld_ops[fixref(list,href,fr_reg,tmpreg),fromsize=OS_F32];
  743. list.concat(taicpu.op_reg_ref(op,reg,href));
  744. if fromsize<>tosize then
  745. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  746. end;
  747. procedure tcgloongarch64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  748. var
  749. op: TAsmOp;
  750. tmpfreg: TRegister;
  751. href: treference;
  752. tmpreg : tregister;
  753. fst_ops: array[boolean,boolean] of TAsmOp = (
  754. (A_FST_D, A_FST_S),
  755. (A_FSTX_D, A_FSTX_S)
  756. );
  757. begin
  758. if fromsize<>tosize then
  759. begin
  760. tmpfreg:=getfpuregister(list,tosize);
  761. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpfreg);
  762. reg:=tmpfreg;
  763. end;
  764. href:=ref;
  765. op:=fst_ops[fixref(list,href,fr_reg,tmpreg),tosize=OS_F32];
  766. list.concat(taicpu.op_reg_ref(op,reg,href));
  767. end;
  768. procedure tcgloongarch64.g_concatcopy(list: TAsmList; const source, dest: treference; len: aint);
  769. var
  770. tmpreg,countreg: TRegister;
  771. src,dst: TReference;
  772. lab: tasmlabel;
  773. len_8,tmplen: longint;
  774. len_1,len_2,len_4: boolean;
  775. begin
  776. { Size is zero }
  777. if len=0 then
  778. exit;
  779. { It's too large or illegal. }
  780. if len>high(longint) then
  781. internalerror(2022111944);
  782. { len = d*8(+4?)(+2?)(+1?). }
  783. len_8:=len div 8;
  784. tmplen:=len-len_8*8;
  785. len_1:=(tmplen and 1)<>0;
  786. len_2:=(tmplen and 2)<>0;
  787. len_4:=(tmplen and 4)<>0;
  788. { Set the reference. }
  789. reference_reset(src,sizeof(aint),[]);
  790. reference_reset(dst,sizeof(aint),[]);
  791. src.base:=GetAddressRegister(list);
  792. dst.base:=GetAddressRegister(list);
  793. src.refaddr:=addr_reg_12i;
  794. dst.refaddr:=addr_reg_12i;
  795. a_loadaddr_ref_reg(list,source,src.base);
  796. a_loadaddr_ref_reg(list,dest,dst.base);
  797. tmpreg:= GetIntRegister(list, OS_INT);
  798. { TODO Some optimization. }
  799. if len_8>0 then
  800. begin
  801. current_asmdata.getjumplabel(lab);
  802. countreg := GetIntRegister(list,OS_INT);
  803. if len_8>1 then
  804. begin
  805. a_load_const_reg(list,OS_INT,len_8,countreg);
  806. a_label(list, lab);
  807. end;
  808. list.concat(taicpu.op_reg_ref(A_LD_D,tmpreg,src));
  809. list.concat(taicpu.op_reg_ref(A_ST_D,tmpreg,dst));
  810. if len_1 or len_2 or len_4 or (len_8>1) then
  811. begin
  812. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,src.base,src.base,8));
  813. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst.base,dst.base,8));
  814. end;
  815. if len_8>1 then
  816. begin
  817. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,countreg,countreg,-1));
  818. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  819. end;
  820. end; { len_8>0 }
  821. if len_4 then
  822. begin
  823. list.concat(taicpu.op_reg_ref(A_LD_W,tmpreg,src));
  824. list.concat(taicpu.op_reg_ref(A_ST_W,tmpreg,dst));
  825. inc(src.offset,4);
  826. inc(dst.offset,4);
  827. end;
  828. if len_2 then
  829. begin
  830. list.concat(taicpu.op_reg_ref(A_LD_H,tmpreg,src));
  831. list.concat(taicpu.op_reg_ref(A_ST_H,tmpreg,dst));
  832. inc(src.offset,2);
  833. inc(dst.offset,2);
  834. end;
  835. if len_1 then
  836. begin
  837. list.concat(taicpu.op_reg_ref(A_LD_B,tmpreg,src));
  838. list.concat(taicpu.op_reg_ref(A_ST_B,tmpreg,dst));
  839. end;
  840. end;
  841. procedure tcgloongarch64.g_overflowcheck(list: TAsmList; const loc: tlocation; def: tdef);
  842. begin
  843. { TODO }
  844. { internalerror(2022111945); }
  845. end;
  846. procedure tcgloongarch64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  847. var
  848. regs, fregs: tcpuregisterset;
  849. r: TSuperRegister;
  850. href: treference;
  851. stackcount, stackAdjust: longint;
  852. begin
  853. if not(nostackframe) then
  854. begin
  855. a_reg_alloc(list,NR_STACK_POINTER_REG);
  856. { Always use $fp. }
  857. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  858. { Int registers }
  859. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  860. regs:=regs+[RS_FRAME_POINTER_REG];
  861. { Does it call another function? }
  862. if (pi_do_call in current_procinfo.flags) or
  863. (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
  864. regs:=regs+[RS_RETURN_ADDRESS_REG];
  865. { Float registers }
  866. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  867. { Calculate the stackcount of all regesters. }
  868. stackcount:=16;
  869. for r:=RS_R1 to RS_R31 do
  870. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  871. inc(stackcount,8);
  872. for r:=RS_F0 to RS_F31 do
  873. if r in fregs then
  874. inc(stackcount,8);
  875. { Calculate the frame total size. }
  876. inc(localsize,stackcount);
  877. if localsize=0 then
  878. exit;
  879. { ADDI instructions only has 12bits-sign-imm range, [-2048,2047]. Once we
  880. use -2048 in the prologue, we cannot get back in epilogue use one ADDI.
  881. Due to LoongArch psABI, we should save the $ra and then use it as free.
  882. We should make $fp as $fp on entry, so ADDI cannot do 2048 size. It
  883. seems use -2032 may a good choice without care of many of cases. }
  884. if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
  885. begin
  886. regs:=regs+[RS_RETURN_ADDRESS_REG];
  887. inc(localsize,8);
  888. inc(stackcount,8);
  889. end;
  890. if (localsize mod 16)<>0 then
  891. inc(localsize,16-(localsize mod 16));
  892. { Do first decrease the stack, and record the stackadjust. }
  893. stackadjust:=0;
  894. if (-localsize<-2032) then
  895. begin
  896. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-2032));
  897. reference_reset_base(href,NR_STACK_POINTER_REG,2032-8,ctempposinvalid,0,[]);
  898. href.refaddr:=addr_reg_12i;
  899. stackadjust:=2032;
  900. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2032);
  901. end
  902. else
  903. begin
  904. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize));
  905. reference_reset_base(href,NR_STACK_POINTER_REG,localsize-8,ctempposinvalid,0,[]);
  906. href.refaddr:=addr_reg_12i;
  907. stackadjust:=localsize;
  908. current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize);
  909. end;
  910. { $ra in cfa -8. }
  911. if RS_RETURN_ADDRESS_REG in regs then
  912. begin
  913. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
  914. current_asmdata.asmcfi.cfa_offset(list,NR_RETURN_ADDRESS_REG,-8);
  915. end;
  916. { $fp in cfa -16. }
  917. dec(href.offset,8);
  918. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
  919. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-16);
  920. { $fp = cfa. }
  921. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackadjust));
  922. current_asmdata.asmcfi.cfa_def_cfa(list,NR_FRAME_POINTER_REG,0);
  923. { Int registers }
  924. for r:=RS_R1 to RS_R31 do
  925. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  926. begin
  927. dec(href.offset,8);
  928. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  929. current_asmdata.asmcfi.cfa_offset(list,newreg(R_INTREGISTER,r,R_SUBWHOLE),href.offset-stackadjust);
  930. end;
  931. { Float registers }
  932. for r:=RS_F0 to RS_F31 do
  933. if r in fregs then
  934. begin
  935. dec(href.offset,8);
  936. list.concat(taicpu.op_reg_ref(A_FST_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  937. current_asmdata.asmcfi.cfa_offset(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href.offset);
  938. end;
  939. { Decrese the remaining stack size. }
  940. if (localsize-stackadjust)>2048 then
  941. begin
  942. a_load_const_reg(list,OS_INT,localsize-stackadjust,NR_RETURN_ADDRESS_REG);
  943. list.concat(taicpu.op_reg_reg_reg(A_SUB_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
  944. end
  945. else if (localsize-stackadjust)>0 then
  946. begin
  947. { TODO It seems to no need $ra. }
  948. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackadjust-localsize));
  949. end;
  950. end;
  951. end; { g_proc_entry }
  952. procedure tcgloongarch64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  953. var
  954. r: tsuperregister;
  955. regs, fregs: tcpuregisterset;
  956. stackcount, localsize, stackleft: longint;
  957. href: treference;
  958. begin
  959. if not(nostackframe) then
  960. begin
  961. localsize:=current_procinfo.calc_stackframe_size;
  962. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  963. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  964. regs:=regs+[RS_FRAME_POINTER_REG];
  965. if (pi_do_call in current_procinfo.flags) or
  966. (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
  967. regs:=regs+[RS_RETURN_ADDRESS_REG];
  968. stackcount:=16;
  969. for r:=RS_R1 to RS_R31 do
  970. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  971. inc(stackcount,8);
  972. for r:=RS_F0 to RS_F31 do
  973. if r in fregs then
  974. inc(stackcount,8);
  975. inc(localsize,stackcount);
  976. if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
  977. begin
  978. regs:=regs+[RS_RETURN_ADDRESS_REG];
  979. inc(localsize,8);
  980. inc(stackcount,8);
  981. end;
  982. if (localsize mod 16)<>0 then
  983. inc(localsize,16-(localsize mod 16));
  984. stackleft:=0;
  985. if (-localsize<-2032) then
  986. stackleft:=2032
  987. else
  988. stackleft:=localsize;
  989. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,-stackleft));
  990. reference_reset_base(href,NR_STACK_POINTER_REG,stackleft-8,ctempposinvalid,0,[]);
  991. href.refaddr:=addr_reg_12i;
  992. { Restore registers. }
  993. if RS_RETURN_ADDRESS_REG in regs then
  994. begin
  995. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
  996. current_asmdata.asmcfi.cfa_restore(list,NR_RETURN_ADDRESS_REG);
  997. end;
  998. dec(href.offset,8);
  999. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
  1000. current_asmdata.asmcfi.cfa_restore(list,NR_FRAME_POINTER_REG);
  1001. current_asmdata.asmcfi.cfa_def_cfa(list,NR_STACK_POINTER_REG,stackleft);
  1002. for r:=RS_R1 to RS_R31 do
  1003. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  1004. begin
  1005. dec(href.offset,8);
  1006. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  1007. current_asmdata.asmcfi.cfa_restore(list,newreg(R_INTREGISTER,r,R_SUBWHOLE));
  1008. end;
  1009. for r:=RS_F0 to RS_F31 do
  1010. if r in fregs then
  1011. begin
  1012. dec(href.offset,8);
  1013. list.concat(taicpu.op_reg_ref(A_FLD_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  1014. current_asmdata.asmcfi.cfa_restore(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE));
  1015. end;
  1016. { Restore $sp. }
  1017. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackleft));
  1018. end;
  1019. { jr $ra. }
  1020. reference_reset_base(href,NR_RETURN_ADDRESS_REG,0,ctempposinvalid,0,[]);
  1021. href.refaddr:=addr_reg;
  1022. list.concat(taicpu.op_ref(A_JR,href));
  1023. end; { g_proc_exit }
  1024. procedure tcgloongarch64.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1025. var
  1026. signed: Boolean;
  1027. l: TAsmLabel;
  1028. tmpreg: tregister;
  1029. ai: taicpu;
  1030. href: treference;
  1031. tmpreg0,tmpreg1: tregister;
  1032. begin
  1033. if setflags then
  1034. begin
  1035. if is_simm12(a) and (op=OP_ADD) then
  1036. begin
  1037. current_asmdata.getjumplabel(l);
  1038. reference_reset_symbol(href,l,0,0,[]);
  1039. href.refaddr:=addr_pcrel;
  1040. tmpreg1:=getintregister(list,OS_INT);
  1041. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1042. begin
  1043. { Backup src so we can compare with it. }
  1044. a_load_reg_reg(list,OS_INT,OS_INT,src,tmpreg1);
  1045. end;
  1046. if size in [OS_64,OS_S64] then
  1047. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst,src,a))
  1048. else
  1049. list.concat(taicpu.op_reg_reg_const(A_ADDI_W,dst,src,a));
  1050. case size of
  1051. OS_S64,OS_S32:
  1052. begin
  1053. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
  1054. if a<0 then
  1055. ai.condition:=C_LT
  1056. else
  1057. ai.condition:=C_GE;
  1058. end;
  1059. OS_S16,OS_S8:
  1060. begin
  1061. tmpreg0:=getintregister(list,OS_INT);
  1062. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1063. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1064. ai.condition:=C_EQ;
  1065. end;
  1066. OS_64,OS_32:
  1067. begin
  1068. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
  1069. ai.condition:=C_GEU;
  1070. end;
  1071. OS_16,OS_8:
  1072. begin
  1073. tmpreg0:=getintregister(list,OS_INT);
  1074. if size=OS_16 then
  1075. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1076. else
  1077. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1078. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1079. ai.condition:=C_GTU;
  1080. end;
  1081. else
  1082. internalerror(2022082303);
  1083. end;
  1084. ai.is_jmp:=true;
  1085. list.concat(ai);
  1086. a_call_name(list,'FPC_OVERFLOW',false);
  1087. a_label(list,l);
  1088. end
  1089. else if op in [OP_ADD,OP_SUB,OP_MUL,OP_IMUL,OP_IDIV] then
  1090. begin
  1091. tmpreg:=getintregister(list,size);
  1092. a_load_const_reg(list,size,a,tmpreg);
  1093. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  1094. end
  1095. else
  1096. internalerror(2022082302);
  1097. end
  1098. else
  1099. a_op_const_reg_reg(list,op,size,a,src,dst);
  1100. end;
  1101. procedure tcgloongarch64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1102. var
  1103. signed: Boolean;
  1104. l: TAsmLabel;
  1105. tmpreg0,tmpreg1,tmpreg2,tmpreg3: tregister;
  1106. ai: taicpu;
  1107. href: treference;
  1108. begin
  1109. signed:=tcgsize2unsigned[size]<>size;
  1110. if setflags then
  1111. case op of
  1112. OP_ADD:
  1113. begin
  1114. current_asmdata.getjumplabel(l);
  1115. reference_reset_symbol(href,l,0,0,[]);
  1116. href.refaddr:=addr_pcrel;
  1117. tmpreg2:=getintregister(list,OS_INT);
  1118. tmpreg3:=getintregister(list,OS_INT);
  1119. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1120. begin
  1121. { Backup src so we can compare with it. }
  1122. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1123. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1124. end;
  1125. if size in [OS_S64,OS_64] then
  1126. list.Concat(taicpu.op_reg_reg_reg(A_ADD_D,dst,src2,src1))
  1127. else
  1128. list.Concat(taicpu.op_reg_reg_reg(A_ADD_W,dst,src2,src1));
  1129. case size of
  1130. OS_S64,OS_S32:
  1131. begin
  1132. { if (src1<0)<>(dst<src2) overflow; }
  1133. tmpreg0:=getintregister(list,OS_INT);
  1134. tmpreg1:=getintregister(list,OS_INT);
  1135. list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg0,tmpreg2,0));
  1136. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
  1137. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1138. ai.condition:=C_EQ;
  1139. end;
  1140. OS_S16,OS_S8:
  1141. begin
  1142. tmpreg0:=getintregister(list,OS_INT);
  1143. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1144. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1145. ai.condition:=C_EQ;
  1146. end;
  1147. OS_64,OS_32:
  1148. begin
  1149. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
  1150. ai.condition:=C_GEU;
  1151. end;
  1152. OS_16,OS_8:
  1153. begin
  1154. tmpreg0:=getintregister(list,OS_INT);
  1155. if size=OS_16 then
  1156. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1157. else
  1158. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1159. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1160. ai.condition:=C_GTU;
  1161. end;
  1162. else
  1163. internalerror(2022082304);
  1164. end;
  1165. ai.is_jmp:=true;
  1166. list.concat(ai);
  1167. a_call_name(list,'FPC_OVERFLOW',false);
  1168. a_label(list,l);
  1169. end;
  1170. OP_SUB:
  1171. begin
  1172. current_asmdata.getjumplabel(l);
  1173. reference_reset_symbol(href,l,0,0,[]);
  1174. href.refaddr:=addr_pcrel;
  1175. tmpreg2:=getintregister(list,OS_INT);
  1176. tmpreg3:=getintregister(list,OS_INT);
  1177. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1178. begin
  1179. { Backup src so we can compare with it. }
  1180. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1181. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1182. end;
  1183. if size in [OS_S64,OS_64] then
  1184. list.Concat(taicpu.op_reg_reg_reg(A_SUB_D,dst,src2,src1))
  1185. else
  1186. list.Concat(taicpu.op_reg_reg_reg(A_SUB_W,dst,src2,src1));
  1187. case size of
  1188. OS_S64,OS_S32:
  1189. begin
  1190. { if (src1<0)<>(dst<src2) overflow; }
  1191. tmpreg0:=getintregister(list,OS_INT);
  1192. tmpreg1:=getintregister(list,OS_INT);
  1193. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_R0,tmpreg2));
  1194. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
  1195. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1196. ai.condition:=C_EQ;
  1197. end;
  1198. OS_S16,OS_S8:
  1199. begin
  1200. tmpreg0:=getintregister(list,OS_INT);
  1201. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1202. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1203. ai.condition:=C_EQ;
  1204. end;
  1205. OS_64,OS_32:
  1206. begin
  1207. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg3,dst,href);
  1208. ai.condition:=C_GEU;
  1209. end;
  1210. OS_16,OS_8:
  1211. begin
  1212. tmpreg0:=getintregister(list,OS_INT);
  1213. if size=OS_16 then
  1214. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1215. else
  1216. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1217. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1218. ai.condition:=C_GTU;
  1219. end;
  1220. else
  1221. internalerror(2022082305);
  1222. end;
  1223. ai.is_jmp:=true;
  1224. list.concat(ai);
  1225. a_call_name(list,'FPC_OVERFLOW',false);
  1226. a_label(list,l);
  1227. end;
  1228. OP_IMUL:
  1229. begin
  1230. { No overflow if upper result is same as sign of result }
  1231. current_asmdata.getjumplabel(l);
  1232. reference_reset_symbol(href,l,0,0,[]);
  1233. href.refaddr:=addr_pcrel;
  1234. tmpreg0:=getintregister(list,OS_INT);
  1235. tmpreg1:=getintregister(list,OS_INT);
  1236. if size in [OS_S64,OS_64] then
  1237. begin
  1238. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
  1239. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
  1240. list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
  1241. list.Concat(taicpu.op_reg_reg_reg(A_MULH_D,tmpreg0,tmpreg0,tmpreg1));
  1242. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg1,dst,63));
  1243. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1244. ai.condition:=C_EQ;
  1245. end
  1246. else
  1247. begin
  1248. list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_W,dst,src1,src2));
  1249. case size of
  1250. OS_S32,OS_32:
  1251. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
  1252. OS_S16,OS_16:
  1253. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
  1254. OS_S8,OS_8:
  1255. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
  1256. else
  1257. internalerror(2022082306);
  1258. end;
  1259. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,tmpreg0,tmpreg0,1));
  1260. list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg1,tmpreg0,2));
  1261. ai:=taicpu.op_reg_ref(A_BXX,tmpreg1,href);
  1262. ai.condition:=C_NEZ;
  1263. end;
  1264. ai.is_jmp:=true;
  1265. list.concat(ai);
  1266. a_call_name(list,'FPC_OVERFLOW',false);
  1267. a_label(list,l);
  1268. end;
  1269. OP_MUL:
  1270. begin
  1271. { No overflow if upper result is 0 }
  1272. current_asmdata.getjumplabel(l);
  1273. reference_reset_symbol(href,l,0,0,[]);
  1274. href.refaddr:=addr_pcrel;
  1275. tmpreg0:=getintregister(list,OS_INT);
  1276. if size in [OS_S64,OS_64] then
  1277. begin
  1278. tmpreg1:=getintregister(list,OS_INT);
  1279. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
  1280. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
  1281. list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
  1282. list.Concat(taicpu.op_reg_reg_reg(A_MULH_DU,tmpreg0,tmpreg0,tmpreg1));
  1283. ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
  1284. ai.condition:=C_EQZ;
  1285. end
  1286. else
  1287. begin
  1288. list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_WU,dst,src1,src2));
  1289. case size of
  1290. OS_S32,OS_32:
  1291. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
  1292. OS_S16,OS_16:
  1293. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
  1294. OS_S8,OS_8:
  1295. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
  1296. else
  1297. internalerror(2022082307);
  1298. end;
  1299. ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
  1300. ai.condition:=C_EQZ;
  1301. end;
  1302. ai.is_jmp:=true;
  1303. list.concat(ai);
  1304. a_call_name(list,'FPC_OVERFLOW',false);
  1305. a_label(list,l);
  1306. end;
  1307. OP_IDIV:
  1308. begin
  1309. { Only overflow if -2^(N-1)/(-1) }
  1310. current_asmdata.getjumplabel(l);
  1311. reference_reset_symbol(href,l,0,0,[]);
  1312. href.refaddr:=addr_pcrel;
  1313. tmpreg2:=getintregister(list,OS_INT);
  1314. tmpreg3:=getintregister(list,OS_INT);
  1315. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1316. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1317. if size in [OS_S64,OS_64] then
  1318. list.Concat(taicpu.op_reg_reg_reg(A_DIV_D,dst,src1,src2))
  1319. else
  1320. list.Concat(taicpu.op_reg_reg_reg(A_DIV_W,dst,src1,src2));
  1321. if size in [OS_S64,OS_64,OS_S32,OS_32] then
  1322. begin
  1323. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
  1324. ai.condition:=C_NE;
  1325. ai.is_jmp:=true;
  1326. list.concat(ai);
  1327. ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
  1328. ai.condition:=C_GEZ;
  1329. ai.is_jmp:=true;
  1330. list.concat(ai);
  1331. end
  1332. else
  1333. begin
  1334. ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
  1335. ai.condition:=C_GEZ;
  1336. ai.is_jmp:=true;
  1337. list.concat(ai);
  1338. tmpreg0:=getintregister(list,OS_INT);
  1339. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1340. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg3,href);
  1341. ai.condition:=C_NE;
  1342. ai.is_jmp:=true;
  1343. list.concat(ai);
  1344. end;
  1345. a_call_name(list,'FPC_OVERFLOW',false);
  1346. a_label(list,l);
  1347. end;
  1348. else
  1349. internalerror(2022082301);
  1350. end
  1351. else
  1352. a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1353. end;
  1354. procedure tcgloongarch64.ungetregister(r : tregister;list : TAsmList);
  1355. var
  1356. supreg : tsuperregister;
  1357. rt : tregistertype;
  1358. live : tai;
  1359. function is_in_list(t : tai;hlist : TAsmList) : boolean;
  1360. var
  1361. current : tai;
  1362. begin
  1363. result:=false;
  1364. if not assigned(t) then
  1365. exit;
  1366. current:=tai(hlist.first);
  1367. while assigned(current) do
  1368. begin
  1369. if (current=t) then
  1370. begin
  1371. result:=true;
  1372. exit;
  1373. end
  1374. else
  1375. current:=tai(current.next);
  1376. end;
  1377. end;
  1378. begin
  1379. if not assigned(list) then
  1380. exit;
  1381. supreg:=getsupreg(r);
  1382. rt:=getregtype(r);
  1383. if assigned(rg[rt]) then
  1384. begin
  1385. if is_in_list(rg[rt].live_start[supreg],list) then
  1386. rg[rt].live_start[supreg]:=nil;
  1387. if is_in_list(rg[rt].live_end[supreg],list) then
  1388. rg[rt].live_end[supreg]:=nil;
  1389. end;
  1390. end;
  1391. function tcgloongarch64.fixref(list: TAsmList; var ref: treference; mode : tfixref; out tmpreg : tregister): boolean;
  1392. var
  1393. href: treference;
  1394. begin
  1395. tmpreg:=NR_NO;
  1396. if ref.refaddr=addr_reg_12i then
  1397. begin
  1398. result:=mode=fr_normal;
  1399. exit;
  1400. end
  1401. else if ref.refaddr=addr_reg_reg then
  1402. begin
  1403. result:=mode=fr_reg;
  1404. exit;
  1405. end
  1406. else if ref.refaddr=addr_reg_reg then
  1407. begin
  1408. result:=mode=fr_big;
  1409. exit;
  1410. end;
  1411. { Reference with symbol, load symbol address first. }
  1412. if assigned(ref.symbol) then
  1413. begin
  1414. tmpreg:=getintregister(list,OS_INT);
  1415. if ((cs_create_pic in current_settings.moduleswitches) and
  1416. (ref.symbol.bind in [AB_LOCAL,AB_TEMP])) or
  1417. ((not(cs_create_pic in current_settings.moduleswitches)) and
  1418. (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL,AB_TEMP])) then
  1419. begin
  1420. { Load symbol address as local. }
  1421. reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
  1422. ref.symbol:=nil;
  1423. ref.offset:=0;
  1424. href.refaddr:=addr_pc_hi20;
  1425. list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
  1426. href.refaddr:=addr_pc_lo12;
  1427. list.concat(taicpu.op_reg_reg_ref(A_ADDI_D,tmpreg,tmpreg,href));
  1428. end
  1429. else
  1430. begin
  1431. { Load symbol address as global. }
  1432. reference_reset_symbol(href,ref.symbol,0,0,[]);
  1433. ref.symbol:=nil;
  1434. href.refaddr:=addr_got_pc_hi20;
  1435. list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
  1436. href.refaddr:=addr_got_pc_lo12;
  1437. list.concat(taicpu.op_reg_reg_ref(A_LD_D,tmpreg,tmpreg,href));
  1438. end;
  1439. { Make address format become basereg (+indexreg). }
  1440. if (ref.index<>NR_NO) and (ref.base<>NR_NO) then
  1441. begin
  1442. a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
  1443. ref.base:=tmpreg;
  1444. end
  1445. else if (ref.base=NR_NO) then
  1446. ref.base:=tmpreg
  1447. else { ref.index=NR_NO }
  1448. ref.index:=tmpreg;
  1449. end
  1450. { Refernce only offset, make offset become a reg. }
  1451. else if (ref.index=NR_NO) and (ref.base=NR_NO) then
  1452. begin
  1453. tmpreg:=getintregister(list,OS_INT);
  1454. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  1455. reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
  1456. ref.index:=NR_R0;
  1457. end;
  1458. if (ref.index<>NR_NO) and (ref.base=NR_NO) then
  1459. begin
  1460. ref.base:=ref.index;
  1461. ref.index:=NR_R0;
  1462. end;
  1463. if (ref.index=NR_NO) then
  1464. ref.index:=NR_R0;
  1465. { The normal type is widely applicable. When we find it is better to
  1466. use the normal type, we prevent other types. Or add strong types and
  1467. adjust it in the future. }
  1468. if is_simm12(ref.offset) then
  1469. begin
  1470. if ref.index<>NR_R0 then
  1471. begin
  1472. tmpreg:=getintregister(list,OS_INT);
  1473. a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
  1474. ref.base:=tmpreg;
  1475. end;
  1476. ref.index:=NR_NO;
  1477. ref.refaddr:=addr_reg_12i;
  1478. result:=mode=fr_normal;
  1479. exit;
  1480. end;
  1481. if (mode=fr_big) and (is_simm16_and_quadruple(ref.offset)) then
  1482. begin
  1483. if ref.index<>NR_NO then
  1484. begin
  1485. tmpreg:=getintregister(list,OS_INT);
  1486. a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
  1487. ref.base:=tmpreg;
  1488. end;
  1489. ref.index:=NR_NO;
  1490. ref.refaddr:=addr_reg_14i;
  1491. result:=true;
  1492. exit;
  1493. end;
  1494. if mode=fr_reg then
  1495. begin
  1496. if ref.offset<>0 then
  1497. begin
  1498. tmpreg:=getintregister(list,OS_INT);
  1499. a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
  1500. if ref.index<>NR_R0 then
  1501. begin
  1502. a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
  1503. ref.index:=tmpreg;
  1504. end
  1505. else
  1506. ref.index:=tmpreg;
  1507. end;
  1508. ref.refaddr:=addr_reg_reg;
  1509. ref.offset:=0;
  1510. result:=true;
  1511. exit;
  1512. end;
  1513. tmpreg:=getintregister(list,OS_INT);
  1514. a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
  1515. if ref.index<>NR_R0 then
  1516. a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
  1517. a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
  1518. ref.base:=tmpreg;
  1519. ref.index:=NR_NO;
  1520. ref.offset:=0;
  1521. result:=mode=fr_normal;
  1522. end;
  1523. procedure tcgloongarch64.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
  1524. const
  1525. overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1526. begin
  1527. if (op in overflowops) and
  1528. (size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  1529. a_load_reg_reg(list,OS_INT,size,dst,dst)
  1530. else if (op in [OP_ROL,OP_ROR]) and (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1531. a_load_reg_reg(list,OS_INT,size,dst,dst);
  1532. end;
  1533. procedure create_codegen;
  1534. begin
  1535. cg := tcgloongarch64.create;
  1536. cg128:=tcg128.create;
  1537. end;
  1538. end.