cgcpu.pas 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999
  1. {
  2. Copyright (c) 1998-2012 by Florian Klaempfl and David Zhang
  3. This unit implements the code generator for MIPS
  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, parabase,
  22. cgbase, cgutils, cgobj, cg64f32, cpupara,
  23. aasmbase, aasmtai, aasmcpu, aasmdata,
  24. cpubase, cpuinfo,
  25. node, symconst, SymType, symdef,
  26. rgcpu;
  27. type
  28. TCGMIPS = class(tcg)
  29. public
  30. procedure init_register_allocators; override;
  31. procedure done_register_allocators; override;
  32. /// { needed by cg64 }
  33. procedure make_simple_ref(list: tasmlist; var ref: treference);
  34. procedure handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  35. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  36. procedure overflowcheck_internal(list: TAsmList; arg1, arg2: TRegister);
  37. { parameter }
  38. procedure a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override;
  39. procedure a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); override;
  40. procedure a_call_name(list: tasmlist; const s: string; weak : boolean); override;
  41. procedure a_call_reg(list: tasmlist; Reg: TRegister); override;
  42. procedure a_call_sym_pic(list: tasmlist; sym: tasmsymbol);
  43. { General purpose instructions }
  44. procedure a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister); override;
  45. procedure a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  46. procedure a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  47. procedure a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  48. procedure a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  49. procedure a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  50. { move instructions }
  51. procedure a_load_const_reg(list: tasmlist; size: tcgsize; a: tcgint; reg: tregister); override;
  52. procedure a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference); override;
  53. procedure a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCgSize; reg: TRegister; const ref: TReference); override;
  54. procedure a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister); override;
  55. procedure a_load_reg_reg(list: tasmlist; FromSize, ToSize: TCgSize; reg1, reg2: tregister); override;
  56. procedure a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister); override;
  57. { fpu move instructions }
  58. procedure a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  59. procedure a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister); override;
  60. procedure a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference); override;
  61. { comparison operations }
  62. procedure a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  63. procedure a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  64. procedure a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel); override;
  65. procedure g_flags2reg(list: tasmlist; size: TCgSize; const f: TResFlags; reg: tregister); override;
  66. procedure a_jmp_always(List: tasmlist; l: TAsmLabel); override;
  67. procedure a_jmp_name(list: tasmlist; const s: string); override;
  68. procedure g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); override;
  69. procedure g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation); override;
  70. procedure g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean); override;
  71. procedure g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean); override;
  72. procedure g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  73. procedure g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  74. procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  75. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  76. procedure g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint); override;
  77. procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);override;
  78. procedure g_profilecode(list: TAsmList);override;
  79. { Transform unsupported methods into Internal errors }
  80. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  81. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  82. end;
  83. TCg64MPSel = class(tcg64f32)
  84. public
  85. procedure a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference); override;
  86. procedure a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64); override;
  87. procedure a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara); override;
  88. procedure a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64); override;
  89. procedure a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64); override;
  90. procedure a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64); override;
  91. procedure a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64); override;
  92. procedure a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  93. procedure a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  94. end;
  95. procedure create_codegen;
  96. const
  97. TOpCmp2AsmCond : array[topcmp] of TAsmCond=(C_NONE,
  98. C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU
  99. );
  100. implementation
  101. uses
  102. globals, verbose, systems, cutils,
  103. paramgr, fmodule,
  104. symtable, symsym,
  105. tgobj,
  106. procinfo, cpupi;
  107. const
  108. TOpcg2AsmOp: array[TOpCg] of TAsmOp = (
  109. A_NONE,A_NONE,A_ADDU,A_AND,A_NONE,A_NONE,A_MULT,A_MULTU,A_NONE,A_NONE,
  110. A_OR,A_SRAV,A_SLLV,A_SRLV,A_SUBU,A_XOR,A_NONE,A_NONE
  111. );
  112. procedure TCGMIPS.make_simple_ref(list: tasmlist; var ref: treference);
  113. var
  114. tmpreg, tmpreg1: tregister;
  115. tmpref: treference;
  116. base_replaced: boolean;
  117. begin
  118. { Enforce some discipline for callers:
  119. - gp is always implicit
  120. - reference is processed only once }
  121. if (ref.base=NR_GP) or (ref.index=NR_GP) then
  122. InternalError(2013022801);
  123. if (ref.refaddr<>addr_no) then
  124. InternalError(2013022802);
  125. { fixup base/index, if both are present then add them together }
  126. base_replaced:=false;
  127. tmpreg:=ref.base;
  128. if (tmpreg=NR_NO) then
  129. tmpreg:=ref.index
  130. else if (ref.index<>NR_NO) then
  131. begin
  132. tmpreg:=getintregister(list,OS_ADDR);
  133. list.concat(taicpu.op_reg_reg_reg(A_ADDU,tmpreg,ref.base,ref.index));
  134. base_replaced:=true;
  135. end;
  136. ref.base:=tmpreg;
  137. ref.index:=NR_NO;
  138. if (ref.symbol=nil) and
  139. (ref.offset>=simm16lo) and
  140. (ref.offset<=simm16hi-sizeof(pint)) then
  141. exit;
  142. { Symbol present or offset > 16bits }
  143. if assigned(ref.symbol) then
  144. begin
  145. ref.base:=getintregister(list,OS_ADDR);
  146. reference_reset_symbol(tmpref,ref.symbol,ref.offset,ref.alignment);
  147. if (cs_create_pic in current_settings.moduleswitches) then
  148. begin
  149. if not (pi_needs_got in current_procinfo.flags) then
  150. InternalError(2013060102);
  151. { For PIC global symbols offset must be handled separately.
  152. Otherwise (non-PIC or local symbols) offset can be encoded
  153. into relocation even if exceeds 16 bits. }
  154. if (ref.symbol.bind<>AB_LOCAL) then
  155. tmpref.offset:=0;
  156. tmpref.refaddr:=addr_pic;
  157. tmpref.base:=NR_GP;
  158. list.concat(taicpu.op_reg_ref(A_LW,ref.base,tmpref));
  159. end
  160. else
  161. begin
  162. tmpref.refaddr:=addr_high;
  163. list.concat(taicpu.op_reg_ref(A_LUI,ref.base,tmpref));
  164. end;
  165. { Add original base/index, if any. }
  166. if (tmpreg<>NR_NO) then
  167. list.concat(taicpu.op_reg_reg_reg(A_ADDU,ref.base,tmpreg,ref.base));
  168. if (ref.symbol.bind=AB_LOCAL) or
  169. not (cs_create_pic in current_settings.moduleswitches) then
  170. begin
  171. ref.refaddr:=addr_low;
  172. exit;
  173. end;
  174. { PIC global symbol }
  175. ref.symbol:=nil;
  176. if (ref.offset=0) then
  177. exit;
  178. if (ref.offset>=simm16lo) and
  179. (ref.offset<=simm16hi-sizeof(pint)) then
  180. begin
  181. list.concat(taicpu.op_reg_reg_const(A_ADDIU,ref.base,ref.base,ref.offset));
  182. ref.offset:=0;
  183. exit;
  184. end;
  185. { fallthrough to the case of large offset }
  186. end;
  187. tmpreg1:=getintregister(list,OS_INT);
  188. a_load_const_reg(list,OS_INT,ref.offset,tmpreg1);
  189. if (ref.base=NR_NO) then
  190. ref.base:=tmpreg1 { offset alone, weird but possible }
  191. else
  192. begin
  193. if (not base_replaced) then
  194. ref.base:=getintregister(list,OS_ADDR);
  195. list.concat(taicpu.op_reg_reg_reg(A_ADDU,ref.base,tmpreg,tmpreg1))
  196. end;
  197. ref.offset:=0;
  198. end;
  199. procedure TCGMIPS.handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  200. var
  201. tmpreg: tregister;
  202. op2: Tasmop;
  203. negate: boolean;
  204. begin
  205. case op of
  206. A_ADD,A_SUB:
  207. op2:=A_ADDI;
  208. A_ADDU,A_SUBU:
  209. op2:=A_ADDIU;
  210. else
  211. InternalError(2013052001);
  212. end;
  213. negate:=op in [A_SUB,A_SUBU];
  214. { subtraction is actually addition of negated value, so possible range is
  215. off by one (-32767..32768) }
  216. if (a < simm16lo+ord(negate)) or
  217. (a > simm16hi+ord(negate)) then
  218. begin
  219. tmpreg := GetIntRegister(list, OS_INT);
  220. a_load_const_reg(list, OS_INT, a, tmpreg);
  221. list.concat(taicpu.op_reg_reg_reg(op, dst, src, tmpreg));
  222. end
  223. else
  224. begin
  225. if negate then
  226. a:=-a;
  227. list.concat(taicpu.op_reg_reg_const(op2, dst, src, a));
  228. end;
  229. end;
  230. {****************************************************************************
  231. Assembler code
  232. ****************************************************************************}
  233. procedure TCGMIPS.init_register_allocators;
  234. begin
  235. inherited init_register_allocators;
  236. { Keep RS_R25, i.e. $t9 for PIC call }
  237. if (cs_create_pic in current_settings.moduleswitches) and assigned(current_procinfo) and
  238. (pi_needs_got in current_procinfo.flags) then
  239. begin
  240. current_procinfo.got := NR_GP;
  241. rg[R_INTREGISTER] := Trgintcpu.Create(R_INTREGISTER, R_SUBD,
  242. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  243. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  244. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  245. first_int_imreg, []);
  246. end
  247. else
  248. rg[R_INTREGISTER] := trgintcpu.Create(R_INTREGISTER, R_SUBD,
  249. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  250. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  251. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  252. first_int_imreg, []);
  253. {
  254. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  255. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
  256. RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,
  257. RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,
  258. RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],
  259. first_fpu_imreg, []);
  260. }
  261. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  262. [RS_F0,RS_F2,RS_F4,RS_F6, RS_F8,RS_F10,RS_F12,RS_F14,
  263. RS_F16,RS_F18,RS_F20,RS_F22, RS_F24,RS_F26,RS_F28,RS_F30],
  264. first_fpu_imreg, []);
  265. { needs at least one element for rgobj not to crash }
  266. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  267. [RS_R0],first_mm_imreg,[]);
  268. end;
  269. procedure TCGMIPS.done_register_allocators;
  270. begin
  271. rg[R_INTREGISTER].Free;
  272. rg[R_FPUREGISTER].Free;
  273. rg[R_MMREGISTER].Free;
  274. inherited done_register_allocators;
  275. end;
  276. procedure TCGMIPS.a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara);
  277. var
  278. href, href2: treference;
  279. hloc: pcgparalocation;
  280. begin
  281. { TODO: inherited cannot deal with individual locations for each of OS_32 registers.
  282. Must change parameter management to allocate a single 64-bit register pair,
  283. then this method can be removed. }
  284. href := ref;
  285. hloc := paraloc.location;
  286. while assigned(hloc) do
  287. begin
  288. paramanager.allocparaloc(list,hloc);
  289. case hloc^.loc of
  290. LOC_REGISTER:
  291. a_load_ref_reg(list, hloc^.size, hloc^.size, href, hloc^.Register);
  292. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  293. a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  294. LOC_REFERENCE:
  295. begin
  296. paraloc.check_simple_location;
  297. reference_reset_base(href2,paraloc.location^.reference.index,paraloc.location^.reference.offset,paraloc.alignment);
  298. { concatcopy should choose the best way to copy the data }
  299. g_concatcopy(list,ref,href2,tcgsize2size[size]);
  300. end;
  301. else
  302. internalerror(200408241);
  303. end;
  304. Inc(href.offset, tcgsize2size[hloc^.size]);
  305. hloc := hloc^.Next;
  306. end;
  307. end;
  308. procedure TCGMIPS.a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara);
  309. var
  310. href: treference;
  311. begin
  312. if paraloc.Location^.next=nil then
  313. begin
  314. inherited a_loadfpu_reg_cgpara(list,size,r,paraloc);
  315. exit;
  316. end;
  317. tg.GetTemp(list, TCGSize2Size[size], TCGSize2Size[size], tt_normal, href);
  318. a_loadfpu_reg_ref(list, size, size, r, href);
  319. a_loadfpu_ref_cgpara(list, size, href, paraloc);
  320. tg.Ungettemp(list, href);
  321. end;
  322. procedure TCGMIPS.a_call_sym_pic(list: tasmlist; sym: tasmsymbol);
  323. var
  324. href: treference;
  325. begin
  326. reference_reset_symbol(href,sym,0,sizeof(aint));
  327. if (sym.bind=AB_LOCAL) then
  328. href.refaddr:=addr_pic
  329. else
  330. href.refaddr:=addr_pic_call16;
  331. href.base:=NR_GP;
  332. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  333. if (sym.bind=AB_LOCAL) then
  334. begin
  335. href.refaddr:=addr_low;
  336. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  337. end;
  338. list.concat(taicpu.op_reg(A_JALR,NR_PIC_FUNC));
  339. { Delay slot }
  340. list.concat(taicpu.op_none(A_NOP));
  341. { Restore GP if in PIC mode }
  342. if (cs_create_pic in current_settings.moduleswitches) then
  343. begin
  344. if TMIPSProcinfo(current_procinfo).save_gp_ref.offset=0 then
  345. InternalError(2013071001);
  346. list.concat(taicpu.op_reg_ref(A_LW,NR_GP,TMIPSProcinfo(current_procinfo).save_gp_ref));
  347. end;
  348. end;
  349. procedure TCGMIPS.a_call_name(list: tasmlist; const s: string; weak: boolean);
  350. var
  351. sym: tasmsymbol;
  352. begin
  353. if assigned(current_procinfo) and
  354. not (pi_do_call in current_procinfo.flags) then
  355. InternalError(2013022101);
  356. if weak then
  357. sym:=current_asmdata.WeakRefAsmSymbol(s)
  358. else
  359. sym:=current_asmdata.RefAsmSymbol(s);
  360. if (cs_create_pic in current_settings.moduleswitches) then
  361. a_call_sym_pic(list,sym)
  362. else
  363. begin
  364. list.concat(taicpu.op_sym(A_JAL,sym));
  365. { Delay slot }
  366. list.concat(taicpu.op_none(A_NOP));
  367. end;
  368. end;
  369. procedure TCGMIPS.a_call_reg(list: tasmlist; Reg: TRegister);
  370. begin
  371. if assigned(current_procinfo) and
  372. not (pi_do_call in current_procinfo.flags) then
  373. InternalError(2013022102);
  374. if (Reg <> NR_PIC_FUNC) then
  375. list.concat(taicpu.op_reg_reg(A_MOVE,NR_PIC_FUNC,reg));
  376. list.concat(taicpu.op_reg(A_JALR,NR_PIC_FUNC));
  377. { Delay slot }
  378. list.concat(taicpu.op_none(A_NOP));
  379. { Restore GP if in PIC mode }
  380. if (cs_create_pic in current_settings.moduleswitches) then
  381. begin
  382. if TMIPSProcinfo(current_procinfo).save_gp_ref.offset=0 then
  383. InternalError(2013071002);
  384. list.concat(taicpu.op_reg_ref(A_LW,NR_GP,TMIPSProcinfo(current_procinfo).save_gp_ref));
  385. end;
  386. end;
  387. {********************** load instructions ********************}
  388. procedure TCGMIPS.a_load_const_reg(list: tasmlist; size: TCGSize; a: tcgint; reg: TRegister);
  389. begin
  390. if (a = 0) then
  391. list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0))
  392. else if (a >= simm16lo) and (a <= simm16hi) then
  393. list.concat(taicpu.op_reg_reg_const(A_ADDIU, reg, NR_R0, a))
  394. else if (a>=0) and (a <= 65535) then
  395. list.concat(taicpu.op_reg_reg_const(A_ORI, reg, NR_R0, a))
  396. else
  397. begin
  398. list.concat(taicpu.op_reg_const(A_LUI, reg, aint(a) shr 16));
  399. if (a and aint($FFFF))<>0 then
  400. list.concat(taicpu.op_reg_reg_const(A_ORI,reg,reg,a and aint($FFFF)));
  401. end;
  402. end;
  403. procedure TCGMIPS.a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference);
  404. begin
  405. if a = 0 then
  406. a_load_reg_ref(list, size, size, NR_R0, ref)
  407. else
  408. inherited a_load_const_ref(list, size, a, ref);
  409. end;
  410. procedure TCGMIPS.a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCGSize; reg: tregister; const Ref: TReference);
  411. var
  412. op: tasmop;
  413. href: treference;
  414. begin
  415. if (TCGSize2Size[fromsize] < TCGSize2Size[tosize]) then
  416. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  417. case tosize of
  418. OS_8,
  419. OS_S8:
  420. Op := A_SB;
  421. OS_16,
  422. OS_S16:
  423. Op := A_SH;
  424. OS_32,
  425. OS_S32:
  426. Op := A_SW;
  427. else
  428. InternalError(2002122100);
  429. end;
  430. href:=ref;
  431. make_simple_ref(list,href);
  432. list.concat(taicpu.op_reg_ref(op,reg,href));
  433. end;
  434. procedure TCGMIPS.a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister);
  435. var
  436. op: tasmop;
  437. href: treference;
  438. begin
  439. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  440. fromsize := tosize;
  441. case fromsize of
  442. OS_S8:
  443. Op := A_LB;{Load Signed Byte}
  444. OS_8:
  445. Op := A_LBU;{Load Unsigned Byte}
  446. OS_S16:
  447. Op := A_LH;{Load Signed Halfword}
  448. OS_16:
  449. Op := A_LHU;{Load Unsigned Halfword}
  450. OS_S32:
  451. Op := A_LW;{Load Word}
  452. OS_32:
  453. Op := A_LW;//A_LWU;{Load Unsigned Word}
  454. OS_S64,
  455. OS_64:
  456. Op := A_LD;{Load a Long Word}
  457. else
  458. InternalError(2002122101);
  459. end;
  460. href:=ref;
  461. make_simple_ref(list,href);
  462. list.concat(taicpu.op_reg_ref(op,reg,href));
  463. if (fromsize=OS_S8) and (tosize=OS_16) then
  464. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  465. end;
  466. procedure TCGMIPS.a_load_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  467. var
  468. instr: taicpu;
  469. done: boolean;
  470. begin
  471. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  472. (
  473. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and (tosize <> fromsize)
  474. ) or ((fromsize = OS_S8) and
  475. (tosize = OS_16)) then
  476. begin
  477. done:=true;
  478. case tosize of
  479. OS_8:
  480. list.concat(taicpu.op_reg_reg_const(A_ANDI, reg2, reg1, $ff));
  481. OS_16:
  482. list.concat(taicpu.op_reg_reg_const(A_ANDI, reg2, reg1, $ffff));
  483. OS_32,
  484. OS_S32:
  485. done:=false;
  486. OS_S8:
  487. begin
  488. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 24));
  489. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 24));
  490. end;
  491. OS_S16:
  492. begin
  493. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 16));
  494. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 16));
  495. end;
  496. else
  497. internalerror(2002090901);
  498. end;
  499. end
  500. else
  501. done:=false;
  502. if (not done) and (reg1 <> reg2) then
  503. begin
  504. { same size, only a register mov required }
  505. instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1);
  506. list.Concat(instr);
  507. { Notify the register allocator that we have written a move instruction so
  508. it can try to eliminate it. }
  509. add_move_instruction(instr);
  510. end;
  511. end;
  512. procedure TCGMIPS.a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister);
  513. var
  514. href: treference;
  515. hreg: tregister;
  516. begin
  517. { Enforce some discipline for callers:
  518. - reference must be a "raw" one and not use gp }
  519. if (ref.base=NR_GP) or (ref.index=NR_GP) then
  520. InternalError(2013022803);
  521. if (ref.refaddr<>addr_no) then
  522. InternalError(2013022804);
  523. if (ref.base=NR_NO) and (ref.index<>NR_NO) then
  524. InternalError(200306171);
  525. if (ref.symbol=nil) then
  526. begin
  527. if (ref.base<>NR_NO) then
  528. begin
  529. if (ref.offset<simm16lo) or (ref.offset>simm16hi) then
  530. begin
  531. hreg:=getintregister(list,OS_INT);
  532. a_load_const_reg(list,OS_INT,ref.offset,hreg);
  533. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,ref.base,hreg));
  534. end
  535. else if (ref.offset<>0) then
  536. list.concat(taicpu.op_reg_reg_const(A_ADDIU,r,ref.base,ref.offset))
  537. else
  538. a_load_reg_reg(list,OS_INT,OS_INT,ref.base,r); { emit optimizable move }
  539. if (ref.index<>NR_NO) then
  540. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.index));
  541. end
  542. else
  543. a_load_const_reg(list,OS_INT,ref.offset,r);
  544. exit;
  545. end;
  546. reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment);
  547. if (cs_create_pic in current_settings.moduleswitches) then
  548. begin
  549. if not (pi_needs_got in current_procinfo.flags) then
  550. InternalError(2013060103);
  551. { For PIC global symbols offset must be handled separately.
  552. Otherwise (non-PIC or local symbols) offset can be encoded
  553. into relocation even if exceeds 16 bits. }
  554. if (href.symbol.bind<>AB_LOCAL) then
  555. href.offset:=0;
  556. href.refaddr:=addr_pic;
  557. href.base:=NR_GP;
  558. list.concat(taicpu.op_reg_ref(A_LW,r,href));
  559. end
  560. else
  561. begin
  562. href.refaddr:=addr_high;
  563. list.concat(taicpu.op_reg_ref(A_LUI,r,href));
  564. end;
  565. { Add original base/index, if any. }
  566. if (ref.base<>NR_NO) then
  567. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.base));
  568. if (ref.index<>NR_NO) then
  569. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.index));
  570. { add low part if necessary }
  571. if (ref.symbol.bind=AB_LOCAL) or
  572. not (cs_create_pic in current_settings.moduleswitches) then
  573. begin
  574. href.refaddr:=addr_low;
  575. href.base:=NR_NO;
  576. list.concat(taicpu.op_reg_reg_ref(A_ADDIU,r,r,href));
  577. exit;
  578. end;
  579. if (ref.offset<simm16lo) or (ref.offset>simm16hi) then
  580. begin
  581. hreg:=getintregister(list,OS_INT);
  582. a_load_const_reg(list,OS_INT,ref.offset,hreg);
  583. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,hreg));
  584. end
  585. else if (ref.offset<>0) then
  586. list.concat(taicpu.op_reg_reg_const(A_ADDIU,r,r,ref.offset));
  587. end;
  588. procedure TCGMIPS.a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  589. const
  590. FpuMovInstr: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  591. ((A_MOV_S, A_CVT_D_S),(A_CVT_S_D,A_MOV_D));
  592. var
  593. instr: taicpu;
  594. begin
  595. if (reg1 <> reg2) or (fromsize<>tosize) then
  596. begin
  597. instr := taicpu.op_reg_reg(fpumovinstr[fromsize,tosize], reg2, reg1);
  598. list.Concat(instr);
  599. { Notify the register allocator that we have written a move instruction so
  600. it can try to eliminate it. }
  601. if (fromsize=tosize) then
  602. add_move_instruction(instr);
  603. end;
  604. end;
  605. procedure TCGMIPS.a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister);
  606. var
  607. href: TReference;
  608. begin
  609. href:=ref;
  610. make_simple_ref(list,href);
  611. case fromsize of
  612. OS_F32:
  613. list.concat(taicpu.op_reg_ref(A_LWC1,reg,href));
  614. OS_F64:
  615. list.concat(taicpu.op_reg_ref(A_LDC1,reg,href));
  616. else
  617. InternalError(2007042701);
  618. end;
  619. if tosize<>fromsize then
  620. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  621. end;
  622. procedure TCGMIPS.a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference);
  623. var
  624. href: TReference;
  625. begin
  626. if tosize<>fromsize then
  627. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  628. href:=ref;
  629. make_simple_ref(list,href);
  630. case tosize of
  631. OS_F32:
  632. list.concat(taicpu.op_reg_ref(A_SWC1,reg,href));
  633. OS_F64:
  634. list.concat(taicpu.op_reg_ref(A_SDC1,reg,href));
  635. else
  636. InternalError(2007042702);
  637. end;
  638. end;
  639. procedure TCGMIPS.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  640. const
  641. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  642. begin
  643. if (op in overflowops) and
  644. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  645. a_load_reg_reg(list,OS_32,size,dst,dst);
  646. end;
  647. procedure TCGMIPS.overflowcheck_internal(list: tasmlist; arg1, arg2: tregister);
  648. var
  649. carry, hreg: tregister;
  650. begin
  651. if (arg1=arg2) then
  652. InternalError(2013050501);
  653. carry:=GetIntRegister(list,OS_INT);
  654. hreg:=GetIntRegister(list,OS_INT);
  655. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,arg1,arg2));
  656. { if carry<>0, this will cause hardware overflow interrupt }
  657. a_load_const_reg(list,OS_INT,$80000000,hreg);
  658. list.concat(taicpu.op_reg_reg_reg(A_SUB,hreg,hreg,carry));
  659. end;
  660. const
  661. ops_add: array[boolean] of TAsmOp = (A_ADDU, A_ADD);
  662. ops_sub: array[boolean] of TAsmOp = (A_SUBU, A_SUB);
  663. ops_slt: array[boolean] of TAsmOp = (A_SLTU, A_SLT);
  664. ops_slti: array[boolean] of TAsmOp = (A_SLTIU, A_SLTI);
  665. ops_and: array[boolean] of TAsmOp = (A_AND, A_ANDI);
  666. ops_or: array[boolean] of TAsmOp = (A_OR, A_ORI);
  667. ops_xor: array[boolean] of TasmOp = (A_XOR, A_XORI);
  668. procedure TCGMIPS.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister);
  669. begin
  670. optimize_op_const(size,op,a);
  671. case op of
  672. OP_NONE:
  673. exit;
  674. OP_MOVE:
  675. a_load_const_reg(list,size,a,reg);
  676. OP_NEG,OP_NOT:
  677. internalerror(200306011);
  678. else
  679. a_op_const_reg_reg(list,op,size,a,reg,reg);
  680. end;
  681. end;
  682. procedure TCGMIPS.a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  683. begin
  684. case Op of
  685. OP_NEG:
  686. list.concat(taicpu.op_reg_reg_reg(A_SUBU, dst, NR_R0, src));
  687. OP_NOT:
  688. list.concat(taicpu.op_reg_reg_reg(A_NOR, dst, NR_R0, src));
  689. OP_IMUL,OP_MUL:
  690. begin
  691. list.concat(taicpu.op_reg_reg(TOpcg2AsmOp[op], dst, src));
  692. list.concat(taicpu.op_reg(A_MFLO, dst));
  693. end;
  694. else
  695. a_op_reg_reg_reg(list, op, size, src, dst, dst);
  696. exit;
  697. end;
  698. maybeadjustresult(list,op,size,dst);
  699. end;
  700. procedure TCGMIPS.a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  701. var
  702. l: TLocation;
  703. begin
  704. a_op_const_reg_reg_checkoverflow(list, op, size, a, src, dst, false, l);
  705. end;
  706. procedure TCGMIPS.a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  707. var
  708. hreg: tregister;
  709. begin
  710. if (TOpcg2AsmOp[op]=A_NONE) then
  711. InternalError(2013070305);
  712. if (op=OP_SAR) then
  713. begin
  714. if (size in [OS_S8,OS_S16]) then
  715. begin
  716. { Shift left by 16/24 bits and increase amount of right shift by same value }
  717. list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src2, 32-(tcgsize2size[size]*8)));
  718. hreg:=GetIntRegister(list,OS_INT);
  719. a_op_const_reg_reg(list,OP_ADD,OS_INT,32-(tcgsize2size[size]*8),src1,dst);
  720. src1:=hreg;
  721. end
  722. else if not (size in [OS_32,OS_S32]) then
  723. InternalError(2013070306);
  724. end;
  725. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  726. maybeadjustresult(list,op,size,dst);
  727. end;
  728. procedure TCGMIPS.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  729. var
  730. signed,immed: boolean;
  731. hreg: TRegister;
  732. asmop: TAsmOp;
  733. begin
  734. ovloc.loc := LOC_VOID;
  735. optimize_op_const(size,op,a);
  736. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  737. if (setflags and (not signed) and (src=dst) and (op in [OP_ADD,OP_SUB])) then
  738. hreg:=GetIntRegister(list,OS_INT)
  739. else
  740. hreg:=dst;
  741. case op of
  742. OP_NONE:
  743. a_load_reg_reg(list,size,size,src,dst);
  744. OP_MOVE:
  745. a_load_const_reg(list,size,a,dst);
  746. OP_ADD:
  747. begin
  748. handle_reg_const_reg(list,ops_add[setflags and signed],src,a,hreg);
  749. if setflags and (not signed) then
  750. overflowcheck_internal(list,hreg,src);
  751. { does nothing if hreg=dst }
  752. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  753. end;
  754. OP_SUB:
  755. begin
  756. handle_reg_const_reg(list,ops_sub[setflags and signed],src,a,hreg);
  757. if setflags and (not signed) then
  758. overflowcheck_internal(list,src,hreg);
  759. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  760. end;
  761. OP_MUL,OP_IMUL:
  762. begin
  763. hreg:=GetIntRegister(list,OS_INT);
  764. a_load_const_reg(list,OS_INT,a,hreg);
  765. a_op_reg_reg_reg_checkoverflow(list,op,size,src,hreg,dst,setflags,ovloc);
  766. exit;
  767. end;
  768. OP_AND,OP_OR,OP_XOR:
  769. begin
  770. { logical operations zero-extend, not sign-extend, the immediate }
  771. immed:=(a>=0) and (a<=65535);
  772. case op of
  773. OP_AND: asmop:=ops_and[immed];
  774. OP_OR: asmop:=ops_or[immed];
  775. OP_XOR: asmop:=ops_xor[immed];
  776. else
  777. InternalError(2013050401);
  778. end;
  779. if immed then
  780. list.concat(taicpu.op_reg_reg_const(asmop,dst,src,a))
  781. else
  782. begin
  783. hreg:=GetIntRegister(list,OS_INT);
  784. a_load_const_reg(list,OS_INT,a,hreg);
  785. list.concat(taicpu.op_reg_reg_reg(asmop,dst,src,hreg));
  786. end;
  787. end;
  788. OP_SHL:
  789. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,a));
  790. OP_SHR:
  791. list.concat(taicpu.op_reg_reg_const(A_SRL,dst,src,a));
  792. OP_SAR:
  793. begin
  794. if (size in [OS_S8,OS_S16]) then
  795. begin
  796. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,32-(tcgsize2size[size]*8)));
  797. inc(a,32-tcgsize2size[size]*8);
  798. src:=dst;
  799. end
  800. else if not (size in [OS_32,OS_S32]) then
  801. InternalError(2013070303);
  802. list.concat(taicpu.op_reg_reg_const(A_SRA,dst,src,a));
  803. end;
  804. else
  805. internalerror(2007012601);
  806. end;
  807. maybeadjustresult(list,op,size,dst);
  808. end;
  809. procedure TCGMIPS.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  810. var
  811. signed: boolean;
  812. hreg,hreg2: TRegister;
  813. hl: tasmlabel;
  814. begin
  815. ovloc.loc := LOC_VOID;
  816. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  817. if (setflags and (not signed) and (src2=dst) and (op in [OP_ADD,OP_SUB])) then
  818. hreg:=GetIntRegister(list,OS_INT)
  819. else
  820. hreg:=dst;
  821. case op of
  822. OP_ADD:
  823. begin
  824. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], hreg, src2, src1));
  825. if setflags and (not signed) then
  826. overflowcheck_internal(list, hreg, src2);
  827. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  828. end;
  829. OP_SUB:
  830. begin
  831. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], hreg, src2, src1));
  832. if setflags and (not signed) then
  833. overflowcheck_internal(list, src2, hreg);
  834. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  835. end;
  836. OP_MUL,OP_IMUL:
  837. begin
  838. list.concat(taicpu.op_reg_reg(TOpCg2AsmOp[op], src2, src1));
  839. list.concat(taicpu.op_reg(A_MFLO, dst));
  840. if setflags then
  841. begin
  842. current_asmdata.getjumplabel(hl);
  843. hreg:=GetIntRegister(list,OS_INT);
  844. list.concat(taicpu.op_reg(A_MFHI,hreg));
  845. if (op=OP_IMUL) then
  846. begin
  847. hreg2:=GetIntRegister(list,OS_INT);
  848. list.concat(taicpu.op_reg_reg_const(A_SRA,hreg2,dst,31));
  849. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg2,hreg,hl);
  850. end
  851. else
  852. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg,NR_R0,hl);
  853. list.concat(taicpu.op_const(A_BREAK,6));
  854. a_label(list,hl);
  855. end;
  856. end;
  857. OP_AND,OP_OR,OP_XOR:
  858. begin
  859. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  860. end;
  861. else
  862. internalerror(2007012602);
  863. end;
  864. maybeadjustresult(list,op,size,dst);
  865. end;
  866. {*************** compare instructructions ****************}
  867. procedure TCGMIPS.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  868. var
  869. tmpreg: tregister;
  870. begin
  871. if a = 0 then
  872. a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
  873. else
  874. begin
  875. tmpreg := GetIntRegister(list,OS_INT);
  876. if (a>=simm16lo) and (a<=simm16hi) and
  877. (cmp_op in [OC_LT,OC_B,OC_GTE,OC_AE]) then
  878. begin
  879. list.concat(taicpu.op_reg_reg_const(ops_slti[cmp_op in [OC_LT,OC_GTE]],tmpreg,reg,a));
  880. if cmp_op in [OC_LT,OC_B] then
  881. a_cmp_reg_reg_label(list,size,OC_NE,NR_R0,tmpreg,l)
  882. else
  883. a_cmp_reg_reg_label(list,size,OC_EQ,NR_R0,tmpreg,l);
  884. end
  885. else
  886. begin
  887. a_load_const_reg(list,OS_INT,a,tmpreg);
  888. a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
  889. end;
  890. end;
  891. end;
  892. const
  893. TOpCmp2AsmCond_z : array[OC_GT..OC_LTE] of TAsmCond=(
  894. C_GTZ,C_LTZ,C_GEZ,C_LEZ
  895. );
  896. TOpCmp2AsmCond_eqne: array[topcmp] of TAsmCond = (C_NONE,
  897. { eq gt lt gte lte ne }
  898. C_NONE, C_NE, C_NE, C_EQ, C_EQ, C_NONE,
  899. { be b ae a }
  900. C_EQ, C_NE, C_EQ, C_NE
  901. );
  902. procedure TCGMIPS.a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  903. var
  904. ai : Taicpu;
  905. op: TAsmOp;
  906. hreg: TRegister;
  907. begin
  908. if not (cmp_op in [OC_EQ,OC_NE]) then
  909. begin
  910. if ((reg1=NR_R0) or (reg2=NR_R0)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
  911. begin
  912. if (reg2=NR_R0) then
  913. begin
  914. ai:=taicpu.op_reg_sym(A_BC,reg1,l);
  915. ai.setcondition(TOpCmp2AsmCond_z[swap_opcmp(cmp_op)]);
  916. end
  917. else
  918. begin
  919. ai:=taicpu.op_reg_sym(A_BC,reg2,l);
  920. ai.setcondition(TOpCmp2AsmCond_z[cmp_op]);
  921. end;
  922. end
  923. else
  924. begin
  925. hreg:=GetIntRegister(list,OS_INT);
  926. op:=ops_slt[cmp_op in [OC_LT,OC_LTE,OC_GT,OC_GTE]];
  927. if (cmp_op in [OC_LTE,OC_GT,OC_BE,OC_A]) then { swap operands }
  928. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg1,reg2))
  929. else
  930. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg2,reg1));
  931. if (TOpCmp2AsmCond_eqne[cmp_op]=C_NONE) then
  932. InternalError(2013051501);
  933. ai:=taicpu.op_reg_reg_sym(A_BC,hreg,NR_R0,l);
  934. ai.SetCondition(TOpCmp2AsmCond_eqne[cmp_op]);
  935. end;
  936. end
  937. else
  938. begin
  939. ai:=taicpu.op_reg_reg_sym(A_BC,reg2,reg1,l);
  940. ai.SetCondition(TOpCmp2AsmCond[cmp_op]);
  941. end;
  942. list.concat(ai);
  943. { Delay slot }
  944. list.Concat(TAiCpu.Op_none(A_NOP));
  945. end;
  946. procedure TCGMIPS.a_jmp_always(List: tasmlist; l: TAsmLabel);
  947. var
  948. ai : Taicpu;
  949. begin
  950. ai := taicpu.op_sym(A_BA, l);
  951. list.concat(ai);
  952. { Delay slot }
  953. list.Concat(TAiCpu.Op_none(A_NOP));
  954. end;
  955. procedure TCGMIPS.a_jmp_name(list: tasmlist; const s: string);
  956. begin
  957. List.Concat(TAiCpu.op_sym(A_BA, current_asmdata.RefAsmSymbol(s)));
  958. { Delay slot }
  959. list.Concat(TAiCpu.Op_none(A_NOP));
  960. end;
  961. procedure TCGMIPS.a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel);
  962. begin
  963. if f.use_const then
  964. a_cmp_const_reg_label(list,OS_INT,f.cond,f.value,f.reg1,l)
  965. else
  966. a_cmp_reg_reg_label(list,OS_INT,f.cond,f.reg2,f.reg1,l);
  967. end;
  968. procedure TCGMIPS.g_flags2reg(list: tasmlist; size: tcgsize; const f: tresflags; reg: tregister);
  969. var
  970. left,right: tregister;
  971. unsigned: boolean;
  972. begin
  973. if (f.cond in [OC_EQ,OC_NE]) then
  974. begin
  975. left:=reg;
  976. if f.use_const and (f.value>=0) and (f.value<=65535) then
  977. begin
  978. if (f.value<>0) then
  979. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,f.reg1,f.value))
  980. else
  981. left:=f.reg1;
  982. end
  983. else
  984. begin
  985. if f.use_const then
  986. begin
  987. right:=GetIntRegister(list,OS_INT);
  988. a_load_const_reg(list,OS_INT,f.value,right);
  989. end
  990. else
  991. right:=f.reg2;
  992. list.concat(taicpu.op_reg_reg_reg(A_XOR,reg,f.reg1,right));
  993. end;
  994. if f.cond=OC_EQ then
  995. list.concat(taicpu.op_reg_reg_const(A_SLTIU,reg,left,1))
  996. else
  997. list.concat(taicpu.op_reg_reg_reg(A_SLTU,reg,NR_R0,left));
  998. end
  999. else
  1000. begin
  1001. {
  1002. sle x,a,b --> slt x,b,a; xori x,x,1 immediate not possible (or must be at left)
  1003. sgt x,a,b --> slt x,b,a likewise
  1004. sge x,a,b --> slt x,a,b; xori x,x,1
  1005. slt x,a,b --> unchanged
  1006. }
  1007. unsigned:=f.cond in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  1008. if (f.cond in [OC_GTE,OC_LT,OC_B,OC_AE]) and
  1009. f.use_const and
  1010. (f.value>=simm16lo) and
  1011. (f.value<=simm16hi) then
  1012. list.Concat(taicpu.op_reg_reg_const(ops_slti[unsigned],reg,f.reg1,f.value))
  1013. else
  1014. begin
  1015. if f.use_const then
  1016. begin
  1017. if (f.value=0) then
  1018. right:=NR_R0
  1019. else
  1020. begin
  1021. right:=GetIntRegister(list,OS_INT);
  1022. a_load_const_reg(list,OS_INT,f.value,right);
  1023. end;
  1024. end
  1025. else
  1026. right:=f.reg2;
  1027. if (f.cond in [OC_LTE,OC_GT,OC_BE,OC_A]) then
  1028. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,right,f.reg1))
  1029. else
  1030. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,f.reg1,right));
  1031. end;
  1032. if (f.cond in [OC_LTE,OC_GTE,OC_BE,OC_AE]) then
  1033. list.Concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  1034. end;
  1035. end;
  1036. procedure TCGMIPS.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef);
  1037. begin
  1038. // this is an empty procedure
  1039. end;
  1040. procedure TCGMIPS.g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation);
  1041. begin
  1042. // this is an empty procedure
  1043. end;
  1044. { *********** entry/exit code and address loading ************ }
  1045. procedure FixupOffsets(p:TObject;arg:pointer);
  1046. var
  1047. sym: tabstractnormalvarsym absolute p;
  1048. begin
  1049. if (tsym(p).typ=paravarsym) and
  1050. (sym.localloc.loc=LOC_REFERENCE) and
  1051. (sym.localloc.reference.base=NR_FRAME_POINTER_REG) then
  1052. begin
  1053. sym.localloc.reference.base:=NR_STACK_POINTER_REG;
  1054. Inc(sym.localloc.reference.offset,PLongint(arg)^);
  1055. end;
  1056. end;
  1057. procedure TCGMIPS.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean);
  1058. var
  1059. lastintoffset,lastfpuoffset,
  1060. nextoffset : aint;
  1061. i : longint;
  1062. ra_save,framesave : taicpu;
  1063. fmask,mask : dword;
  1064. saveregs : tcpuregisterset;
  1065. href: treference;
  1066. reg : Tsuperregister;
  1067. helplist : TAsmList;
  1068. largeoffs : boolean;
  1069. begin
  1070. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1071. if nostackframe then
  1072. exit;
  1073. if (pi_needs_stackframe in current_procinfo.flags) then
  1074. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1075. helplist:=TAsmList.Create;
  1076. reference_reset(href,0);
  1077. href.base:=NR_STACK_POINTER_REG;
  1078. fmask:=0;
  1079. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1080. lastfpuoffset:=LocalSize;
  1081. for reg := RS_F0 to RS_F31 do { to check: what if F30 is double? }
  1082. begin
  1083. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1084. begin
  1085. fmask:=fmask or (1 shl ord(reg));
  1086. href.offset:=nextoffset;
  1087. lastfpuoffset:=nextoffset;
  1088. helplist.concat(taicpu.op_reg_ref(A_SWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1089. inc(nextoffset,4);
  1090. { IEEE Double values are stored in floating point
  1091. register pairs f2X/f2X+1,
  1092. as the f2X+1 register is not correctly marked as used for now,
  1093. we simply assume it is also used if f2X is used
  1094. Should be fixed by a proper inclusion of f2X+1 into used_in_proc }
  1095. if (ord(reg)-ord(RS_F0)) mod 2 = 0 then
  1096. include(rg[R_FPUREGISTER].used_in_proc,succ(reg));
  1097. end;
  1098. end;
  1099. mask:=0;
  1100. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1101. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1102. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1103. include(saveregs,RS_R31);
  1104. if (pi_needs_stackframe in current_procinfo.flags) then
  1105. include(saveregs,RS_FRAME_POINTER_REG);
  1106. lastintoffset:=LocalSize;
  1107. framesave:=nil;
  1108. ra_save:=nil;
  1109. for reg:=RS_R1 to RS_R31 do
  1110. begin
  1111. if reg in saveregs then
  1112. begin
  1113. mask:=mask or (1 shl ord(reg));
  1114. href.offset:=nextoffset;
  1115. lastintoffset:=nextoffset;
  1116. if (reg=RS_FRAME_POINTER_REG) then
  1117. framesave:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1118. else if (reg=RS_R31) then
  1119. ra_save:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1120. else
  1121. helplist.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1122. inc(nextoffset,4);
  1123. end;
  1124. end;
  1125. //list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,current_procinfo.para_stack_size));
  1126. list.concat(Taicpu.op_none(A_P_SET_NOMIPS16));
  1127. list.concat(Taicpu.op_reg_const_reg(A_P_FRAME,current_procinfo.framepointer,LocalSize,NR_R31));
  1128. list.concat(Taicpu.op_const_const(A_P_MASK,mask,-(LocalSize-lastintoffset)));
  1129. list.concat(Taicpu.op_const_const(A_P_FMASK,Fmask,-(LocalSize-lastfpuoffset)));
  1130. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1131. if (cs_create_pic in current_settings.moduleswitches) and
  1132. (pi_needs_got in current_procinfo.flags) then
  1133. begin
  1134. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1135. end;
  1136. if (-LocalSize >= simm16lo) and (-LocalSize <= simm16hi) then
  1137. begin
  1138. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1139. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-LocalSize));
  1140. if assigned(ra_save) then
  1141. list.concat(ra_save);
  1142. if assigned(framesave) then
  1143. begin
  1144. list.concat(framesave);
  1145. list.concat(Taicpu.op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,
  1146. NR_STACK_POINTER_REG,LocalSize));
  1147. end;
  1148. end
  1149. else
  1150. begin
  1151. a_load_const_reg(list,OS_32,-LocalSize,NR_R9);
  1152. list.concat(Taicpu.Op_reg_reg_reg(A_ADDU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R9));
  1153. if assigned(ra_save) then
  1154. list.concat(ra_save);
  1155. if assigned(framesave) then
  1156. begin
  1157. list.concat(framesave);
  1158. list.concat(Taicpu.op_reg_reg_reg(A_SUBU,NR_FRAME_POINTER_REG,
  1159. NR_STACK_POINTER_REG,NR_R9));
  1160. end;
  1161. { The instructions before are macros that can extend to multiple instructions,
  1162. the settings of R9 to -LocalSize surely does,
  1163. but the saving of RA and FP also might, and might
  1164. even use AT register, which is why we use R9 instead of AT here for -LocalSize }
  1165. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1166. end;
  1167. if (cs_create_pic in current_settings.moduleswitches) and
  1168. (pi_needs_got in current_procinfo.flags) then
  1169. begin
  1170. largeoffs:=(TMIPSProcinfo(current_procinfo).save_gp_ref.offset>simm16hi);
  1171. if largeoffs then
  1172. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1173. list.concat(Taicpu.op_const(A_P_CPRESTORE,TMIPSProcinfo(current_procinfo).save_gp_ref.offset));
  1174. if largeoffs then
  1175. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1176. end;
  1177. href.base:=NR_STACK_POINTER_REG;
  1178. for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
  1179. if TMIPSProcInfo(current_procinfo).register_used[i] then
  1180. begin
  1181. reg:=parasupregs[i];
  1182. href.offset:=i*sizeof(aint)+LocalSize;
  1183. list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
  1184. end;
  1185. list.concatList(helplist);
  1186. helplist.Free;
  1187. if current_procinfo.has_nestedprocs then
  1188. current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@LocalSize);
  1189. end;
  1190. procedure TCGMIPS.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean);
  1191. var
  1192. href : treference;
  1193. stacksize : aint;
  1194. saveregs : tcpuregisterset;
  1195. nextoffset : aint;
  1196. reg : Tsuperregister;
  1197. begin
  1198. stacksize:=current_procinfo.calc_stackframe_size;
  1199. if nostackframe then
  1200. begin
  1201. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1202. list.concat(Taicpu.op_none(A_NOP));
  1203. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1204. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1205. end
  1206. else
  1207. begin
  1208. if TMIPSProcinfo(current_procinfo).save_gp_ref.offset<>0 then
  1209. tg.ungettemp(list,TMIPSProcinfo(current_procinfo).save_gp_ref);
  1210. reference_reset(href,0);
  1211. href.base:=NR_STACK_POINTER_REG;
  1212. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1213. for reg := RS_F0 to RS_F31 do
  1214. begin
  1215. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1216. begin
  1217. href.offset:=nextoffset;
  1218. list.concat(taicpu.op_reg_ref(A_LWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1219. inc(nextoffset,4);
  1220. end;
  1221. end;
  1222. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1223. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1224. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1225. include(saveregs,RS_R31);
  1226. if (pi_needs_stackframe in current_procinfo.flags) then
  1227. include(saveregs,RS_FRAME_POINTER_REG);
  1228. // GP does not need to be restored on exit
  1229. for reg:=RS_R1 to RS_R31 do
  1230. begin
  1231. if reg in saveregs then
  1232. begin
  1233. href.offset:=nextoffset;
  1234. list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1235. inc(nextoffset,sizeof(aint));
  1236. end;
  1237. end;
  1238. if (-stacksize >= simm16lo) and (-stacksize <= simm16hi) then
  1239. begin
  1240. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1241. { correct stack pointer in the delay slot }
  1242. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, stacksize));
  1243. end
  1244. else
  1245. begin
  1246. a_load_const_reg(list,OS_32,stacksize,NR_R1);
  1247. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1248. { correct stack pointer in the delay slot }
  1249. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R1));
  1250. end;
  1251. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1252. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1253. end;
  1254. end;
  1255. { ************* concatcopy ************ }
  1256. procedure TCGMIPS.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  1257. var
  1258. paraloc1, paraloc2, paraloc3: TCGPara;
  1259. pd: tprocdef;
  1260. begin
  1261. pd:=search_system_proc('MOVE');
  1262. paraloc1.init;
  1263. paraloc2.init;
  1264. paraloc3.init;
  1265. paramanager.getintparaloc(pd, 1, paraloc1);
  1266. paramanager.getintparaloc(pd, 2, paraloc2);
  1267. paramanager.getintparaloc(pd, 3, paraloc3);
  1268. a_load_const_cgpara(list, OS_SINT, len, paraloc3);
  1269. a_loadaddr_ref_cgpara(list, dest, paraloc2);
  1270. a_loadaddr_ref_cgpara(list, Source, paraloc1);
  1271. paramanager.freecgpara(list, paraloc3);
  1272. paramanager.freecgpara(list, paraloc2);
  1273. paramanager.freecgpara(list, paraloc1);
  1274. alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1275. alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1276. a_call_name(list, 'FPC_MOVE', false);
  1277. dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1278. dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1279. paraloc3.done;
  1280. paraloc2.done;
  1281. paraloc1.done;
  1282. end;
  1283. procedure TCGMIPS.g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint);
  1284. var
  1285. tmpreg1, hreg, countreg: TRegister;
  1286. src, dst: TReference;
  1287. lab: tasmlabel;
  1288. Count, count2: aint;
  1289. function reference_is_reusable(const ref: treference): boolean;
  1290. begin
  1291. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1292. (ref.symbol=nil) and
  1293. (ref.offset>=simm16lo) and (ref.offset+len<=simm16hi);
  1294. end;
  1295. begin
  1296. if len > high(longint) then
  1297. internalerror(2002072704);
  1298. { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
  1299. allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
  1300. i.e. before secondpass. Other internal procedures request correct stack frame
  1301. by setting pi_do_call during firstpass, but for this particular one it is impossible.
  1302. Therefore, if the current procedure is a leaf one, we have to leave it that way. }
  1303. { anybody wants to determine a good value here :)? }
  1304. if (len > 100) and
  1305. assigned(current_procinfo) and
  1306. (pi_do_call in current_procinfo.flags) then
  1307. g_concatcopy_move(list, Source, dest, len)
  1308. else
  1309. begin
  1310. Count := len div 4;
  1311. if (count<=4) and reference_is_reusable(source) then
  1312. src:=source
  1313. else
  1314. begin
  1315. reference_reset(src,sizeof(aint));
  1316. { load the address of source into src.base }
  1317. src.base := GetAddressRegister(list);
  1318. a_loadaddr_ref_reg(list, Source, src.base);
  1319. end;
  1320. if (count<=4) and reference_is_reusable(dest) then
  1321. dst:=dest
  1322. else
  1323. begin
  1324. reference_reset(dst,sizeof(aint));
  1325. { load the address of dest into dst.base }
  1326. dst.base := GetAddressRegister(list);
  1327. a_loadaddr_ref_reg(list, dest, dst.base);
  1328. end;
  1329. { generate a loop }
  1330. if Count > 4 then
  1331. begin
  1332. countreg := GetIntRegister(list, OS_INT);
  1333. tmpreg1 := GetIntRegister(list, OS_INT);
  1334. a_load_const_reg(list, OS_INT, Count, countreg);
  1335. current_asmdata.getjumplabel(lab);
  1336. a_label(list, lab);
  1337. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1338. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1339. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4));
  1340. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4));
  1341. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1342. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1343. len := len mod 4;
  1344. end;
  1345. { unrolled loop }
  1346. Count := len div 4;
  1347. if Count > 0 then
  1348. begin
  1349. tmpreg1 := GetIntRegister(list, OS_INT);
  1350. for count2 := 1 to Count do
  1351. begin
  1352. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1353. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1354. Inc(src.offset, 4);
  1355. Inc(dst.offset, 4);
  1356. end;
  1357. len := len mod 4;
  1358. end;
  1359. if (len and 4) <> 0 then
  1360. begin
  1361. hreg := GetIntRegister(list, OS_INT);
  1362. a_load_ref_reg(list, OS_32, OS_32, src, hreg);
  1363. a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
  1364. Inc(src.offset, 4);
  1365. Inc(dst.offset, 4);
  1366. end;
  1367. { copy the leftovers }
  1368. if (len and 2) <> 0 then
  1369. begin
  1370. hreg := GetIntRegister(list, OS_INT);
  1371. a_load_ref_reg(list, OS_16, OS_16, src, hreg);
  1372. a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
  1373. Inc(src.offset, 2);
  1374. Inc(dst.offset, 2);
  1375. end;
  1376. if (len and 1) <> 0 then
  1377. begin
  1378. hreg := GetIntRegister(list, OS_INT);
  1379. a_load_ref_reg(list, OS_8, OS_8, src, hreg);
  1380. a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
  1381. end;
  1382. end;
  1383. end;
  1384. procedure TCGMIPS.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint);
  1385. var
  1386. src, dst: TReference;
  1387. tmpreg1, countreg: TRegister;
  1388. i: aint;
  1389. lab: tasmlabel;
  1390. begin
  1391. if (len > 31) and
  1392. { see comment in g_concatcopy }
  1393. assigned(current_procinfo) and
  1394. (pi_do_call in current_procinfo.flags) then
  1395. g_concatcopy_move(list, Source, dest, len)
  1396. else
  1397. begin
  1398. reference_reset(src,sizeof(aint));
  1399. reference_reset(dst,sizeof(aint));
  1400. { load the address of source into src.base }
  1401. src.base := GetAddressRegister(list);
  1402. a_loadaddr_ref_reg(list, Source, src.base);
  1403. { load the address of dest into dst.base }
  1404. dst.base := GetAddressRegister(list);
  1405. a_loadaddr_ref_reg(list, dest, dst.base);
  1406. { generate a loop }
  1407. if len > 4 then
  1408. begin
  1409. countreg := GetIntRegister(list, OS_INT);
  1410. tmpreg1 := GetIntRegister(list, OS_INT);
  1411. a_load_const_reg(list, OS_INT, len, countreg);
  1412. current_asmdata.getjumplabel(lab);
  1413. a_label(list, lab);
  1414. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1415. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1416. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1));
  1417. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1));
  1418. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1419. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1420. end
  1421. else
  1422. begin
  1423. { unrolled loop }
  1424. tmpreg1 := GetIntRegister(list, OS_INT);
  1425. for i := 1 to len do
  1426. begin
  1427. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1428. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1429. Inc(src.offset);
  1430. Inc(dst.offset);
  1431. end;
  1432. end;
  1433. end;
  1434. end;
  1435. procedure TCGMIPS.g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint);
  1436. var
  1437. make_global: boolean;
  1438. hsym: tsym;
  1439. href: treference;
  1440. paraloc: Pcgparalocation;
  1441. IsVirtual: boolean;
  1442. begin
  1443. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1444. Internalerror(200006137);
  1445. if not assigned(procdef.struct) or
  1446. (procdef.procoptions * [po_classmethod, po_staticmethod,
  1447. po_methodpointer, po_interrupt, po_iocheck] <> []) then
  1448. Internalerror(200006138);
  1449. if procdef.owner.symtabletype <> objectsymtable then
  1450. Internalerror(200109191);
  1451. make_global := False;
  1452. if (not current_module.is_unit) or create_smartlink or
  1453. (procdef.owner.defowner.owner.symtabletype = globalsymtable) then
  1454. make_global := True;
  1455. if make_global then
  1456. List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0))
  1457. else
  1458. List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0));
  1459. IsVirtual:=(po_virtualmethod in procdef.procoptions) and
  1460. not is_objectpascal_helper(procdef.struct);
  1461. if (cs_create_pic in current_settings.moduleswitches) and
  1462. (not IsVirtual) then
  1463. begin
  1464. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1465. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1466. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1467. end;
  1468. { set param1 interface to self }
  1469. procdef.init_paraloc_info(callerside);
  1470. hsym:=tsym(procdef.parast.Find('self'));
  1471. if not(assigned(hsym) and
  1472. (hsym.typ=paravarsym)) then
  1473. internalerror(2010103101);
  1474. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1475. if assigned(paraloc^.next) then
  1476. InternalError(2013020101);
  1477. case paraloc^.loc of
  1478. LOC_REGISTER:
  1479. begin
  1480. if ((ioffset>=simm16lo) and (ioffset<=simm16hi)) then
  1481. a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
  1482. else
  1483. begin
  1484. a_load_const_reg(list, paraloc^.size, ioffset, NR_R1);
  1485. a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_R1, paraloc^.register);
  1486. end;
  1487. end;
  1488. else
  1489. internalerror(2010103102);
  1490. end;
  1491. if IsVirtual then
  1492. begin
  1493. { load VMT pointer }
  1494. reference_reset_base(href,paraloc^.register,0,sizeof(aint));
  1495. list.concat(taicpu.op_reg_ref(A_LW,NR_VMT,href));
  1496. if (procdef.extnumber=$ffff) then
  1497. Internalerror(200006139);
  1498. { TODO: case of large VMT is not handled }
  1499. { We have no reason not to use $t9 even in non-PIC mode. }
  1500. reference_reset_base(href, NR_VMT, tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber), sizeof(aint));
  1501. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1502. list.concat(taicpu.op_reg(A_JR, NR_PIC_FUNC));
  1503. end
  1504. else if not (cs_create_pic in current_settings.moduleswitches) then
  1505. list.concat(taicpu.op_sym(A_J,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  1506. else
  1507. begin
  1508. { GAS does not expand "J symbol" into PIC sequence }
  1509. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0,sizeof(pint));
  1510. href.base:=NR_GP;
  1511. href.refaddr:=addr_pic_call16;
  1512. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1513. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1514. end;
  1515. { Delay slot }
  1516. list.Concat(TAiCpu.Op_none(A_NOP));
  1517. List.concat(Tai_symbol_end.Createname(labelname));
  1518. end;
  1519. procedure TCGMIPS.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  1520. var
  1521. href: treference;
  1522. begin
  1523. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname),0,sizeof(aint));
  1524. { Always do indirect jump using $t9, it won't harm in non-PIC mode }
  1525. if (cs_create_pic in current_settings.moduleswitches) then
  1526. begin
  1527. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1528. list.concat(taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1529. href.base:=NR_GP;
  1530. href.refaddr:=addr_pic_call16;
  1531. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1532. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1533. { Delay slot }
  1534. list.Concat(taicpu.op_none(A_NOP));
  1535. list.Concat(taicpu.op_none(A_P_SET_REORDER));
  1536. end
  1537. else
  1538. begin
  1539. href.refaddr:=addr_high;
  1540. list.concat(taicpu.op_reg_ref(A_LUI,NR_PIC_FUNC,href));
  1541. href.refaddr:=addr_low;
  1542. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  1543. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1544. { Delay slot }
  1545. list.Concat(taicpu.op_none(A_NOP));
  1546. end;
  1547. end;
  1548. procedure TCGMIPS.g_profilecode(list:TAsmList);
  1549. var
  1550. href: treference;
  1551. begin
  1552. if not (cs_create_pic in current_settings.moduleswitches) then
  1553. begin
  1554. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('_gp'),0,sizeof(pint));
  1555. a_loadaddr_ref_reg(list,href,NR_GP);
  1556. end;
  1557. list.concat(taicpu.op_reg_reg(A_MOVE,NR_R1,NR_RA));
  1558. list.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_SP,NR_SP,-8));
  1559. a_call_sym_pic(list,current_asmdata.RefAsmSymbol('_mcount'));
  1560. end;
  1561. procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1562. begin
  1563. { This method is integrated into g_intf_wrapper and shouldn't be called separately }
  1564. InternalError(2013020102);
  1565. end;
  1566. procedure TCGMIPS.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1567. begin
  1568. Comment(V_Error,'TCgMPSel.g_stackpointer_alloc method not implemented');
  1569. end;
  1570. procedure TCGMIPS.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1571. begin
  1572. Comment(V_Error,'TCgMPSel.a_bit_scan_reg_reg method not implemented');
  1573. end;
  1574. {****************************************************************************
  1575. TCG64_MIPSel
  1576. ****************************************************************************}
  1577. procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference);
  1578. var
  1579. tmpref: treference;
  1580. tmpreg: tregister;
  1581. begin
  1582. if target_info.endian = endian_big then
  1583. begin
  1584. tmpreg := reg.reglo;
  1585. reg.reglo := reg.reghi;
  1586. reg.reghi := tmpreg;
  1587. end;
  1588. tmpref := ref;
  1589. tcgmips(cg).make_simple_ref(list,tmpref);
  1590. list.concat(taicpu.op_reg_ref(A_SW,reg.reglo,tmpref));
  1591. Inc(tmpref.offset, 4);
  1592. list.concat(taicpu.op_reg_ref(A_SW,reg.reghi,tmpref));
  1593. end;
  1594. procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64);
  1595. var
  1596. tmpref: treference;
  1597. tmpreg: tregister;
  1598. begin
  1599. if target_info.endian = endian_big then
  1600. begin
  1601. tmpreg := reg.reglo;
  1602. reg.reglo := reg.reghi;
  1603. reg.reghi := tmpreg;
  1604. end;
  1605. tmpref := ref;
  1606. tcgmips(cg).make_simple_ref(list,tmpref);
  1607. list.concat(taicpu.op_reg_ref(A_LW,reg.reglo,tmpref));
  1608. Inc(tmpref.offset, 4);
  1609. list.concat(taicpu.op_reg_ref(A_LW,reg.reghi,tmpref));
  1610. end;
  1611. procedure TCg64MPSel.a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara);
  1612. var
  1613. hreg64: tregister64;
  1614. begin
  1615. { Override this function to prevent loading the reference twice.
  1616. Use here some extra registers, but those are optimized away by the RA }
  1617. hreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1618. hreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1619. a_load64_ref_reg(list, r, hreg64);
  1620. a_load64_reg_cgpara(list, hreg64, paraloc);
  1621. end;
  1622. procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64);
  1623. var
  1624. tmpreg1: TRegister;
  1625. begin
  1626. case op of
  1627. OP_NEG:
  1628. begin
  1629. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1630. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo));
  1631. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_R0, regdst.reglo));
  1632. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi));
  1633. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg1));
  1634. end;
  1635. OP_NOT:
  1636. begin
  1637. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo));
  1638. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi));
  1639. end;
  1640. else
  1641. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1642. end;
  1643. end;
  1644. procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64);
  1645. begin
  1646. a_op64_const_reg_reg(list, op, size, value, regdst, regdst);
  1647. end;
  1648. procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64);
  1649. var
  1650. l: tlocation;
  1651. begin
  1652. a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l);
  1653. end;
  1654. procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64);
  1655. var
  1656. l: tlocation;
  1657. begin
  1658. a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l);
  1659. end;
  1660. procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1661. var
  1662. tmplo,carry: TRegister;
  1663. hisize: tcgsize;
  1664. begin
  1665. carry:=NR_NO;
  1666. if (size in [OS_S64]) then
  1667. hisize:=OS_S32
  1668. else
  1669. hisize:=OS_32;
  1670. case op of
  1671. OP_AND,OP_OR,OP_XOR:
  1672. begin
  1673. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1674. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1675. end;
  1676. OP_ADD:
  1677. begin
  1678. if lo(value)<>0 then
  1679. begin
  1680. tmplo:=cg.GetIntRegister(list,OS_32);
  1681. carry:=cg.GetIntRegister(list,OS_32);
  1682. tcgmips(cg).handle_reg_const_reg(list,A_ADDU,regsrc.reglo,aint(lo(value)),tmplo);
  1683. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
  1684. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1685. end
  1686. else
  1687. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1688. { With overflow checking and unsigned args, this generates slighly suboptimal code
  1689. ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
  1690. look worth the effort. }
  1691. cg.a_op_const_reg_reg_checkoverflow(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1692. if carry<>NR_NO then
  1693. cg.a_op_reg_reg_reg_checkoverflow(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1694. end;
  1695. OP_SUB:
  1696. begin
  1697. carry:=NR_NO;
  1698. if lo(value)<>0 then
  1699. begin
  1700. tmplo:=cg.GetIntRegister(list,OS_32);
  1701. carry:=cg.GetIntRegister(list,OS_32);
  1702. tcgmips(cg).handle_reg_const_reg(list,A_SUBU,regsrc.reglo,aint(lo(value)),tmplo);
  1703. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
  1704. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1705. end
  1706. else
  1707. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1708. cg.a_op_const_reg_reg_checkoverflow(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1709. if carry<>NR_NO then
  1710. cg.a_op_reg_reg_reg_checkoverflow(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1711. end;
  1712. else
  1713. InternalError(2013050301);
  1714. end;
  1715. end;
  1716. procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1717. var
  1718. tmplo,tmphi,carry,hreg: TRegister;
  1719. signed: boolean;
  1720. begin
  1721. case op of
  1722. OP_ADD:
  1723. begin
  1724. signed:=(size in [OS_S64]);
  1725. tmplo := cg.GetIntRegister(list,OS_S32);
  1726. carry := cg.GetIntRegister(list,OS_S32);
  1727. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1728. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1729. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
  1730. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1731. if signed or (not setflags) then
  1732. begin
  1733. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1734. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1735. end
  1736. else
  1737. begin
  1738. tmphi:=cg.GetIntRegister(list,OS_INT);
  1739. hreg:=cg.GetIntRegister(list,OS_INT);
  1740. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1741. // first add carry to one of the addends
  1742. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmphi, regsrc2.reghi, carry));
  1743. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
  1744. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1745. // then add another addend
  1746. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, tmphi, regsrc1.reghi));
  1747. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
  1748. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1749. end;
  1750. end;
  1751. OP_SUB:
  1752. begin
  1753. signed:=(size in [OS_S64]);
  1754. tmplo := cg.GetIntRegister(list,OS_S32);
  1755. carry := cg.GetIntRegister(list,OS_S32);
  1756. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1757. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1758. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
  1759. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1760. if signed or (not setflags) then
  1761. begin
  1762. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1763. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1764. end
  1765. else
  1766. begin
  1767. tmphi:=cg.GetIntRegister(list,OS_INT);
  1768. hreg:=cg.GetIntRegister(list,OS_INT);
  1769. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1770. // first subtract the carry...
  1771. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmphi, regsrc2.reghi, carry));
  1772. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
  1773. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1774. // ...then the subtrahend
  1775. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, tmphi, regsrc1.reghi));
  1776. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
  1777. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1778. end;
  1779. end;
  1780. OP_AND,OP_OR,OP_XOR:
  1781. begin
  1782. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1783. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1784. end;
  1785. else
  1786. internalerror(200306017);
  1787. end;
  1788. end;
  1789. procedure create_codegen;
  1790. begin
  1791. cg:=TCGMIPS.Create;
  1792. cg64:=TCg64MPSel.Create;
  1793. end;
  1794. end.