cgcpu.pas 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714
  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,
  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 : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : taasmoutput;const s : string);override;
  37. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  38. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  39. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  40. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  41. size: tcgsize; a: aint; src, dst: tregister); override;
  42. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  43. size: tcgsize; src1, src2, dst: tregister); override;
  44. procedure a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  45. procedure a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. { move instructions }
  47. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);override;
  48. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  49. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  50. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  51. { fpu move instructions }
  52. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  53. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  54. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  55. procedure a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  56. { comparison operations }
  57. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  58. l : tasmlabel);override;
  59. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  60. procedure a_jmp_name(list : taasmoutput;const s : string); override;
  61. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  62. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  63. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  64. procedure g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);override;
  65. procedure g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean); override;
  66. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  67. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);override;
  68. procedure g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);override;
  69. procedure g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  70. procedure g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  71. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  72. procedure g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  73. procedure g_save_standard_registers(list : taasmoutput);override;
  74. procedure g_restore_standard_registers(list : taasmoutput);override;
  75. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  76. procedure fixref(list : taasmoutput;var ref : treference);
  77. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  78. procedure g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  79. end;
  80. tcg64farm = class(tcg64f32)
  81. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  82. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  83. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  84. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  85. procedure a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  86. procedure a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  87. end;
  88. const
  89. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  90. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  91. function get_fpu_postfix(def : tdef) : toppostfix;
  92. implementation
  93. uses
  94. globals,verbose,systems,cutils,
  95. fmodule,
  96. symconst,symsym,
  97. tgobj,
  98. procinfo,cpupi,
  99. paramgr;
  100. function get_fpu_postfix(def : tdef) : toppostfix;
  101. begin
  102. if def.deftype=floatdef then
  103. begin
  104. case tfloatdef(def).typ of
  105. s32real:
  106. result:=PF_S;
  107. s64real:
  108. result:=PF_D;
  109. s80real:
  110. result:=PF_E;
  111. else
  112. internalerror(200401272);
  113. end;
  114. end
  115. else
  116. internalerror(200401271);
  117. end;
  118. procedure tcgarm.init_register_allocators;
  119. begin
  120. inherited init_register_allocators;
  121. { currently, we save R14 always, so we can use it }
  122. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  123. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  124. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  125. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  126. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  127. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  128. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  129. end;
  130. procedure tcgarm.done_register_allocators;
  131. begin
  132. rg[R_INTREGISTER].free;
  133. rg[R_FPUREGISTER].free;
  134. rg[R_MMREGISTER].free;
  135. inherited done_register_allocators;
  136. end;
  137. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);
  138. var
  139. ref: treference;
  140. begin
  141. paraloc.check_simple_location;
  142. case paraloc.location^.loc of
  143. LOC_REGISTER,LOC_CREGISTER:
  144. a_load_const_reg(list,size,a,paraloc.location^.register);
  145. LOC_REFERENCE:
  146. begin
  147. reference_reset(ref);
  148. ref.base:=paraloc.location^.reference.index;
  149. ref.offset:=paraloc.location^.reference.offset;
  150. a_load_const_ref(list,size,a,ref);
  151. end;
  152. else
  153. internalerror(2002081101);
  154. end;
  155. end;
  156. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);
  157. var
  158. tmpref, ref: treference;
  159. location: pcgparalocation;
  160. sizeleft: aint;
  161. begin
  162. location := paraloc.location;
  163. tmpref := r;
  164. sizeleft := paraloc.intsize;
  165. while assigned(location) do
  166. begin
  167. case location^.loc of
  168. LOC_REGISTER,LOC_CREGISTER:
  169. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  170. LOC_REFERENCE:
  171. begin
  172. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  173. g_concatcopy(list,tmpref,ref,sizeleft);
  174. if assigned(location^.next) then
  175. internalerror(2005010710);
  176. end;
  177. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  178. case location^.size of
  179. OS_F32, OS_F64:
  180. a_loadfpu_ref_reg(list,location^.size,tmpref,location^.register);
  181. else
  182. internalerror(2002072801);
  183. end;
  184. LOC_VOID:
  185. begin
  186. // nothing to do
  187. end;
  188. else
  189. internalerror(2002081103);
  190. end;
  191. inc(tmpref.offset,tcgsize2size[location^.size]);
  192. dec(sizeleft,tcgsize2size[location^.size]);
  193. location := location^.next;
  194. end;
  195. end;
  196. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);
  197. var
  198. ref: treference;
  199. tmpreg: tregister;
  200. begin
  201. paraloc.check_simple_location;
  202. case paraloc.location^.loc of
  203. LOC_REGISTER,LOC_CREGISTER:
  204. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  205. LOC_REFERENCE:
  206. begin
  207. reference_reset(ref);
  208. ref.base := paraloc.location^.reference.index;
  209. ref.offset := paraloc.location^.reference.offset;
  210. tmpreg := getintregister(list,OS_ADDR);
  211. a_loadaddr_ref_reg(list,r,tmpreg);
  212. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  213. end;
  214. else
  215. internalerror(2002080701);
  216. end;
  217. end;
  218. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  219. begin
  220. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  221. {
  222. the compiler does not properly set this flag anymore in pass 1, and
  223. for now we only need it after pass 2 (I hope) (JM)
  224. if not(pi_do_call in current_procinfo.flags) then
  225. internalerror(2003060703);
  226. }
  227. include(current_procinfo.flags,pi_do_call);
  228. end;
  229. procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
  230. var
  231. r : tregister;
  232. begin
  233. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  234. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  235. {
  236. the compiler does not properly set this flag anymore in pass 1, and
  237. for now we only need it after pass 2 (I hope) (JM)
  238. if not(pi_do_call in current_procinfo.flags) then
  239. internalerror(2003060703);
  240. }
  241. include(current_procinfo.flags,pi_do_call);
  242. end;
  243. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  244. begin
  245. a_op_const_reg_reg(list,op,size,a,reg,reg);
  246. end;
  247. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  248. begin
  249. case op of
  250. OP_NEG:
  251. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  252. OP_NOT:
  253. begin
  254. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  255. case size of
  256. OS_8 :
  257. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  258. OS_16 :
  259. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  260. end;
  261. end
  262. else
  263. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  264. end;
  265. end;
  266. const
  267. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  268. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  269. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  270. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  271. size: tcgsize; a: aint; src, dst: tregister);
  272. var
  273. ovloc : tlocation;
  274. begin
  275. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  276. end;
  277. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  278. size: tcgsize; src1, src2, dst: tregister);
  279. var
  280. ovloc : tlocation;
  281. begin
  282. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  283. end;
  284. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  285. var
  286. shift : byte;
  287. tmpreg : tregister;
  288. so : tshifterop;
  289. l1 : longint;
  290. begin
  291. ovloc.loc:=LOC_VOID;
  292. if is_shifter_const(-a,shift) then
  293. case op of
  294. OP_ADD:
  295. begin
  296. op:=OP_SUB;
  297. a:=dword(-a);
  298. end;
  299. OP_SUB:
  300. begin
  301. op:=OP_ADD;
  302. a:=dword(-a);
  303. end
  304. end;
  305. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  306. case op of
  307. OP_NEG,OP_NOT,
  308. OP_DIV,OP_IDIV:
  309. internalerror(200308281);
  310. OP_SHL:
  311. begin
  312. if a>32 then
  313. internalerror(200308291);
  314. if a<>0 then
  315. begin
  316. shifterop_reset(so);
  317. so.shiftmode:=SM_LSL;
  318. so.shiftimm:=a;
  319. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  320. end
  321. else
  322. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  323. end;
  324. OP_SHR:
  325. begin
  326. if a>32 then
  327. internalerror(200308292);
  328. shifterop_reset(so);
  329. if a<>0 then
  330. begin
  331. so.shiftmode:=SM_LSR;
  332. so.shiftimm:=a;
  333. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  334. end
  335. else
  336. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  337. end;
  338. OP_SAR:
  339. begin
  340. if a>32 then
  341. internalerror(200308291);
  342. if a<>0 then
  343. begin
  344. shifterop_reset(so);
  345. so.shiftmode:=SM_ASR;
  346. so.shiftimm:=a;
  347. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  348. end
  349. else
  350. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  351. end;
  352. else
  353. list.concat(setoppostfix(
  354. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  355. ));
  356. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  357. begin
  358. ovloc.loc:=LOC_FLAGS;
  359. case op of
  360. OP_ADD:
  361. ovloc.resflags:=F_CS;
  362. OP_SUB:
  363. ovloc.resflags:=F_CC;
  364. end;
  365. end;
  366. end
  367. else
  368. begin
  369. { there could be added some more sophisticated optimizations }
  370. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  371. a_load_reg_reg(list,size,size,src,dst)
  372. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  373. a_load_const_reg(list,size,0,dst)
  374. else if (op in [OP_IMUL]) and (a=-1) then
  375. a_op_reg_reg(list,OP_NEG,size,src,dst)
  376. { we do this here instead in the peephole optimizer because
  377. it saves us a register }
  378. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  379. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  380. else
  381. begin
  382. tmpreg:=getintregister(list,size);
  383. a_load_const_reg(list,size,a,tmpreg);
  384. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  385. end;
  386. end;
  387. end;
  388. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  389. var
  390. so : tshifterop;
  391. tmpreg,overflowreg : tregister;
  392. asmop : tasmop;
  393. begin
  394. ovloc.loc:=LOC_VOID;
  395. case op of
  396. OP_NEG,OP_NOT,
  397. OP_DIV,OP_IDIV:
  398. internalerror(200308281);
  399. OP_SHL:
  400. begin
  401. shifterop_reset(so);
  402. so.rs:=src1;
  403. so.shiftmode:=SM_LSL;
  404. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  405. end;
  406. OP_SHR:
  407. begin
  408. shifterop_reset(so);
  409. so.rs:=src1;
  410. so.shiftmode:=SM_LSR;
  411. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  412. end;
  413. OP_SAR:
  414. begin
  415. shifterop_reset(so);
  416. so.rs:=src1;
  417. so.shiftmode:=SM_ASR;
  418. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  419. end;
  420. OP_IMUL,
  421. OP_MUL:
  422. begin
  423. if cgsetflags or setflags then
  424. begin
  425. overflowreg:=getintregister(list,size);
  426. if op=OP_IMUL then
  427. asmop:=A_SMULL
  428. else
  429. asmop:=A_UMULL;
  430. { the arm doesn't allow that rd and rm are the same }
  431. if dst=src2 then
  432. begin
  433. if dst<>src1 then
  434. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  435. else
  436. begin
  437. tmpreg:=getintregister(list,size);
  438. a_load_reg_reg(list,size,size,src2,dst);
  439. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  440. end;
  441. end
  442. else
  443. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  444. if op=OP_IMUL then
  445. begin
  446. shifterop_reset(so);
  447. so.shiftmode:=SM_ASR;
  448. so.shiftimm:=31;
  449. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  450. end
  451. else
  452. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  453. ovloc.loc:=LOC_FLAGS;
  454. ovloc.resflags:=F_NE;
  455. end
  456. else
  457. begin
  458. { the arm doesn't allow that rd and rm are the same }
  459. if dst=src2 then
  460. begin
  461. if dst<>src1 then
  462. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  463. else
  464. begin
  465. tmpreg:=getintregister(list,size);
  466. a_load_reg_reg(list,size,size,src2,dst);
  467. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  468. end;
  469. end
  470. else
  471. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  472. end;
  473. end;
  474. else
  475. list.concat(setoppostfix(
  476. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  477. ));
  478. end;
  479. end;
  480. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);
  481. var
  482. imm_shift : byte;
  483. l : tasmlabel;
  484. hr : treference;
  485. begin
  486. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  487. internalerror(2002090902);
  488. if is_shifter_const(a,imm_shift) then
  489. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  490. else if is_shifter_const(not(a),imm_shift) then
  491. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  492. else
  493. begin
  494. reference_reset(hr);
  495. objectlibrary.getjumplabel(l);
  496. cg.a_label(current_procinfo.aktlocaldata,l);
  497. hr.symboldata:=current_procinfo.aktlocaldata.last;
  498. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  499. hr.symbol:=l;
  500. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  501. end;
  502. end;
  503. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  504. var
  505. tmpreg : tregister;
  506. tmpref : treference;
  507. l : tasmlabel;
  508. begin
  509. tmpreg:=NR_NO;
  510. { Be sure to have a base register }
  511. if (ref.base=NR_NO) then
  512. begin
  513. if ref.shiftmode<>SM_None then
  514. internalerror(200308294);
  515. ref.base:=ref.index;
  516. ref.index:=NR_NO;
  517. end;
  518. { absolute symbols can't be handled directly, we've to store the symbol reference
  519. in the text segment and access it pc relative
  520. For now, we assume that references where base or index equals to PC are already
  521. relative, all other references are assumed to be absolute and thus they need
  522. to be handled extra.
  523. A proper solution would be to change refoptions to a set and store the information
  524. if the symbol is absolute or relative there.
  525. }
  526. if (assigned(ref.symbol) and
  527. not(is_pc(ref.base)) and
  528. not(is_pc(ref.index))
  529. ) or
  530. { [#xxx] isn't a valid address operand }
  531. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  532. (ref.offset<-4095) or
  533. (ref.offset>4095) or
  534. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  535. ((ref.offset<-255) or
  536. (ref.offset>255)
  537. )
  538. ) or
  539. ((op in [A_LDF,A_STF]) and
  540. ((ref.offset<-1020) or
  541. (ref.offset>1020) or
  542. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  543. assigned(ref.symbol)
  544. )
  545. ) then
  546. begin
  547. reference_reset(tmpref);
  548. { load symbol }
  549. tmpreg:=getintregister(list,OS_INT);
  550. if assigned(ref.symbol) then
  551. begin
  552. objectlibrary.getjumplabel(l);
  553. cg.a_label(current_procinfo.aktlocaldata,l);
  554. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  555. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  556. { load consts entry }
  557. tmpref.symbol:=l;
  558. tmpref.base:=NR_R15;
  559. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  560. end
  561. else
  562. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  563. if (ref.base<>NR_NO) then
  564. begin
  565. if ref.index<>NR_NO then
  566. begin
  567. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  568. ref.base:=tmpreg;
  569. end
  570. else
  571. begin
  572. ref.index:=tmpreg;
  573. ref.shiftimm:=0;
  574. ref.signindex:=1;
  575. ref.shiftmode:=SM_None;
  576. end;
  577. end
  578. else
  579. ref.base:=tmpreg;
  580. ref.offset:=0;
  581. ref.symbol:=nil;
  582. end;
  583. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  584. begin
  585. if tmpreg<>NR_NO then
  586. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  587. else
  588. begin
  589. tmpreg:=getintregister(list,OS_ADDR);
  590. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  591. ref.base:=tmpreg;
  592. end;
  593. ref.offset:=0;
  594. end;
  595. { floating point operations have only limited references
  596. we expect here, that a base is already set }
  597. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  598. begin
  599. if ref.shiftmode<>SM_none then
  600. internalerror(200309121);
  601. if tmpreg<>NR_NO then
  602. begin
  603. if ref.base=tmpreg then
  604. begin
  605. if ref.signindex<0 then
  606. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  607. else
  608. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  609. ref.index:=NR_NO;
  610. end
  611. else
  612. begin
  613. if ref.index<>tmpreg then
  614. internalerror(200403161);
  615. if ref.signindex<0 then
  616. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  617. else
  618. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  619. ref.base:=tmpreg;
  620. ref.index:=NR_NO;
  621. end;
  622. end
  623. else
  624. begin
  625. tmpreg:=getintregister(list,OS_ADDR);
  626. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  627. ref.base:=tmpreg;
  628. ref.index:=NR_NO;
  629. end;
  630. end;
  631. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  632. end;
  633. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  634. var
  635. oppostfix:toppostfix;
  636. begin
  637. case ToSize of
  638. { signed integer registers }
  639. OS_8,
  640. OS_S8:
  641. oppostfix:=PF_B;
  642. OS_16,
  643. OS_S16:
  644. oppostfix:=PF_H;
  645. OS_32,
  646. OS_S32:
  647. oppostfix:=PF_None;
  648. else
  649. InternalError(200308295);
  650. end;
  651. handle_load_store(list,A_STR,oppostfix,reg,ref);
  652. end;
  653. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  654. var
  655. oppostfix:toppostfix;
  656. begin
  657. case FromSize of
  658. { signed integer registers }
  659. OS_8:
  660. oppostfix:=PF_B;
  661. OS_S8:
  662. oppostfix:=PF_SB;
  663. OS_16:
  664. oppostfix:=PF_H;
  665. OS_S16:
  666. oppostfix:=PF_SH;
  667. OS_32,
  668. OS_S32:
  669. oppostfix:=PF_None;
  670. else
  671. InternalError(200308291);
  672. end;
  673. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  674. end;
  675. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  676. var
  677. instr: taicpu;
  678. so : tshifterop;
  679. begin
  680. shifterop_reset(so);
  681. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  682. (
  683. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  684. (tosize <> fromsize) and
  685. not(fromsize in [OS_32,OS_S32])
  686. ) then
  687. begin
  688. case tosize of
  689. OS_8:
  690. list.concat(taicpu.op_reg_reg_const(A_AND,
  691. reg2,reg1,$ff));
  692. OS_S8:
  693. begin
  694. so.shiftmode:=SM_LSL;
  695. so.shiftimm:=24;
  696. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  697. so.shiftmode:=SM_ASR;
  698. so.shiftimm:=24;
  699. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  700. end;
  701. OS_16:
  702. begin
  703. so.shiftmode:=SM_LSL;
  704. so.shiftimm:=16;
  705. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  706. so.shiftmode:=SM_LSR;
  707. so.shiftimm:=16;
  708. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  709. end;
  710. OS_S16:
  711. begin
  712. so.shiftmode:=SM_LSL;
  713. so.shiftimm:=16;
  714. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  715. so.shiftmode:=SM_ASR;
  716. so.shiftimm:=16;
  717. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  718. end;
  719. OS_32,OS_S32:
  720. begin
  721. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  722. list.concat(instr);
  723. add_move_instruction(instr);
  724. end;
  725. else internalerror(2002090901);
  726. end;
  727. end
  728. else
  729. begin
  730. if reg1<>reg2 then
  731. begin
  732. { same size, only a register mov required }
  733. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  734. list.Concat(instr);
  735. { Notify the register allocator that we have written a move instruction so
  736. it can try to eliminate it. }
  737. add_move_instruction(instr);
  738. end;
  739. end;
  740. end;
  741. procedure tcgarm.a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  742. var
  743. href,href2 : treference;
  744. hloc : pcgparalocation;
  745. begin
  746. href:=ref;
  747. hloc:=paraloc.location;
  748. while assigned(hloc) do
  749. begin
  750. case hloc^.loc of
  751. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  752. a_loadfpu_ref_reg(list,size,ref,hloc^.register);
  753. LOC_REGISTER :
  754. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  755. LOC_REFERENCE :
  756. begin
  757. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  758. a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2);
  759. end;
  760. else
  761. internalerror(200408241);
  762. end;
  763. inc(href.offset,tcgsize2size[hloc^.size]);
  764. hloc:=hloc^.next;
  765. end;
  766. end;
  767. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  768. begin
  769. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  770. end;
  771. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  772. var
  773. oppostfix:toppostfix;
  774. begin
  775. case size of
  776. OS_F32:
  777. oppostfix:=PF_S;
  778. OS_F64:
  779. oppostfix:=PF_D;
  780. OS_F80:
  781. oppostfix:=PF_E;
  782. else
  783. InternalError(200309021);
  784. end;
  785. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  786. end;
  787. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  788. var
  789. oppostfix:toppostfix;
  790. begin
  791. case size of
  792. OS_F32:
  793. oppostfix:=PF_S;
  794. OS_F64:
  795. oppostfix:=PF_D;
  796. OS_F80:
  797. oppostfix:=PF_E;
  798. else
  799. InternalError(200309022);
  800. end;
  801. handle_load_store(list,A_STF,oppostfix,reg,ref);
  802. end;
  803. { comparison operations }
  804. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  805. l : tasmlabel);
  806. var
  807. tmpreg : tregister;
  808. b : byte;
  809. begin
  810. if is_shifter_const(a,b) then
  811. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  812. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  813. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  814. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  815. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  816. else
  817. begin
  818. tmpreg:=getintregister(list,size);
  819. a_load_const_reg(list,size,a,tmpreg);
  820. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  821. end;
  822. a_jmp_cond(list,cmp_op,l);
  823. end;
  824. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  825. begin
  826. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  827. a_jmp_cond(list,cmp_op,l);
  828. end;
  829. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  830. begin
  831. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  832. end;
  833. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  834. begin
  835. list.concat(taicpu.op_sym(A_B,l));
  836. end;
  837. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  838. var
  839. ai : taicpu;
  840. begin
  841. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  842. ai.is_jmp:=true;
  843. list.concat(ai);
  844. end;
  845. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  846. var
  847. ai : taicpu;
  848. begin
  849. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  850. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  851. end;
  852. procedure tcgarm.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);
  853. var
  854. ref : treference;
  855. shift : byte;
  856. firstfloatreg,lastfloatreg,
  857. r : byte;
  858. begin
  859. LocalSize:=align(LocalSize,4);
  860. if not(nostackframe) then
  861. begin
  862. firstfloatreg:=RS_NO;
  863. { save floating point registers? }
  864. for r:=RS_F0 to RS_F7 do
  865. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  866. begin
  867. if firstfloatreg=RS_NO then
  868. firstfloatreg:=r;
  869. lastfloatreg:=r;
  870. end;
  871. a_reg_alloc(list,NR_STACK_POINTER_REG);
  872. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  873. a_reg_alloc(list,NR_R12);
  874. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  875. { save int registers }
  876. reference_reset(ref);
  877. ref.index:=NR_STACK_POINTER_REG;
  878. ref.addressmode:=AM_PREINDEXED;
  879. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  880. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  881. PF_FD));
  882. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  883. { allocate necessary stack size }
  884. { don't use a_op_const_reg_reg here because we don't allow register allocations
  885. in the entry/exit code }
  886. if not(is_shifter_const(localsize,shift)) then
  887. begin
  888. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  889. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  890. a_reg_dealloc(list,NR_R12);
  891. end
  892. else
  893. begin
  894. a_reg_dealloc(list,NR_R12);
  895. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  896. end;
  897. if firstfloatreg<>RS_NO then
  898. begin
  899. reference_reset(ref);
  900. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  901. begin
  902. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  903. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  904. ref.base:=NR_R12;
  905. end
  906. else
  907. begin
  908. ref.base:=NR_FRAME_POINTER_REG;
  909. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  910. end;
  911. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  912. lastfloatreg-firstfloatreg+1,ref));
  913. end;
  914. end;
  915. end;
  916. procedure tcgarm.g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean);
  917. var
  918. ref : treference;
  919. firstfloatreg,lastfloatreg,
  920. r : byte;
  921. shift : byte;
  922. begin
  923. if not(nostackframe) then
  924. begin
  925. { restore floating point register }
  926. firstfloatreg:=RS_NO;
  927. { save floating point registers? }
  928. for r:=RS_F0 to RS_F7 do
  929. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  930. begin
  931. if firstfloatreg=RS_NO then
  932. firstfloatreg:=r;
  933. lastfloatreg:=r;
  934. end;
  935. if firstfloatreg<>RS_NO then
  936. begin
  937. reference_reset(ref);
  938. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  939. begin
  940. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  941. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  942. ref.base:=NR_R12;
  943. end
  944. else
  945. begin
  946. ref.base:=NR_FRAME_POINTER_REG;
  947. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  948. end;
  949. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  950. lastfloatreg-firstfloatreg+1,ref));
  951. end;
  952. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  953. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  954. else
  955. begin
  956. { restore int registers and return }
  957. reference_reset(ref);
  958. ref.index:=NR_FRAME_POINTER_REG;
  959. 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));
  960. end;
  961. end
  962. else
  963. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  964. end;
  965. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  966. var
  967. b : byte;
  968. tmpref : treference;
  969. instr : taicpu;
  970. begin
  971. if ref.addressmode<>AM_OFFSET then
  972. internalerror(200309071);
  973. tmpref:=ref;
  974. { Be sure to have a base register }
  975. if (tmpref.base=NR_NO) then
  976. begin
  977. if tmpref.shiftmode<>SM_None then
  978. internalerror(200308294);
  979. if tmpref.signindex<0 then
  980. internalerror(200312023);
  981. tmpref.base:=tmpref.index;
  982. tmpref.index:=NR_NO;
  983. end;
  984. if assigned(tmpref.symbol) or
  985. not((is_shifter_const(tmpref.offset,b)) or
  986. (is_shifter_const(-tmpref.offset,b))
  987. ) then
  988. fixref(list,tmpref);
  989. { expect a base here if there is an index }
  990. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  991. internalerror(200312022);
  992. if tmpref.index<>NR_NO then
  993. begin
  994. if tmpref.shiftmode<>SM_None then
  995. internalerror(200312021);
  996. if tmpref.signindex<0 then
  997. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  998. else
  999. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1000. if tmpref.offset<>0 then
  1001. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1002. end
  1003. else
  1004. begin
  1005. if tmpref.offset<>0 then
  1006. begin
  1007. if tmpref.base<>NR_NO then
  1008. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1009. else
  1010. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  1011. end
  1012. else
  1013. begin
  1014. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1015. list.concat(instr);
  1016. add_move_instruction(instr);
  1017. end;
  1018. end;
  1019. end;
  1020. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  1021. var
  1022. tmpreg : tregister;
  1023. tmpref : treference;
  1024. l : tasmlabel;
  1025. begin
  1026. { absolute symbols can't be handled directly, we've to store the symbol reference
  1027. in the text segment and access it pc relative
  1028. For now, we assume that references where base or index equals to PC are already
  1029. relative, all other references are assumed to be absolute and thus they need
  1030. to be handled extra.
  1031. A proper solution would be to change refoptions to a set and store the information
  1032. if the symbol is absolute or relative there.
  1033. }
  1034. { create consts entry }
  1035. reference_reset(tmpref);
  1036. objectlibrary.getjumplabel(l);
  1037. cg.a_label(current_procinfo.aktlocaldata,l);
  1038. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1039. if assigned(ref.symbol) then
  1040. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1041. else
  1042. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1043. { load consts entry }
  1044. tmpreg:=getintregister(list,OS_INT);
  1045. tmpref.symbol:=l;
  1046. tmpref.base:=NR_PC;
  1047. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1048. if (ref.base<>NR_NO) then
  1049. begin
  1050. if ref.index<>NR_NO then
  1051. begin
  1052. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1053. ref.base:=tmpreg;
  1054. end
  1055. else
  1056. begin
  1057. ref.index:=tmpreg;
  1058. ref.shiftimm:=0;
  1059. ref.signindex:=1;
  1060. ref.shiftmode:=SM_None;
  1061. end;
  1062. end
  1063. else
  1064. ref.base:=tmpreg;
  1065. ref.offset:=0;
  1066. ref.symbol:=nil;
  1067. end;
  1068. procedure tcgarm.g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  1069. var
  1070. paraloc1,paraloc2,paraloc3 : TCGPara;
  1071. begin
  1072. paraloc1.init;
  1073. paraloc2.init;
  1074. paraloc3.init;
  1075. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1076. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1077. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1078. paramanager.allocparaloc(list,paraloc3);
  1079. a_param_const(list,OS_INT,len,paraloc3);
  1080. paramanager.allocparaloc(list,paraloc2);
  1081. a_paramaddr_ref(list,dest,paraloc2);
  1082. paramanager.allocparaloc(list,paraloc2);
  1083. a_paramaddr_ref(list,source,paraloc1);
  1084. paramanager.freeparaloc(list,paraloc3);
  1085. paramanager.freeparaloc(list,paraloc2);
  1086. paramanager.freeparaloc(list,paraloc1);
  1087. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1088. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1089. a_call_name(list,'FPC_MOVE');
  1090. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1091. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1092. paraloc3.done;
  1093. paraloc2.done;
  1094. paraloc1.done;
  1095. end;
  1096. procedure tcgarm.g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  1097. var
  1098. srcref,dstref:treference;
  1099. srcreg,destreg,countreg,r:tregister;
  1100. helpsize:aword;
  1101. copysize:byte;
  1102. cgsize:Tcgsize;
  1103. procedure genloop(count : aword;size : byte);
  1104. const
  1105. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1106. var
  1107. l : tasmlabel;
  1108. begin
  1109. objectlibrary.getjumplabel(l);
  1110. a_load_const_reg(list,OS_INT,count,countreg);
  1111. cg.a_label(list,l);
  1112. srcref.addressmode:=AM_POSTINDEXED;
  1113. dstref.addressmode:=AM_POSTINDEXED;
  1114. srcref.offset:=size;
  1115. dstref.offset:=size;
  1116. r:=getintregister(list,size2opsize[size]);
  1117. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1118. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1119. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1120. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  1121. { keep the registers alive }
  1122. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1123. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1124. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1125. end;
  1126. begin
  1127. if len=0 then
  1128. exit;
  1129. helpsize:=12;
  1130. dstref:=dest;
  1131. srcref:=source;
  1132. if cs_littlesize in aktglobalswitches then
  1133. helpsize:=8;
  1134. if (len<=helpsize) and aligned then
  1135. begin
  1136. copysize:=4;
  1137. cgsize:=OS_32;
  1138. while len<>0 do
  1139. begin
  1140. if len<2 then
  1141. begin
  1142. copysize:=1;
  1143. cgsize:=OS_8;
  1144. end
  1145. else if len<4 then
  1146. begin
  1147. copysize:=2;
  1148. cgsize:=OS_16;
  1149. end;
  1150. dec(len,copysize);
  1151. r:=getintregister(list,cgsize);
  1152. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1153. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1154. inc(srcref.offset,copysize);
  1155. inc(dstref.offset,copysize);
  1156. end;
  1157. end
  1158. else
  1159. begin
  1160. destreg:=getintregister(list,OS_ADDR);
  1161. a_loadaddr_ref_reg(list,dest,destreg);
  1162. reference_reset_base(dstref,destreg,0);
  1163. srcreg:=getintregister(list,OS_ADDR);
  1164. a_loadaddr_ref_reg(list,source,srcreg);
  1165. reference_reset_base(srcref,srcreg,0);
  1166. countreg:=getintregister(list,OS_32);
  1167. // if cs_littlesize in aktglobalswitches then
  1168. genloop(len,1);
  1169. {
  1170. else
  1171. begin
  1172. helpsize:=len shr 2;
  1173. len:=len and 3;
  1174. if helpsize>1 then
  1175. begin
  1176. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1177. list.concat(Taicpu.op_none(A_REP,S_NO));
  1178. end;
  1179. if helpsize>0 then
  1180. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1181. if len>1 then
  1182. begin
  1183. dec(len,2);
  1184. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1185. end;
  1186. if len=1 then
  1187. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1188. end;
  1189. }
  1190. end;
  1191. end;
  1192. procedure tcgarm.g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);
  1193. begin
  1194. g_concatcopy_internal(list,source,dest,len,false);
  1195. end;
  1196. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);
  1197. begin
  1198. g_concatcopy_internal(list,source,dest,len,true);
  1199. end;
  1200. procedure tcgarm.g_overflowCheck(list : taasmoutput;const l : tlocation;def : tdef);
  1201. var
  1202. ovloc : tlocation;
  1203. begin
  1204. ovloc.loc:=LOC_VOID;
  1205. g_overflowCheck_loc(list,l,def,ovloc);
  1206. end;
  1207. procedure tcgarm.g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1208. var
  1209. hl : tasmlabel;
  1210. ai:TAiCpu;
  1211. hflags : tresflags;
  1212. begin
  1213. if not(cs_check_overflow in aktlocalswitches) then
  1214. exit;
  1215. objectlibrary.getjumplabel(hl);
  1216. case ovloc.loc of
  1217. LOC_VOID:
  1218. begin
  1219. ai:=taicpu.op_sym(A_B,hl);
  1220. ai.is_jmp:=true;
  1221. if not((def.deftype=pointerdef) or
  1222. ((def.deftype=orddef) and
  1223. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1224. ai.SetCondition(C_VC)
  1225. else
  1226. ai.SetCondition(C_CC);
  1227. list.concat(ai);
  1228. end;
  1229. LOC_FLAGS:
  1230. begin
  1231. hflags:=ovloc.resflags;
  1232. inverse_flags(hflags);
  1233. cg.a_jmp_flags(list,hflags,hl);
  1234. end;
  1235. else
  1236. internalerror(200409281);
  1237. end;
  1238. a_call_name(list,'FPC_OVERFLOW');
  1239. a_label(list,hl);
  1240. end;
  1241. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1242. begin
  1243. { this work is done in g_proc_entry }
  1244. end;
  1245. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1246. begin
  1247. { this work is done in g_proc_exit }
  1248. end;
  1249. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1250. var
  1251. ai : taicpu;
  1252. begin
  1253. ai:=Taicpu.Op_sym(A_B,l);
  1254. ai.SetCondition(OpCmp2AsmCond[cond]);
  1255. ai.is_jmp:=true;
  1256. list.concat(ai);
  1257. end;
  1258. procedure tcgarm.g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  1259. procedure loadvmttor12;
  1260. var
  1261. href : treference;
  1262. begin
  1263. reference_reset_base(href,NR_R0,0);
  1264. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1265. end;
  1266. procedure op_onr12methodaddr;
  1267. var
  1268. href : treference;
  1269. begin
  1270. if (procdef.extnumber=$ffff) then
  1271. Internalerror(200006139);
  1272. { call/jmp vmtoffs(%eax) ; method offs }
  1273. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1274. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1275. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1276. end;
  1277. var
  1278. lab : tasmsymbol;
  1279. make_global : boolean;
  1280. href : treference;
  1281. begin
  1282. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1283. Internalerror(200006137);
  1284. if not assigned(procdef._class) or
  1285. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1286. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1287. Internalerror(200006138);
  1288. if procdef.owner.symtabletype<>objectsymtable then
  1289. Internalerror(200109191);
  1290. make_global:=false;
  1291. if (not current_module.is_unit) or
  1292. (cs_create_smart in aktmoduleswitches) or
  1293. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1294. make_global:=true;
  1295. if make_global then
  1296. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1297. else
  1298. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1299. { set param1 interface to self }
  1300. g_adjust_self_value(list,procdef,ioffset);
  1301. { case 4 }
  1302. if po_virtualmethod in procdef.procoptions then
  1303. begin
  1304. loadvmttor12;
  1305. op_onr12methodaddr;
  1306. end
  1307. { case 0 }
  1308. else
  1309. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION)));
  1310. list.concat(Tai_symbol_end.Createname(labelname));
  1311. end;
  1312. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1313. var
  1314. tmpreg : tregister;
  1315. begin
  1316. case op of
  1317. OP_NEG:
  1318. begin
  1319. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1320. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1321. end;
  1322. OP_NOT:
  1323. begin
  1324. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1325. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1326. end;
  1327. else
  1328. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1329. end;
  1330. end;
  1331. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1332. begin
  1333. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1334. end;
  1335. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1336. var
  1337. ovloc : tlocation;
  1338. begin
  1339. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1340. end;
  1341. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1342. var
  1343. ovloc : tlocation;
  1344. begin
  1345. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1346. end;
  1347. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1348. var
  1349. tmpreg : tregister;
  1350. b : byte;
  1351. begin
  1352. ovloc.loc:=LOC_VOID;
  1353. case op of
  1354. OP_NEG,
  1355. OP_NOT :
  1356. internalerror(200306017);
  1357. end;
  1358. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1359. begin
  1360. case op of
  1361. OP_ADD:
  1362. begin
  1363. if is_shifter_const(lo(value),b) then
  1364. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1365. else
  1366. begin
  1367. tmpreg:=cg.getintregister(list,OS_32);
  1368. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1369. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1370. end;
  1371. if is_shifter_const(hi(value),b) then
  1372. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1373. else
  1374. begin
  1375. tmpreg:=cg.getintregister(list,OS_32);
  1376. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1377. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1378. end;
  1379. end;
  1380. OP_SUB:
  1381. begin
  1382. if is_shifter_const(lo(value),b) then
  1383. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1384. else
  1385. begin
  1386. tmpreg:=cg.getintregister(list,OS_32);
  1387. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1388. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1389. end;
  1390. if is_shifter_const(hi(value),b) then
  1391. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1392. else
  1393. begin
  1394. tmpreg:=cg.getintregister(list,OS_32);
  1395. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1396. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1397. end;
  1398. end;
  1399. else
  1400. internalerror(200502131);
  1401. end;
  1402. if size=OS_64 then
  1403. begin
  1404. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1405. ovloc.loc:=LOC_FLAGS;
  1406. case op of
  1407. OP_ADD:
  1408. ovloc.resflags:=F_CS;
  1409. OP_SUB:
  1410. ovloc.resflags:=F_CC;
  1411. end;
  1412. end;
  1413. end
  1414. else
  1415. begin
  1416. case op of
  1417. OP_AND,OP_OR,OP_XOR:
  1418. begin
  1419. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1420. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1421. end;
  1422. OP_ADD:
  1423. begin
  1424. if is_shifter_const(lo(value),b) then
  1425. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1426. else
  1427. begin
  1428. tmpreg:=cg.getintregister(list,OS_32);
  1429. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1430. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1431. end;
  1432. if is_shifter_const(hi(value),b) then
  1433. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1434. else
  1435. begin
  1436. tmpreg:=cg.getintregister(list,OS_32);
  1437. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1438. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1439. end;
  1440. end;
  1441. OP_SUB:
  1442. begin
  1443. if is_shifter_const(lo(value),b) then
  1444. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1445. else
  1446. begin
  1447. tmpreg:=cg.getintregister(list,OS_32);
  1448. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1449. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1450. end;
  1451. if is_shifter_const(hi(value),b) then
  1452. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1453. else
  1454. begin
  1455. tmpreg:=cg.getintregister(list,OS_32);
  1456. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1457. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1458. end;
  1459. end;
  1460. else
  1461. internalerror(2003083101);
  1462. end;
  1463. end;
  1464. end;
  1465. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1466. var
  1467. op1,op2:TAsmOp;
  1468. begin
  1469. ovloc.loc:=LOC_VOID;
  1470. case op of
  1471. OP_NEG,
  1472. OP_NOT :
  1473. internalerror(200306017);
  1474. end;
  1475. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1476. begin
  1477. case op of
  1478. OP_ADD:
  1479. begin
  1480. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1481. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1482. end;
  1483. OP_SUB:
  1484. begin
  1485. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1486. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1487. end;
  1488. else
  1489. internalerror(2003083101);
  1490. end;
  1491. if size=OS_64 then
  1492. begin
  1493. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1494. ovloc.loc:=LOC_FLAGS;
  1495. case op of
  1496. OP_ADD:
  1497. ovloc.resflags:=F_CC;
  1498. OP_SUB:
  1499. ovloc.resflags:=F_CS;
  1500. end;
  1501. end;
  1502. end
  1503. else
  1504. begin
  1505. case op of
  1506. OP_AND,OP_OR,OP_XOR:
  1507. begin
  1508. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1509. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1510. end;
  1511. OP_ADD:
  1512. begin
  1513. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1514. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1515. end;
  1516. OP_SUB:
  1517. begin
  1518. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1519. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1520. end;
  1521. else
  1522. internalerror(2003083101);
  1523. end;
  1524. end;
  1525. end;
  1526. begin
  1527. cg:=tcgarm.create;
  1528. cg64:=tcg64farm.create;
  1529. end.