aasmcpu.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. {
  2. Copyright (c) 1999-2002 by Jonas Maebe
  3. Contains the assembler object for the PowerPC64. Heavily based on code
  4. from the PowerPC platform
  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 aasmcpu;
  19. {$I fpcdefs.inc}
  20. interface
  21. uses
  22. globtype, verbose,
  23. aasmbase, aasmtai,
  24. cpubase, cgbase, cgutils;
  25. const
  26. { "mov reg,reg" source operand number }
  27. O_MOV_SOURCE = 1;
  28. { "mov reg,reg" source operand number }
  29. O_MOV_DEST = 0;
  30. type
  31. taicpu = class(tai_cpu_abstract)
  32. constructor op_none(op: tasmop);
  33. constructor op_reg(op: tasmop; _op1: tregister);
  34. constructor op_const(op: tasmop; _op1: aint);
  35. constructor op_reg_reg(op: tasmop; _op1, _op2: tregister);
  36. constructor op_reg_ref(op: tasmop; _op1: tregister; const _op2: treference);
  37. constructor op_reg_const(op: tasmop; _op1: tregister; _op2: aint);
  38. constructor op_const_reg(op: tasmop; _op1: aint; _op2: tregister);
  39. constructor op_const_const(op: tasmop; _op1, _op2: aint);
  40. constructor op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3,
  41. _op4: aint);
  42. constructor op_reg_reg_reg(op: tasmop; _op1, _op2, _op3: tregister);
  43. constructor op_reg_reg_const(op: tasmop; _op1, _op2: tregister; _op3: aint);
  44. constructor op_reg_reg_sym_ofs(op: tasmop; _op1, _op2: tregister; _op3:
  45. tasmsymbol; _op3ofs: aint);
  46. constructor op_reg_reg_ref(op: tasmop; _op1, _op2: tregister; const _op3:
  47. treference);
  48. constructor op_const_reg_reg(op: tasmop; _op1: aint; _op2, _op3: tregister);
  49. constructor op_const_reg_const(op: tasmop; _op1: aint; _op2: tregister;
  50. _op3: aint);
  51. constructor op_const_const_const(op: tasmop; _op1: aint; _op2: aint; _op3:
  52. aint);
  53. constructor op_reg_reg_reg_reg(op: tasmop; _op1, _op2, _op3, _op4:
  54. tregister);
  55. constructor op_reg_bool_reg_reg(op: tasmop; _op1: tregister; _op2: boolean;
  56. _op3, _op4: tregister);
  57. constructor op_reg_bool_reg_const(op: tasmop; _op1: tregister; _op2:
  58. boolean; _op3: tregister; _op4: aint);
  59. constructor op_reg_reg_reg_const_const(op: tasmop; _op1, _op2, _op3:
  60. tregister; _op4, _op5: aint);
  61. constructor op_reg_reg_const_const_const(op: tasmop; _op1, _op2: tregister;
  62. _op3, _op4, _op5: aint);
  63. { this is for Jmp instructions }
  64. constructor op_cond_sym(op: tasmop; cond: TAsmCond; _op1: tasmsymbol);
  65. constructor op_const_const_sym(op: tasmop; _op1, _op2: aint; _op3:
  66. tasmsymbol);
  67. constructor op_sym(op: tasmop; _op1: tasmsymbol);
  68. constructor op_sym_ofs(op: tasmop; _op1: tasmsymbol; _op1ofs: aint);
  69. constructor op_reg_sym_ofs(op: tasmop; _op1: tregister; _op2: tasmsymbol;
  70. _op2ofs: aint);
  71. constructor op_sym_ofs_ref(op: tasmop; _op1: tasmsymbol; _op1ofs: aint; const
  72. _op2: treference);
  73. procedure loadbool(opidx: aint; _b: boolean);
  74. function is_same_reg_move(regtype: Tregistertype): boolean; override;
  75. { register spilling code }
  76. function spilling_get_operation_type(opnr: longint): topertype;override;
  77. function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override;
  78. end;
  79. tai_align = class(tai_align_abstract)
  80. { nothing to add }
  81. end;
  82. procedure InitAsm;
  83. procedure DoneAsm;
  84. function spilling_create_load(const ref: treference; r: tregister): tai;
  85. function spilling_create_store(r: tregister; const ref: treference): tai;
  86. procedure fixup_jmps(list: taasmoutput);
  87. implementation
  88. uses cutils, cclasses;
  89. {*****************************************************************************
  90. taicpu Constructors
  91. *****************************************************************************}
  92. procedure taicpu.loadbool(opidx: aint; _b: boolean);
  93. begin
  94. if opidx >= ops then
  95. ops := opidx + 1;
  96. with oper[opidx]^ do
  97. begin
  98. if typ = top_ref then
  99. dispose(ref);
  100. b := _b;
  101. typ := top_bool;
  102. end;
  103. end;
  104. constructor taicpu.op_none(op: tasmop);
  105. begin
  106. inherited create(op);
  107. end;
  108. constructor taicpu.op_reg(op: tasmop; _op1: tregister);
  109. begin
  110. inherited create(op);
  111. ops := 1;
  112. loadreg(0, _op1);
  113. end;
  114. constructor taicpu.op_const(op: tasmop; _op1: aint);
  115. begin
  116. inherited create(op);
  117. ops := 1;
  118. loadconst(0, _op1);
  119. end;
  120. constructor taicpu.op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister;
  121. _op3, _op4: aint);
  122. begin
  123. inherited create(op);
  124. ops := 4;
  125. loadreg(0, _op1);
  126. loadreg(1, _op2);
  127. loadconst(2, _op3);
  128. loadconst(3, _op4);
  129. end;
  130. constructor taicpu.op_reg_reg(op: tasmop; _op1, _op2: tregister);
  131. begin
  132. inherited create(op);
  133. ops := 2;
  134. loadreg(0, _op1);
  135. loadreg(1, _op2);
  136. end;
  137. constructor taicpu.op_reg_const(op: tasmop; _op1: tregister; _op2: aint);
  138. begin
  139. inherited create(op);
  140. ops := 2;
  141. loadreg(0, _op1);
  142. loadconst(1, _op2);
  143. end;
  144. constructor taicpu.op_const_reg(op: tasmop; _op1: aint; _op2: tregister);
  145. begin
  146. inherited create(op);
  147. ops := 2;
  148. loadconst(0, _op1);
  149. loadreg(1, _op2);
  150. end;
  151. constructor taicpu.op_reg_ref(op: tasmop; _op1: tregister; const _op2:
  152. treference);
  153. begin
  154. inherited create(op);
  155. ops := 2;
  156. loadreg(0, _op1);
  157. loadref(1, _op2);
  158. end;
  159. constructor taicpu.op_const_const(op: tasmop; _op1, _op2: aint);
  160. begin
  161. inherited create(op);
  162. ops := 2;
  163. loadconst(0, _op1);
  164. loadconst(1, _op2);
  165. end;
  166. constructor taicpu.op_reg_reg_reg(op: tasmop; _op1, _op2, _op3: tregister);
  167. begin
  168. inherited create(op);
  169. ops := 3;
  170. loadreg(0, _op1);
  171. loadreg(1, _op2);
  172. loadreg(2, _op3);
  173. end;
  174. constructor taicpu.op_reg_reg_const(op: tasmop; _op1, _op2: tregister; _op3:
  175. aint);
  176. begin
  177. inherited create(op);
  178. ops := 3;
  179. loadreg(0, _op1);
  180. loadreg(1, _op2);
  181. loadconst(2, _op3);
  182. end;
  183. constructor taicpu.op_reg_reg_sym_ofs(op: tasmop; _op1, _op2: tregister; _op3:
  184. tasmsymbol; _op3ofs: aint);
  185. begin
  186. inherited create(op);
  187. ops := 3;
  188. loadreg(0, _op1);
  189. loadreg(1, _op2);
  190. loadsymbol(0, _op3, _op3ofs);
  191. end;
  192. constructor taicpu.op_reg_reg_ref(op: tasmop; _op1, _op2: tregister; const _op3:
  193. treference);
  194. begin
  195. inherited create(op);
  196. ops := 3;
  197. loadreg(0, _op1);
  198. loadreg(1, _op2);
  199. loadref(2, _op3);
  200. end;
  201. constructor taicpu.op_const_reg_reg(op: tasmop; _op1: aint; _op2, _op3:
  202. tregister);
  203. begin
  204. inherited create(op);
  205. ops := 3;
  206. loadconst(0, _op1);
  207. loadreg(1, _op2);
  208. loadreg(2, _op3);
  209. end;
  210. constructor taicpu.op_const_reg_const(op: tasmop; _op1: aint; _op2: tregister;
  211. _op3: aint);
  212. begin
  213. inherited create(op);
  214. ops := 3;
  215. loadconst(0, _op1);
  216. loadreg(1, _op2);
  217. loadconst(2, _op3);
  218. end;
  219. constructor taicpu.op_const_const_const(op: tasmop; _op1: aint; _op2: aint;
  220. _op3: aint);
  221. begin
  222. inherited create(op);
  223. ops := 3;
  224. loadconst(0, _op1);
  225. loadconst(1, _op2);
  226. loadconst(2, _op3);
  227. end;
  228. constructor taicpu.op_reg_reg_reg_reg(op: tasmop; _op1, _op2, _op3, _op4:
  229. tregister);
  230. begin
  231. inherited create(op);
  232. ops := 4;
  233. loadreg(0, _op1);
  234. loadreg(1, _op2);
  235. loadreg(2, _op3);
  236. loadreg(3, _op4);
  237. end;
  238. constructor taicpu.op_reg_bool_reg_reg(op: tasmop; _op1: tregister; _op2:
  239. boolean; _op3, _op4: tregister);
  240. begin
  241. inherited create(op);
  242. ops := 4;
  243. loadreg(0, _op1);
  244. loadbool(1, _op2);
  245. loadreg(2, _op3);
  246. loadreg(3, _op4);
  247. end;
  248. constructor taicpu.op_reg_bool_reg_const(op: tasmop; _op1: tregister; _op2:
  249. boolean; _op3: tregister; _op4: aint);
  250. begin
  251. inherited create(op);
  252. ops := 4;
  253. loadreg(0, _op1);
  254. loadbool(0, _op2);
  255. loadreg(0, _op3);
  256. loadconst(0, cardinal(_op4));
  257. end;
  258. constructor taicpu.op_reg_reg_reg_const_const(op: tasmop; _op1, _op2, _op3:
  259. tregister; _op4, _op5: aint);
  260. begin
  261. inherited create(op);
  262. ops := 5;
  263. loadreg(0, _op1);
  264. loadreg(1, _op2);
  265. loadreg(2, _op3);
  266. loadconst(3, cardinal(_op4));
  267. loadconst(4, cardinal(_op5));
  268. end;
  269. constructor taicpu.op_reg_reg_const_const_const(op: tasmop; _op1, _op2:
  270. tregister; _op3, _op4, _op5: aint);
  271. begin
  272. inherited create(op);
  273. ops := 5;
  274. loadreg(0, _op1);
  275. loadreg(1, _op2);
  276. loadconst(2, _op3);
  277. loadconst(3, _op4);
  278. loadconst(4, _op5);
  279. end;
  280. constructor taicpu.op_cond_sym(op: tasmop; cond: TAsmCond; _op1: tasmsymbol);
  281. begin
  282. inherited create(op);
  283. condition := cond;
  284. ops := 1;
  285. loadsymbol(0, _op1, 0);
  286. end;
  287. constructor taicpu.op_const_const_sym(op: tasmop; _op1, _op2: aint; _op3:
  288. tasmsymbol);
  289. begin
  290. inherited create(op);
  291. ops := 3;
  292. loadconst(0, _op1);
  293. loadconst(1, _op2);
  294. loadsymbol(2, _op3, 0);
  295. end;
  296. constructor taicpu.op_sym(op: tasmop; _op1: tasmsymbol);
  297. begin
  298. inherited create(op);
  299. ops := 1;
  300. loadsymbol(0, _op1, 0);
  301. end;
  302. constructor taicpu.op_sym_ofs(op: tasmop; _op1: tasmsymbol; _op1ofs: aint);
  303. begin
  304. inherited create(op);
  305. ops := 1;
  306. loadsymbol(0, _op1, _op1ofs);
  307. end;
  308. constructor taicpu.op_reg_sym_ofs(op: tasmop; _op1: tregister; _op2: tasmsymbol;
  309. _op2ofs: aint);
  310. begin
  311. inherited create(op);
  312. ops := 2;
  313. loadreg(0, _op1);
  314. loadsymbol(1, _op2, _op2ofs);
  315. end;
  316. constructor taicpu.op_sym_ofs_ref(op: tasmop; _op1: tasmsymbol; _op1ofs: aint;
  317. const _op2: treference);
  318. begin
  319. inherited create(op);
  320. ops := 2;
  321. loadsymbol(0, _op1, _op1ofs);
  322. loadref(1, _op2);
  323. end;
  324. { ****************************** newra stuff *************************** }
  325. function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
  326. begin
  327. result :=
  328. (((opcode=A_MR) and
  329. (regtype = R_INTREGISTER)) or
  330. ((opcode = A_FMR) and
  331. (regtype = R_FPUREGISTER))) and
  332. { these opcodes can only have registers as operands }
  333. (oper[0]^.reg=oper[1]^.reg);
  334. end;
  335. function taicpu.spilling_get_operation_type(opnr: longint): topertype;
  336. begin
  337. result := operand_read;
  338. case opcode of
  339. A_STMW,A_LMW:
  340. internalerror(2005021805);
  341. A_STBU, A_STBUX, A_STHU, A_STHUX,
  342. A_STWU, A_STWUX, A_STDU, A_STDUX,
  343. A_STFSU, A_STFSUX, A_STFDU, A_STFDUX,
  344. A_STB, A_STBX, A_STH, A_STHX,
  345. A_STW, A_STWX, A_STD, A_STDX,
  346. A_STFS, A_STFSX, A_STFD, A_STFDX, A_STFIWX, A_STHBRX, A_STWBRX, A_STWCX_, A_STDCX_,
  347. A_CMP, A_CMPI, A_CMPL, A_CMPLI, A_CMPD, A_CMPDI, A_CMPLD, A_CMPLDI,
  348. A_DCBA, A_DCBI, A_DCBST, A_DCBT, A_DCBTST, A_DCBZ,
  349. A_ECOWX, A_FCMPO, A_FCMPU, A_MTMSR, A_TLBIE, A_TW, A_TWI, A_MFXER,
  350. A_CMPWI, A_CMPW, A_CMPLWI, A_CMPLW, A_MT, A_MTLR, A_MTCTR:;
  351. else
  352. if opnr = 0 then
  353. result := operand_write;
  354. end;
  355. end;
  356. function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;
  357. begin
  358. result := operand_read;
  359. case opcode of
  360. A_STBU, A_STBUX, A_STHU, A_STHUX, A_STWU, A_STWUX, A_STDU, A_STDUX,
  361. A_STFSU, A_STFSUX, A_STFDU, A_STFDUX:
  362. if (oper[opnr]^.ref^.base = reg) then
  363. result := operand_readwrite;
  364. end;
  365. end;
  366. function spilling_create_load(const ref: treference; r: tregister): tai;
  367. begin
  368. case getregtype(r) of
  369. R_INTREGISTER:
  370. result:=taicpu.op_reg_ref(A_LD,r,ref);
  371. R_FPUREGISTER:
  372. result:=taicpu.op_reg_ref(A_LFD,r,ref);
  373. else
  374. internalerror(2005123101);
  375. end;
  376. end;
  377. function spilling_create_store(r: tregister; const ref: treference): tai;
  378. begin
  379. case getregtype(r) of
  380. R_INTREGISTER:
  381. result:=taicpu.op_reg_ref(A_STD,r,ref);
  382. R_FPUREGISTER:
  383. result:=taicpu.op_reg_ref(A_STFD,r,ref);
  384. else
  385. internalerror(2005123102);
  386. end;
  387. end;
  388. procedure InitAsm;
  389. begin
  390. end;
  391. procedure DoneAsm;
  392. begin
  393. end;
  394. procedure fixup_jmps(list: taasmoutput);
  395. var
  396. p: tai;
  397. newjmp: taicpu;
  398. labelpositions: tlist;
  399. instrpos: ptrint;
  400. l: tasmlabel;
  401. inserted_something: boolean;
  402. begin
  403. // if certainly not enough instructions to cause an overflow, don't bother
  404. if (list.count <= (high(smallint) div 4)) then
  405. exit;
  406. labelpositions := tlist.create;
  407. p := tai(list.first);
  408. instrpos := 1;
  409. // record label positions
  410. while assigned(p) do
  411. begin
  412. if p.typ = ait_label then
  413. begin
  414. if (tai_label(p).l.labelnr >= labelpositions.count) then
  415. labelpositions.count := tai_label(p).l.labelnr * 2;
  416. labelpositions[tai_label(p).l.labelnr] := pointer(instrpos);
  417. end;
  418. if p.typ = ait_instruction then
  419. inc(instrpos);
  420. p := tai(p.next);
  421. end;
  422. // check and fix distances
  423. repeat
  424. inserted_something := false;
  425. p := tai(list.first);
  426. instrpos := 1;
  427. while assigned(p) do
  428. begin
  429. case p.typ of
  430. ait_label:
  431. // update labelposition in case it changed due to insertion
  432. // of jumps
  433. begin
  434. // can happen because of newly inserted labels
  435. if (tai_label(p).l.labelnr > labelpositions.count) then
  436. labelpositions.count := tai_label(p).l.labelnr * 2;
  437. labelpositions[tai_label(p).l.labelnr] := pointer(instrpos);
  438. end;
  439. ait_instruction:
  440. begin
  441. inc(instrpos);
  442. case taicpu(p).opcode of
  443. A_BC:
  444. if (taicpu(p).oper[0]^.typ = top_ref) and
  445. assigned(taicpu(p).oper[0]^.ref^.symbol) and
  446. (taicpu(p).oper[0]^.ref^.symbol is tasmlabel) and
  447. (labelpositions[tasmlabel(taicpu(p).oper[0]^.ref^.symbol).labelnr] <> NIL) and
  448. (ptruint(abs(ptrint(labelpositions[tasmlabel(taicpu(p).oper[0]^.ref^.symbol).labelnr]-instrpos)) - (low(smallint) div 4)) > ptruint((high(smallint) - low(smallint)) div 4)) then
  449. begin
  450. // add a new label after this jump
  451. objectlibrary.getjumplabel(l);
  452. list.insertafter(tai_label.create(l),p);
  453. // add a new unconditional jump between this jump and the label
  454. newjmp := taicpu.op_sym(A_B,taicpu(p).oper[0]^.ref^.symbol);
  455. newjmp.is_jmp := true;
  456. newjmp.fileinfo := taicpu(p).fileinfo;
  457. list.insertafter(newjmp,p);
  458. inc(instrpos);
  459. // change the conditional jump to point to the newly inserted label
  460. tasmlabel(taicpu(p).oper[0]^.ref^.symbol).decrefs;
  461. taicpu(p).oper[0]^.ref^.symbol := l;
  462. l.increfs;
  463. // and invert its condition code
  464. taicpu(p).condition := inverse_cond(taicpu(p).condition);
  465. // we inserted an instruction, so will have to check everything again
  466. inserted_something := true;
  467. end;
  468. end;
  469. end;
  470. end;
  471. p := tai(p.next);
  472. end;
  473. until not inserted_something;
  474. labelpositions.free;
  475. end;
  476. begin
  477. cai_align := tai_align;
  478. cai_cpu := taicpu;
  479. end.