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