cgcpu.pas 82 KB

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