cgcpu.pas 64 KB

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