cgcpu.pas 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. cgsetflags : boolean;
  31. procedure init_register_allocators;override;
  32. procedure done_register_allocators;override;
  33. procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : TAsmList;const s : string);override;
  37. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  38. procedure a_call_ref(list : TAsmList;ref: treference);override;
  39. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  42. size: tcgsize; a: aint; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  47. { move instructions }
  48. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  49. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  50. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  51. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  52. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  53. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  54. { fpu move instructions }
  55. procedure a_loadfpu_reg_reg(list: TAsmList; size: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; size: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; size: tcgsize; reg: tregister; const ref: treference); override;
  58. procedure a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  59. { comparison operations }
  60. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  61. l : tasmlabel);override;
  62. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  63. procedure a_jmp_name(list : TAsmList;const s : string); override;
  64. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  65. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  67. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  68. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  69. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  70. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
  71. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
  72. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  73. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  74. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  75. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  76. procedure g_save_standard_registers(list : TAsmList);override;
  77. procedure g_restore_standard_registers(list : TAsmList);override;
  78. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  79. procedure fixref(list : TAsmList;var ref : treference);
  80. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  81. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  82. end;
  83. tcg64farm = class(tcg64f32)
  84. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  85. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  86. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  87. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  88. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  89. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  90. end;
  91. const
  92. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  93. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  94. winstackpagesize = 4096;
  95. function get_fpu_postfix(def : tdef) : toppostfix;
  96. implementation
  97. uses
  98. globals,verbose,systems,cutils,
  99. fmodule,
  100. symconst,symsym,
  101. tgobj,
  102. procinfo,cpupi,
  103. paramgr;
  104. function get_fpu_postfix(def : tdef) : toppostfix;
  105. begin
  106. if def.typ=floatdef then
  107. begin
  108. case tfloatdef(def).floattype of
  109. s32real:
  110. result:=PF_S;
  111. s64real:
  112. result:=PF_D;
  113. s80real:
  114. result:=PF_E;
  115. else
  116. internalerror(200401272);
  117. end;
  118. end
  119. else
  120. internalerror(200401271);
  121. end;
  122. procedure tcgarm.init_register_allocators;
  123. begin
  124. inherited init_register_allocators;
  125. { currently, we save R14 always, so we can use it }
  126. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  127. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  128. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  129. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  130. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  131. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  132. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  133. end;
  134. procedure tcgarm.done_register_allocators;
  135. begin
  136. rg[R_INTREGISTER].free;
  137. rg[R_FPUREGISTER].free;
  138. rg[R_MMREGISTER].free;
  139. inherited done_register_allocators;
  140. end;
  141. procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  142. var
  143. ref: treference;
  144. begin
  145. paraloc.check_simple_location;
  146. case paraloc.location^.loc of
  147. LOC_REGISTER,LOC_CREGISTER:
  148. a_load_const_reg(list,size,a,paraloc.location^.register);
  149. LOC_REFERENCE:
  150. begin
  151. reference_reset(ref);
  152. ref.base:=paraloc.location^.reference.index;
  153. ref.offset:=paraloc.location^.reference.offset;
  154. a_load_const_ref(list,size,a,ref);
  155. end;
  156. else
  157. internalerror(2002081101);
  158. end;
  159. end;
  160. procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  161. var
  162. tmpref, ref: treference;
  163. location: pcgparalocation;
  164. sizeleft: aint;
  165. begin
  166. location := paraloc.location;
  167. tmpref := r;
  168. sizeleft := paraloc.intsize;
  169. while assigned(location) do
  170. begin
  171. case location^.loc of
  172. LOC_REGISTER,LOC_CREGISTER:
  173. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  174. LOC_REFERENCE:
  175. begin
  176. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  177. { doubles in softemu mode have a strange order of registers and references }
  178. if location^.size=OS_32 then
  179. g_concatcopy(list,tmpref,ref,4)
  180. else
  181. begin
  182. g_concatcopy(list,tmpref,ref,sizeleft);
  183. if assigned(location^.next) then
  184. internalerror(2005010710);
  185. end;
  186. end;
  187. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  188. case location^.size of
  189. OS_F32, OS_F64:
  190. a_loadfpu_ref_reg(list,location^.size,tmpref,location^.register);
  191. else
  192. internalerror(2002072801);
  193. end;
  194. LOC_VOID:
  195. begin
  196. // nothing to do
  197. end;
  198. else
  199. internalerror(2002081103);
  200. end;
  201. inc(tmpref.offset,tcgsize2size[location^.size]);
  202. dec(sizeleft,tcgsize2size[location^.size]);
  203. location := location^.next;
  204. end;
  205. end;
  206. procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
  207. var
  208. ref: treference;
  209. tmpreg: tregister;
  210. begin
  211. paraloc.check_simple_location;
  212. case paraloc.location^.loc of
  213. LOC_REGISTER,LOC_CREGISTER:
  214. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  215. LOC_REFERENCE:
  216. begin
  217. reference_reset(ref);
  218. ref.base := paraloc.location^.reference.index;
  219. ref.offset := paraloc.location^.reference.offset;
  220. tmpreg := getintregister(list,OS_ADDR);
  221. a_loadaddr_ref_reg(list,r,tmpreg);
  222. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  223. end;
  224. else
  225. internalerror(2002080701);
  226. end;
  227. end;
  228. procedure tcgarm.a_call_name(list : TAsmList;const s : string);
  229. begin
  230. list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)));
  231. {
  232. the compiler does not properly set this flag anymore in pass 1, and
  233. for now we only need it after pass 2 (I hope) (JM)
  234. if not(pi_do_call in current_procinfo.flags) then
  235. internalerror(2003060703);
  236. }
  237. include(current_procinfo.flags,pi_do_call);
  238. end;
  239. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  240. var
  241. r : tregister;
  242. begin
  243. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  244. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  245. {
  246. the compiler does not properly set this flag anymore in pass 1, and
  247. for now we only need it after pass 2 (I hope) (JM)
  248. if not(pi_do_call in current_procinfo.flags) then
  249. internalerror(2003060703);
  250. }
  251. include(current_procinfo.flags,pi_do_call);
  252. end;
  253. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  254. begin
  255. a_reg_alloc(list,NR_R12);
  256. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  257. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  258. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  259. a_reg_dealloc(list,NR_R12);
  260. include(current_procinfo.flags,pi_do_call);
  261. end;
  262. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  263. begin
  264. a_op_const_reg_reg(list,op,size,a,reg,reg);
  265. end;
  266. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  267. begin
  268. case op of
  269. OP_NEG:
  270. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  271. OP_NOT:
  272. begin
  273. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  274. case size of
  275. OS_8 :
  276. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  277. OS_16 :
  278. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  279. end;
  280. end
  281. else
  282. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  283. end;
  284. end;
  285. const
  286. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  287. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  288. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  289. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  290. size: tcgsize; a: aint; src, dst: tregister);
  291. var
  292. ovloc : tlocation;
  293. begin
  294. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  295. end;
  296. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  297. size: tcgsize; src1, src2, dst: tregister);
  298. var
  299. ovloc : tlocation;
  300. begin
  301. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  302. end;
  303. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  304. var
  305. shift : byte;
  306. tmpreg : tregister;
  307. so : tshifterop;
  308. l1 : longint;
  309. begin
  310. ovloc.loc:=LOC_VOID;
  311. if is_shifter_const(-a,shift) then
  312. case op of
  313. OP_ADD:
  314. begin
  315. op:=OP_SUB;
  316. a:=dword(-a);
  317. end;
  318. OP_SUB:
  319. begin
  320. op:=OP_ADD;
  321. a:=dword(-a);
  322. end
  323. end;
  324. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  325. case op of
  326. OP_NEG,OP_NOT,
  327. OP_DIV,OP_IDIV:
  328. internalerror(200308281);
  329. OP_SHL:
  330. begin
  331. if a>32 then
  332. internalerror(200308294);
  333. if a<>0 then
  334. begin
  335. shifterop_reset(so);
  336. so.shiftmode:=SM_LSL;
  337. so.shiftimm:=a;
  338. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  339. end
  340. else
  341. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  342. end;
  343. OP_SHR:
  344. begin
  345. if a>32 then
  346. internalerror(200308292);
  347. shifterop_reset(so);
  348. if a<>0 then
  349. begin
  350. so.shiftmode:=SM_LSR;
  351. so.shiftimm:=a;
  352. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  353. end
  354. else
  355. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  356. end;
  357. OP_SAR:
  358. begin
  359. if a>32 then
  360. internalerror(200308295);
  361. if a<>0 then
  362. begin
  363. shifterop_reset(so);
  364. so.shiftmode:=SM_ASR;
  365. so.shiftimm:=a;
  366. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  367. end
  368. else
  369. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  370. end;
  371. else
  372. list.concat(setoppostfix(
  373. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  374. ));
  375. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  376. begin
  377. ovloc.loc:=LOC_FLAGS;
  378. case op of
  379. OP_ADD:
  380. ovloc.resflags:=F_CS;
  381. OP_SUB:
  382. ovloc.resflags:=F_CC;
  383. end;
  384. end;
  385. end
  386. else
  387. begin
  388. { there could be added some more sophisticated optimizations }
  389. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  390. a_load_reg_reg(list,size,size,src,dst)
  391. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  392. a_load_const_reg(list,size,0,dst)
  393. else if (op in [OP_IMUL]) and (a=-1) then
  394. a_op_reg_reg(list,OP_NEG,size,src,dst)
  395. { we do this here instead in the peephole optimizer because
  396. it saves us a register }
  397. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  398. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  399. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  400. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  401. begin
  402. if l1>32 then{roozbeh does this ever happen?}
  403. internalerror(200308296);
  404. shifterop_reset(so);
  405. so.shiftmode:=SM_LSL;
  406. so.shiftimm:=l1;
  407. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  408. end
  409. else
  410. begin
  411. tmpreg:=getintregister(list,size);
  412. a_load_const_reg(list,size,a,tmpreg);
  413. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  414. end;
  415. end;
  416. end;
  417. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  418. var
  419. so : tshifterop;
  420. tmpreg,overflowreg : tregister;
  421. asmop : tasmop;
  422. begin
  423. ovloc.loc:=LOC_VOID;
  424. case op of
  425. OP_NEG,OP_NOT,
  426. OP_DIV,OP_IDIV:
  427. internalerror(200308281);
  428. OP_SHL:
  429. begin
  430. shifterop_reset(so);
  431. so.rs:=src1;
  432. so.shiftmode:=SM_LSL;
  433. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  434. end;
  435. OP_SHR:
  436. begin
  437. shifterop_reset(so);
  438. so.rs:=src1;
  439. so.shiftmode:=SM_LSR;
  440. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  441. end;
  442. OP_SAR:
  443. begin
  444. shifterop_reset(so);
  445. so.rs:=src1;
  446. so.shiftmode:=SM_ASR;
  447. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  448. end;
  449. OP_IMUL,
  450. OP_MUL:
  451. begin
  452. if cgsetflags or setflags then
  453. begin
  454. overflowreg:=getintregister(list,size);
  455. if op=OP_IMUL then
  456. asmop:=A_SMULL
  457. else
  458. asmop:=A_UMULL;
  459. { the arm doesn't allow that rd and rm are the same }
  460. if dst=src2 then
  461. begin
  462. if dst<>src1 then
  463. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  464. else
  465. begin
  466. tmpreg:=getintregister(list,size);
  467. a_load_reg_reg(list,size,size,src2,dst);
  468. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  469. end;
  470. end
  471. else
  472. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  473. if op=OP_IMUL then
  474. begin
  475. shifterop_reset(so);
  476. so.shiftmode:=SM_ASR;
  477. so.shiftimm:=31;
  478. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  479. end
  480. else
  481. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  482. ovloc.loc:=LOC_FLAGS;
  483. ovloc.resflags:=F_NE;
  484. end
  485. else
  486. begin
  487. { the arm doesn't allow that rd and rm are the same }
  488. if dst=src2 then
  489. begin
  490. if dst<>src1 then
  491. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  492. else
  493. begin
  494. tmpreg:=getintregister(list,size);
  495. a_load_reg_reg(list,size,size,src2,dst);
  496. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  497. end;
  498. end
  499. else
  500. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  501. end;
  502. end;
  503. else
  504. list.concat(setoppostfix(
  505. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  506. ));
  507. end;
  508. end;
  509. procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  510. var
  511. imm_shift : byte;
  512. l : tasmlabel;
  513. hr : treference;
  514. tmpreg : tregister;
  515. begin
  516. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  517. internalerror(2002090902);
  518. if is_shifter_const(a,imm_shift) then
  519. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  520. else if is_shifter_const(not(a),imm_shift) then
  521. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  522. { loading of constants with mov and orr }
  523. {else [if (is_shifter_const(a-byte(a),imm_shift)) then
  524. begin
  525. }{ roozbeh:why using tmpreg later causes error in compiling of system.pp,and also those other similars}
  526. {list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  527. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  528. end
  529. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  530. begin
  531. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  532. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  533. end
  534. else if (is_shifter_const(a-(longint(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((longint(a) shl 8) shr 8,imm_shift)) then
  535. begin
  536. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(longint(a) shl 8)shr 8));
  537. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(longint(a) shl 8)shr 8));
  538. end}
  539. else
  540. begin
  541. reference_reset(hr);
  542. current_asmdata.getjumplabel(l);
  543. cg.a_label(current_procinfo.aktlocaldata,l);
  544. hr.symboldata:=current_procinfo.aktlocaldata.last;
  545. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  546. hr.symbol:=l;
  547. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  548. end;
  549. end;
  550. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  551. var
  552. tmpreg,tmpreg2 : tregister;
  553. tmpref : treference;
  554. l : tasmlabel;
  555. so : tshifterop;
  556. begin
  557. tmpreg:=NR_NO;
  558. { Be sure to have a base register }
  559. if (ref.base=NR_NO) then
  560. begin
  561. if ref.shiftmode<>SM_None then
  562. internalerror(200308294);
  563. ref.base:=ref.index;
  564. ref.index:=NR_NO;
  565. end;
  566. { absolute symbols can't be handled directly, we've to store the symbol reference
  567. in the text segment and access it pc relative
  568. For now, we assume that references where base or index equals to PC are already
  569. relative, all other references are assumed to be absolute and thus they need
  570. to be handled extra.
  571. A proper solution would be to change refoptions to a set and store the information
  572. if the symbol is absolute or relative there.
  573. }
  574. if (assigned(ref.symbol) and
  575. not(is_pc(ref.base)) and
  576. not(is_pc(ref.index))
  577. ) or
  578. { [#xxx] isn't a valid address operand }
  579. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  580. (ref.offset<-4095) or
  581. (ref.offset>4095) or
  582. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  583. ((ref.offset<-255) or
  584. (ref.offset>255)
  585. )
  586. ) or
  587. ((op in [A_LDF,A_STF]) and
  588. ((ref.offset<-1020) or
  589. (ref.offset>1020) or
  590. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  591. assigned(ref.symbol)
  592. )
  593. ) then
  594. begin
  595. reference_reset(tmpref);
  596. { load symbol }
  597. tmpreg:=getintregister(list,OS_INT);
  598. if assigned(ref.symbol) then
  599. begin
  600. current_asmdata.getjumplabel(l);
  601. cg.a_label(current_procinfo.aktlocaldata,l);
  602. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  603. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  604. { load consts entry }
  605. tmpref.symbol:=l;
  606. tmpref.base:=NR_R15;
  607. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  608. end
  609. else
  610. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  611. if (ref.base<>NR_NO) then
  612. begin
  613. if ref.index<>NR_NO then
  614. begin
  615. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  616. ref.base:=tmpreg;
  617. end
  618. else
  619. begin
  620. ref.index:=tmpreg;
  621. ref.shiftimm:=0;
  622. ref.signindex:=1;
  623. ref.shiftmode:=SM_None;
  624. end;
  625. end
  626. else
  627. ref.base:=tmpreg;
  628. ref.offset:=0;
  629. ref.symbol:=nil;
  630. end;
  631. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  632. begin
  633. if tmpreg<>NR_NO then
  634. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  635. else
  636. begin
  637. tmpreg:=getintregister(list,OS_ADDR);
  638. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  639. ref.base:=tmpreg;
  640. end;
  641. ref.offset:=0;
  642. end;
  643. { floating point operations have only limited references
  644. we expect here, that a base is already set }
  645. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  646. begin
  647. if ref.shiftmode<>SM_none then
  648. internalerror(200309121);
  649. if tmpreg<>NR_NO then
  650. begin
  651. if ref.base=tmpreg then
  652. begin
  653. if ref.signindex<0 then
  654. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  655. else
  656. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  657. ref.index:=NR_NO;
  658. end
  659. else
  660. begin
  661. if ref.index<>tmpreg then
  662. internalerror(200403161);
  663. if ref.signindex<0 then
  664. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  665. else
  666. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  667. ref.base:=tmpreg;
  668. ref.index:=NR_NO;
  669. end;
  670. end
  671. else
  672. begin
  673. tmpreg:=getintregister(list,OS_ADDR);
  674. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  675. ref.base:=tmpreg;
  676. ref.index:=NR_NO;
  677. end;
  678. end;
  679. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  680. Result := ref;
  681. end;
  682. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  683. var
  684. oppostfix:toppostfix;
  685. usedtmpref,usedtmpref2: treference;
  686. tmpreg,tmpreg2 : tregister;
  687. so : tshifterop;
  688. begin
  689. case ToSize of
  690. { signed integer registers }
  691. OS_8,
  692. OS_S8:
  693. oppostfix:=PF_B;
  694. OS_16,
  695. OS_S16:
  696. oppostfix:=PF_H;
  697. OS_32,
  698. OS_S32:
  699. oppostfix:=PF_None;
  700. else
  701. InternalError(200308295);
  702. end;
  703. if ref.alignment<>0 then
  704. begin
  705. case FromSize of
  706. OS_16,OS_S16:
  707. begin
  708. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  709. tmpreg:=getintregister(list,OS_INT);
  710. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
  711. inc(usedtmpref.offset);
  712. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  713. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  714. end;
  715. OS_32,OS_S32:
  716. begin
  717. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  718. tmpreg:=getintregister(list,OS_INT);
  719. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
  720. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  721. inc(usedtmpref.offset);
  722. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  723. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  724. inc(usedtmpref.offset);
  725. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  726. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  727. inc(usedtmpref.offset);
  728. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  729. end
  730. else
  731. handle_load_store(list,A_STR,oppostfix,reg,ref);
  732. end;
  733. end
  734. else
  735. handle_load_store(list,A_STR,oppostfix,reg,ref);
  736. end;
  737. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  738. var
  739. oppostfix:toppostfix;
  740. usedtmpref,usedtmpref2: treference;
  741. tmpreg,tmpreg2,tmpreg3 : tregister;
  742. so : tshifterop;
  743. begin
  744. case FromSize of
  745. { signed integer registers }
  746. OS_8:
  747. oppostfix:=PF_B;
  748. OS_S8:
  749. oppostfix:=PF_SB;
  750. OS_16:
  751. oppostfix:=PF_H;
  752. OS_S16:
  753. oppostfix:=PF_SH;
  754. OS_32,
  755. OS_S32:
  756. oppostfix:=PF_None;
  757. else
  758. InternalError(200308297);
  759. end;
  760. if Ref.alignment<>0 then
  761. begin
  762. case FromSize of
  763. OS_16,OS_S16:
  764. begin
  765. tmpreg3:=getintregister(list,OS_INT);
  766. a_loadaddr_ref_reg(list,ref,tmpreg3);
  767. reference_reset_base(usedtmpref,tmpreg3,0);
  768. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  769. tmpreg:=getintregister(list,OS_INT);
  770. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  771. inc(usedtmpref.offset);
  772. tmpreg2:=getintregister(list,OS_INT);
  773. if FromSize=OS_16 then
  774. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2)
  775. else
  776. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg2);
  777. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  778. end;
  779. OS_32,OS_S32:
  780. begin
  781. tmpreg:=getintregister(list,OS_INT);
  782. tmpreg2:=getintregister(list,OS_INT);
  783. tmpreg3:=getintregister(list,OS_INT);
  784. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  785. a_loadaddr_ref_reg(list,ref,tmpreg3);
  786. reference_reset_base(usedtmpref,tmpreg3,0);
  787. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  788. inc(usedtmpref.offset);
  789. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  790. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg2,reg,tmpreg,so));
  791. inc(usedtmpref.offset);
  792. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  793. so.shiftimm:=16;
  794. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg,tmpreg2,reg,so));
  795. inc(usedtmpref.offset);
  796. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
  797. so.shiftimm:=24;
  798. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  799. end
  800. else
  801. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  802. end;
  803. end
  804. else
  805. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  806. end;
  807. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  808. var
  809. oppostfix:toppostfix;
  810. begin
  811. case ToSize of
  812. { signed integer registers }
  813. OS_8,
  814. OS_S8:
  815. oppostfix:=PF_B;
  816. OS_16,
  817. OS_S16:
  818. oppostfix:=PF_H;
  819. OS_32,
  820. OS_S32:
  821. oppostfix:=PF_None;
  822. else
  823. InternalError(2003082910);
  824. end;
  825. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  826. end;
  827. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  828. var
  829. oppostfix:toppostfix;
  830. begin
  831. case FromSize of
  832. { signed integer registers }
  833. OS_8:
  834. oppostfix:=PF_B;
  835. OS_S8:
  836. oppostfix:=PF_SB;
  837. OS_16:
  838. oppostfix:=PF_H;
  839. OS_S16:
  840. oppostfix:=PF_SH;
  841. OS_32,
  842. OS_S32:
  843. oppostfix:=PF_None;
  844. else
  845. InternalError(200308291);
  846. end;
  847. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  848. end;
  849. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  850. var
  851. instr: taicpu;
  852. so : tshifterop;
  853. begin
  854. shifterop_reset(so);
  855. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  856. (
  857. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  858. (tosize <> fromsize) and
  859. not(fromsize in [OS_32,OS_S32])
  860. ) then
  861. begin
  862. case tosize of
  863. OS_8:
  864. list.concat(taicpu.op_reg_reg_const(A_AND,
  865. reg2,reg1,$ff));
  866. OS_S8:
  867. begin
  868. so.shiftmode:=SM_LSL;
  869. so.shiftimm:=24;
  870. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  871. so.shiftmode:=SM_ASR;
  872. so.shiftimm:=24;
  873. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  874. end;
  875. OS_16:
  876. begin
  877. so.shiftmode:=SM_LSL;
  878. so.shiftimm:=16;
  879. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  880. so.shiftmode:=SM_LSR;
  881. so.shiftimm:=16;
  882. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  883. end;
  884. OS_S16:
  885. begin
  886. so.shiftmode:=SM_LSL;
  887. so.shiftimm:=16;
  888. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  889. so.shiftmode:=SM_ASR;
  890. so.shiftimm:=16;
  891. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  892. end;
  893. OS_32,OS_S32:
  894. begin
  895. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  896. list.concat(instr);
  897. add_move_instruction(instr);
  898. end;
  899. else internalerror(2002090901);
  900. end;
  901. end
  902. else
  903. begin
  904. if reg1<>reg2 then
  905. begin
  906. { same size, only a register mov required }
  907. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  908. list.Concat(instr);
  909. { Notify the register allocator that we have written a move instruction so
  910. it can try to eliminate it. }
  911. add_move_instruction(instr);
  912. end;
  913. end;
  914. end;
  915. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  916. var
  917. href,href2 : treference;
  918. hloc : pcgparalocation;
  919. begin
  920. href:=ref;
  921. hloc:=paraloc.location;
  922. while assigned(hloc) do
  923. begin
  924. case hloc^.loc of
  925. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  926. a_loadfpu_ref_reg(list,size,ref,hloc^.register);
  927. LOC_REGISTER :
  928. case hloc^.size of
  929. OS_F32:
  930. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  931. OS_64,
  932. OS_F64:
  933. cg64.a_param64_ref(list,href,paraloc);
  934. else
  935. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  936. end;
  937. LOC_REFERENCE :
  938. begin
  939. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  940. { concatcopy should choose the best way to copy the data }
  941. g_concatcopy(list,href,href2,tcgsize2size[size]);
  942. end;
  943. else
  944. internalerror(200408241);
  945. end;
  946. inc(href.offset,tcgsize2size[hloc^.size]);
  947. hloc:=hloc^.next;
  948. end;
  949. end;
  950. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; size: tcgsize; reg1, reg2: tregister);
  951. begin
  952. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  953. end;
  954. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; size: tcgsize; const ref: treference; reg: tregister);
  955. var
  956. oppostfix:toppostfix;
  957. begin
  958. case size of
  959. OS_32,
  960. OS_F32:
  961. oppostfix:=PF_S;
  962. OS_64,
  963. OS_F64:
  964. oppostfix:=PF_D;
  965. OS_F80:
  966. oppostfix:=PF_E;
  967. else
  968. InternalError(200309021);
  969. end;
  970. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  971. end;
  972. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; size: tcgsize; reg: tregister; const ref: treference);
  973. var
  974. oppostfix:toppostfix;
  975. begin
  976. case size of
  977. OS_F32:
  978. oppostfix:=PF_S;
  979. OS_F64:
  980. oppostfix:=PF_D;
  981. OS_F80:
  982. oppostfix:=PF_E;
  983. else
  984. InternalError(200309022);
  985. end;
  986. handle_load_store(list,A_STF,oppostfix,reg,ref);
  987. end;
  988. { comparison operations }
  989. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  990. l : tasmlabel);
  991. var
  992. tmpreg : tregister;
  993. b : byte;
  994. begin
  995. if is_shifter_const(a,b) then
  996. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  997. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  998. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  999. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1000. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1001. else
  1002. begin
  1003. tmpreg:=getintregister(list,size);
  1004. a_load_const_reg(list,size,a,tmpreg);
  1005. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1006. end;
  1007. a_jmp_cond(list,cmp_op,l);
  1008. end;
  1009. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1010. begin
  1011. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1012. a_jmp_cond(list,cmp_op,l);
  1013. end;
  1014. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1015. var
  1016. ai : taicpu;
  1017. begin
  1018. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1019. ai.is_jmp:=true;
  1020. list.concat(ai);
  1021. end;
  1022. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1023. var
  1024. ai : taicpu;
  1025. begin
  1026. ai:=taicpu.op_sym(A_B,l);
  1027. ai.is_jmp:=true;
  1028. list.concat(ai);
  1029. end;
  1030. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1031. var
  1032. ai : taicpu;
  1033. begin
  1034. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1035. ai.is_jmp:=true;
  1036. list.concat(ai);
  1037. end;
  1038. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1039. var
  1040. ai : taicpu;
  1041. begin
  1042. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1043. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1044. end;
  1045. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1046. var
  1047. ref,href : treference;
  1048. shift : byte;
  1049. firstfloatreg,lastfloatreg,
  1050. r : byte;
  1051. i : aint;
  1052. again : tasmlabel;
  1053. regs : tcpuregisterset;
  1054. begin
  1055. LocalSize:=align(LocalSize,4);
  1056. if not(nostackframe) then
  1057. begin
  1058. firstfloatreg:=RS_NO;
  1059. { save floating point registers? }
  1060. for r:=RS_F0 to RS_F7 do
  1061. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1062. begin
  1063. if firstfloatreg=RS_NO then
  1064. firstfloatreg:=r;
  1065. lastfloatreg:=r;
  1066. end;
  1067. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1068. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1069. begin
  1070. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1071. a_reg_alloc(list,NR_R12);
  1072. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1073. end;
  1074. { save int registers }
  1075. reference_reset(ref);
  1076. ref.index:=NR_STACK_POINTER_REG;
  1077. ref.addressmode:=AM_PREINDEXED;
  1078. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1079. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1080. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1081. else
  1082. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1083. include(regs,RS_R14);
  1084. if regs<>[] then
  1085. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1086. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1087. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1088. { allocate necessary stack size
  1089. not necessary according to Yury Sidorov
  1090. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1091. in the entry/exit code }
  1092. if (target_info.system in [system_arm_wince]) and
  1093. (localsize>=winstackpagesize) then
  1094. begin
  1095. if localsize div winstackpagesize<=5 then
  1096. begin
  1097. if is_shifter_const(localsize,shift) then
  1098. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
  1099. else
  1100. begin
  1101. a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
  1102. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1103. end;
  1104. for i:=1 to localsize div winstackpagesize do
  1105. begin
  1106. if localsize-i*winstackpagesize<4096 then
  1107. reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
  1108. else
  1109. begin
  1110. a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
  1111. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1112. href.index:=NR_R12;
  1113. end;
  1114. { the data stored doesn't matter }
  1115. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1116. end;
  1117. a_reg_dealloc(list,NR_R12);
  1118. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1119. { the data stored doesn't matter }
  1120. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1121. end
  1122. else
  1123. begin
  1124. current_asmdata.getjumplabel(again);
  1125. list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
  1126. a_label(list,again);
  1127. { always shifterop }
  1128. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
  1129. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1130. { the data stored doesn't matter }
  1131. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1132. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
  1133. a_jmp_cond(list,OC_NE,again);
  1134. if is_shifter_const(localsize mod winstackpagesize,shift) then
  1135. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
  1136. else
  1137. begin
  1138. a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
  1139. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1140. end;
  1141. a_reg_dealloc(list,NR_R12);
  1142. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1143. { the data stored doesn't matter }
  1144. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1145. end
  1146. end
  1147. else
  1148. }
  1149. if LocalSize<>0 then
  1150. if not(is_shifter_const(localsize,shift)) then
  1151. begin
  1152. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1153. a_reg_alloc(list,NR_R12);
  1154. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1155. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1156. a_reg_dealloc(list,NR_R12);
  1157. end
  1158. else
  1159. begin
  1160. a_reg_dealloc(list,NR_R12);
  1161. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1162. end;
  1163. if firstfloatreg<>RS_NO then
  1164. begin
  1165. reference_reset(ref);
  1166. if tarmprocinfo(current_procinfo).floatregstart<=-1023 then
  1167. begin
  1168. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1169. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  1170. ref.base:=NR_R12;
  1171. end
  1172. else
  1173. begin
  1174. ref.base:=NR_FRAME_POINTER_REG;
  1175. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1176. end;
  1177. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1178. lastfloatreg-firstfloatreg+1,ref));
  1179. end;
  1180. end;
  1181. end;
  1182. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1183. var
  1184. ref : treference;
  1185. firstfloatreg,lastfloatreg,
  1186. r : byte;
  1187. shift : byte;
  1188. regs : tcpuregisterset;
  1189. LocalSize : longint;
  1190. begin
  1191. if not(nostackframe) then
  1192. begin
  1193. { restore floating point register }
  1194. firstfloatreg:=RS_NO;
  1195. { save floating point registers? }
  1196. for r:=RS_F0 to RS_F7 do
  1197. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1198. begin
  1199. if firstfloatreg=RS_NO then
  1200. firstfloatreg:=r;
  1201. lastfloatreg:=r;
  1202. end;
  1203. if firstfloatreg<>RS_NO then
  1204. begin
  1205. reference_reset(ref);
  1206. if tarmprocinfo(current_procinfo).floatregstart<=-1023 then
  1207. begin
  1208. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1209. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  1210. ref.base:=NR_R12;
  1211. end
  1212. else
  1213. begin
  1214. ref.base:=NR_FRAME_POINTER_REG;
  1215. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1216. end;
  1217. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1218. lastfloatreg-firstfloatreg+1,ref));
  1219. end;
  1220. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1221. begin
  1222. LocalSize:=current_procinfo.calc_stackframe_size;
  1223. if LocalSize<>0 then
  1224. if not(is_shifter_const(LocalSize,shift)) then
  1225. begin
  1226. a_reg_alloc(list,NR_R12);
  1227. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1228. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1229. a_reg_dealloc(list,NR_R12);
  1230. end
  1231. else
  1232. begin
  1233. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1234. end;
  1235. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1236. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1237. begin
  1238. exclude(regs,RS_R14);
  1239. include(regs,RS_R15);
  1240. end;
  1241. if regs=[] then
  1242. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1243. else
  1244. begin
  1245. reference_reset(ref);
  1246. ref.index:=NR_STACK_POINTER_REG;
  1247. ref.addressmode:=AM_PREINDEXED;
  1248. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1249. end;
  1250. end
  1251. else
  1252. begin
  1253. { restore int registers and return }
  1254. reference_reset(ref);
  1255. ref.index:=NR_FRAME_POINTER_REG;
  1256. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
  1257. end;
  1258. end
  1259. else
  1260. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1261. end;
  1262. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1263. var
  1264. b : byte;
  1265. tmpref : treference;
  1266. instr : taicpu;
  1267. begin
  1268. if ref.addressmode<>AM_OFFSET then
  1269. internalerror(200309071);
  1270. tmpref:=ref;
  1271. { Be sure to have a base register }
  1272. if (tmpref.base=NR_NO) then
  1273. begin
  1274. if tmpref.shiftmode<>SM_None then
  1275. internalerror(200308294);
  1276. if tmpref.signindex<0 then
  1277. internalerror(200312023);
  1278. tmpref.base:=tmpref.index;
  1279. tmpref.index:=NR_NO;
  1280. end;
  1281. if assigned(tmpref.symbol) or
  1282. not((is_shifter_const(tmpref.offset,b)) or
  1283. (is_shifter_const(-tmpref.offset,b))
  1284. ) then
  1285. fixref(list,tmpref);
  1286. { expect a base here if there is an index }
  1287. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1288. internalerror(200312022);
  1289. if tmpref.index<>NR_NO then
  1290. begin
  1291. if tmpref.shiftmode<>SM_None then
  1292. internalerror(200312021);
  1293. if tmpref.signindex<0 then
  1294. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1295. else
  1296. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1297. if tmpref.offset<>0 then
  1298. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1299. end
  1300. else
  1301. begin
  1302. if tmpref.offset<>0 then
  1303. begin
  1304. if tmpref.base<>NR_NO then
  1305. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1306. else
  1307. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  1308. end
  1309. else
  1310. begin
  1311. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1312. list.concat(instr);
  1313. add_move_instruction(instr);
  1314. end;
  1315. end;
  1316. end;
  1317. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1318. var
  1319. tmpreg : tregister;
  1320. tmpref : treference;
  1321. l : tasmlabel;
  1322. begin
  1323. { absolute symbols can't be handled directly, we've to store the symbol reference
  1324. in the text segment and access it pc relative
  1325. For now, we assume that references where base or index equals to PC are already
  1326. relative, all other references are assumed to be absolute and thus they need
  1327. to be handled extra.
  1328. A proper solution would be to change refoptions to a set and store the information
  1329. if the symbol is absolute or relative there.
  1330. }
  1331. { create consts entry }
  1332. reference_reset(tmpref);
  1333. current_asmdata.getjumplabel(l);
  1334. cg.a_label(current_procinfo.aktlocaldata,l);
  1335. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1336. if assigned(ref.symbol) then
  1337. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1338. else
  1339. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1340. { load consts entry }
  1341. tmpreg:=getintregister(list,OS_INT);
  1342. tmpref.symbol:=l;
  1343. tmpref.base:=NR_PC;
  1344. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1345. if (ref.base<>NR_NO) then
  1346. begin
  1347. if ref.index<>NR_NO then
  1348. begin
  1349. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1350. ref.base:=tmpreg;
  1351. end
  1352. else
  1353. if ref.base<>NR_PC then
  1354. begin
  1355. ref.index:=tmpreg;
  1356. ref.shiftimm:=0;
  1357. ref.signindex:=1;
  1358. ref.shiftmode:=SM_None;
  1359. end
  1360. else
  1361. ref.base:=tmpreg;
  1362. end
  1363. else
  1364. ref.base:=tmpreg;
  1365. ref.offset:=0;
  1366. ref.symbol:=nil;
  1367. end;
  1368. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1369. var
  1370. paraloc1,paraloc2,paraloc3 : TCGPara;
  1371. begin
  1372. paraloc1.init;
  1373. paraloc2.init;
  1374. paraloc3.init;
  1375. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1376. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1377. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1378. paramanager.allocparaloc(list,paraloc3);
  1379. a_param_const(list,OS_INT,len,paraloc3);
  1380. paramanager.allocparaloc(list,paraloc2);
  1381. a_paramaddr_ref(list,dest,paraloc2);
  1382. paramanager.allocparaloc(list,paraloc2);
  1383. a_paramaddr_ref(list,source,paraloc1);
  1384. paramanager.freeparaloc(list,paraloc3);
  1385. paramanager.freeparaloc(list,paraloc2);
  1386. paramanager.freeparaloc(list,paraloc1);
  1387. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1388. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1389. a_call_name(list,'FPC_MOVE');
  1390. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1391. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1392. paraloc3.done;
  1393. paraloc2.done;
  1394. paraloc1.done;
  1395. end;
  1396. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1397. const
  1398. maxtmpreg=10;{roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
  1399. var
  1400. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1401. srcreg,destreg,countreg,r,tmpreg,tmpreg2:tregister;
  1402. helpsize:aword;
  1403. copysize:byte;
  1404. cgsize:Tcgsize;
  1405. so:tshifterop;
  1406. tmpregisters:array[1..maxtmpreg]of tregister;
  1407. tmpregi,tmpregi2:byte;
  1408. { will never be called with count<=4 }
  1409. procedure genloop(count : aword;size : byte);
  1410. const
  1411. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1412. var
  1413. l : tasmlabel;
  1414. begin
  1415. current_asmdata.getjumplabel(l);
  1416. if count<size then size:=1;
  1417. a_load_const_reg(list,OS_INT,count div size,countreg);
  1418. cg.a_label(list,l);
  1419. srcref.addressmode:=AM_POSTINDEXED;
  1420. dstref.addressmode:=AM_POSTINDEXED;
  1421. srcref.offset:=size;
  1422. dstref.offset:=size;
  1423. r:=getintregister(list,size2opsize[size]);
  1424. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1425. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1426. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1427. a_jmp_flags(list,F_NE,l);
  1428. srcref.offset:=1;
  1429. dstref.offset:=1;
  1430. case count mod size of
  1431. 1:
  1432. begin
  1433. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1434. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1435. end;
  1436. 2:
  1437. if aligned then
  1438. begin
  1439. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1440. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1441. end
  1442. else
  1443. begin
  1444. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1445. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1446. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1447. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1448. end;
  1449. 3:
  1450. if aligned then
  1451. begin
  1452. srcref.offset:=2;
  1453. dstref.offset:=2;
  1454. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1455. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1456. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1457. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1458. end
  1459. else
  1460. begin
  1461. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1462. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1463. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1464. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1465. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1466. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1467. end;
  1468. end;
  1469. { keep the registers alive }
  1470. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1471. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1472. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1473. end;
  1474. begin
  1475. if len=0 then
  1476. exit;
  1477. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1478. dstref:=dest;
  1479. srcref:=source;
  1480. if cs_opt_size in current_settings.optimizerswitches then
  1481. helpsize:=8;
  1482. if (len<=helpsize) and aligned then
  1483. begin
  1484. tmpregi:=0;
  1485. srcreg:=getintregister(list,OS_ADDR);
  1486. { explicit pc relative addressing, could be
  1487. e.g. a floating point constant }
  1488. if source.base=NR_PC then
  1489. begin
  1490. { ... then we don't need a loadaddr }
  1491. srcref:=source;
  1492. end
  1493. else
  1494. begin
  1495. a_loadaddr_ref_reg(list,source,srcreg);
  1496. reference_reset_base(srcref,srcreg,0);
  1497. end;
  1498. while (len div 4 <> 0) and (tmpregi<=maxtmpreg) do
  1499. begin
  1500. inc(tmpregi);
  1501. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1502. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1503. inc(srcref.offset,4);
  1504. dec(len,4);
  1505. end;
  1506. destreg:=getintregister(list,OS_ADDR);
  1507. a_loadaddr_ref_reg(list,dest,destreg);
  1508. reference_reset_base(dstref,destreg,0);
  1509. tmpregi2:=1;
  1510. while (tmpregi2<=tmpregi) do
  1511. begin
  1512. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1513. inc(dstref.offset,4);
  1514. inc(tmpregi2);
  1515. end;
  1516. copysize:=4;
  1517. cgsize:=OS_32;
  1518. while len<>0 do
  1519. begin
  1520. if len<2 then
  1521. begin
  1522. copysize:=1;
  1523. cgsize:=OS_8;
  1524. end
  1525. else if len<4 then
  1526. begin
  1527. copysize:=2;
  1528. cgsize:=OS_16;
  1529. end;
  1530. dec(len,copysize);
  1531. r:=getintregister(list,cgsize);
  1532. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1533. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1534. inc(srcref.offset,copysize);
  1535. inc(dstref.offset,copysize);
  1536. end;{end of while}
  1537. end
  1538. else
  1539. begin
  1540. cgsize:=OS_32;
  1541. if (len<=4) then{len<=4 and not aligned}
  1542. begin
  1543. r:=getintregister(list,cgsize);
  1544. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1545. if Len=1 then
  1546. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1547. else
  1548. begin
  1549. tmpreg:=getintregister(list,cgsize);
  1550. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1551. inc(usedtmpref.offset,1);
  1552. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1553. inc(usedtmpref2.offset,1);
  1554. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1555. if len>2 then
  1556. begin
  1557. inc(usedtmpref.offset,1);
  1558. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1559. inc(usedtmpref2.offset,1);
  1560. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1561. if len>3 then
  1562. begin
  1563. inc(usedtmpref.offset,1);
  1564. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1565. inc(usedtmpref2.offset,1);
  1566. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1567. end;
  1568. end;
  1569. end;
  1570. end{end of if len<=4}
  1571. else
  1572. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1573. destreg:=getintregister(list,OS_ADDR);
  1574. a_loadaddr_ref_reg(list,dest,destreg);
  1575. reference_reset_base(dstref,destreg,0);
  1576. srcreg:=getintregister(list,OS_ADDR);
  1577. a_loadaddr_ref_reg(list,source,srcreg);
  1578. reference_reset_base(srcref,srcreg,0);
  1579. countreg:=getintregister(list,OS_32);
  1580. // if cs_opt_size in current_settings.optimizerswitches then
  1581. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1582. {if aligned then
  1583. genloop(len,4)
  1584. else}
  1585. genloop(len,1);
  1586. end;
  1587. end;
  1588. end;
  1589. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1590. begin
  1591. g_concatcopy_internal(list,source,dest,len,false);
  1592. end;
  1593. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1594. begin
  1595. if (source.alignment in [1..3]) or
  1596. (dest.alignment in [1..3]) then
  1597. g_concatcopy_internal(list,source,dest,len,false)
  1598. else
  1599. g_concatcopy_internal(list,source,dest,len,true);
  1600. end;
  1601. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1602. var
  1603. ovloc : tlocation;
  1604. begin
  1605. ovloc.loc:=LOC_VOID;
  1606. g_overflowCheck_loc(list,l,def,ovloc);
  1607. end;
  1608. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1609. var
  1610. hl : tasmlabel;
  1611. ai:TAiCpu;
  1612. hflags : tresflags;
  1613. begin
  1614. if not(cs_check_overflow in current_settings.localswitches) then
  1615. exit;
  1616. current_asmdata.getjumplabel(hl);
  1617. case ovloc.loc of
  1618. LOC_VOID:
  1619. begin
  1620. ai:=taicpu.op_sym(A_B,hl);
  1621. ai.is_jmp:=true;
  1622. if not((def.typ=pointerdef) or
  1623. ((def.typ=orddef) and
  1624. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1625. ai.SetCondition(C_VC)
  1626. else
  1627. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1628. ai.SetCondition(C_CS)
  1629. else
  1630. ai.SetCondition(C_CC);
  1631. list.concat(ai);
  1632. end;
  1633. LOC_FLAGS:
  1634. begin
  1635. hflags:=ovloc.resflags;
  1636. inverse_flags(hflags);
  1637. cg.a_jmp_flags(list,hflags,hl);
  1638. end;
  1639. else
  1640. internalerror(200409281);
  1641. end;
  1642. a_call_name(list,'FPC_OVERFLOW');
  1643. a_label(list,hl);
  1644. end;
  1645. procedure tcgarm.g_save_standard_registers(list : TAsmList);
  1646. begin
  1647. { this work is done in g_proc_entry }
  1648. end;
  1649. procedure tcgarm.g_restore_standard_registers(list : TAsmList);
  1650. begin
  1651. { this work is done in g_proc_exit }
  1652. end;
  1653. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1654. var
  1655. ai : taicpu;
  1656. begin
  1657. ai:=Taicpu.Op_sym(A_B,l);
  1658. ai.SetCondition(OpCmp2AsmCond[cond]);
  1659. ai.is_jmp:=true;
  1660. list.concat(ai);
  1661. end;
  1662. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1663. procedure loadvmttor12;
  1664. var
  1665. href : treference;
  1666. begin
  1667. reference_reset_base(href,NR_R0,0);
  1668. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1669. end;
  1670. procedure op_onr12methodaddr;
  1671. var
  1672. href : treference;
  1673. begin
  1674. if (procdef.extnumber=$ffff) then
  1675. Internalerror(200006139);
  1676. { call/jmp vmtoffs(%eax) ; method offs }
  1677. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1678. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1679. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1680. end;
  1681. var
  1682. lab : tasmsymbol;
  1683. make_global : boolean;
  1684. href : treference;
  1685. begin
  1686. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1687. Internalerror(200006137);
  1688. if not assigned(procdef._class) or
  1689. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1690. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1691. Internalerror(200006138);
  1692. if procdef.owner.symtabletype<>ObjectSymtable then
  1693. Internalerror(200109191);
  1694. make_global:=false;
  1695. if (not current_module.is_unit) or
  1696. (cs_create_smart in current_settings.moduleswitches) or
  1697. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1698. make_global:=true;
  1699. if make_global then
  1700. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1701. else
  1702. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1703. { set param1 interface to self }
  1704. g_adjust_self_value(list,procdef,ioffset);
  1705. { case 4 }
  1706. if po_virtualmethod in procdef.procoptions then
  1707. begin
  1708. loadvmttor12;
  1709. op_onr12methodaddr;
  1710. end
  1711. { case 0 }
  1712. else
  1713. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1714. list.concat(Tai_symbol_end.Createname(labelname));
  1715. end;
  1716. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1717. var
  1718. tmpreg : tregister;
  1719. begin
  1720. case op of
  1721. OP_NEG:
  1722. begin
  1723. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1724. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1725. end;
  1726. OP_NOT:
  1727. begin
  1728. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1729. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1730. end;
  1731. else
  1732. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1733. end;
  1734. end;
  1735. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1736. begin
  1737. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1738. end;
  1739. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1740. var
  1741. ovloc : tlocation;
  1742. begin
  1743. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1744. end;
  1745. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1746. var
  1747. ovloc : tlocation;
  1748. begin
  1749. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1750. end;
  1751. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1752. var
  1753. tmpreg : tregister;
  1754. b : byte;
  1755. begin
  1756. ovloc.loc:=LOC_VOID;
  1757. case op of
  1758. OP_NEG,
  1759. OP_NOT :
  1760. internalerror(200306017);
  1761. end;
  1762. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1763. begin
  1764. case op of
  1765. OP_ADD:
  1766. begin
  1767. if is_shifter_const(lo(value),b) then
  1768. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1769. else
  1770. begin
  1771. tmpreg:=cg.getintregister(list,OS_32);
  1772. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1773. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1774. end;
  1775. if is_shifter_const(hi(value),b) then
  1776. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1777. else
  1778. begin
  1779. tmpreg:=cg.getintregister(list,OS_32);
  1780. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1781. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1782. end;
  1783. end;
  1784. OP_SUB:
  1785. begin
  1786. if is_shifter_const(lo(value),b) then
  1787. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1788. else
  1789. begin
  1790. tmpreg:=cg.getintregister(list,OS_32);
  1791. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1792. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1793. end;
  1794. if is_shifter_const(hi(value),b) then
  1795. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1796. else
  1797. begin
  1798. tmpreg:=cg.getintregister(list,OS_32);
  1799. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1800. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1801. end;
  1802. end;
  1803. else
  1804. internalerror(200502131);
  1805. end;
  1806. if size=OS_64 then
  1807. begin
  1808. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1809. ovloc.loc:=LOC_FLAGS;
  1810. case op of
  1811. OP_ADD:
  1812. ovloc.resflags:=F_CS;
  1813. OP_SUB:
  1814. ovloc.resflags:=F_CC;
  1815. end;
  1816. end;
  1817. end
  1818. else
  1819. begin
  1820. case op of
  1821. OP_AND,OP_OR,OP_XOR:
  1822. begin
  1823. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1824. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1825. end;
  1826. OP_ADD:
  1827. begin
  1828. if is_shifter_const(lo(value),b) then
  1829. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1830. else
  1831. begin
  1832. tmpreg:=cg.getintregister(list,OS_32);
  1833. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1834. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1835. end;
  1836. if is_shifter_const(hi(value),b) then
  1837. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1838. else
  1839. begin
  1840. tmpreg:=cg.getintregister(list,OS_32);
  1841. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1842. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1843. end;
  1844. end;
  1845. OP_SUB:
  1846. begin
  1847. if is_shifter_const(lo(value),b) then
  1848. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1849. else
  1850. begin
  1851. tmpreg:=cg.getintregister(list,OS_32);
  1852. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1853. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1854. end;
  1855. if is_shifter_const(hi(value),b) then
  1856. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1857. else
  1858. begin
  1859. tmpreg:=cg.getintregister(list,OS_32);
  1860. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1861. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1862. end;
  1863. end;
  1864. else
  1865. internalerror(2003083101);
  1866. end;
  1867. end;
  1868. end;
  1869. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1870. var
  1871. op1,op2:TAsmOp;
  1872. begin
  1873. ovloc.loc:=LOC_VOID;
  1874. case op of
  1875. OP_NEG,
  1876. OP_NOT :
  1877. internalerror(200306017);
  1878. end;
  1879. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1880. begin
  1881. case op of
  1882. OP_ADD:
  1883. begin
  1884. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1885. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1886. end;
  1887. OP_SUB:
  1888. begin
  1889. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1890. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1891. end;
  1892. else
  1893. internalerror(2003083101);
  1894. end;
  1895. if size=OS_64 then
  1896. begin
  1897. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1898. ovloc.loc:=LOC_FLAGS;
  1899. case op of
  1900. OP_ADD:
  1901. ovloc.resflags:=F_CS;
  1902. OP_SUB:
  1903. ovloc.resflags:=F_CC;
  1904. end;
  1905. end;
  1906. end
  1907. else
  1908. begin
  1909. case op of
  1910. OP_AND,OP_OR,OP_XOR:
  1911. begin
  1912. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1913. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1914. end;
  1915. OP_ADD:
  1916. begin
  1917. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1918. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1919. end;
  1920. OP_SUB:
  1921. begin
  1922. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1923. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1924. end;
  1925. else
  1926. internalerror(2003083101);
  1927. end;
  1928. end;
  1929. end;
  1930. begin
  1931. cg:=tcgarm.create;
  1932. cg64:=tcg64farm.create;
  1933. end.