cgcpu.pas 61 KB

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