n68kadd.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
  3. Code generation for add nodes on the Motorola 680x0 family
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit n68kadd;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nadd,ncgadd,cpubase;
  22. type
  23. t68kaddnode = class(tcgaddnode)
  24. private
  25. function getresflags(unsigned: boolean) : tresflags;
  26. protected
  27. procedure second_addfloat;override;
  28. procedure second_cmpordinal;override;
  29. procedure second_cmpsmallset;override;
  30. procedure second_cmp64bit;override;
  31. procedure second_cmpboolean;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,
  37. symconst,symdef,paramgr,
  38. aasmbase,aasmtai,aasmcpu,defutil,htypechk,
  39. cgbase,cpuinfo,pass_1,pass_2,regvars,
  40. cpupara,cgutils,
  41. ncon,nset,
  42. ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  43. {*****************************************************************************
  44. Helpers
  45. *****************************************************************************}
  46. function t68kaddnode.getresflags(unsigned : boolean) : tresflags;
  47. begin
  48. case nodetype of
  49. equaln : getresflags:=F_E;
  50. unequaln : getresflags:=F_NE;
  51. else
  52. if not(unsigned) then
  53. begin
  54. if nf_swaped in flags then
  55. case nodetype of
  56. ltn : getresflags:=F_G;
  57. lten : getresflags:=F_GE;
  58. gtn : getresflags:=F_L;
  59. gten : getresflags:=F_LE;
  60. end
  61. else
  62. case nodetype of
  63. ltn : getresflags:=F_L;
  64. lten : getresflags:=F_LE;
  65. gtn : getresflags:=F_G;
  66. gten : getresflags:=F_GE;
  67. end;
  68. end
  69. else
  70. begin
  71. if nf_swaped in flags then
  72. case nodetype of
  73. ltn : getresflags:=F_A;
  74. lten : getresflags:=F_AE;
  75. gtn : getresflags:=F_B;
  76. gten : getresflags:=F_BE;
  77. end
  78. else
  79. case nodetype of
  80. ltn : getresflags:=F_B;
  81. lten : getresflags:=F_BE;
  82. gtn : getresflags:=F_A;
  83. gten : getresflags:=F_AE;
  84. end;
  85. end;
  86. end;
  87. end;
  88. {*****************************************************************************
  89. AddFloat
  90. *****************************************************************************}
  91. procedure t68kaddnode.second_addfloat;
  92. var
  93. op : TAsmOp;
  94. cmpop : boolean;
  95. begin
  96. pass_left_right;
  97. cmpop:=false;
  98. case nodetype of
  99. addn :
  100. op:=A_FADD;
  101. muln :
  102. op:=A_FMUL;
  103. subn :
  104. op:=A_FSUB;
  105. slashn :
  106. op:=A_FDIV;
  107. ltn,lten,gtn,gten,
  108. equaln,unequaln :
  109. begin
  110. // op:=A_FCMPO;
  111. cmpop:=true;
  112. end;
  113. else
  114. internalerror(200403182);
  115. end;
  116. // get the operands in the correct order, there are no special cases
  117. // here, everything is register-based
  118. if nf_swaped in flags then
  119. swapleftright;
  120. // put both operands in a register
  121. location_force_fpureg(exprasmlist,right.location,true);
  122. location_force_fpureg(exprasmlist,left.location,true);
  123. // initialize de result
  124. if not cmpop then
  125. begin
  126. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  127. if left.location.loc = LOC_FPUREGISTER then
  128. location.register := left.location.register
  129. else if right.location.loc = LOC_FPUREGISTER then
  130. location.register := right.location.register
  131. else
  132. location.register := cg.getfpuregister(exprasmlist,location.size);
  133. end
  134. else
  135. begin
  136. location_reset(location,LOC_FLAGS,OS_NO);
  137. // FIX ME!
  138. // location.resflags := getresflags;
  139. end;
  140. // emit the actual operation
  141. if not cmpop then
  142. begin
  143. {
  144. exprasmlist.concat(taicpu.op_reg_reg_reg(op,
  145. location.register,left.location.register,
  146. right.location.register))
  147. }
  148. end
  149. else
  150. begin
  151. { exprasmlist.concat(taicpu.op_reg_reg_reg(op,
  152. newreg(R_SPECIALREGISTER,location.resflags.cr,R_SUBNONE),left.location.register,right.location.register))}
  153. end;
  154. end;
  155. {*****************************************************************************
  156. Smallsets
  157. *****************************************************************************}
  158. procedure t68kaddnode.second_cmpsmallset;
  159. var
  160. tmpreg : tregister;
  161. begin
  162. location_reset(location,LOC_FLAGS,OS_NO);
  163. case nodetype of
  164. equaln,
  165. unequaln :
  166. begin
  167. {emit_compare(true);}
  168. end;
  169. lten,gten:
  170. begin
  171. If (not(nf_swaped in flags) and
  172. (nodetype = lten)) or
  173. ((nf_swaped in flags) and
  174. (nodetype = gten)) then
  175. swapleftright;
  176. // now we have to check whether left >= right
  177. tmpreg := cg.getintregister(exprasmlist,OS_INT);
  178. if left.location.loc = LOC_CONSTANT then
  179. begin
  180. cg.a_op_const_reg_reg(exprasmlist,OP_AND,OS_INT,
  181. not(left.location.value),right.location.register,tmpreg);
  182. exprasmlist.concat(taicpu.op_reg(A_TST,S_L,tmpreg));
  183. // the two instructions above should be folded together by
  184. // the peepholeoptimizer
  185. end
  186. else
  187. begin
  188. if right.location.loc = LOC_CONSTANT then
  189. begin
  190. cg.a_load_const_reg(exprasmlist,OS_INT,
  191. aword(right.location.value),tmpreg);
  192. exprasmlist.concat(taicpu.op_reg_reg(A_AND,S_L,
  193. tmpreg,left.location.register));
  194. end
  195. else
  196. exprasmlist.concat(taicpu.op_reg_reg(A_AND,S_L,
  197. right.location.register,left.location.register));
  198. end;
  199. // cg.ungetcpuregister(exprasmlist,tmpreg);
  200. location.resflags := getresflags(true);
  201. end;
  202. else
  203. internalerror(2002072701);
  204. end;
  205. end;
  206. {*****************************************************************************
  207. Ordinals
  208. *****************************************************************************}
  209. procedure t68kaddnode.second_cmpordinal;
  210. var
  211. unsigned : boolean;
  212. useconst : boolean;
  213. tmpreg : tregister;
  214. op : tasmop;
  215. begin
  216. // writeln('second_cmpordinal');
  217. pass_left_right;
  218. { set result location }
  219. location_reset(location,LOC_JUMP,OS_NO);
  220. { load values into registers (except constants) }
  221. force_reg_left_right(true, false);
  222. { determine if the comparison will be unsigned }
  223. unsigned:=not(is_signed(left.resulttype.def)) or
  224. not(is_signed(right.resulttype.def));
  225. // get the constant on the right if there is one
  226. if (left.location.loc = LOC_CONSTANT) then
  227. swapleftright;
  228. // can we use an immediate, or do we have to load the
  229. // constant in a register first?
  230. if (right.location.loc = LOC_CONSTANT) then
  231. begin
  232. {$ifdef extdebug}
  233. if (right.location.size in [OS_64,OS_S64]) and (hi(right.location.value64)<>0) and ((hi(right.location.value64)<>-1) or unsigned) then
  234. internalerror(2002080301);
  235. {$endif extdebug}
  236. if (nodetype in [equaln,unequaln]) then
  237. if (unsigned and
  238. (right.location.value > high(word))) or
  239. (not unsigned and
  240. (longint(right.location.value) < low(smallint)) or
  241. (longint(right.location.value) > high(smallint))) then
  242. { we can then maybe use a constant in the 'othersigned' case
  243. (the sign doesn't matter for // equal/unequal)}
  244. unsigned := not unsigned;
  245. if (unsigned and
  246. ((right.location.value) <= high(word))) or
  247. (not(unsigned) and
  248. (longint(right.location.value) >= low(smallint)) and
  249. (longint(right.location.value) <= high(smallint))) then
  250. useconst := true
  251. else
  252. begin
  253. useconst := false;
  254. tmpreg := cg.getintregister(exprasmlist,OS_INT);
  255. cg.a_load_const_reg(exprasmlist,OS_INT,
  256. aword(right.location.value),tmpreg);
  257. end
  258. end
  259. else
  260. useconst := false;
  261. location.loc := LOC_FLAGS;
  262. location.resflags := getresflags(unsigned);
  263. op := A_CMP;
  264. if (right.location.loc = LOC_CONSTANT) then
  265. if useconst then
  266. exprasmlist.concat(taicpu.op_reg_const(op,S_L,
  267. left.location.register,longint(right.location.value)))
  268. else
  269. begin
  270. exprasmlist.concat(taicpu.op_reg_reg(op,S_L,
  271. left.location.register,tmpreg));
  272. // cg.ungetcpuregister(exprasmlist,tmpreg);
  273. end
  274. else
  275. exprasmlist.concat(taicpu.op_reg_reg(op,S_L,
  276. left.location.register,right.location.register));
  277. end;
  278. {*****************************************************************************
  279. Boolean
  280. *****************************************************************************}
  281. procedure t68kaddnode.second_cmpboolean;
  282. var
  283. cgop : TOpCg;
  284. cgsize : TCgSize;
  285. isjump : boolean;
  286. otl,ofl : tasmlabel;
  287. begin
  288. // writeln('second_cmpboolean');
  289. if (torddef(left.resulttype.def).typ=bool8bit) or
  290. (torddef(right.resulttype.def).typ=bool8bit) then
  291. cgsize:=OS_8
  292. else
  293. if (torddef(left.resulttype.def).typ=bool16bit) or
  294. (torddef(right.resulttype.def).typ=bool16bit) then
  295. cgsize:=OS_16
  296. else
  297. cgsize:=OS_32;
  298. if (cs_full_boolean_eval in aktlocalswitches) or
  299. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  300. begin
  301. if left.nodetype in [ordconstn,realconstn] then
  302. swapleftright;
  303. isjump:=(left.location.loc=LOC_JUMP);
  304. if isjump then
  305. begin
  306. otl:=truelabel;
  307. objectlibrary.getjumplabel(truelabel);
  308. ofl:=falselabel;
  309. objectlibrary.getjumplabel(falselabel);
  310. end;
  311. secondpass(left);
  312. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then begin
  313. // writeln('ajjaj');
  314. location_force_reg(exprasmlist,left.location,cgsize,false);
  315. // writeln('reccs?');
  316. end;
  317. if isjump then
  318. begin
  319. truelabel:=otl;
  320. falselabel:=ofl;
  321. end;
  322. isjump:=(right.location.loc=LOC_JUMP);
  323. if isjump then
  324. begin
  325. otl:=truelabel;
  326. objectlibrary.getjumplabel(truelabel);
  327. ofl:=falselabel;
  328. objectlibrary.getjumplabel(falselabel);
  329. end;
  330. secondpass(right);
  331. if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
  332. location_force_reg(exprasmlist,right.location,cgsize,false);
  333. if isjump then
  334. begin
  335. truelabel:=otl;
  336. falselabel:=ofl;
  337. end;
  338. location_reset(location,LOC_FLAGS,OS_NO);
  339. force_reg_left_right(true,false);
  340. if (left.location.loc = LOC_CONSTANT) then
  341. swapleftright;
  342. if (right.location.loc <> LOC_CONSTANT) then
  343. exprasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,
  344. left.location.register,right.location.register))
  345. else
  346. exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,
  347. longint(right.location.value),left.location.register));
  348. location.resflags := getresflags(true);
  349. end;
  350. //release_reg_left_right;
  351. end;
  352. {*****************************************************************************
  353. 64-bit
  354. *****************************************************************************}
  355. procedure t68kaddnode.second_cmp64bit;
  356. begin
  357. writeln('second_cmp64bit');
  358. (* load_left_right(true,false);
  359. case nodetype of
  360. ltn,lten,
  361. gtn,gten:
  362. begin
  363. emit_cmp64_hi;
  364. firstjmp64bitcmp;
  365. emit_cmp64_lo;
  366. secondjmp64bitcmp;
  367. end;
  368. equaln,unequaln:
  369. begin
  370. // instead of doing a complicated compare, do
  371. // (left.hi xor right.hi) or (left.lo xor right.lo)
  372. // (somewhate optimized so that no superfluous 'mr's are
  373. // generated)
  374. if (left.location.loc = LOC_CONSTANT) then
  375. swapleftright;
  376. if (right.location.loc = LOC_CONSTANT) then
  377. begin
  378. if left.location.loc = LOC_REGISTER then
  379. begin
  380. tempreg64.reglo := left.location.register64.reglo;
  381. tempreg64.reghi := left.location.register64.reghi;
  382. end
  383. else
  384. begin
  385. if (aword(right.location.valueqword) <> 0) then
  386. tempreg64.reglo := cg.getintregister(exprasmlist)
  387. else
  388. tempreg64.reglo := left.location.register64.reglo;
  389. if ((right.location.valueqword shr 32) <> 0) then
  390. tempreg64.reghi := cg.getintregister(exprasmlist)
  391. else
  392. tempreg64.reghi := left.location.register64.reghi;
  393. end;
  394. if (aword(right.location.valueqword) <> 0) then
  395. { negative values can be handled using SUB, }
  396. { positive values < 65535 using XOR. }
  397. if (longint(right.location.valueqword) >= -32767) and
  398. (longint(right.location.valueqword) < 0) then
  399. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,OS_INT,
  400. aword(right.location.valueqword),
  401. left.location.register64.reglo,tempreg64.reglo)
  402. else
  403. cg.a_op_const_reg_reg(exprasmlist,OP_XOR,OS_INT,
  404. aword(right.location.valueqword),
  405. left.location.register64.reglo,tempreg64.reglo);
  406. if ((right.location.valueqword shr 32) <> 0) then
  407. if (longint(right.location.valueqword shr 32) >= -32767) and
  408. (longint(right.location.valueqword shr 32) < 0) then
  409. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,OS_INT,
  410. aword(right.location.valueqword shr 32),
  411. left.location.register64.reghi,tempreg64.reghi)
  412. else
  413. cg.a_op_const_reg_reg(exprasmlist,OP_XOR,OS_INT,
  414. aword(right.location.valueqword shr 32),
  415. left.location.register64.reghi,tempreg64.reghi);
  416. end
  417. else
  418. begin
  419. tempreg64.reglo := cg.getintregister(exprasmlist);
  420. tempreg64.reghi := cg.getintregister(exprasmlist);
  421. cg64.a_op64_reg_reg_reg(exprasmlist,OP_XOR,
  422. left.location.register64,right.location.register64,
  423. tempreg64);
  424. end;
  425. cg.a_reg_alloc(exprasmlist,R_0);
  426. exprasmlist.concat(taicpu.op_reg_reg_reg(A_OR_,R_0,
  427. tempreg64.reglo,tempreg64.reghi));
  428. cg.a_reg_dealloc(exprasmlist,R_0);
  429. if (tempreg64.reglo <> left.location.register64.reglo) then
  430. cg.ungetregister(exprasmlist,tempreg64.reglo);
  431. if (tempreg64.reghi <> left.location.register64.reghi) then
  432. cg.ungetregister(exprasmlist,tempreg64.reghi);
  433. location_reset(location,LOC_FLAGS,OS_NO);
  434. location.resflags := getresflags;
  435. end;
  436. else
  437. internalerror(2002072803);
  438. end;
  439. { set result location }
  440. { (emit_compare sets it to LOC_FLAGS for compares, so set the }
  441. { real location only now) (JM) }
  442. if cmpop and
  443. not(nodetype in [equaln,unequaln]) then
  444. location_reset(location,LOC_JUMP,OS_NO);
  445. *)
  446. location_reset(location,LOC_JUMP,OS_NO);
  447. end;
  448. begin
  449. caddnode:=t68kaddnode;
  450. end.