cgcpu.pas 68 KB

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