cgcpu.pas 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996
  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. begin
  708. if (TOpcg2AsmOp[op]=A_NONE) then
  709. InternalError(2013070305);
  710. if (op=OP_SAR) then
  711. begin
  712. if (size in [OS_S8,OS_S16]) then
  713. begin
  714. { Sign-extend before shiting }
  715. list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src2, 32-(tcgsize2size[size]*8)));
  716. list.concat(taicpu.op_reg_reg_const(A_SRA, dst, dst, 32-(tcgsize2size[size]*8)));
  717. src2:=dst;
  718. end
  719. else if not (size in [OS_32,OS_S32]) then
  720. InternalError(2013070306);
  721. end;
  722. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  723. maybeadjustresult(list,op,size,dst);
  724. end;
  725. procedure TCGMIPS.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  726. var
  727. signed,immed: boolean;
  728. hreg: TRegister;
  729. asmop: TAsmOp;
  730. begin
  731. ovloc.loc := LOC_VOID;
  732. optimize_op_const(size,op,a);
  733. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  734. if (setflags and (not signed) and (src=dst) and (op in [OP_ADD,OP_SUB])) then
  735. hreg:=GetIntRegister(list,OS_INT)
  736. else
  737. hreg:=dst;
  738. case op of
  739. OP_NONE:
  740. a_load_reg_reg(list,size,size,src,dst);
  741. OP_MOVE:
  742. a_load_const_reg(list,size,a,dst);
  743. OP_ADD:
  744. begin
  745. handle_reg_const_reg(list,ops_add[setflags and signed],src,a,hreg);
  746. if setflags and (not signed) then
  747. overflowcheck_internal(list,hreg,src);
  748. { does nothing if hreg=dst }
  749. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  750. end;
  751. OP_SUB:
  752. begin
  753. handle_reg_const_reg(list,ops_sub[setflags and signed],src,a,hreg);
  754. if setflags and (not signed) then
  755. overflowcheck_internal(list,src,hreg);
  756. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  757. end;
  758. OP_MUL,OP_IMUL:
  759. begin
  760. hreg:=GetIntRegister(list,OS_INT);
  761. a_load_const_reg(list,OS_INT,a,hreg);
  762. a_op_reg_reg_reg_checkoverflow(list,op,size,src,hreg,dst,setflags,ovloc);
  763. exit;
  764. end;
  765. OP_AND,OP_OR,OP_XOR:
  766. begin
  767. { logical operations zero-extend, not sign-extend, the immediate }
  768. immed:=(a>=0) and (a<=65535);
  769. case op of
  770. OP_AND: asmop:=ops_and[immed];
  771. OP_OR: asmop:=ops_or[immed];
  772. OP_XOR: asmop:=ops_xor[immed];
  773. else
  774. InternalError(2013050401);
  775. end;
  776. if immed then
  777. list.concat(taicpu.op_reg_reg_const(asmop,dst,src,a))
  778. else
  779. begin
  780. hreg:=GetIntRegister(list,OS_INT);
  781. a_load_const_reg(list,OS_INT,a,hreg);
  782. list.concat(taicpu.op_reg_reg_reg(asmop,dst,src,hreg));
  783. end;
  784. end;
  785. OP_SHL:
  786. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,a));
  787. OP_SHR:
  788. list.concat(taicpu.op_reg_reg_const(A_SRL,dst,src,a));
  789. OP_SAR:
  790. begin
  791. if (size in [OS_S8,OS_S16]) then
  792. begin
  793. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,32-(tcgsize2size[size]*8)));
  794. inc(a,32-tcgsize2size[size]*8);
  795. src:=dst;
  796. end
  797. else if not (size in [OS_32,OS_S32]) then
  798. InternalError(2013070303);
  799. list.concat(taicpu.op_reg_reg_const(A_SRA,dst,src,a));
  800. end;
  801. else
  802. internalerror(2007012601);
  803. end;
  804. maybeadjustresult(list,op,size,dst);
  805. end;
  806. procedure TCGMIPS.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  807. var
  808. signed: boolean;
  809. hreg,hreg2: TRegister;
  810. hl: tasmlabel;
  811. begin
  812. ovloc.loc := LOC_VOID;
  813. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  814. if (setflags and (not signed) and (src2=dst) and (op in [OP_ADD,OP_SUB])) then
  815. hreg:=GetIntRegister(list,OS_INT)
  816. else
  817. hreg:=dst;
  818. case op of
  819. OP_ADD:
  820. begin
  821. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], hreg, src2, src1));
  822. if setflags and (not signed) then
  823. overflowcheck_internal(list, hreg, src2);
  824. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  825. end;
  826. OP_SUB:
  827. begin
  828. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], hreg, src2, src1));
  829. if setflags and (not signed) then
  830. overflowcheck_internal(list, src2, hreg);
  831. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  832. end;
  833. OP_MUL,OP_IMUL:
  834. begin
  835. list.concat(taicpu.op_reg_reg(TOpCg2AsmOp[op], src2, src1));
  836. list.concat(taicpu.op_reg(A_MFLO, dst));
  837. if setflags then
  838. begin
  839. current_asmdata.getjumplabel(hl);
  840. hreg:=GetIntRegister(list,OS_INT);
  841. list.concat(taicpu.op_reg(A_MFHI,hreg));
  842. if (op=OP_IMUL) then
  843. begin
  844. hreg2:=GetIntRegister(list,OS_INT);
  845. list.concat(taicpu.op_reg_reg_const(A_SRA,hreg2,dst,31));
  846. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg2,hreg,hl);
  847. end
  848. else
  849. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg,NR_R0,hl);
  850. list.concat(taicpu.op_const(A_BREAK,6));
  851. a_label(list,hl);
  852. end;
  853. end;
  854. OP_AND,OP_OR,OP_XOR:
  855. begin
  856. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  857. end;
  858. else
  859. internalerror(2007012602);
  860. end;
  861. maybeadjustresult(list,op,size,dst);
  862. end;
  863. {*************** compare instructructions ****************}
  864. procedure TCGMIPS.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  865. var
  866. tmpreg: tregister;
  867. begin
  868. if a = 0 then
  869. a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
  870. else
  871. begin
  872. tmpreg := GetIntRegister(list,OS_INT);
  873. if (a>=simm16lo) and (a<=simm16hi) and
  874. (cmp_op in [OC_LT,OC_B,OC_GTE,OC_AE]) then
  875. begin
  876. list.concat(taicpu.op_reg_reg_const(ops_slti[cmp_op in [OC_LT,OC_GTE]],tmpreg,reg,a));
  877. if cmp_op in [OC_LT,OC_B] then
  878. a_cmp_reg_reg_label(list,size,OC_NE,NR_R0,tmpreg,l)
  879. else
  880. a_cmp_reg_reg_label(list,size,OC_EQ,NR_R0,tmpreg,l);
  881. end
  882. else
  883. begin
  884. a_load_const_reg(list,OS_INT,a,tmpreg);
  885. a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
  886. end;
  887. end;
  888. end;
  889. const
  890. TOpCmp2AsmCond_z : array[OC_GT..OC_LTE] of TAsmCond=(
  891. C_GTZ,C_LTZ,C_GEZ,C_LEZ
  892. );
  893. TOpCmp2AsmCond_eqne: array[topcmp] of TAsmCond = (C_NONE,
  894. { eq gt lt gte lte ne }
  895. C_NONE, C_NE, C_NE, C_EQ, C_EQ, C_NONE,
  896. { be b ae a }
  897. C_EQ, C_NE, C_EQ, C_NE
  898. );
  899. procedure TCGMIPS.a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  900. var
  901. ai : Taicpu;
  902. op: TAsmOp;
  903. hreg: TRegister;
  904. begin
  905. if not (cmp_op in [OC_EQ,OC_NE]) then
  906. begin
  907. if ((reg1=NR_R0) or (reg2=NR_R0)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
  908. begin
  909. if (reg2=NR_R0) then
  910. begin
  911. ai:=taicpu.op_reg_sym(A_BC,reg1,l);
  912. ai.setcondition(TOpCmp2AsmCond_z[swap_opcmp(cmp_op)]);
  913. end
  914. else
  915. begin
  916. ai:=taicpu.op_reg_sym(A_BC,reg2,l);
  917. ai.setcondition(TOpCmp2AsmCond_z[cmp_op]);
  918. end;
  919. end
  920. else
  921. begin
  922. hreg:=GetIntRegister(list,OS_INT);
  923. op:=ops_slt[cmp_op in [OC_LT,OC_LTE,OC_GT,OC_GTE]];
  924. if (cmp_op in [OC_LTE,OC_GT,OC_BE,OC_A]) then { swap operands }
  925. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg1,reg2))
  926. else
  927. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg2,reg1));
  928. if (TOpCmp2AsmCond_eqne[cmp_op]=C_NONE) then
  929. InternalError(2013051501);
  930. ai:=taicpu.op_reg_reg_sym(A_BC,hreg,NR_R0,l);
  931. ai.SetCondition(TOpCmp2AsmCond_eqne[cmp_op]);
  932. end;
  933. end
  934. else
  935. begin
  936. ai:=taicpu.op_reg_reg_sym(A_BC,reg2,reg1,l);
  937. ai.SetCondition(TOpCmp2AsmCond[cmp_op]);
  938. end;
  939. list.concat(ai);
  940. { Delay slot }
  941. list.Concat(TAiCpu.Op_none(A_NOP));
  942. end;
  943. procedure TCGMIPS.a_jmp_always(List: tasmlist; l: TAsmLabel);
  944. var
  945. ai : Taicpu;
  946. begin
  947. ai := taicpu.op_sym(A_BA, l);
  948. list.concat(ai);
  949. { Delay slot }
  950. list.Concat(TAiCpu.Op_none(A_NOP));
  951. end;
  952. procedure TCGMIPS.a_jmp_name(list: tasmlist; const s: string);
  953. begin
  954. List.Concat(TAiCpu.op_sym(A_BA, current_asmdata.RefAsmSymbol(s)));
  955. { Delay slot }
  956. list.Concat(TAiCpu.Op_none(A_NOP));
  957. end;
  958. procedure TCGMIPS.a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel);
  959. begin
  960. if f.use_const then
  961. a_cmp_const_reg_label(list,OS_INT,f.cond,f.value,f.reg1,l)
  962. else
  963. a_cmp_reg_reg_label(list,OS_INT,f.cond,f.reg2,f.reg1,l);
  964. end;
  965. procedure TCGMIPS.g_flags2reg(list: tasmlist; size: tcgsize; const f: tresflags; reg: tregister);
  966. var
  967. left,right: tregister;
  968. unsigned: boolean;
  969. begin
  970. if (f.cond in [OC_EQ,OC_NE]) then
  971. begin
  972. left:=reg;
  973. if f.use_const and (f.value>=0) and (f.value<=65535) then
  974. begin
  975. if (f.value<>0) then
  976. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,f.reg1,f.value))
  977. else
  978. left:=f.reg1;
  979. end
  980. else
  981. begin
  982. if f.use_const then
  983. begin
  984. right:=GetIntRegister(list,OS_INT);
  985. a_load_const_reg(list,OS_INT,f.value,right);
  986. end
  987. else
  988. right:=f.reg2;
  989. list.concat(taicpu.op_reg_reg_reg(A_XOR,reg,f.reg1,right));
  990. end;
  991. if f.cond=OC_EQ then
  992. list.concat(taicpu.op_reg_reg_const(A_SLTIU,reg,left,1))
  993. else
  994. list.concat(taicpu.op_reg_reg_reg(A_SLTU,reg,NR_R0,left));
  995. end
  996. else
  997. begin
  998. {
  999. sle x,a,b --> slt x,b,a; xori x,x,1 immediate not possible (or must be at left)
  1000. sgt x,a,b --> slt x,b,a likewise
  1001. sge x,a,b --> slt x,a,b; xori x,x,1
  1002. slt x,a,b --> unchanged
  1003. }
  1004. unsigned:=f.cond in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  1005. if (f.cond in [OC_GTE,OC_LT,OC_B,OC_AE]) and
  1006. f.use_const and
  1007. (f.value>=simm16lo) and
  1008. (f.value<=simm16hi) then
  1009. list.Concat(taicpu.op_reg_reg_const(ops_slti[unsigned],reg,f.reg1,f.value))
  1010. else
  1011. begin
  1012. if f.use_const then
  1013. begin
  1014. if (f.value=0) then
  1015. right:=NR_R0
  1016. else
  1017. begin
  1018. right:=GetIntRegister(list,OS_INT);
  1019. a_load_const_reg(list,OS_INT,f.value,right);
  1020. end;
  1021. end
  1022. else
  1023. right:=f.reg2;
  1024. if (f.cond in [OC_LTE,OC_GT,OC_BE,OC_A]) then
  1025. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,right,f.reg1))
  1026. else
  1027. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,f.reg1,right));
  1028. end;
  1029. if (f.cond in [OC_LTE,OC_GTE,OC_BE,OC_AE]) then
  1030. list.Concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  1031. end;
  1032. end;
  1033. procedure TCGMIPS.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef);
  1034. begin
  1035. // this is an empty procedure
  1036. end;
  1037. procedure TCGMIPS.g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation);
  1038. begin
  1039. // this is an empty procedure
  1040. end;
  1041. { *********** entry/exit code and address loading ************ }
  1042. procedure FixupOffsets(p:TObject;arg:pointer);
  1043. var
  1044. sym: tabstractnormalvarsym absolute p;
  1045. begin
  1046. if (tsym(p).typ=paravarsym) and
  1047. (sym.localloc.loc=LOC_REFERENCE) and
  1048. (sym.localloc.reference.base=NR_FRAME_POINTER_REG) then
  1049. begin
  1050. sym.localloc.reference.base:=NR_STACK_POINTER_REG;
  1051. Inc(sym.localloc.reference.offset,PLongint(arg)^);
  1052. end;
  1053. end;
  1054. procedure TCGMIPS.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean);
  1055. var
  1056. lastintoffset,lastfpuoffset,
  1057. nextoffset : aint;
  1058. i : longint;
  1059. ra_save,framesave : taicpu;
  1060. fmask,mask : dword;
  1061. saveregs : tcpuregisterset;
  1062. href: treference;
  1063. reg : Tsuperregister;
  1064. helplist : TAsmList;
  1065. largeoffs : boolean;
  1066. begin
  1067. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1068. if nostackframe then
  1069. exit;
  1070. if (pi_needs_stackframe in current_procinfo.flags) then
  1071. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1072. helplist:=TAsmList.Create;
  1073. reference_reset(href,0);
  1074. href.base:=NR_STACK_POINTER_REG;
  1075. fmask:=0;
  1076. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1077. lastfpuoffset:=LocalSize;
  1078. for reg := RS_F0 to RS_F31 do { to check: what if F30 is double? }
  1079. begin
  1080. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1081. begin
  1082. fmask:=fmask or (1 shl ord(reg));
  1083. href.offset:=nextoffset;
  1084. lastfpuoffset:=nextoffset;
  1085. helplist.concat(taicpu.op_reg_ref(A_SWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1086. inc(nextoffset,4);
  1087. { IEEE Double values are stored in floating point
  1088. register pairs f2X/f2X+1,
  1089. as the f2X+1 register is not correctly marked as used for now,
  1090. we simply assume it is also used if f2X is used
  1091. Should be fixed by a proper inclusion of f2X+1 into used_in_proc }
  1092. if (ord(reg)-ord(RS_F0)) mod 2 = 0 then
  1093. include(rg[R_FPUREGISTER].used_in_proc,succ(reg));
  1094. end;
  1095. end;
  1096. mask:=0;
  1097. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1098. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1099. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1100. include(saveregs,RS_R31);
  1101. if (pi_needs_stackframe in current_procinfo.flags) then
  1102. include(saveregs,RS_FRAME_POINTER_REG);
  1103. lastintoffset:=LocalSize;
  1104. framesave:=nil;
  1105. ra_save:=nil;
  1106. for reg:=RS_R1 to RS_R31 do
  1107. begin
  1108. if reg in saveregs then
  1109. begin
  1110. mask:=mask or (1 shl ord(reg));
  1111. href.offset:=nextoffset;
  1112. lastintoffset:=nextoffset;
  1113. if (reg=RS_FRAME_POINTER_REG) then
  1114. framesave:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1115. else if (reg=RS_R31) then
  1116. ra_save:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1117. else
  1118. helplist.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1119. inc(nextoffset,4);
  1120. end;
  1121. end;
  1122. //list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,current_procinfo.para_stack_size));
  1123. list.concat(Taicpu.op_none(A_P_SET_NOMIPS16));
  1124. list.concat(Taicpu.op_reg_const_reg(A_P_FRAME,current_procinfo.framepointer,LocalSize,NR_R31));
  1125. list.concat(Taicpu.op_const_const(A_P_MASK,mask,-(LocalSize-lastintoffset)));
  1126. list.concat(Taicpu.op_const_const(A_P_FMASK,Fmask,-(LocalSize-lastfpuoffset)));
  1127. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1128. if (cs_create_pic in current_settings.moduleswitches) and
  1129. (pi_needs_got in current_procinfo.flags) then
  1130. begin
  1131. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1132. end;
  1133. if (-LocalSize >= simm16lo) and (-LocalSize <= simm16hi) then
  1134. begin
  1135. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1136. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-LocalSize));
  1137. if assigned(ra_save) then
  1138. list.concat(ra_save);
  1139. if assigned(framesave) then
  1140. begin
  1141. list.concat(framesave);
  1142. list.concat(Taicpu.op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,
  1143. NR_STACK_POINTER_REG,LocalSize));
  1144. end;
  1145. end
  1146. else
  1147. begin
  1148. a_load_const_reg(list,OS_32,-LocalSize,NR_R9);
  1149. list.concat(Taicpu.Op_reg_reg_reg(A_ADDU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R9));
  1150. if assigned(ra_save) then
  1151. list.concat(ra_save);
  1152. if assigned(framesave) then
  1153. begin
  1154. list.concat(framesave);
  1155. list.concat(Taicpu.op_reg_reg_reg(A_SUBU,NR_FRAME_POINTER_REG,
  1156. NR_STACK_POINTER_REG,NR_R9));
  1157. end;
  1158. { The instructions before are macros that can extend to multiple instructions,
  1159. the settings of R9 to -LocalSize surely does,
  1160. but the saving of RA and FP also might, and might
  1161. even use AT register, which is why we use R9 instead of AT here for -LocalSize }
  1162. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1163. end;
  1164. if (cs_create_pic in current_settings.moduleswitches) and
  1165. (pi_needs_got in current_procinfo.flags) then
  1166. begin
  1167. largeoffs:=(TMIPSProcinfo(current_procinfo).save_gp_ref.offset>simm16hi);
  1168. if largeoffs then
  1169. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1170. list.concat(Taicpu.op_const(A_P_CPRESTORE,TMIPSProcinfo(current_procinfo).save_gp_ref.offset));
  1171. if largeoffs then
  1172. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1173. end;
  1174. href.base:=NR_STACK_POINTER_REG;
  1175. for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
  1176. if TMIPSProcInfo(current_procinfo).register_used[i] then
  1177. begin
  1178. reg:=parasupregs[i];
  1179. href.offset:=i*sizeof(aint)+LocalSize;
  1180. list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
  1181. end;
  1182. list.concatList(helplist);
  1183. helplist.Free;
  1184. if current_procinfo.has_nestedprocs then
  1185. current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@LocalSize);
  1186. end;
  1187. procedure TCGMIPS.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean);
  1188. var
  1189. href : treference;
  1190. stacksize : aint;
  1191. saveregs : tcpuregisterset;
  1192. nextoffset : aint;
  1193. reg : Tsuperregister;
  1194. begin
  1195. stacksize:=current_procinfo.calc_stackframe_size;
  1196. if nostackframe then
  1197. begin
  1198. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1199. list.concat(Taicpu.op_none(A_NOP));
  1200. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1201. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1202. end
  1203. else
  1204. begin
  1205. if TMIPSProcinfo(current_procinfo).save_gp_ref.offset<>0 then
  1206. tg.ungettemp(list,TMIPSProcinfo(current_procinfo).save_gp_ref);
  1207. reference_reset(href,0);
  1208. href.base:=NR_STACK_POINTER_REG;
  1209. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1210. for reg := RS_F0 to RS_F31 do
  1211. begin
  1212. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1213. begin
  1214. href.offset:=nextoffset;
  1215. list.concat(taicpu.op_reg_ref(A_LWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1216. inc(nextoffset,4);
  1217. end;
  1218. end;
  1219. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1220. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1221. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1222. include(saveregs,RS_R31);
  1223. if (pi_needs_stackframe in current_procinfo.flags) then
  1224. include(saveregs,RS_FRAME_POINTER_REG);
  1225. // GP does not need to be restored on exit
  1226. for reg:=RS_R1 to RS_R31 do
  1227. begin
  1228. if reg in saveregs then
  1229. begin
  1230. href.offset:=nextoffset;
  1231. list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1232. inc(nextoffset,sizeof(aint));
  1233. end;
  1234. end;
  1235. if (-stacksize >= simm16lo) and (-stacksize <= simm16hi) then
  1236. begin
  1237. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1238. { correct stack pointer in the delay slot }
  1239. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, stacksize));
  1240. end
  1241. else
  1242. begin
  1243. a_load_const_reg(list,OS_32,stacksize,NR_R1);
  1244. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1245. { correct stack pointer in the delay slot }
  1246. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R1));
  1247. end;
  1248. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1249. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1250. end;
  1251. end;
  1252. { ************* concatcopy ************ }
  1253. procedure TCGMIPS.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  1254. var
  1255. paraloc1, paraloc2, paraloc3: TCGPara;
  1256. pd: tprocdef;
  1257. begin
  1258. pd:=search_system_proc('MOVE');
  1259. paraloc1.init;
  1260. paraloc2.init;
  1261. paraloc3.init;
  1262. paramanager.getintparaloc(pd, 1, paraloc1);
  1263. paramanager.getintparaloc(pd, 2, paraloc2);
  1264. paramanager.getintparaloc(pd, 3, paraloc3);
  1265. a_load_const_cgpara(list, OS_SINT, len, paraloc3);
  1266. a_loadaddr_ref_cgpara(list, dest, paraloc2);
  1267. a_loadaddr_ref_cgpara(list, Source, paraloc1);
  1268. paramanager.freecgpara(list, paraloc3);
  1269. paramanager.freecgpara(list, paraloc2);
  1270. paramanager.freecgpara(list, paraloc1);
  1271. alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1272. alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1273. a_call_name(list, 'FPC_MOVE', false);
  1274. dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1275. dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1276. paraloc3.done;
  1277. paraloc2.done;
  1278. paraloc1.done;
  1279. end;
  1280. procedure TCGMIPS.g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint);
  1281. var
  1282. tmpreg1, hreg, countreg: TRegister;
  1283. src, dst: TReference;
  1284. lab: tasmlabel;
  1285. Count, count2: aint;
  1286. function reference_is_reusable(const ref: treference): boolean;
  1287. begin
  1288. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1289. (ref.symbol=nil) and
  1290. (ref.offset>=simm16lo) and (ref.offset+len<=simm16hi);
  1291. end;
  1292. begin
  1293. if len > high(longint) then
  1294. internalerror(2002072704);
  1295. { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
  1296. allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
  1297. i.e. before secondpass. Other internal procedures request correct stack frame
  1298. by setting pi_do_call during firstpass, but for this particular one it is impossible.
  1299. Therefore, if the current procedure is a leaf one, we have to leave it that way. }
  1300. { anybody wants to determine a good value here :)? }
  1301. if (len > 100) and
  1302. assigned(current_procinfo) and
  1303. (pi_do_call in current_procinfo.flags) then
  1304. g_concatcopy_move(list, Source, dest, len)
  1305. else
  1306. begin
  1307. Count := len div 4;
  1308. if (count<=4) and reference_is_reusable(source) then
  1309. src:=source
  1310. else
  1311. begin
  1312. reference_reset(src,sizeof(aint));
  1313. { load the address of source into src.base }
  1314. src.base := GetAddressRegister(list);
  1315. a_loadaddr_ref_reg(list, Source, src.base);
  1316. end;
  1317. if (count<=4) and reference_is_reusable(dest) then
  1318. dst:=dest
  1319. else
  1320. begin
  1321. reference_reset(dst,sizeof(aint));
  1322. { load the address of dest into dst.base }
  1323. dst.base := GetAddressRegister(list);
  1324. a_loadaddr_ref_reg(list, dest, dst.base);
  1325. end;
  1326. { generate a loop }
  1327. if Count > 4 then
  1328. begin
  1329. countreg := GetIntRegister(list, OS_INT);
  1330. tmpreg1 := GetIntRegister(list, OS_INT);
  1331. a_load_const_reg(list, OS_INT, Count, countreg);
  1332. current_asmdata.getjumplabel(lab);
  1333. a_label(list, lab);
  1334. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1335. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1336. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4));
  1337. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4));
  1338. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1339. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1340. len := len mod 4;
  1341. end;
  1342. { unrolled loop }
  1343. Count := len div 4;
  1344. if Count > 0 then
  1345. begin
  1346. tmpreg1 := GetIntRegister(list, OS_INT);
  1347. for count2 := 1 to Count do
  1348. begin
  1349. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1350. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1351. Inc(src.offset, 4);
  1352. Inc(dst.offset, 4);
  1353. end;
  1354. len := len mod 4;
  1355. end;
  1356. if (len and 4) <> 0 then
  1357. begin
  1358. hreg := GetIntRegister(list, OS_INT);
  1359. a_load_ref_reg(list, OS_32, OS_32, src, hreg);
  1360. a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
  1361. Inc(src.offset, 4);
  1362. Inc(dst.offset, 4);
  1363. end;
  1364. { copy the leftovers }
  1365. if (len and 2) <> 0 then
  1366. begin
  1367. hreg := GetIntRegister(list, OS_INT);
  1368. a_load_ref_reg(list, OS_16, OS_16, src, hreg);
  1369. a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
  1370. Inc(src.offset, 2);
  1371. Inc(dst.offset, 2);
  1372. end;
  1373. if (len and 1) <> 0 then
  1374. begin
  1375. hreg := GetIntRegister(list, OS_INT);
  1376. a_load_ref_reg(list, OS_8, OS_8, src, hreg);
  1377. a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
  1378. end;
  1379. end;
  1380. end;
  1381. procedure TCGMIPS.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint);
  1382. var
  1383. src, dst: TReference;
  1384. tmpreg1, countreg: TRegister;
  1385. i: aint;
  1386. lab: tasmlabel;
  1387. begin
  1388. if (len > 31) and
  1389. { see comment in g_concatcopy }
  1390. assigned(current_procinfo) and
  1391. (pi_do_call in current_procinfo.flags) then
  1392. g_concatcopy_move(list, Source, dest, len)
  1393. else
  1394. begin
  1395. reference_reset(src,sizeof(aint));
  1396. reference_reset(dst,sizeof(aint));
  1397. { load the address of source into src.base }
  1398. src.base := GetAddressRegister(list);
  1399. a_loadaddr_ref_reg(list, Source, src.base);
  1400. { load the address of dest into dst.base }
  1401. dst.base := GetAddressRegister(list);
  1402. a_loadaddr_ref_reg(list, dest, dst.base);
  1403. { generate a loop }
  1404. if len > 4 then
  1405. begin
  1406. countreg := GetIntRegister(list, OS_INT);
  1407. tmpreg1 := GetIntRegister(list, OS_INT);
  1408. a_load_const_reg(list, OS_INT, len, countreg);
  1409. current_asmdata.getjumplabel(lab);
  1410. a_label(list, lab);
  1411. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1412. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1413. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1));
  1414. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1));
  1415. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1416. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1417. end
  1418. else
  1419. begin
  1420. { unrolled loop }
  1421. tmpreg1 := GetIntRegister(list, OS_INT);
  1422. for i := 1 to len do
  1423. begin
  1424. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1425. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1426. Inc(src.offset);
  1427. Inc(dst.offset);
  1428. end;
  1429. end;
  1430. end;
  1431. end;
  1432. procedure TCGMIPS.g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint);
  1433. var
  1434. make_global: boolean;
  1435. hsym: tsym;
  1436. href: treference;
  1437. paraloc: Pcgparalocation;
  1438. IsVirtual: boolean;
  1439. begin
  1440. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1441. Internalerror(200006137);
  1442. if not assigned(procdef.struct) or
  1443. (procdef.procoptions * [po_classmethod, po_staticmethod,
  1444. po_methodpointer, po_interrupt, po_iocheck] <> []) then
  1445. Internalerror(200006138);
  1446. if procdef.owner.symtabletype <> objectsymtable then
  1447. Internalerror(200109191);
  1448. make_global := False;
  1449. if (not current_module.is_unit) or create_smartlink or
  1450. (procdef.owner.defowner.owner.symtabletype = globalsymtable) then
  1451. make_global := True;
  1452. if make_global then
  1453. List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0))
  1454. else
  1455. List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0));
  1456. IsVirtual:=(po_virtualmethod in procdef.procoptions) and
  1457. not is_objectpascal_helper(procdef.struct);
  1458. if (cs_create_pic in current_settings.moduleswitches) and
  1459. (not IsVirtual) then
  1460. begin
  1461. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1462. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1463. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1464. end;
  1465. { set param1 interface to self }
  1466. procdef.init_paraloc_info(callerside);
  1467. hsym:=tsym(procdef.parast.Find('self'));
  1468. if not(assigned(hsym) and
  1469. (hsym.typ=paravarsym)) then
  1470. internalerror(2010103101);
  1471. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1472. if assigned(paraloc^.next) then
  1473. InternalError(2013020101);
  1474. case paraloc^.loc of
  1475. LOC_REGISTER:
  1476. begin
  1477. if ((ioffset>=simm16lo) and (ioffset<=simm16hi)) then
  1478. a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
  1479. else
  1480. begin
  1481. a_load_const_reg(list, paraloc^.size, ioffset, NR_R1);
  1482. a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_R1, paraloc^.register);
  1483. end;
  1484. end;
  1485. else
  1486. internalerror(2010103102);
  1487. end;
  1488. if IsVirtual then
  1489. begin
  1490. { load VMT pointer }
  1491. reference_reset_base(href,paraloc^.register,0,sizeof(aint));
  1492. list.concat(taicpu.op_reg_ref(A_LW,NR_VMT,href));
  1493. if (procdef.extnumber=$ffff) then
  1494. Internalerror(200006139);
  1495. { TODO: case of large VMT is not handled }
  1496. { We have no reason not to use $t9 even in non-PIC mode. }
  1497. reference_reset_base(href, NR_VMT, tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber), sizeof(aint));
  1498. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1499. list.concat(taicpu.op_reg(A_JR, NR_PIC_FUNC));
  1500. end
  1501. else if not (cs_create_pic in current_settings.moduleswitches) then
  1502. list.concat(taicpu.op_sym(A_J,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  1503. else
  1504. begin
  1505. { GAS does not expand "J symbol" into PIC sequence }
  1506. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0,sizeof(pint));
  1507. href.base:=NR_GP;
  1508. href.refaddr:=addr_pic_call16;
  1509. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1510. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1511. end;
  1512. { Delay slot }
  1513. list.Concat(TAiCpu.Op_none(A_NOP));
  1514. List.concat(Tai_symbol_end.Createname(labelname));
  1515. end;
  1516. procedure TCGMIPS.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  1517. var
  1518. href: treference;
  1519. begin
  1520. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname),0,sizeof(aint));
  1521. { Always do indirect jump using $t9, it won't harm in non-PIC mode }
  1522. if (cs_create_pic in current_settings.moduleswitches) then
  1523. begin
  1524. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1525. list.concat(taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1526. href.base:=NR_GP;
  1527. href.refaddr:=addr_pic_call16;
  1528. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1529. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1530. { Delay slot }
  1531. list.Concat(taicpu.op_none(A_NOP));
  1532. list.Concat(taicpu.op_none(A_P_SET_REORDER));
  1533. end
  1534. else
  1535. begin
  1536. href.refaddr:=addr_high;
  1537. list.concat(taicpu.op_reg_ref(A_LUI,NR_PIC_FUNC,href));
  1538. href.refaddr:=addr_low;
  1539. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  1540. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1541. { Delay slot }
  1542. list.Concat(taicpu.op_none(A_NOP));
  1543. end;
  1544. end;
  1545. procedure TCGMIPS.g_profilecode(list:TAsmList);
  1546. var
  1547. href: treference;
  1548. begin
  1549. if not (cs_create_pic in current_settings.moduleswitches) then
  1550. begin
  1551. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('_gp'),0,sizeof(pint));
  1552. a_loadaddr_ref_reg(list,href,NR_GP);
  1553. end;
  1554. list.concat(taicpu.op_reg_reg(A_MOVE,NR_R1,NR_RA));
  1555. list.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_SP,NR_SP,-8));
  1556. a_call_sym_pic(list,current_asmdata.RefAsmSymbol('_mcount'));
  1557. end;
  1558. procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1559. begin
  1560. { This method is integrated into g_intf_wrapper and shouldn't be called separately }
  1561. InternalError(2013020102);
  1562. end;
  1563. procedure TCGMIPS.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1564. begin
  1565. Comment(V_Error,'TCgMPSel.g_stackpointer_alloc method not implemented');
  1566. end;
  1567. procedure TCGMIPS.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1568. begin
  1569. Comment(V_Error,'TCgMPSel.a_bit_scan_reg_reg method not implemented');
  1570. end;
  1571. {****************************************************************************
  1572. TCG64_MIPSel
  1573. ****************************************************************************}
  1574. procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference);
  1575. var
  1576. tmpref: treference;
  1577. tmpreg: tregister;
  1578. begin
  1579. if target_info.endian = endian_big then
  1580. begin
  1581. tmpreg := reg.reglo;
  1582. reg.reglo := reg.reghi;
  1583. reg.reghi := tmpreg;
  1584. end;
  1585. tmpref := ref;
  1586. tcgmips(cg).make_simple_ref(list,tmpref);
  1587. list.concat(taicpu.op_reg_ref(A_SW,reg.reglo,tmpref));
  1588. Inc(tmpref.offset, 4);
  1589. list.concat(taicpu.op_reg_ref(A_SW,reg.reghi,tmpref));
  1590. end;
  1591. procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64);
  1592. var
  1593. tmpref: treference;
  1594. tmpreg: tregister;
  1595. begin
  1596. if target_info.endian = endian_big then
  1597. begin
  1598. tmpreg := reg.reglo;
  1599. reg.reglo := reg.reghi;
  1600. reg.reghi := tmpreg;
  1601. end;
  1602. tmpref := ref;
  1603. tcgmips(cg).make_simple_ref(list,tmpref);
  1604. list.concat(taicpu.op_reg_ref(A_LW,reg.reglo,tmpref));
  1605. Inc(tmpref.offset, 4);
  1606. list.concat(taicpu.op_reg_ref(A_LW,reg.reghi,tmpref));
  1607. end;
  1608. procedure TCg64MPSel.a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara);
  1609. var
  1610. hreg64: tregister64;
  1611. begin
  1612. { Override this function to prevent loading the reference twice.
  1613. Use here some extra registers, but those are optimized away by the RA }
  1614. hreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1615. hreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1616. a_load64_ref_reg(list, r, hreg64);
  1617. a_load64_reg_cgpara(list, hreg64, paraloc);
  1618. end;
  1619. procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64);
  1620. var
  1621. tmpreg1: TRegister;
  1622. begin
  1623. case op of
  1624. OP_NEG:
  1625. begin
  1626. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1627. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo));
  1628. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_R0, regdst.reglo));
  1629. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi));
  1630. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg1));
  1631. end;
  1632. OP_NOT:
  1633. begin
  1634. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo));
  1635. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi));
  1636. end;
  1637. else
  1638. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1639. end;
  1640. end;
  1641. procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64);
  1642. begin
  1643. a_op64_const_reg_reg(list, op, size, value, regdst, regdst);
  1644. end;
  1645. procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64);
  1646. var
  1647. l: tlocation;
  1648. begin
  1649. a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l);
  1650. end;
  1651. procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64);
  1652. var
  1653. l: tlocation;
  1654. begin
  1655. a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l);
  1656. end;
  1657. procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1658. var
  1659. tmplo,carry: TRegister;
  1660. hisize: tcgsize;
  1661. begin
  1662. carry:=NR_NO;
  1663. if (size in [OS_S64]) then
  1664. hisize:=OS_S32
  1665. else
  1666. hisize:=OS_32;
  1667. case op of
  1668. OP_AND,OP_OR,OP_XOR:
  1669. begin
  1670. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1671. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1672. end;
  1673. OP_ADD:
  1674. begin
  1675. if lo(value)<>0 then
  1676. begin
  1677. tmplo:=cg.GetIntRegister(list,OS_32);
  1678. carry:=cg.GetIntRegister(list,OS_32);
  1679. tcgmips(cg).handle_reg_const_reg(list,A_ADDU,regsrc.reglo,aint(lo(value)),tmplo);
  1680. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
  1681. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1682. end
  1683. else
  1684. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1685. { With overflow checking and unsigned args, this generates slighly suboptimal code
  1686. ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
  1687. look worth the effort. }
  1688. cg.a_op_const_reg_reg_checkoverflow(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1689. if carry<>NR_NO then
  1690. cg.a_op_reg_reg_reg_checkoverflow(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1691. end;
  1692. OP_SUB:
  1693. begin
  1694. carry:=NR_NO;
  1695. if lo(value)<>0 then
  1696. begin
  1697. tmplo:=cg.GetIntRegister(list,OS_32);
  1698. carry:=cg.GetIntRegister(list,OS_32);
  1699. tcgmips(cg).handle_reg_const_reg(list,A_SUBU,regsrc.reglo,aint(lo(value)),tmplo);
  1700. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
  1701. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1702. end
  1703. else
  1704. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1705. cg.a_op_const_reg_reg_checkoverflow(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1706. if carry<>NR_NO then
  1707. cg.a_op_reg_reg_reg_checkoverflow(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1708. end;
  1709. else
  1710. InternalError(2013050301);
  1711. end;
  1712. end;
  1713. procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1714. var
  1715. tmplo,tmphi,carry,hreg: TRegister;
  1716. signed: boolean;
  1717. begin
  1718. case op of
  1719. OP_ADD:
  1720. begin
  1721. signed:=(size in [OS_S64]);
  1722. tmplo := cg.GetIntRegister(list,OS_S32);
  1723. carry := cg.GetIntRegister(list,OS_S32);
  1724. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1725. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1726. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
  1727. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1728. if signed or (not setflags) then
  1729. begin
  1730. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1731. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1732. end
  1733. else
  1734. begin
  1735. tmphi:=cg.GetIntRegister(list,OS_INT);
  1736. hreg:=cg.GetIntRegister(list,OS_INT);
  1737. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1738. // first add carry to one of the addends
  1739. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmphi, regsrc2.reghi, carry));
  1740. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
  1741. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1742. // then add another addend
  1743. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, tmphi, regsrc1.reghi));
  1744. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
  1745. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1746. end;
  1747. end;
  1748. OP_SUB:
  1749. begin
  1750. signed:=(size in [OS_S64]);
  1751. tmplo := cg.GetIntRegister(list,OS_S32);
  1752. carry := cg.GetIntRegister(list,OS_S32);
  1753. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1754. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1755. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
  1756. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1757. if signed or (not setflags) then
  1758. begin
  1759. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1760. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1761. end
  1762. else
  1763. begin
  1764. tmphi:=cg.GetIntRegister(list,OS_INT);
  1765. hreg:=cg.GetIntRegister(list,OS_INT);
  1766. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1767. // first subtract the carry...
  1768. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmphi, regsrc2.reghi, carry));
  1769. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
  1770. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1771. // ...then the subtrahend
  1772. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, tmphi, regsrc1.reghi));
  1773. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
  1774. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1775. end;
  1776. end;
  1777. OP_AND,OP_OR,OP_XOR:
  1778. begin
  1779. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1780. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1781. end;
  1782. else
  1783. internalerror(200306017);
  1784. end;
  1785. end;
  1786. procedure create_codegen;
  1787. begin
  1788. cg:=TCGMIPS.Create;
  1789. cg64:=TCg64MPSel.Create;
  1790. end;
  1791. end.