cgcpu.pas 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697
  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. { [#xxx] isn't a valid address operand }
  539. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  540. (ref.offset<-4095) or
  541. (ref.offset>4095) or
  542. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  543. ((ref.offset<-255) or
  544. (ref.offset>255)
  545. )
  546. ) or
  547. ((op in [A_LDF,A_STF]) and
  548. ((ref.offset<-1020) or
  549. (ref.offset>1020)
  550. )
  551. ) then
  552. begin
  553. reference_reset(tmpref);
  554. { load symbol }
  555. tmpreg:=getintregister(list,OS_INT);
  556. if assigned(ref.symbol) then
  557. begin
  558. objectlibrary.getlabel(l);
  559. cg.a_label(current_procinfo.aktlocaldata,l);
  560. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  561. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  562. { load consts entry }
  563. tmpref.symbol:=l;
  564. tmpref.base:=NR_R15;
  565. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  566. end
  567. else
  568. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  569. if (ref.base<>NR_NO) then
  570. begin
  571. if ref.index<>NR_NO then
  572. begin
  573. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  574. ref.base:=tmpreg;
  575. end
  576. else
  577. begin
  578. ref.index:=tmpreg;
  579. ref.shiftimm:=0;
  580. ref.signindex:=1;
  581. ref.shiftmode:=SM_None;
  582. end;
  583. end
  584. else
  585. ref.base:=tmpreg;
  586. ref.offset:=0;
  587. ref.symbol:=nil;
  588. end;
  589. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  590. begin
  591. if tmpreg<>NR_NO then
  592. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  593. else
  594. begin
  595. tmpreg:=getintregister(list,OS_ADDR);
  596. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  597. ref.base:=tmpreg;
  598. end;
  599. ref.offset:=0;
  600. end;
  601. { floating point operations have only limited references
  602. we expect here, that a base is already set }
  603. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  604. begin
  605. if ref.shiftmode<>SM_none then
  606. internalerror(200309121);
  607. if tmpreg<>NR_NO then
  608. begin
  609. if ref.base=tmpreg then
  610. begin
  611. if ref.signindex<0 then
  612. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  613. else
  614. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  615. ref.index:=NR_NO;
  616. end
  617. else
  618. begin
  619. if ref.index<>tmpreg then
  620. internalerror(200403161);
  621. if ref.signindex<0 then
  622. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  623. else
  624. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  625. ref.base:=tmpreg;
  626. ref.index:=NR_NO;
  627. end;
  628. end
  629. else
  630. begin
  631. tmpreg:=getintregister(list,OS_ADDR);
  632. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  633. ref.base:=tmpreg;
  634. ref.index:=NR_NO;
  635. end;
  636. end;
  637. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  638. end;
  639. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  640. var
  641. oppostfix:toppostfix;
  642. begin
  643. case ToSize of
  644. { signed integer registers }
  645. OS_8,
  646. OS_S8:
  647. oppostfix:=PF_B;
  648. OS_16,
  649. OS_S16:
  650. oppostfix:=PF_H;
  651. OS_32,
  652. OS_S32:
  653. oppostfix:=PF_None;
  654. else
  655. InternalError(200308295);
  656. end;
  657. handle_load_store(list,A_STR,oppostfix,reg,ref);
  658. end;
  659. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  660. var
  661. oppostfix:toppostfix;
  662. begin
  663. case FromSize of
  664. { signed integer registers }
  665. OS_8:
  666. oppostfix:=PF_B;
  667. OS_S8:
  668. oppostfix:=PF_SB;
  669. OS_16:
  670. oppostfix:=PF_H;
  671. OS_S16:
  672. oppostfix:=PF_SH;
  673. OS_32,
  674. OS_S32:
  675. oppostfix:=PF_None;
  676. else
  677. InternalError(200308291);
  678. end;
  679. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  680. end;
  681. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  682. var
  683. instr: taicpu;
  684. so : tshifterop;
  685. begin
  686. shifterop_reset(so);
  687. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  688. (
  689. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  690. (tosize <> fromsize) and
  691. not(fromsize in [OS_32,OS_S32])
  692. ) then
  693. begin
  694. case tosize of
  695. OS_8:
  696. list.concat(taicpu.op_reg_reg_const(A_AND,
  697. reg2,reg1,$ff));
  698. OS_S8:
  699. begin
  700. so.shiftmode:=SM_LSL;
  701. so.shiftimm:=24;
  702. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  703. so.shiftmode:=SM_ASR;
  704. so.shiftimm:=24;
  705. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  706. end;
  707. OS_16:
  708. begin
  709. so.shiftmode:=SM_LSL;
  710. so.shiftimm:=16;
  711. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  712. so.shiftmode:=SM_LSR;
  713. so.shiftimm:=16;
  714. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  715. end;
  716. OS_S16:
  717. begin
  718. so.shiftmode:=SM_LSL;
  719. so.shiftimm:=16;
  720. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  721. so.shiftmode:=SM_ASR;
  722. so.shiftimm:=16;
  723. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  724. end;
  725. OS_32,OS_S32:
  726. begin
  727. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  728. list.concat(instr);
  729. add_move_instruction(instr);
  730. end;
  731. else internalerror(2002090901);
  732. end;
  733. end
  734. else
  735. begin
  736. if reg1<>reg2 then
  737. begin
  738. { same size, only a register mov required }
  739. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  740. list.Concat(instr);
  741. { Notify the register allocator that we have written a move instruction so
  742. it can try to eliminate it. }
  743. add_move_instruction(instr);
  744. end;
  745. end;
  746. end;
  747. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  748. begin
  749. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  750. end;
  751. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  752. var
  753. oppostfix:toppostfix;
  754. begin
  755. case size of
  756. OS_F32:
  757. oppostfix:=PF_S;
  758. OS_F64:
  759. oppostfix:=PF_D;
  760. OS_F80:
  761. oppostfix:=PF_E;
  762. else
  763. InternalError(200309021);
  764. end;
  765. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  766. end;
  767. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  768. var
  769. oppostfix:toppostfix;
  770. begin
  771. case size of
  772. OS_F32:
  773. oppostfix:=PF_S;
  774. OS_F64:
  775. oppostfix:=PF_D;
  776. OS_F80:
  777. oppostfix:=PF_E;
  778. else
  779. InternalError(200309021);
  780. end;
  781. handle_load_store(list,A_STF,oppostfix,reg,ref);
  782. end;
  783. { comparison operations }
  784. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  785. l : tasmlabel);
  786. var
  787. tmpreg : tregister;
  788. b : byte;
  789. begin
  790. if is_shifter_const(a,b) then
  791. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  792. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  793. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  794. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  795. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  796. else
  797. begin
  798. tmpreg:=getintregister(list,size);
  799. a_load_const_reg(list,size,a,tmpreg);
  800. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  801. end;
  802. a_jmp_cond(list,cmp_op,l);
  803. end;
  804. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  805. begin
  806. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  807. a_jmp_cond(list,cmp_op,l);
  808. end;
  809. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  810. begin
  811. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  812. end;
  813. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  814. begin
  815. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
  816. end;
  817. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  818. var
  819. ai : taicpu;
  820. begin
  821. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  822. ai.is_jmp:=true;
  823. list.concat(ai);
  824. end;
  825. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  826. var
  827. ai : taicpu;
  828. begin
  829. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  830. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  831. end;
  832. procedure tcgarm.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);
  833. var
  834. ref : treference;
  835. shift : byte;
  836. firstfloatreg,lastfloatreg,
  837. r : byte;
  838. begin
  839. LocalSize:=align(LocalSize,4);
  840. if not(nostackframe) then
  841. begin
  842. firstfloatreg:=RS_NO;
  843. { save floating point registers? }
  844. for r:=RS_F0 to RS_F7 do
  845. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  846. begin
  847. if firstfloatreg=RS_NO then
  848. firstfloatreg:=r;
  849. lastfloatreg:=r;
  850. end;
  851. a_reg_alloc(list,NR_STACK_POINTER_REG);
  852. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  853. a_reg_alloc(list,NR_R12);
  854. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  855. { save int registers }
  856. reference_reset(ref);
  857. ref.index:=NR_STACK_POINTER_REG;
  858. ref.addressmode:=AM_PREINDEXED;
  859. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  860. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  861. PF_FD));
  862. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  863. { allocate necessary stack size }
  864. { don't use a_op_const_reg_reg here because we don't allow register allocations
  865. in the entry/exit code }
  866. if not(is_shifter_const(localsize,shift)) then
  867. begin
  868. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  869. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  870. a_reg_dealloc(list,NR_R12);
  871. end
  872. else
  873. begin
  874. a_reg_dealloc(list,NR_R12);
  875. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  876. end;
  877. if firstfloatreg<>RS_NO then
  878. begin
  879. reference_reset(ref);
  880. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  881. begin
  882. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  883. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  884. ref.base:=NR_R12;
  885. end
  886. else
  887. begin
  888. ref.base:=NR_FRAME_POINTER_REG;
  889. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  890. end;
  891. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  892. lastfloatreg-firstfloatreg+1,ref));
  893. end;
  894. end;
  895. end;
  896. procedure tcgarm.g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean);
  897. var
  898. ref : treference;
  899. firstfloatreg,lastfloatreg,
  900. r : byte;
  901. shift : byte;
  902. begin
  903. if not(nostackframe) then
  904. begin
  905. { restore floating point register }
  906. firstfloatreg:=RS_NO;
  907. { save floating point registers? }
  908. for r:=RS_F0 to RS_F7 do
  909. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  910. begin
  911. if firstfloatreg=RS_NO then
  912. firstfloatreg:=r;
  913. lastfloatreg:=r;
  914. end;
  915. if firstfloatreg<>RS_NO then
  916. begin
  917. reference_reset(ref);
  918. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  919. begin
  920. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  921. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  922. ref.base:=NR_R12;
  923. end
  924. else
  925. begin
  926. ref.base:=NR_FRAME_POINTER_REG;
  927. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  928. end;
  929. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  930. lastfloatreg-firstfloatreg+1,ref));
  931. end;
  932. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  933. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  934. else
  935. begin
  936. { restore int registers and return }
  937. reference_reset(ref);
  938. ref.index:=NR_FRAME_POINTER_REG;
  939. 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));
  940. end;
  941. end
  942. else
  943. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  944. end;
  945. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  946. var
  947. b : byte;
  948. tmpref : treference;
  949. instr : taicpu;
  950. begin
  951. if ref.addressmode<>AM_OFFSET then
  952. internalerror(200309071);
  953. tmpref:=ref;
  954. { Be sure to have a base register }
  955. if (tmpref.base=NR_NO) then
  956. begin
  957. if tmpref.shiftmode<>SM_None then
  958. internalerror(200308294);
  959. if tmpref.signindex<0 then
  960. internalerror(200312023);
  961. tmpref.base:=tmpref.index;
  962. tmpref.index:=NR_NO;
  963. end;
  964. if assigned(tmpref.symbol) or
  965. not((is_shifter_const(tmpref.offset,b)) or
  966. (is_shifter_const(-tmpref.offset,b))
  967. ) then
  968. fixref(list,tmpref);
  969. { expect a base here if there is an index }
  970. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  971. internalerror(200312022);
  972. if tmpref.index<>NR_NO then
  973. begin
  974. if tmpref.shiftmode<>SM_None then
  975. internalerror(200312021);
  976. if tmpref.signindex<0 then
  977. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  978. else
  979. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  980. if tmpref.offset<>0 then
  981. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  982. end
  983. else
  984. begin
  985. if tmpref.offset<>0 then
  986. begin
  987. if tmpref.base<>NR_NO then
  988. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  989. else
  990. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  991. end
  992. else
  993. begin
  994. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  995. list.concat(instr);
  996. add_move_instruction(instr);
  997. end;
  998. end;
  999. end;
  1000. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  1001. var
  1002. tmpreg : tregister;
  1003. tmpref : treference;
  1004. l : tasmlabel;
  1005. begin
  1006. { absolute symbols can't be handled directly, we've to store the symbol reference
  1007. in the text segment and access it pc relative
  1008. For now, we assume that references where base or index equals to PC are already
  1009. relative, all other references are assumed to be absolute and thus they need
  1010. to be handled extra.
  1011. A proper solution would be to change refoptions to a set and store the information
  1012. if the symbol is absolute or relative there.
  1013. }
  1014. { create consts entry }
  1015. reference_reset(tmpref);
  1016. objectlibrary.getlabel(l);
  1017. cg.a_label(current_procinfo.aktlocaldata,l);
  1018. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1019. if assigned(ref.symbol) then
  1020. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1021. else
  1022. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1023. { load consts entry }
  1024. tmpreg:=getintregister(list,OS_INT);
  1025. tmpref.symbol:=l;
  1026. tmpref.base:=NR_PC;
  1027. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1028. if (ref.base<>NR_NO) then
  1029. begin
  1030. if ref.index<>NR_NO then
  1031. begin
  1032. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1033. ref.base:=tmpreg;
  1034. end
  1035. else
  1036. begin
  1037. ref.index:=tmpreg;
  1038. ref.shiftimm:=0;
  1039. ref.signindex:=1;
  1040. ref.shiftmode:=SM_None;
  1041. end;
  1042. end
  1043. else
  1044. ref.base:=tmpreg;
  1045. ref.offset:=0;
  1046. ref.symbol:=nil;
  1047. end;
  1048. procedure tcgarm.g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  1049. var
  1050. paraloc1,paraloc2,paraloc3 : TCGPara;
  1051. begin
  1052. paraloc1.init;
  1053. paraloc2.init;
  1054. paraloc3.init;
  1055. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1056. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1057. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1058. paramanager.allocparaloc(list,paraloc3);
  1059. a_param_const(list,OS_INT,len,paraloc3);
  1060. paramanager.allocparaloc(list,paraloc2);
  1061. a_paramaddr_ref(list,dest,paraloc2);
  1062. paramanager.allocparaloc(list,paraloc2);
  1063. a_paramaddr_ref(list,source,paraloc1);
  1064. paramanager.freeparaloc(list,paraloc3);
  1065. paramanager.freeparaloc(list,paraloc2);
  1066. paramanager.freeparaloc(list,paraloc1);
  1067. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1068. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1069. a_call_name(list,'FPC_MOVE');
  1070. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1071. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1072. paraloc3.done;
  1073. paraloc2.done;
  1074. paraloc1.done;
  1075. end;
  1076. procedure tcgarm.g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  1077. var
  1078. srcref,dstref:treference;
  1079. srcreg,destreg,countreg,r:tregister;
  1080. helpsize:aword;
  1081. copysize:byte;
  1082. cgsize:Tcgsize;
  1083. procedure genloop(count : aword;size : byte);
  1084. const
  1085. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1086. var
  1087. l : tasmlabel;
  1088. begin
  1089. objectlibrary.getlabel(l);
  1090. a_load_const_reg(list,OS_INT,count,countreg);
  1091. cg.a_label(list,l);
  1092. srcref.addressmode:=AM_POSTINDEXED;
  1093. dstref.addressmode:=AM_POSTINDEXED;
  1094. srcref.offset:=size;
  1095. dstref.offset:=size;
  1096. r:=getintregister(list,size2opsize[size]);
  1097. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1098. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1099. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1100. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  1101. { keep the registers alive }
  1102. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1103. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1104. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1105. end;
  1106. begin
  1107. if len=0 then
  1108. exit;
  1109. helpsize:=12;
  1110. dstref:=dest;
  1111. srcref:=source;
  1112. if cs_littlesize in aktglobalswitches then
  1113. helpsize:=8;
  1114. if (len<=helpsize) and aligned then
  1115. begin
  1116. copysize:=4;
  1117. cgsize:=OS_32;
  1118. while len<>0 do
  1119. begin
  1120. if len<2 then
  1121. begin
  1122. copysize:=1;
  1123. cgsize:=OS_8;
  1124. end
  1125. else if len<4 then
  1126. begin
  1127. copysize:=2;
  1128. cgsize:=OS_16;
  1129. end;
  1130. dec(len,copysize);
  1131. r:=getintregister(list,cgsize);
  1132. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1133. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1134. inc(srcref.offset,copysize);
  1135. inc(dstref.offset,copysize);
  1136. end;
  1137. end
  1138. else
  1139. begin
  1140. destreg:=getintregister(list,OS_ADDR);
  1141. a_loadaddr_ref_reg(list,dest,destreg);
  1142. reference_reset_base(dstref,destreg,0);
  1143. srcreg:=getintregister(list,OS_ADDR);
  1144. a_loadaddr_ref_reg(list,source,srcreg);
  1145. reference_reset_base(srcref,srcreg,0);
  1146. countreg:=getintregister(list,OS_32);
  1147. // if cs_littlesize in aktglobalswitches then
  1148. genloop(len,1);
  1149. {
  1150. else
  1151. begin
  1152. helpsize:=len shr 2;
  1153. len:=len and 3;
  1154. if helpsize>1 then
  1155. begin
  1156. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1157. list.concat(Taicpu.op_none(A_REP,S_NO));
  1158. end;
  1159. if helpsize>0 then
  1160. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1161. if len>1 then
  1162. begin
  1163. dec(len,2);
  1164. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1165. end;
  1166. if len=1 then
  1167. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1168. end;
  1169. }
  1170. end;
  1171. end;
  1172. procedure tcgarm.g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);
  1173. begin
  1174. g_concatcopy_internal(list,source,dest,len,false);
  1175. end;
  1176. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);
  1177. begin
  1178. g_concatcopy_internal(list,source,dest,len,true);
  1179. end;
  1180. procedure tcgarm.g_overflowCheck(list : taasmoutput;const l : tlocation;def : tdef);
  1181. var
  1182. ovloc : tlocation;
  1183. begin
  1184. ovloc.loc:=LOC_VOID;
  1185. g_overflowCheck_loc(list,l,def,ovloc);
  1186. end;
  1187. procedure tcgarm.g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1188. var
  1189. hl : tasmlabel;
  1190. ai:TAiCpu;
  1191. hflags : tresflags;
  1192. begin
  1193. if not(cs_check_overflow in aktlocalswitches) then
  1194. exit;
  1195. objectlibrary.getlabel(hl);
  1196. case ovloc.loc of
  1197. LOC_VOID:
  1198. begin
  1199. ai:=taicpu.op_sym(A_B,hl);
  1200. ai.is_jmp:=true;
  1201. if not((def.deftype=pointerdef) or
  1202. ((def.deftype=orddef) and
  1203. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1204. ai.SetCondition(C_VC)
  1205. else
  1206. ai.SetCondition(C_CC);
  1207. list.concat(ai);
  1208. end;
  1209. LOC_FLAGS:
  1210. begin
  1211. hflags:=ovloc.resflags;
  1212. inverse_flags(hflags);
  1213. cg.a_jmp_flags(list,hflags,hl);
  1214. end;
  1215. else
  1216. internalerror(200409281);
  1217. end;
  1218. a_call_name(list,'FPC_OVERFLOW');
  1219. a_label(list,hl);
  1220. end;
  1221. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1222. begin
  1223. { this work is done in g_proc_entry }
  1224. end;
  1225. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1226. begin
  1227. { this work is done in g_proc_exit }
  1228. end;
  1229. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1230. var
  1231. ai : taicpu;
  1232. begin
  1233. ai:=Taicpu.Op_sym(A_B,l);
  1234. ai.SetCondition(OpCmp2AsmCond[cond]);
  1235. ai.is_jmp:=true;
  1236. list.concat(ai);
  1237. end;
  1238. procedure tcgarm.g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  1239. procedure loadvmttor12;
  1240. var
  1241. href : treference;
  1242. begin
  1243. reference_reset_base(href,NR_R0,0);
  1244. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1245. end;
  1246. procedure op_onr12methodaddr;
  1247. var
  1248. href : treference;
  1249. begin
  1250. if (procdef.extnumber=$ffff) then
  1251. Internalerror(200006139);
  1252. { call/jmp vmtoffs(%eax) ; method offs }
  1253. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1254. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1255. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1256. end;
  1257. var
  1258. lab : tasmsymbol;
  1259. make_global : boolean;
  1260. href : treference;
  1261. begin
  1262. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1263. Internalerror(200006137);
  1264. if not assigned(procdef._class) or
  1265. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1266. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1267. Internalerror(200006138);
  1268. if procdef.owner.symtabletype<>objectsymtable then
  1269. Internalerror(200109191);
  1270. make_global:=false;
  1271. if (not current_module.is_unit) or
  1272. (cs_create_smart in aktmoduleswitches) or
  1273. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1274. make_global:=true;
  1275. if make_global then
  1276. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1277. else
  1278. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1279. { set param1 interface to self }
  1280. g_adjust_self_value(list,procdef,ioffset);
  1281. { case 4 }
  1282. if po_virtualmethod in procdef.procoptions then
  1283. begin
  1284. loadvmttor12;
  1285. op_onr12methodaddr;
  1286. end
  1287. { case 0 }
  1288. else
  1289. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION)));
  1290. list.concat(Tai_symbol_end.Createname(labelname));
  1291. end;
  1292. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1293. var
  1294. tmpreg : tregister;
  1295. begin
  1296. case op of
  1297. OP_NEG:
  1298. begin
  1299. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1300. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1301. end;
  1302. OP_NOT:
  1303. begin
  1304. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1305. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1306. end;
  1307. else
  1308. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1309. end;
  1310. end;
  1311. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1312. begin
  1313. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1314. end;
  1315. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1316. var
  1317. ovloc : tlocation;
  1318. begin
  1319. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1320. end;
  1321. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1322. var
  1323. ovloc : tlocation;
  1324. begin
  1325. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1326. end;
  1327. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1328. var
  1329. tmpreg : tregister;
  1330. b : byte;
  1331. begin
  1332. ovloc.loc:=LOC_VOID;
  1333. case op of
  1334. OP_NEG,
  1335. OP_NOT :
  1336. internalerror(200306017);
  1337. end;
  1338. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1339. begin
  1340. case op of
  1341. OP_ADD:
  1342. begin
  1343. if is_shifter_const(lo(value),b) then
  1344. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1345. else
  1346. begin
  1347. tmpreg:=cg.getintregister(list,OS_32);
  1348. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1349. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1350. end;
  1351. if is_shifter_const(hi(value),b) then
  1352. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1353. else
  1354. begin
  1355. tmpreg:=cg.getintregister(list,OS_32);
  1356. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1357. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1358. end;
  1359. end;
  1360. OP_SUB:
  1361. begin
  1362. if is_shifter_const(lo(value),b) then
  1363. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1364. else
  1365. begin
  1366. tmpreg:=cg.getintregister(list,OS_32);
  1367. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1368. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1369. end;
  1370. if is_shifter_const(hi(value),b) then
  1371. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1372. else
  1373. begin
  1374. tmpreg:=cg.getintregister(list,OS_32);
  1375. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1376. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1377. end;
  1378. end;
  1379. else
  1380. internalerror(200502131);
  1381. end;
  1382. if size=OS_64 then
  1383. begin
  1384. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1385. ovloc.loc:=LOC_FLAGS;
  1386. case op of
  1387. OP_ADD:
  1388. ovloc.resflags:=F_CS;
  1389. OP_SUB:
  1390. ovloc.resflags:=F_CC;
  1391. end;
  1392. end;
  1393. end
  1394. else
  1395. begin
  1396. case op of
  1397. OP_AND,OP_OR,OP_XOR:
  1398. begin
  1399. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1400. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1401. end;
  1402. OP_ADD:
  1403. begin
  1404. if is_shifter_const(lo(value),b) then
  1405. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1406. else
  1407. begin
  1408. tmpreg:=cg.getintregister(list,OS_32);
  1409. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1410. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1411. end;
  1412. if is_shifter_const(hi(value),b) then
  1413. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1414. else
  1415. begin
  1416. tmpreg:=cg.getintregister(list,OS_32);
  1417. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1418. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1419. end;
  1420. end;
  1421. OP_SUB:
  1422. begin
  1423. if is_shifter_const(lo(value),b) then
  1424. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1425. else
  1426. begin
  1427. tmpreg:=cg.getintregister(list,OS_32);
  1428. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1429. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1430. end;
  1431. if is_shifter_const(hi(value),b) then
  1432. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1433. else
  1434. begin
  1435. tmpreg:=cg.getintregister(list,OS_32);
  1436. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1437. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1438. end;
  1439. end;
  1440. else
  1441. internalerror(2003083101);
  1442. end;
  1443. end;
  1444. end;
  1445. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1446. var
  1447. op1,op2:TAsmOp;
  1448. begin
  1449. ovloc.loc:=LOC_VOID;
  1450. case op of
  1451. OP_NEG,
  1452. OP_NOT :
  1453. internalerror(200306017);
  1454. end;
  1455. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1456. begin
  1457. case op of
  1458. OP_ADD:
  1459. begin
  1460. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1461. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1462. end;
  1463. OP_SUB:
  1464. begin
  1465. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1466. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1467. end;
  1468. else
  1469. internalerror(2003083101);
  1470. end;
  1471. if size=OS_64 then
  1472. begin
  1473. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1474. ovloc.loc:=LOC_FLAGS;
  1475. case op of
  1476. OP_ADD:
  1477. ovloc.resflags:=F_CC;
  1478. OP_SUB:
  1479. ovloc.resflags:=F_CS;
  1480. end;
  1481. end;
  1482. end
  1483. else
  1484. begin
  1485. case op of
  1486. OP_AND,OP_OR,OP_XOR:
  1487. begin
  1488. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1489. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1490. end;
  1491. OP_ADD:
  1492. begin
  1493. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1494. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1495. end;
  1496. OP_SUB:
  1497. begin
  1498. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1499. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1500. end;
  1501. else
  1502. internalerror(2003083101);
  1503. end;
  1504. end;
  1505. end;
  1506. begin
  1507. cg:=tcgarm.create;
  1508. cg64:=tcg64farm.create;
  1509. end.