cgcpu.pas 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002
  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. list.concat(tai_directive.create(asd_ent,current_procinfo.procdef.mangledname));
  1068. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1069. if nostackframe then
  1070. begin
  1071. list.concat(taicpu.op_none(A_P_SET_NOMIPS16));
  1072. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1073. exit;
  1074. end;
  1075. if (pi_needs_stackframe in current_procinfo.flags) then
  1076. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1077. helplist:=TAsmList.Create;
  1078. reference_reset(href,0);
  1079. href.base:=NR_STACK_POINTER_REG;
  1080. fmask:=0;
  1081. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1082. lastfpuoffset:=LocalSize;
  1083. for reg := RS_F0 to RS_F31 do { to check: what if F30 is double? }
  1084. begin
  1085. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1086. begin
  1087. fmask:=fmask or (1 shl ord(reg));
  1088. href.offset:=nextoffset;
  1089. lastfpuoffset:=nextoffset;
  1090. helplist.concat(taicpu.op_reg_ref(A_SWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1091. inc(nextoffset,4);
  1092. { IEEE Double values are stored in floating point
  1093. register pairs f2X/f2X+1,
  1094. as the f2X+1 register is not correctly marked as used for now,
  1095. we simply assume it is also used if f2X is used
  1096. Should be fixed by a proper inclusion of f2X+1 into used_in_proc }
  1097. if (ord(reg)-ord(RS_F0)) mod 2 = 0 then
  1098. include(rg[R_FPUREGISTER].used_in_proc,succ(reg));
  1099. end;
  1100. end;
  1101. mask:=0;
  1102. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1103. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1104. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1105. include(saveregs,RS_R31);
  1106. if (pi_needs_stackframe in current_procinfo.flags) then
  1107. include(saveregs,RS_FRAME_POINTER_REG);
  1108. lastintoffset:=LocalSize;
  1109. framesave:=nil;
  1110. ra_save:=nil;
  1111. for reg:=RS_R1 to RS_R31 do
  1112. begin
  1113. if reg in saveregs then
  1114. begin
  1115. mask:=mask or (1 shl ord(reg));
  1116. href.offset:=nextoffset;
  1117. lastintoffset:=nextoffset;
  1118. if (reg=RS_FRAME_POINTER_REG) then
  1119. framesave:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1120. else if (reg=RS_R31) then
  1121. ra_save:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1122. else
  1123. helplist.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1124. inc(nextoffset,4);
  1125. end;
  1126. end;
  1127. //list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,current_procinfo.para_stack_size));
  1128. list.concat(Taicpu.op_none(A_P_SET_NOMIPS16));
  1129. list.concat(Taicpu.op_reg_const_reg(A_P_FRAME,current_procinfo.framepointer,LocalSize,NR_R31));
  1130. list.concat(Taicpu.op_const_const(A_P_MASK,mask,-(LocalSize-lastintoffset)));
  1131. list.concat(Taicpu.op_const_const(A_P_FMASK,Fmask,-(LocalSize-lastfpuoffset)));
  1132. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1133. if (cs_create_pic in current_settings.moduleswitches) and
  1134. (pi_needs_got in current_procinfo.flags) then
  1135. begin
  1136. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1137. end;
  1138. if (-LocalSize >= simm16lo) and (-LocalSize <= simm16hi) then
  1139. begin
  1140. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1141. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-LocalSize));
  1142. if assigned(ra_save) then
  1143. list.concat(ra_save);
  1144. if assigned(framesave) then
  1145. begin
  1146. list.concat(framesave);
  1147. list.concat(Taicpu.op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,
  1148. NR_STACK_POINTER_REG,LocalSize));
  1149. end;
  1150. end
  1151. else
  1152. begin
  1153. a_load_const_reg(list,OS_32,-LocalSize,NR_R9);
  1154. list.concat(Taicpu.Op_reg_reg_reg(A_ADDU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R9));
  1155. if assigned(ra_save) then
  1156. list.concat(ra_save);
  1157. if assigned(framesave) then
  1158. begin
  1159. list.concat(framesave);
  1160. list.concat(Taicpu.op_reg_reg_reg(A_SUBU,NR_FRAME_POINTER_REG,
  1161. NR_STACK_POINTER_REG,NR_R9));
  1162. end;
  1163. { The instructions before are macros that can extend to multiple instructions,
  1164. the settings of R9 to -LocalSize surely does,
  1165. but the saving of RA and FP also might, and might
  1166. even use AT register, which is why we use R9 instead of AT here for -LocalSize }
  1167. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1168. end;
  1169. if (cs_create_pic in current_settings.moduleswitches) and
  1170. (pi_needs_got in current_procinfo.flags) then
  1171. begin
  1172. largeoffs:=(TMIPSProcinfo(current_procinfo).save_gp_ref.offset>simm16hi);
  1173. if largeoffs then
  1174. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1175. list.concat(Taicpu.op_const(A_P_CPRESTORE,TMIPSProcinfo(current_procinfo).save_gp_ref.offset));
  1176. if largeoffs then
  1177. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1178. end;
  1179. href.base:=NR_STACK_POINTER_REG;
  1180. for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
  1181. if TMIPSProcInfo(current_procinfo).register_used[i] then
  1182. begin
  1183. reg:=parasupregs[i];
  1184. href.offset:=i*sizeof(aint)+LocalSize;
  1185. list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
  1186. end;
  1187. list.concatList(helplist);
  1188. helplist.Free;
  1189. if current_procinfo.has_nestedprocs then
  1190. current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@LocalSize);
  1191. end;
  1192. procedure TCGMIPS.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean);
  1193. var
  1194. href : treference;
  1195. stacksize : aint;
  1196. saveregs : tcpuregisterset;
  1197. nextoffset : aint;
  1198. reg : Tsuperregister;
  1199. begin
  1200. stacksize:=current_procinfo.calc_stackframe_size;
  1201. if nostackframe then
  1202. begin
  1203. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1204. list.concat(Taicpu.op_none(A_NOP));
  1205. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1206. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1207. end
  1208. else
  1209. begin
  1210. if TMIPSProcinfo(current_procinfo).save_gp_ref.offset<>0 then
  1211. tg.ungettemp(list,TMIPSProcinfo(current_procinfo).save_gp_ref);
  1212. reference_reset(href,0);
  1213. href.base:=NR_STACK_POINTER_REG;
  1214. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1215. for reg := RS_F0 to RS_F31 do
  1216. begin
  1217. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1218. begin
  1219. href.offset:=nextoffset;
  1220. list.concat(taicpu.op_reg_ref(A_LWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1221. inc(nextoffset,4);
  1222. end;
  1223. end;
  1224. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1225. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1226. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1227. include(saveregs,RS_R31);
  1228. if (pi_needs_stackframe in current_procinfo.flags) then
  1229. include(saveregs,RS_FRAME_POINTER_REG);
  1230. // GP does not need to be restored on exit
  1231. for reg:=RS_R1 to RS_R31 do
  1232. begin
  1233. if reg in saveregs then
  1234. begin
  1235. href.offset:=nextoffset;
  1236. list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1237. inc(nextoffset,sizeof(aint));
  1238. end;
  1239. end;
  1240. if (-stacksize >= simm16lo) and (-stacksize <= simm16hi) then
  1241. begin
  1242. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1243. { correct stack pointer in the delay slot }
  1244. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, stacksize));
  1245. end
  1246. else
  1247. begin
  1248. a_load_const_reg(list,OS_32,stacksize,NR_R1);
  1249. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1250. { correct stack pointer in the delay slot }
  1251. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R1));
  1252. end;
  1253. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1254. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1255. end;
  1256. list.concat(tai_directive.create(asd_ent_end,current_procinfo.procdef.mangledname));
  1257. end;
  1258. { ************* concatcopy ************ }
  1259. procedure TCGMIPS.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  1260. var
  1261. paraloc1, paraloc2, paraloc3: TCGPara;
  1262. pd: tprocdef;
  1263. begin
  1264. pd:=search_system_proc('MOVE');
  1265. paraloc1.init;
  1266. paraloc2.init;
  1267. paraloc3.init;
  1268. paramanager.getintparaloc(pd, 1, paraloc1);
  1269. paramanager.getintparaloc(pd, 2, paraloc2);
  1270. paramanager.getintparaloc(pd, 3, paraloc3);
  1271. a_load_const_cgpara(list, OS_SINT, len, paraloc3);
  1272. a_loadaddr_ref_cgpara(list, dest, paraloc2);
  1273. a_loadaddr_ref_cgpara(list, Source, paraloc1);
  1274. paramanager.freecgpara(list, paraloc3);
  1275. paramanager.freecgpara(list, paraloc2);
  1276. paramanager.freecgpara(list, paraloc1);
  1277. alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1278. alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1279. a_call_name(list, 'FPC_MOVE', false);
  1280. dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1281. dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1282. paraloc3.done;
  1283. paraloc2.done;
  1284. paraloc1.done;
  1285. end;
  1286. procedure TCGMIPS.g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint);
  1287. var
  1288. tmpreg1, hreg, countreg: TRegister;
  1289. src, dst: TReference;
  1290. lab: tasmlabel;
  1291. Count, count2: aint;
  1292. function reference_is_reusable(const ref: treference): boolean;
  1293. begin
  1294. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1295. (ref.symbol=nil) and
  1296. (ref.offset>=simm16lo) and (ref.offset+len<=simm16hi);
  1297. end;
  1298. begin
  1299. if len > high(longint) then
  1300. internalerror(2002072704);
  1301. { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
  1302. allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
  1303. i.e. before secondpass. Other internal procedures request correct stack frame
  1304. by setting pi_do_call during firstpass, but for this particular one it is impossible.
  1305. Therefore, if the current procedure is a leaf one, we have to leave it that way. }
  1306. { anybody wants to determine a good value here :)? }
  1307. if (len > 100) and
  1308. assigned(current_procinfo) and
  1309. (pi_do_call in current_procinfo.flags) then
  1310. g_concatcopy_move(list, Source, dest, len)
  1311. else
  1312. begin
  1313. Count := len div 4;
  1314. if (count<=4) and reference_is_reusable(source) then
  1315. src:=source
  1316. else
  1317. begin
  1318. reference_reset(src,sizeof(aint));
  1319. { load the address of source into src.base }
  1320. src.base := GetAddressRegister(list);
  1321. a_loadaddr_ref_reg(list, Source, src.base);
  1322. end;
  1323. if (count<=4) and reference_is_reusable(dest) then
  1324. dst:=dest
  1325. else
  1326. begin
  1327. reference_reset(dst,sizeof(aint));
  1328. { load the address of dest into dst.base }
  1329. dst.base := GetAddressRegister(list);
  1330. a_loadaddr_ref_reg(list, dest, dst.base);
  1331. end;
  1332. { generate a loop }
  1333. if Count > 4 then
  1334. begin
  1335. countreg := GetIntRegister(list, OS_INT);
  1336. tmpreg1 := GetIntRegister(list, OS_INT);
  1337. a_load_const_reg(list, OS_INT, Count, countreg);
  1338. current_asmdata.getjumplabel(lab);
  1339. a_label(list, lab);
  1340. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1341. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1342. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4));
  1343. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4));
  1344. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1345. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1346. len := len mod 4;
  1347. end;
  1348. { unrolled loop }
  1349. Count := len div 4;
  1350. if Count > 0 then
  1351. begin
  1352. tmpreg1 := GetIntRegister(list, OS_INT);
  1353. for count2 := 1 to Count do
  1354. begin
  1355. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1356. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1357. Inc(src.offset, 4);
  1358. Inc(dst.offset, 4);
  1359. end;
  1360. len := len mod 4;
  1361. end;
  1362. if (len and 4) <> 0 then
  1363. begin
  1364. hreg := GetIntRegister(list, OS_INT);
  1365. a_load_ref_reg(list, OS_32, OS_32, src, hreg);
  1366. a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
  1367. Inc(src.offset, 4);
  1368. Inc(dst.offset, 4);
  1369. end;
  1370. { copy the leftovers }
  1371. if (len and 2) <> 0 then
  1372. begin
  1373. hreg := GetIntRegister(list, OS_INT);
  1374. a_load_ref_reg(list, OS_16, OS_16, src, hreg);
  1375. a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
  1376. Inc(src.offset, 2);
  1377. Inc(dst.offset, 2);
  1378. end;
  1379. if (len and 1) <> 0 then
  1380. begin
  1381. hreg := GetIntRegister(list, OS_INT);
  1382. a_load_ref_reg(list, OS_8, OS_8, src, hreg);
  1383. a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
  1384. end;
  1385. end;
  1386. end;
  1387. procedure TCGMIPS.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint);
  1388. var
  1389. src, dst: TReference;
  1390. tmpreg1, countreg: TRegister;
  1391. i: aint;
  1392. lab: tasmlabel;
  1393. begin
  1394. if (len > 31) and
  1395. { see comment in g_concatcopy }
  1396. assigned(current_procinfo) and
  1397. (pi_do_call in current_procinfo.flags) then
  1398. g_concatcopy_move(list, Source, dest, len)
  1399. else
  1400. begin
  1401. reference_reset(src,sizeof(aint));
  1402. reference_reset(dst,sizeof(aint));
  1403. { load the address of source into src.base }
  1404. src.base := GetAddressRegister(list);
  1405. a_loadaddr_ref_reg(list, Source, src.base);
  1406. { load the address of dest into dst.base }
  1407. dst.base := GetAddressRegister(list);
  1408. a_loadaddr_ref_reg(list, dest, dst.base);
  1409. { generate a loop }
  1410. if len > 4 then
  1411. begin
  1412. countreg := GetIntRegister(list, OS_INT);
  1413. tmpreg1 := GetIntRegister(list, OS_INT);
  1414. a_load_const_reg(list, OS_INT, len, countreg);
  1415. current_asmdata.getjumplabel(lab);
  1416. a_label(list, lab);
  1417. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1418. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1419. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1));
  1420. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1));
  1421. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1422. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1423. end
  1424. else
  1425. begin
  1426. { unrolled loop }
  1427. tmpreg1 := GetIntRegister(list, OS_INT);
  1428. for i := 1 to len do
  1429. begin
  1430. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1431. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1432. Inc(src.offset);
  1433. Inc(dst.offset);
  1434. end;
  1435. end;
  1436. end;
  1437. end;
  1438. procedure TCGMIPS.g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint);
  1439. var
  1440. make_global: boolean;
  1441. hsym: tsym;
  1442. href: treference;
  1443. paraloc: Pcgparalocation;
  1444. IsVirtual: boolean;
  1445. begin
  1446. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1447. Internalerror(200006137);
  1448. if not assigned(procdef.struct) or
  1449. (procdef.procoptions * [po_classmethod, po_staticmethod,
  1450. po_methodpointer, po_interrupt, po_iocheck] <> []) then
  1451. Internalerror(200006138);
  1452. if procdef.owner.symtabletype <> objectsymtable then
  1453. Internalerror(200109191);
  1454. make_global := False;
  1455. if (not current_module.is_unit) or create_smartlink or
  1456. (procdef.owner.defowner.owner.symtabletype = globalsymtable) then
  1457. make_global := True;
  1458. if make_global then
  1459. List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0))
  1460. else
  1461. List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0));
  1462. IsVirtual:=(po_virtualmethod in procdef.procoptions) and
  1463. not is_objectpascal_helper(procdef.struct);
  1464. if (cs_create_pic in current_settings.moduleswitches) and
  1465. (not IsVirtual) then
  1466. begin
  1467. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1468. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1469. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1470. end;
  1471. { set param1 interface to self }
  1472. procdef.init_paraloc_info(callerside);
  1473. hsym:=tsym(procdef.parast.Find('self'));
  1474. if not(assigned(hsym) and
  1475. (hsym.typ=paravarsym)) then
  1476. internalerror(2010103101);
  1477. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1478. if assigned(paraloc^.next) then
  1479. InternalError(2013020101);
  1480. case paraloc^.loc of
  1481. LOC_REGISTER:
  1482. begin
  1483. if ((ioffset>=simm16lo) and (ioffset<=simm16hi)) then
  1484. a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
  1485. else
  1486. begin
  1487. a_load_const_reg(list, paraloc^.size, ioffset, NR_R1);
  1488. a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_R1, paraloc^.register);
  1489. end;
  1490. end;
  1491. else
  1492. internalerror(2010103102);
  1493. end;
  1494. if IsVirtual then
  1495. begin
  1496. { load VMT pointer }
  1497. reference_reset_base(href,paraloc^.register,0,sizeof(aint));
  1498. list.concat(taicpu.op_reg_ref(A_LW,NR_VMT,href));
  1499. if (procdef.extnumber=$ffff) then
  1500. Internalerror(200006139);
  1501. { TODO: case of large VMT is not handled }
  1502. { We have no reason not to use $t9 even in non-PIC mode. }
  1503. reference_reset_base(href, NR_VMT, tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber), sizeof(aint));
  1504. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1505. list.concat(taicpu.op_reg(A_JR, NR_PIC_FUNC));
  1506. end
  1507. else if not (cs_create_pic in current_settings.moduleswitches) then
  1508. list.concat(taicpu.op_sym(A_J,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  1509. else
  1510. begin
  1511. { GAS does not expand "J symbol" into PIC sequence }
  1512. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0,sizeof(pint));
  1513. href.base:=NR_GP;
  1514. href.refaddr:=addr_pic_call16;
  1515. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1516. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1517. end;
  1518. { Delay slot }
  1519. list.Concat(TAiCpu.Op_none(A_NOP));
  1520. List.concat(Tai_symbol_end.Createname(labelname));
  1521. end;
  1522. procedure TCGMIPS.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  1523. var
  1524. href: treference;
  1525. begin
  1526. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname),0,sizeof(aint));
  1527. { Always do indirect jump using $t9, it won't harm in non-PIC mode }
  1528. if (cs_create_pic in current_settings.moduleswitches) then
  1529. begin
  1530. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1531. list.concat(taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1532. href.base:=NR_GP;
  1533. href.refaddr:=addr_pic_call16;
  1534. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1535. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1536. { Delay slot }
  1537. list.Concat(taicpu.op_none(A_NOP));
  1538. list.Concat(taicpu.op_none(A_P_SET_REORDER));
  1539. end
  1540. else
  1541. begin
  1542. href.refaddr:=addr_high;
  1543. list.concat(taicpu.op_reg_ref(A_LUI,NR_PIC_FUNC,href));
  1544. href.refaddr:=addr_low;
  1545. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  1546. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1547. { Delay slot }
  1548. list.Concat(taicpu.op_none(A_NOP));
  1549. end;
  1550. end;
  1551. procedure TCGMIPS.g_profilecode(list:TAsmList);
  1552. var
  1553. href: treference;
  1554. begin
  1555. if not (cs_create_pic in current_settings.moduleswitches) then
  1556. begin
  1557. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('_gp'),0,sizeof(pint));
  1558. a_loadaddr_ref_reg(list,href,NR_GP);
  1559. end;
  1560. list.concat(taicpu.op_reg_reg(A_MOVE,NR_R1,NR_RA));
  1561. list.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_SP,NR_SP,-8));
  1562. a_call_sym_pic(list,current_asmdata.RefAsmSymbol('_mcount'));
  1563. end;
  1564. procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1565. begin
  1566. { This method is integrated into g_intf_wrapper and shouldn't be called separately }
  1567. InternalError(2013020102);
  1568. end;
  1569. procedure TCGMIPS.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1570. begin
  1571. Comment(V_Error,'TCgMPSel.g_stackpointer_alloc method not implemented');
  1572. end;
  1573. procedure TCGMIPS.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1574. begin
  1575. Comment(V_Error,'TCgMPSel.a_bit_scan_reg_reg method not implemented');
  1576. end;
  1577. {****************************************************************************
  1578. TCG64_MIPSel
  1579. ****************************************************************************}
  1580. procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference);
  1581. var
  1582. tmpref: treference;
  1583. tmpreg: tregister;
  1584. begin
  1585. if target_info.endian = endian_big then
  1586. begin
  1587. tmpreg := reg.reglo;
  1588. reg.reglo := reg.reghi;
  1589. reg.reghi := tmpreg;
  1590. end;
  1591. tmpref := ref;
  1592. tcgmips(cg).make_simple_ref(list,tmpref);
  1593. list.concat(taicpu.op_reg_ref(A_SW,reg.reglo,tmpref));
  1594. Inc(tmpref.offset, 4);
  1595. list.concat(taicpu.op_reg_ref(A_SW,reg.reghi,tmpref));
  1596. end;
  1597. procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64);
  1598. var
  1599. tmpref: treference;
  1600. tmpreg: tregister;
  1601. begin
  1602. if target_info.endian = endian_big then
  1603. begin
  1604. tmpreg := reg.reglo;
  1605. reg.reglo := reg.reghi;
  1606. reg.reghi := tmpreg;
  1607. end;
  1608. tmpref := ref;
  1609. tcgmips(cg).make_simple_ref(list,tmpref);
  1610. list.concat(taicpu.op_reg_ref(A_LW,reg.reglo,tmpref));
  1611. Inc(tmpref.offset, 4);
  1612. list.concat(taicpu.op_reg_ref(A_LW,reg.reghi,tmpref));
  1613. end;
  1614. procedure TCg64MPSel.a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara);
  1615. var
  1616. hreg64: tregister64;
  1617. begin
  1618. { Override this function to prevent loading the reference twice.
  1619. Use here some extra registers, but those are optimized away by the RA }
  1620. hreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1621. hreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1622. a_load64_ref_reg(list, r, hreg64);
  1623. a_load64_reg_cgpara(list, hreg64, paraloc);
  1624. end;
  1625. procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64);
  1626. var
  1627. tmpreg1: TRegister;
  1628. begin
  1629. case op of
  1630. OP_NEG:
  1631. begin
  1632. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1633. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo));
  1634. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_R0, regdst.reglo));
  1635. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi));
  1636. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg1));
  1637. end;
  1638. OP_NOT:
  1639. begin
  1640. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo));
  1641. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi));
  1642. end;
  1643. else
  1644. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1645. end;
  1646. end;
  1647. procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64);
  1648. begin
  1649. a_op64_const_reg_reg(list, op, size, value, regdst, regdst);
  1650. end;
  1651. procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64);
  1652. var
  1653. l: tlocation;
  1654. begin
  1655. a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l);
  1656. end;
  1657. procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64);
  1658. var
  1659. l: tlocation;
  1660. begin
  1661. a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l);
  1662. end;
  1663. procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1664. var
  1665. tmplo,carry: TRegister;
  1666. hisize: tcgsize;
  1667. begin
  1668. carry:=NR_NO;
  1669. if (size in [OS_S64]) then
  1670. hisize:=OS_S32
  1671. else
  1672. hisize:=OS_32;
  1673. case op of
  1674. OP_AND,OP_OR,OP_XOR:
  1675. begin
  1676. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1677. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1678. end;
  1679. OP_ADD:
  1680. begin
  1681. if lo(value)<>0 then
  1682. begin
  1683. tmplo:=cg.GetIntRegister(list,OS_32);
  1684. carry:=cg.GetIntRegister(list,OS_32);
  1685. tcgmips(cg).handle_reg_const_reg(list,A_ADDU,regsrc.reglo,aint(lo(value)),tmplo);
  1686. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
  1687. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1688. end
  1689. else
  1690. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1691. { With overflow checking and unsigned args, this generates slighly suboptimal code
  1692. ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
  1693. look worth the effort. }
  1694. cg.a_op_const_reg_reg_checkoverflow(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1695. if carry<>NR_NO then
  1696. cg.a_op_reg_reg_reg_checkoverflow(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1697. end;
  1698. OP_SUB:
  1699. begin
  1700. carry:=NR_NO;
  1701. if lo(value)<>0 then
  1702. begin
  1703. tmplo:=cg.GetIntRegister(list,OS_32);
  1704. carry:=cg.GetIntRegister(list,OS_32);
  1705. tcgmips(cg).handle_reg_const_reg(list,A_SUBU,regsrc.reglo,aint(lo(value)),tmplo);
  1706. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
  1707. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1708. end
  1709. else
  1710. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1711. cg.a_op_const_reg_reg_checkoverflow(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1712. if carry<>NR_NO then
  1713. cg.a_op_reg_reg_reg_checkoverflow(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1714. end;
  1715. else
  1716. InternalError(2013050301);
  1717. end;
  1718. end;
  1719. procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1720. var
  1721. tmplo,tmphi,carry,hreg: TRegister;
  1722. signed: boolean;
  1723. begin
  1724. case op of
  1725. OP_ADD:
  1726. begin
  1727. signed:=(size in [OS_S64]);
  1728. tmplo := cg.GetIntRegister(list,OS_S32);
  1729. carry := cg.GetIntRegister(list,OS_S32);
  1730. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1731. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1732. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
  1733. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1734. if signed or (not setflags) then
  1735. begin
  1736. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1737. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1738. end
  1739. else
  1740. begin
  1741. tmphi:=cg.GetIntRegister(list,OS_INT);
  1742. hreg:=cg.GetIntRegister(list,OS_INT);
  1743. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1744. // first add carry to one of the addends
  1745. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmphi, regsrc2.reghi, carry));
  1746. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
  1747. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1748. // then add another addend
  1749. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, tmphi, regsrc1.reghi));
  1750. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
  1751. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1752. end;
  1753. end;
  1754. OP_SUB:
  1755. begin
  1756. signed:=(size in [OS_S64]);
  1757. tmplo := cg.GetIntRegister(list,OS_S32);
  1758. carry := cg.GetIntRegister(list,OS_S32);
  1759. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1760. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1761. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
  1762. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1763. if signed or (not setflags) then
  1764. begin
  1765. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1766. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1767. end
  1768. else
  1769. begin
  1770. tmphi:=cg.GetIntRegister(list,OS_INT);
  1771. hreg:=cg.GetIntRegister(list,OS_INT);
  1772. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1773. // first subtract the carry...
  1774. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmphi, regsrc2.reghi, carry));
  1775. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
  1776. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1777. // ...then the subtrahend
  1778. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, tmphi, regsrc1.reghi));
  1779. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
  1780. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1781. end;
  1782. end;
  1783. OP_AND,OP_OR,OP_XOR:
  1784. begin
  1785. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1786. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1787. end;
  1788. else
  1789. internalerror(200306017);
  1790. end;
  1791. end;
  1792. procedure create_codegen;
  1793. begin
  1794. cg:=TCGMIPS.Create;
  1795. cg64:=TCg64MPSel.Create;
  1796. end;
  1797. end.