cgcpu.pas 61 KB

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