cgcpu.pas 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601
  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. tmpreg:=getintregister(list,OS_INT);
  513. { Size = 16bits or 8bits do special if rotate. }
  514. if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
  515. begin
  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. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg,src,15,8));
  522. usetmp:=true;
  523. end
  524. { Signext to 32bits if sra 16bits or 8bits}
  525. else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
  526. begin
  527. a_load_reg_reg(list,size,OS_S32,tmpreg,src);
  528. usetmp:=true;
  529. end;
  530. if size in [OS_64,OS_S64] then
  531. begin
  532. { Use tmp cannot be true here. }
  533. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
  534. maybeadjustresult(list,op,size,dst);
  535. end
  536. else { OS_32/S32, OS_16/S16, OS_8/S8 }
  537. begin
  538. if usetmp then
  539. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,tmpreg,a))
  540. else
  541. list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp32[op],dst,src,a));
  542. maybeadjustresult(list,op,size,dst);
  543. end;
  544. end
  545. else
  546. begin
  547. tmpreg:=getintregister(list,OS_INT);
  548. a_load_const_reg(list,size,a,tmpreg);
  549. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  550. end;
  551. end;
  552. procedure tcgloongarch64.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  553. var
  554. tmpreg1, tmpreg2: TRegister;
  555. usetmp1, usetmp2: boolean;
  556. begin
  557. usetmp1:=false;
  558. usetmp2:=false;
  559. tmpreg1:=getintregister(list,OS_INT);
  560. tmpreg2:=getintregister(list,OS_INT);
  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. list.concat(taicpu.op_reg_reg_reg(A_SUB_D,tmpreg1,NR_R0,src1));
  581. usetmp1:=true;
  582. op:=OP_ROR;
  583. end;
  584. if (TOpCG2AsmOp32[op]<>A_NONE) {or (TOpCG2AsmConstOp[op]<>A_NONE)} then
  585. begin
  586. { Size = 16bits or 8bits do special if rotate. }
  587. if (size in [OS_16,OS_S16]) and (op=OP_ROR) then
  588. begin
  589. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,31,16));
  590. usetmp2:=true;
  591. end
  592. else if (size in [OS_8,OS_S8]) and (op=OP_ROR) then
  593. begin
  594. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,src2,15,8));
  595. list.concat(taicpu.op_reg_reg_const_const(A_BSTRINS_W,tmpreg2,tmpreg2,31,16));
  596. usetmp2:=true;
  597. end
  598. { Signext to 32bits if sra 16bits or 8bits}
  599. else if (size in [OS_S16,OS_S8]) and (op=OP_SAR) then
  600. begin
  601. a_load_reg_reg(list,size,OS_S32,src2,tmpreg2);
  602. usetmp2:=true;
  603. end;
  604. if size in [OS_64,OS_S64] then
  605. begin
  606. { usetmp2 cannot be true here. }
  607. if usetmp1 then
  608. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,tmpreg1))
  609. else
  610. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
  611. maybeadjustresult(list,op,size,dst);
  612. end
  613. else
  614. begin
  615. if usetmp1 and usetmp2 then
  616. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,tmpreg1))
  617. else if usetmp1 then
  618. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,tmpreg1))
  619. else if usetmp2 then
  620. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,tmpreg2,src1))
  621. else
  622. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp32[op],dst,src2,src1));
  623. maybeadjustresult(list,op,size,dst);
  624. end;
  625. end;
  626. end;
  627. procedure tcgloongarch64.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  628. var
  629. tmpreg: tregister;
  630. begin
  631. if a = 0 then
  632. a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
  633. else
  634. begin
  635. tmpreg := GetIntRegister(list,OS_INT);
  636. a_load_const_reg(list,OS_INT,a,tmpreg);
  637. a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
  638. end;
  639. end;
  640. procedure tcgloongarch64.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
  641. const
  642. { OC_NONE,OC_EQ,OC_GT,OC_LT,OC_GTE,OC_LTE,OC_NE,OC_BE,OC_B,OC_AE,OC_A }
  643. TOpCmp2AsmCond: Array[TOpCmp] of TAsmCond = (C_NONE,
  644. C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU);
  645. TOpCmp2AsmCondZ: Array[TOpCmp] of TAsmCond = (C_NONE,
  646. C_EQZ,C_GTZ,C_LTZ,C_GEZ,C_LEZ,C_NEZ,C_NONE,C_NONE,C_NONE,C_NONE);
  647. var
  648. href: treference;
  649. ai: taicpu;
  650. begin
  651. reference_reset_symbol(href,l,0,0,[]);
  652. { It is better to use pcrel instead addr_b16 or addr_b21,
  653. because we hardly know the real op after optimizing. }
  654. href.refaddr:=addr_pcrel;
  655. if (reg1=NR_R0) or (reg2=NR_R0) then
  656. begin
  657. if (reg1=NR_R0) and (reg2=NR_R0) then
  658. begin
  659. a_jmp_always(list,l);
  660. exit;
  661. end
  662. else if reg2=NR_R0 then
  663. begin
  664. reg2:=reg1;
  665. reg1:=NR_R0;
  666. cmp_op:=swap_opcmp(cmp_op);
  667. end;
  668. if TOpCmp2AsmCondZ[cmp_op]<>C_NONE then
  669. begin
  670. ai:=taicpu.op_reg_ref(A_BXX,reg2,href);
  671. ai.is_jmp:=true;
  672. ai.condition:=TOpCmp2AsmCondZ[cmp_op];
  673. list.concat(ai);
  674. exit;
  675. end;
  676. end;
  677. ai:=taicpu.op_reg_reg_ref(A_BXX,reg2,reg1,href);
  678. ai.is_jmp:=true;
  679. ai.condition:=TOpCmp2AsmCond[cmp_op];
  680. list.concat(ai);
  681. end;
  682. procedure tcgloongarch64.a_jmp_name(list : TAsmList;const s : string);
  683. var
  684. ai: taicpu;
  685. href: treference;
  686. begin
  687. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
  688. href.refaddr:=addr_b26;
  689. ai:=taicpu.op_ref(A_B,href);
  690. ai.is_jmp:=true;
  691. list.concat(ai);
  692. end;
  693. procedure tcgloongarch64.a_jmp_always(list : TAsmList;l: tasmlabel);
  694. var
  695. ai: taicpu;
  696. href: treference;
  697. begin
  698. reference_reset_symbol(href,l,0,0,[]);
  699. href.refaddr:=addr_b26;
  700. ai:=taicpu.op_ref(A_B,href);
  701. ai.is_jmp:=true;
  702. list.concat(ai);
  703. end;
  704. procedure tcgloongarch64.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  705. var
  706. op: TAsmOp;
  707. ai: taicpu;
  708. const
  709. FpuConvOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  710. ((A_FMOV_S,A_FCVT_D_S),(A_FCVT_S_D,A_FMOV_D));
  711. begin
  712. if (reg1<>reg2) or (fromsize<>tosize) then
  713. begin
  714. ai:= taicpu.op_reg_reg(fpuconvop[fromsize,tosize],reg2,reg1);
  715. list.concat(ai);
  716. if (fromsize=tosize) then
  717. rg[R_FPUREGISTER].add_move_instruction(ai);
  718. end;
  719. end;
  720. procedure tcgloongarch64.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  721. var
  722. op: TAsmOp;
  723. href: treference;
  724. const
  725. fld_ops: array[boolean,boolean] of TAsmOp = (
  726. (A_FLD_D, A_FLD_S),
  727. (A_FLDX_D, A_FLDX_S)
  728. );
  729. begin
  730. href:=ref;
  731. op:=fld_ops[fixref(list,href,fr_reg),fromsize=OS_F32];
  732. list.concat(taicpu.op_reg_ref(op,reg,href));
  733. if fromsize<>tosize then
  734. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  735. end;
  736. procedure tcgloongarch64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  737. var
  738. op: TAsmOp;
  739. tmpfreg: TRegister;
  740. href: treference;
  741. fst_ops: array[boolean,boolean] of TAsmOp = (
  742. (A_FST_D, A_FST_S),
  743. (A_FSTX_D, A_FSTX_S)
  744. );
  745. begin
  746. if fromsize<>tosize then
  747. begin
  748. tmpfreg:=getfpuregister(list,tosize);
  749. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpfreg);
  750. reg:=tmpfreg;
  751. end;
  752. href:=ref;
  753. op:=fst_ops[fixref(list,href,fr_reg),tosize=OS_F32];
  754. list.concat(taicpu.op_reg_ref(op,reg,href));
  755. end;
  756. procedure tcgloongarch64.g_concatcopy(list: TAsmList; const source, dest: treference; len: aint);
  757. var
  758. tmpreg,countreg: TRegister;
  759. src,dst: TReference;
  760. lab: tasmlabel;
  761. len_8,tmplen: longint;
  762. len_1,len_2,len_4: boolean;
  763. begin
  764. { Size is zero }
  765. if len=0 then
  766. exit;
  767. { It's too large or illegal. }
  768. if len>high(longint) then
  769. internalerror(2022111944);
  770. { len = d*8(+4?)(+2?)(+1?). }
  771. len_8:=len div 8;
  772. tmplen:=len-len_8*8;
  773. len_1:=(tmplen and 1)<>0;
  774. len_2:=(tmplen and 2)<>0;
  775. len_4:=(tmplen and 4)<>0;
  776. { Set the reference. }
  777. reference_reset(src,sizeof(aint),[]);
  778. reference_reset(dst,sizeof(aint),[]);
  779. src.base:=GetAddressRegister(list);
  780. dst.base:=GetAddressRegister(list);
  781. src.refaddr:=addr_reg_12i;
  782. dst.refaddr:=addr_reg_12i;
  783. a_loadaddr_ref_reg(list,source,src.base);
  784. a_loadaddr_ref_reg(list,dest,dst.base);
  785. tmpreg:= GetIntRegister(list, OS_INT);
  786. { TODO Some optimization. }
  787. if len_8>0 then
  788. begin
  789. current_asmdata.getjumplabel(lab);
  790. countreg := GetIntRegister(list,OS_INT);
  791. if len_8>1 then
  792. begin
  793. a_load_const_reg(list,OS_INT,len_8,countreg);
  794. a_label(list, lab);
  795. end;
  796. list.concat(taicpu.op_reg_ref(A_LD_D,tmpreg,src));
  797. list.concat(taicpu.op_reg_ref(A_ST_D,tmpreg,dst));
  798. if len_1 or len_2 or len_4 or (len_8>1) then
  799. begin
  800. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,src.base,src.base,8));
  801. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst.base,dst.base,8));
  802. end;
  803. if len_8>1 then
  804. begin
  805. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,countreg,countreg,-1));
  806. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  807. end;
  808. end; { len_8>0 }
  809. if len_4 then
  810. begin
  811. list.concat(taicpu.op_reg_ref(A_LD_W,tmpreg,src));
  812. list.concat(taicpu.op_reg_ref(A_ST_W,tmpreg,dst));
  813. inc(src.offset,4);
  814. inc(dst.offset,4);
  815. end;
  816. if len_2 then
  817. begin
  818. list.concat(taicpu.op_reg_ref(A_LD_H,tmpreg,src));
  819. list.concat(taicpu.op_reg_ref(A_ST_H,tmpreg,dst));
  820. inc(src.offset,2);
  821. inc(dst.offset,2);
  822. end;
  823. if len_1 then
  824. begin
  825. list.concat(taicpu.op_reg_ref(A_LD_B,tmpreg,src));
  826. list.concat(taicpu.op_reg_ref(A_ST_B,tmpreg,dst));
  827. end;
  828. end;
  829. procedure tcgloongarch64.g_overflowcheck(list: TAsmList; const loc: tlocation; def: tdef);
  830. begin
  831. { TODO }
  832. { internalerror(2022111945); }
  833. end;
  834. procedure tcgloongarch64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  835. var
  836. regs, fregs: tcpuregisterset;
  837. r: TSuperRegister;
  838. href: treference;
  839. stackcount, stackAdjust: longint;
  840. begin
  841. if not(nostackframe) then
  842. begin
  843. a_reg_alloc(list,NR_STACK_POINTER_REG);
  844. { Always use $fp. }
  845. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  846. { Int registers }
  847. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  848. regs:=regs+[RS_FRAME_POINTER_REG];
  849. { Does it call another function? }
  850. if (pi_do_call in current_procinfo.flags) or
  851. (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
  852. regs:=regs+[RS_RETURN_ADDRESS_REG];
  853. { Float registers }
  854. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  855. { Calculate the stackcount of all regesters. }
  856. stackcount:=16;
  857. for r:=RS_R1 to RS_R31 do
  858. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  859. inc(stackcount,8);
  860. for r:=RS_F0 to RS_F31 do
  861. if r in fregs then
  862. inc(stackcount,8);
  863. { Calculate the frame total size. }
  864. inc(localsize,stackcount);
  865. if localsize=0 then
  866. exit;
  867. { ADDI instructions only has 12bits-sign-imm range, [-2048,2047]. Once we
  868. use -2048 in the prologue, we cannot get back in epilogue use one ADDI.
  869. Due to LoongArch psABI, we should save the $ra and then use it as free.
  870. We should make $fp as $fp on entry, so ADDI cannot do 2048 size. It
  871. seems use -2032 may a good choice without care of many of cases. }
  872. if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
  873. begin
  874. regs:=regs+[RS_RETURN_ADDRESS_REG];
  875. inc(localsize,8);
  876. inc(stackcount,8);
  877. end;
  878. if (localsize mod 16)<>0 then
  879. inc(localsize,16-(localsize mod 16));
  880. { Do first decrease the stack, and record the stackadjust. }
  881. stackadjust:=0;
  882. if (-localsize<-2032) then
  883. begin
  884. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-2032));
  885. reference_reset_base(href,NR_STACK_POINTER_REG,2032-8,ctempposinvalid,0,[]);
  886. href.refaddr:=addr_reg_12i;
  887. stackadjust:=2032;
  888. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2032);
  889. end
  890. else
  891. begin
  892. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize));
  893. reference_reset_base(href,NR_STACK_POINTER_REG,localsize-8,ctempposinvalid,0,[]);
  894. href.refaddr:=addr_reg_12i;
  895. stackadjust:=localsize;
  896. current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize);
  897. end;
  898. { $ra in cfa -8. }
  899. if RS_RETURN_ADDRESS_REG in regs then
  900. begin
  901. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
  902. current_asmdata.asmcfi.cfa_offset(list,NR_RETURN_ADDRESS_REG,-8);
  903. end;
  904. { $fp in cfa -16. }
  905. dec(href.offset,8);
  906. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
  907. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-16);
  908. { $fp = cfa. }
  909. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackadjust));
  910. current_asmdata.asmcfi.cfa_def_cfa(list,NR_FRAME_POINTER_REG,0);
  911. { Int registers }
  912. for r:=RS_R1 to RS_R31 do
  913. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  914. begin
  915. dec(href.offset,8);
  916. list.concat(taicpu.op_reg_ref(A_ST_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  917. current_asmdata.asmcfi.cfa_offset(list,newreg(R_INTREGISTER,r,R_SUBWHOLE),href.offset-stackadjust);
  918. end;
  919. { Float registers }
  920. for r:=RS_F0 to RS_F31 do
  921. if r in fregs then
  922. begin
  923. dec(href.offset,8);
  924. list.concat(taicpu.op_reg_ref(A_FST_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  925. current_asmdata.asmcfi.cfa_offset(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href.offset);
  926. end;
  927. { Decrese the remaining stack size. }
  928. if (localsize-stackadjust)>2048 then
  929. begin
  930. a_load_const_reg(list,OS_INT,localsize-stackadjust,NR_RETURN_ADDRESS_REG);
  931. list.concat(taicpu.op_reg_reg_reg(A_SUB_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
  932. end
  933. else if (localsize-stackadjust)>0 then
  934. begin
  935. { TODO It seems to no need $ra. }
  936. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackadjust-localsize));
  937. end;
  938. end;
  939. end; { g_proc_entry }
  940. procedure tcgloongarch64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  941. var
  942. r: tsuperregister;
  943. regs, fregs: tcpuregisterset;
  944. stackcount, localsize, stackleft: longint;
  945. href: treference;
  946. begin
  947. if not(nostackframe) then
  948. begin
  949. localsize:=current_procinfo.calc_stackframe_size;
  950. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  951. fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  952. regs:=regs+[RS_FRAME_POINTER_REG];
  953. if (pi_do_call in current_procinfo.flags) or
  954. (RS_R1 in rg[R_INTREGISTER].used_in_proc) then
  955. regs:=regs+[RS_RETURN_ADDRESS_REG];
  956. stackcount:=16;
  957. for r:=RS_R1 to RS_R31 do
  958. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  959. inc(stackcount,8);
  960. for r:=RS_F0 to RS_F31 do
  961. if r in fregs then
  962. inc(stackcount,8);
  963. inc(localsize,stackcount);
  964. if (-localsize<-2032) and (not (RS_RETURN_ADDRESS_REG in regs)) then
  965. begin
  966. regs:=regs+[RS_RETURN_ADDRESS_REG];
  967. inc(localsize,8);
  968. inc(stackcount,8);
  969. end;
  970. if (localsize mod 16)<>0 then
  971. inc(localsize,16-(localsize mod 16));
  972. stackleft:=0;
  973. if (-localsize<-2032) then
  974. stackleft:=2032
  975. else
  976. stackleft:=localsize;
  977. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,-stackleft));
  978. reference_reset_base(href,NR_STACK_POINTER_REG,stackleft-8,ctempposinvalid,0,[]);
  979. href.refaddr:=addr_reg_12i;
  980. { Restore registers. }
  981. if RS_RETURN_ADDRESS_REG in regs then
  982. begin
  983. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_RETURN_ADDRESS_REG,R_SUBWHOLE),href));
  984. current_asmdata.asmcfi.cfa_restore(list,NR_RETURN_ADDRESS_REG);
  985. end;
  986. dec(href.offset,8);
  987. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,RS_FRAME_POINTER_REG,R_SUBWHOLE),href));
  988. current_asmdata.asmcfi.cfa_restore(list,NR_FRAME_POINTER_REG);
  989. current_asmdata.asmcfi.cfa_def_cfa(list,NR_STACK_POINTER_REG,stackleft);
  990. for r:=RS_R1 to RS_R31 do
  991. if (r in regs) and (r<>RS_FRAME_POINTER_REG) and (r<>RS_RETURN_ADDRESS_REG) then
  992. begin
  993. dec(href.offset,8);
  994. list.concat(taicpu.op_reg_ref(A_LD_D,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
  995. current_asmdata.asmcfi.cfa_restore(list,newreg(R_INTREGISTER,r,R_SUBWHOLE));
  996. end;
  997. for r:=RS_F0 to RS_F31 do
  998. if r in fregs then
  999. begin
  1000. dec(href.offset,8);
  1001. list.concat(taicpu.op_reg_ref(A_FLD_D,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
  1002. current_asmdata.asmcfi.cfa_restore(list,newreg(R_FPUREGISTER,r,R_SUBWHOLE));
  1003. end;
  1004. { Restore $sp. }
  1005. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,stackleft));
  1006. end;
  1007. { jr $ra. }
  1008. reference_reset_base(href,NR_RETURN_ADDRESS_REG,0,ctempposinvalid,0,[]);
  1009. href.refaddr:=addr_reg;
  1010. list.concat(taicpu.op_ref(A_JR,href));
  1011. end; { g_proc_exit }
  1012. procedure tcgloongarch64.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1013. var
  1014. signed: Boolean;
  1015. l: TAsmLabel;
  1016. tmpreg: tregister;
  1017. ai: taicpu;
  1018. href: treference;
  1019. tmpreg0,tmpreg1: tregister;
  1020. begin
  1021. if setflags then
  1022. begin
  1023. if is_simm12(a) and (op=OP_ADD) then
  1024. begin
  1025. current_asmdata.getjumplabel(l);
  1026. reference_reset_symbol(href,l,0,0,[]);
  1027. href.refaddr:=addr_pcrel;
  1028. tmpreg1:=getintregister(list,OS_INT);
  1029. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1030. begin
  1031. { Backup src so we can compare with it. }
  1032. a_load_reg_reg(list,OS_INT,OS_INT,src,tmpreg1);
  1033. end;
  1034. if size in [OS_64,OS_S64] then
  1035. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,dst,src,a))
  1036. else
  1037. list.concat(taicpu.op_reg_reg_const(A_ADDI_W,dst,src,a));
  1038. case size of
  1039. OS_S64,OS_S32:
  1040. begin
  1041. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
  1042. if a<0 then
  1043. ai.condition:=C_LT
  1044. else
  1045. ai.condition:=C_GE;
  1046. end;
  1047. OS_S16,OS_S8:
  1048. begin
  1049. tmpreg0:=getintregister(list,OS_INT);
  1050. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1051. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1052. ai.condition:=C_EQ;
  1053. end;
  1054. OS_64,OS_32:
  1055. begin
  1056. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg1,href);
  1057. ai.condition:=C_GEU;
  1058. end;
  1059. OS_16,OS_8:
  1060. begin
  1061. tmpreg0:=getintregister(list,OS_INT);
  1062. if size=OS_16 then
  1063. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1064. else
  1065. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1066. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1067. ai.condition:=C_GTU;
  1068. end;
  1069. else
  1070. internalerror(2022082303);
  1071. end;
  1072. ai.is_jmp:=true;
  1073. list.concat(ai);
  1074. a_call_name(list,'FPC_OVERFLOW',false);
  1075. a_label(list,l);
  1076. end
  1077. else if op in [OP_ADD,OP_SUB,OP_MUL,OP_IMUL,OP_IDIV] then
  1078. begin
  1079. tmpreg:=getintregister(list,size);
  1080. a_load_const_reg(list,size,a,tmpreg);
  1081. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  1082. end
  1083. else
  1084. internalerror(2022082302);
  1085. end
  1086. else
  1087. a_op_const_reg_reg(list,op,size,a,src,dst);
  1088. end;
  1089. procedure tcgloongarch64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1090. var
  1091. signed: Boolean;
  1092. l: TAsmLabel;
  1093. tmpreg0,tmpreg1,tmpreg2,tmpreg3: tregister;
  1094. ai: taicpu;
  1095. href: treference;
  1096. begin
  1097. signed:=tcgsize2unsigned[size]<>size;
  1098. if setflags then
  1099. case op of
  1100. OP_ADD:
  1101. begin
  1102. current_asmdata.getjumplabel(l);
  1103. reference_reset_symbol(href,l,0,0,[]);
  1104. href.refaddr:=addr_pcrel;
  1105. tmpreg2:=getintregister(list,OS_INT);
  1106. tmpreg3:=getintregister(list,OS_INT);
  1107. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1108. begin
  1109. { Backup src so we can compare with it. }
  1110. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1111. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1112. end;
  1113. if size in [OS_S64,OS_64] then
  1114. list.Concat(taicpu.op_reg_reg_reg(A_ADD_D,dst,src2,src1))
  1115. else
  1116. list.Concat(taicpu.op_reg_reg_reg(A_ADD_W,dst,src2,src1));
  1117. case size of
  1118. OS_S64,OS_S32:
  1119. begin
  1120. { if (src1<0)<>(dst<src2) overflow; }
  1121. tmpreg0:=getintregister(list,OS_INT);
  1122. tmpreg1:=getintregister(list,OS_INT);
  1123. list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg0,tmpreg2,0));
  1124. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
  1125. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1126. ai.condition:=C_EQ;
  1127. end;
  1128. OS_S16,OS_S8:
  1129. begin
  1130. tmpreg0:=getintregister(list,OS_INT);
  1131. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1132. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1133. ai.condition:=C_EQ;
  1134. end;
  1135. OS_64,OS_32:
  1136. begin
  1137. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
  1138. ai.condition:=C_GEU;
  1139. end;
  1140. OS_16,OS_8:
  1141. begin
  1142. tmpreg0:=getintregister(list,OS_INT);
  1143. if size=OS_16 then
  1144. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1145. else
  1146. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1147. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1148. ai.condition:=C_GTU;
  1149. end;
  1150. else
  1151. internalerror(2022082304);
  1152. end;
  1153. ai.is_jmp:=true;
  1154. list.concat(ai);
  1155. a_call_name(list,'FPC_OVERFLOW',false);
  1156. a_label(list,l);
  1157. end;
  1158. OP_SUB:
  1159. begin
  1160. current_asmdata.getjumplabel(l);
  1161. reference_reset_symbol(href,l,0,0,[]);
  1162. href.refaddr:=addr_pcrel;
  1163. tmpreg2:=getintregister(list,OS_INT);
  1164. tmpreg3:=getintregister(list,OS_INT);
  1165. if size in [OS_64,OS_S64,OS_32,OS_S32] then
  1166. begin
  1167. { Backup src so we can compare with it. }
  1168. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1169. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1170. end;
  1171. if size in [OS_S64,OS_64] then
  1172. list.Concat(taicpu.op_reg_reg_reg(A_SUB_D,dst,src2,src1))
  1173. else
  1174. list.Concat(taicpu.op_reg_reg_reg(A_SUB_W,dst,src2,src1));
  1175. case size of
  1176. OS_S64,OS_S32:
  1177. begin
  1178. { if (src1<0)<>(dst<src2) overflow; }
  1179. tmpreg0:=getintregister(list,OS_INT);
  1180. tmpreg1:=getintregister(list,OS_INT);
  1181. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_R0,tmpreg2));
  1182. list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg1,dst,tmpreg3));
  1183. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1184. ai.condition:=C_EQ;
  1185. end;
  1186. OS_S16,OS_S8:
  1187. begin
  1188. tmpreg0:=getintregister(list,OS_INT);
  1189. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1190. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1191. ai.condition:=C_EQ;
  1192. end;
  1193. OS_64,OS_32:
  1194. begin
  1195. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg3,dst,href);
  1196. ai.condition:=C_GEU;
  1197. end;
  1198. OS_16,OS_8:
  1199. begin
  1200. tmpreg0:=getintregister(list,OS_INT);
  1201. if size=OS_16 then
  1202. a_load_const_reg(list,OS_INT,1 shl 16,tmpreg0)
  1203. else
  1204. a_load_const_reg(list,OS_INT,1 shl 8,tmpreg0);
  1205. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,dst,href);
  1206. ai.condition:=C_GTU;
  1207. end;
  1208. else
  1209. internalerror(2022082305);
  1210. end;
  1211. ai.is_jmp:=true;
  1212. list.concat(ai);
  1213. a_call_name(list,'FPC_OVERFLOW',false);
  1214. a_label(list,l);
  1215. end;
  1216. OP_IMUL:
  1217. begin
  1218. { No overflow if upper result is same as sign of result }
  1219. current_asmdata.getjumplabel(l);
  1220. reference_reset_symbol(href,l,0,0,[]);
  1221. href.refaddr:=addr_pcrel;
  1222. tmpreg0:=getintregister(list,OS_INT);
  1223. tmpreg1:=getintregister(list,OS_INT);
  1224. if size in [OS_S64,OS_64] then
  1225. begin
  1226. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
  1227. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
  1228. list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
  1229. list.Concat(taicpu.op_reg_reg_reg(A_MULH_D,tmpreg0,tmpreg0,tmpreg1));
  1230. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg1,dst,63));
  1231. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg1,href);
  1232. ai.condition:=C_EQ;
  1233. end
  1234. else
  1235. begin
  1236. list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_W,dst,src1,src2));
  1237. case size of
  1238. OS_S32,OS_32:
  1239. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
  1240. OS_S16,OS_16:
  1241. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
  1242. OS_S8,OS_8:
  1243. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
  1244. else
  1245. internalerror(2022082306);
  1246. end;
  1247. list.concat(taicpu.op_reg_reg_const(A_ADDI_D,tmpreg0,tmpreg0,1));
  1248. list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg1,tmpreg0,2));
  1249. ai:=taicpu.op_reg_ref(A_BXX,tmpreg1,href);
  1250. ai.condition:=C_NEZ;
  1251. end;
  1252. ai.is_jmp:=true;
  1253. list.concat(ai);
  1254. a_call_name(list,'FPC_OVERFLOW',false);
  1255. a_label(list,l);
  1256. end;
  1257. OP_MUL:
  1258. begin
  1259. { No overflow if upper result is 0 }
  1260. current_asmdata.getjumplabel(l);
  1261. reference_reset_symbol(href,l,0,0,[]);
  1262. href.refaddr:=addr_pcrel;
  1263. tmpreg0:=getintregister(list,OS_INT);
  1264. if size in [OS_S64,OS_64] then
  1265. begin
  1266. tmpreg1:=getintregister(list,OS_INT);
  1267. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg0);
  1268. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg1);
  1269. list.Concat(taicpu.op_reg_reg_reg(A_MUL_D,dst,src1,src2));
  1270. list.Concat(taicpu.op_reg_reg_reg(A_MULH_DU,tmpreg0,tmpreg0,tmpreg1));
  1271. ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
  1272. ai.condition:=C_EQZ;
  1273. end
  1274. else
  1275. begin
  1276. list.Concat(taicpu.op_reg_reg_reg(A_MULW_D_WU,dst,src1,src2));
  1277. case size of
  1278. OS_S32,OS_32:
  1279. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,31));
  1280. OS_S16,OS_16:
  1281. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,15));
  1282. OS_S8,OS_8:
  1283. list.concat(taicpu.op_reg_reg_const(A_SRAI_D,tmpreg0,dst,7));
  1284. else
  1285. internalerror(2022082307);
  1286. end;
  1287. ai:=taicpu.op_reg_ref(A_BXX,tmpreg0,href);
  1288. ai.condition:=C_EQZ;
  1289. end;
  1290. ai.is_jmp:=true;
  1291. list.concat(ai);
  1292. a_call_name(list,'FPC_OVERFLOW',false);
  1293. a_label(list,l);
  1294. end;
  1295. OP_IDIV:
  1296. begin
  1297. { Only overflow if -2^(N-1)/(-1) }
  1298. current_asmdata.getjumplabel(l);
  1299. reference_reset_symbol(href,l,0,0,[]);
  1300. href.refaddr:=addr_pcrel;
  1301. tmpreg2:=getintregister(list,OS_INT);
  1302. tmpreg3:=getintregister(list,OS_INT);
  1303. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg2);
  1304. a_load_reg_reg(list,OS_INT,OS_INT,src2,tmpreg3);
  1305. if size in [OS_S64,OS_64] then
  1306. list.Concat(taicpu.op_reg_reg_reg(A_DIV_D,dst,src1,src2))
  1307. else
  1308. list.Concat(taicpu.op_reg_reg_reg(A_DIV_W,dst,src1,src2));
  1309. if size in [OS_S64,OS_64,OS_S32,OS_32] then
  1310. begin
  1311. ai:=taicpu.op_reg_reg_ref(A_BXX,dst,tmpreg3,href);
  1312. ai.condition:=C_NE;
  1313. ai.is_jmp:=true;
  1314. list.concat(ai);
  1315. ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
  1316. ai.condition:=C_GEZ;
  1317. ai.is_jmp:=true;
  1318. list.concat(ai);
  1319. end
  1320. else
  1321. begin
  1322. ai:=taicpu.op_reg_ref(A_BXX,tmpreg2,href);
  1323. ai.condition:=C_GEZ;
  1324. ai.is_jmp:=true;
  1325. list.concat(ai);
  1326. tmpreg0:=getintregister(list,OS_INT);
  1327. a_load_reg_reg(list,OS_INT,size,dst,tmpreg0);
  1328. ai:=taicpu.op_reg_reg_ref(A_BXX,tmpreg0,tmpreg3,href);
  1329. ai.condition:=C_NE;
  1330. ai.is_jmp:=true;
  1331. list.concat(ai);
  1332. end;
  1333. a_call_name(list,'FPC_OVERFLOW',false);
  1334. a_label(list,l);
  1335. end;
  1336. else
  1337. internalerror(2022082301);
  1338. end
  1339. else
  1340. a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1341. end;
  1342. function tcgloongarch64.fixref(list: TAsmList; var ref: treference; mode : tfixref): boolean;
  1343. var
  1344. tmpreg: TRegister;
  1345. href: treference;
  1346. begin
  1347. if ref.refaddr=addr_reg_12i then
  1348. begin
  1349. result:=mode=fr_normal;
  1350. exit;
  1351. end
  1352. else if ref.refaddr=addr_reg_reg then
  1353. begin
  1354. result:=mode=fr_reg;
  1355. exit;
  1356. end
  1357. else if ref.refaddr=addr_reg_reg then
  1358. begin
  1359. result:=mode=fr_big;
  1360. exit;
  1361. end;
  1362. { Reference with symbol, load symbol address first. }
  1363. if assigned(ref.symbol) then
  1364. begin
  1365. tmpreg:=getintregister(list,OS_INT);
  1366. if ((cs_create_pic in current_settings.moduleswitches) and
  1367. (ref.symbol.bind in [AB_LOCAL,AB_TEMP])) or
  1368. ((not(cs_create_pic in current_settings.moduleswitches)) and
  1369. (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL,AB_TEMP])) then
  1370. begin
  1371. { Load symbol address as local. }
  1372. reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
  1373. ref.symbol:=nil;
  1374. ref.offset:=0;
  1375. href.refaddr:=addr_pc_hi20;
  1376. list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
  1377. href.refaddr:=addr_pc_lo12;
  1378. list.concat(taicpu.op_reg_reg_ref(A_ADDI_D,tmpreg,tmpreg,href));
  1379. end
  1380. else
  1381. begin
  1382. { Load symbol address as global. }
  1383. reference_reset_symbol(href,ref.symbol,0,0,[]);
  1384. ref.symbol:=nil;
  1385. href.refaddr:=addr_got_pc_hi20;
  1386. list.concat(taicpu.op_reg_ref(A_PCALAU12I,tmpreg,href));
  1387. href.refaddr:=addr_got_pc_lo12;
  1388. list.concat(taicpu.op_reg_reg_ref(A_LD_D,tmpreg,tmpreg,href));
  1389. end;
  1390. { Make address format become basereg (+indexreg). }
  1391. if (ref.index<>NR_NO) and (ref.base<>NR_NO) then
  1392. begin
  1393. a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
  1394. ref.base:=tmpreg;
  1395. end
  1396. else if (ref.base=NR_NO) then
  1397. ref.base:=tmpreg
  1398. else { ref.index=NR_NO }
  1399. ref.index:=tmpreg;
  1400. end
  1401. { Refernce only offset, make offset become a reg. }
  1402. else if (ref.index=NR_NO) and (ref.base=NR_NO) then
  1403. begin
  1404. tmpreg:=getintregister(list,OS_INT);
  1405. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  1406. reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
  1407. ref.index:=NR_R0;
  1408. end;
  1409. if (ref.index<>NR_NO) and (ref.base=NR_NO) then
  1410. begin
  1411. ref.base:=ref.index;
  1412. ref.index:=NR_R0;
  1413. end;
  1414. if (ref.index=NR_NO) then
  1415. ref.index:=NR_R0;
  1416. { The normal type is widely applicable. When we find it is better to
  1417. use the normal type, we prevent other types. Or add strong types and
  1418. adjust it in the future. }
  1419. if is_simm12(ref.offset) then
  1420. begin
  1421. if ref.index<>NR_R0 then
  1422. begin
  1423. tmpreg:=getintregister(list,OS_INT);
  1424. a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
  1425. ref.base:=tmpreg;
  1426. end;
  1427. ref.index:=NR_NO;
  1428. ref.refaddr:=addr_reg_12i;
  1429. result:=mode=fr_normal;
  1430. exit;
  1431. end;
  1432. if (mode=fr_big) and (is_simm16_and_quadruple(ref.offset)) then
  1433. begin
  1434. if ref.index<>NR_NO then
  1435. begin
  1436. tmpreg:=getintregister(list,OS_INT);
  1437. a_op_reg_reg_reg(list,OP_ADD,OS_INT,ref.base,ref.index,tmpreg);
  1438. ref.base:=tmpreg;
  1439. end;
  1440. ref.index:=NR_NO;
  1441. ref.refaddr:=addr_reg_14i;
  1442. result:=true;
  1443. exit;
  1444. end;
  1445. if mode=fr_reg then
  1446. begin
  1447. if ref.offset<>0 then
  1448. begin
  1449. tmpreg:=getintregister(list,OS_INT);
  1450. a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
  1451. if ref.index<>NR_R0 then
  1452. begin
  1453. a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
  1454. ref.index:=tmpreg;
  1455. end
  1456. else
  1457. ref.index:=tmpreg;
  1458. end;
  1459. ref.refaddr:=addr_reg_reg;
  1460. ref.offset:=0;
  1461. result:=true;
  1462. exit;
  1463. end;
  1464. tmpreg:=getintregister(list,OS_INT);
  1465. a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
  1466. if ref.index<>NR_R0 then
  1467. a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
  1468. a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
  1469. ref.base:=tmpreg;
  1470. ref.index:=NR_NO;
  1471. ref.offset:=0;
  1472. result:=mode=fr_normal;
  1473. end;
  1474. procedure tcgloongarch64.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
  1475. const
  1476. overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1477. begin
  1478. if (op in overflowops) and
  1479. (size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  1480. a_load_reg_reg(list,OS_INT,size,dst,dst)
  1481. else if (op in [OP_ROL,OP_ROR]) and (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1482. a_load_reg_reg(list,OS_INT,size,dst,dst);
  1483. end;
  1484. procedure create_codegen;
  1485. begin
  1486. cg := tcgloongarch64.create;
  1487. cg128:=tcg128.create;
  1488. end;
  1489. end.