cgcpu.pas 68 KB

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