output-ns32k.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /* Subroutines for assembler code output on the NS32000.
  2. Copyright (C) 1988 Free Software Foundation, Inc.
  3. This file is part of GNU CC.
  4. GNU CC is distributed in the hope that it will be useful,
  5. but WITHOUT ANY WARRANTY. No author or distributor
  6. accepts responsibility to anyone for the consequences of using it
  7. or for whether it serves any particular purpose or works at all,
  8. unless he says so in writing. Refer to the GNU CC General Public
  9. License for full details.
  10. Everyone is granted permission to copy, modify and redistribute
  11. GNU CC, but only under the conditions described in the
  12. GNU CC General Public License. A copy of this license is
  13. supposed to have been given to you along with GNU CC so you
  14. can know your rights and responsibilities. It should be in a
  15. file named COPYING. Among other things, the copyright notice
  16. and this notice must be preserved on all copies. */
  17. /* Some output-actions in m68000.md need these. */
  18. #include <stdio.h>
  19. extern FILE *asm_out_file;
  20. #define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16)
  21. /* Generate the rtx that comes from an address expression in the md file */
  22. /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
  23. scale must be converted from an exponent (from ASHIFT) to a
  24. muliplier (for MULT). */
  25. rtx
  26. gen_indexed_expr (base, index, scale)
  27. rtx base, index, scale;
  28. {
  29. rtx addr;
  30. /* This generates an illegal addressing mode, if BASE is
  31. fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
  32. if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
  33. base = gen_rtx (MEM, SImode, base);
  34. addr = gen_rtx (MULT, SImode, index,
  35. gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
  36. addr = gen_rtx (PLUS, SImode, base, addr);
  37. return addr;
  38. }
  39. /* Return 1 if OP is a valid constant int. These can be modeless
  40. (void mode), so we do not mess with their modes.
  41. The main use of this function is as a predicate in match_operand
  42. expressions in the machine description. */
  43. int
  44. const_int (op, mode)
  45. register rtx op;
  46. enum machine_mode mode;
  47. {
  48. return (GET_CODE (op) == CONST_INT);
  49. }
  50. /* Return the best assembler insn template
  51. for moving operands[1] into operands[0] as a fullword. */
  52. static char *
  53. singlemove_string (operands)
  54. rtx *operands;
  55. {
  56. if (GET_CODE (operands[1]) == CONST_INT
  57. && INTVAL (operands[1]) <= 7
  58. && INTVAL (operands[1]) >= -8)
  59. return "movqd %1,%0";
  60. return "movd %1,%0";
  61. }
  62. char *
  63. output_move_double (operands)
  64. rtx *operands;
  65. {
  66. enum { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  67. rtx latehalf[2];
  68. /* First classify both operands. */
  69. if (REG_P (operands[0]))
  70. optype0 = REGOP;
  71. else if (offsetable_memref_p (operands[0]))
  72. optype0 = OFFSOP;
  73. else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  74. optype0 = POPOP;
  75. else
  76. optype0 = RNDOP;
  77. if (REG_P (operands[1]))
  78. optype1 = REGOP;
  79. else if (CONSTANT_ADDRESS_P (operands[1])
  80. || GET_CODE (operands[1]) == CONST_DOUBLE)
  81. optype1 = CNSTOP;
  82. else if (offsetable_memref_p (operands[1]))
  83. optype1 = OFFSOP;
  84. else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  85. optype1 = POPOP;
  86. else
  87. optype1 = RNDOP;
  88. /* Check for the cases that the operand constraints are not
  89. supposed to allow to happen. Abort if we get one,
  90. because generating code for these cases is painful. */
  91. if (optype0 == RNDOP || optype1 == RNDOP)
  92. abort ();
  93. /* Ok, we can do one word at a time.
  94. Normally we do the low-numbered word first,
  95. but if either operand is autodecrementing then we
  96. do the high-numbered word first.
  97. In either case, set up in LATEHALF the operands to use
  98. for the high-numbered word and in some cases alter the
  99. operands in OPERANDS to be suitable for the low-numbered word. */
  100. if (optype0 == REGOP)
  101. latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  102. else if (optype0 == OFFSOP)
  103. latehalf[0] = adj_offsetable_operand (operands[0], 4);
  104. else
  105. latehalf[0] = operands[0];
  106. if (optype1 == REGOP)
  107. latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  108. else if (optype1 == OFFSOP)
  109. latehalf[1] = adj_offsetable_operand (operands[1], 4);
  110. else if (optype1 == CNSTOP)
  111. {
  112. if (CONSTANT_ADDRESS_P (operands[1]))
  113. latehalf[1] = const0_rtx;
  114. else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  115. {
  116. latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
  117. operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
  118. }
  119. }
  120. else
  121. latehalf[1] = operands[1];
  122. /* If one or both operands autodecrementing,
  123. do the two words, high-numbered first. */
  124. if (optype0 == POPOP || optype1 == POPOP)
  125. {
  126. output_asm_insn (singlemove_string (latehalf), latehalf);
  127. return singlemove_string (operands);
  128. }
  129. /* Not autodecrementing. Do the two words, low-numbered first. */
  130. output_asm_insn (singlemove_string (operands), operands);
  131. operands[0] = latehalf[0];
  132. operands[1] = latehalf[1];
  133. return singlemove_string (operands);
  134. }
  135. int
  136. check_reg (oper, reg)
  137. rtx oper;
  138. int reg;
  139. {
  140. register int i;
  141. if (oper == 0)
  142. return 0;
  143. switch (GET_CODE(oper))
  144. {
  145. case REG:
  146. return (REGNO(oper) == reg) ? 1 : 0;
  147. case MEM:
  148. return check_reg(XEXP(oper, 0), reg);
  149. case PLUS:
  150. case MULT:
  151. return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
  152. }
  153. return 0;
  154. }
  155. /* PRINT_OPERAND_ADDRESS is defined to call this function,
  156. which is easier to debug than putting all the code in
  157. a macro definition in tm-ns32k.h . */
  158. print_operand_address (file, addr)
  159. register FILE *file;
  160. register rtx addr;
  161. { register rtx reg1, reg2, breg, ireg;
  162. rtx offset;
  163. static char scales[] = { 'b', 'w', 'd', 0, 'q', };
  164. static char *reg_name[] = REGISTER_NAMES;
  165. retry:
  166. switch (GET_CODE (addr))
  167. {
  168. case MEM:
  169. addr = XEXP (addr, 0);
  170. if (GET_CODE (addr) == REG)
  171. if (REGNO (addr) == STACK_POINTER_REGNUM)
  172. { fprintf (file, "tos"); break; }
  173. else
  174. { fprintf (file, "%s", reg_name [REGNO (addr)]); break; }
  175. else if (CONSTANT_P (addr))
  176. { output_addr_const (file, addr); break; }
  177. else if (GET_CODE (addr) == MULT)
  178. { fprintf (file, "@0"); ireg = addr; goto print_index; }
  179. else if (GET_CODE (addr) == MEM)
  180. {
  181. addr = XEXP (addr, 0);
  182. if (GET_CODE (addr) == PLUS)
  183. {
  184. offset = XEXP (addr, 1);
  185. addr = XEXP (addr, 0);
  186. }
  187. else
  188. {
  189. offset = const0_rtx;
  190. }
  191. output_addr_const (file, offset);
  192. fprintf (file, "(%s)", reg_name [REGNO (addr)]);
  193. break;
  194. }
  195. if (GET_CODE (addr) != PLUS)
  196. abort ();
  197. goto retry;
  198. case REG:
  199. if (REGNO (addr) == STACK_POINTER_REGNUM)
  200. fprintf (file, "tos");
  201. else
  202. fprintf (file, "%s", reg_name [REGNO (addr)]);
  203. break;
  204. case PRE_DEC:
  205. case POST_INC:
  206. fprintf (file, "tos");
  207. break;
  208. case MULT:
  209. fprintf (file, "@0");
  210. ireg = addr; /* [rX:Y] */
  211. goto print_index;
  212. break;
  213. case PLUS:
  214. reg1 = 0; reg2 = 0;
  215. ireg = 0; breg = 0;
  216. offset = const0_rtx;
  217. if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  218. {
  219. offset = XEXP (addr, 0);
  220. addr = XEXP (addr, 1);
  221. }
  222. else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  223. {
  224. offset = XEXP (addr, 1);
  225. addr = XEXP (addr, 0);
  226. }
  227. if (GET_CODE (addr) != PLUS) ;
  228. else if (GET_CODE (XEXP (addr, 0)) == MULT)
  229. {
  230. reg1 = XEXP (addr, 0);
  231. addr = XEXP (addr, 1);
  232. }
  233. else if (GET_CODE (XEXP (addr, 1)) == MULT)
  234. {
  235. reg1 = XEXP (addr, 1);
  236. addr = XEXP (addr, 0);
  237. }
  238. /* The case for memory is somewhat tricky: to get
  239. a MEM here, the only RTX formats that could
  240. get here are either (modulo commutativity)
  241. (PLUS (PLUS (REG *MEM)) CONST) -or-
  242. (PLUS (PLUS (CONST REG/MULT)) *MEM)
  243. We take advantage of that knowledge here. */
  244. else if (GET_CODE (XEXP (addr, 0)) == MEM
  245. || GET_CODE (XEXP (addr, 1)) == MEM)
  246. {
  247. rtx temp;
  248. if (GET_CODE (XEXP (addr, 0)) == MEM)
  249. {
  250. temp = XEXP (addr, 1);
  251. addr = XEXP (addr, 0);
  252. }
  253. else
  254. {
  255. temp = XEXP (addr, 0);
  256. addr = XEXP (addr, 1);
  257. }
  258. if (GET_CODE (temp) == REG)
  259. {
  260. reg1 = temp;
  261. }
  262. else
  263. {
  264. if (GET_CODE (temp) != PLUS)
  265. abort ();
  266. if (GET_CODE (XEXP (temp, 0)) == MULT)
  267. {
  268. reg1 = XEXP (temp, 0);
  269. offset = XEXP (temp, 1);
  270. }
  271. if (GET_CODE (XEXP (temp, 1)) == MULT)
  272. {
  273. reg1 = XEXP (temp, 1);
  274. offset = XEXP (temp, 0);
  275. }
  276. else
  277. abort ();
  278. }
  279. }
  280. else if (GET_CODE (XEXP (addr, 0)) == REG
  281. || GET_CODE (XEXP (addr, 1)) == REG)
  282. {
  283. rtx temp;
  284. if (GET_CODE (XEXP (addr, 0)) == REG)
  285. {
  286. temp = XEXP (addr, 0);
  287. addr = XEXP (addr, 1);
  288. }
  289. else
  290. {
  291. temp = XEXP (addr, 1);
  292. addr = XEXP (addr, 0);
  293. }
  294. if (GET_CODE (addr) == REG)
  295. {
  296. if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  297. { reg1 = addr; addr = temp; }
  298. else
  299. { reg1 = temp; }
  300. }
  301. else if (CONSTANT_P (addr))
  302. {
  303. if (GET_CODE (offset) == CONST_INT
  304. && INTVAL (offset))
  305. offset = plus_constant (addr, INTVAL (offset));
  306. addr = temp;
  307. }
  308. else if (GET_CODE (addr) != PLUS)
  309. abort ();
  310. else
  311. {
  312. if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  313. {
  314. offset = XEXP (addr, 0);
  315. addr = XEXP (addr, 1);
  316. }
  317. else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  318. {
  319. offset = XEXP (addr, 1);
  320. addr = XEXP (addr, 0);
  321. }
  322. else abort ();
  323. if (GET_CODE (addr) == REG)
  324. {
  325. if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  326. { reg1 = addr; addr = temp; }
  327. else
  328. { reg1 = temp; }
  329. }
  330. else
  331. reg1 = temp;
  332. }
  333. }
  334. if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  335. { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; }
  336. if (addr != 0)
  337. { if (CONSTANT_P (addr) && reg1)
  338. {
  339. if (offset != const0_rtx)
  340. {
  341. output_addr_const (file, offset);
  342. putc ('+', file);
  343. }
  344. output_addr_const (file, addr);
  345. ireg = reg1;
  346. goto print_index;
  347. }
  348. else if (GET_CODE (addr) != MEM)
  349. abort ();
  350. output_addr_const (file, offset);
  351. if (! SEQUENT_ADDRESS_BUG) {
  352. putc ('(', file);
  353. output_address (addr);
  354. putc (')', file);
  355. } else {
  356. if ((GET_CODE (offset) == SYMBOL_REF
  357. || GET_CODE (offset) == CONST)
  358. && GET_CODE (addr) == REG) {
  359. if (reg1) abort ();
  360. fprintf (file, "[%s:b]", reg_name [REGNO (addr)]);
  361. }
  362. else {
  363. putc ('(', file);
  364. output_address (addr);
  365. putc (')', file);
  366. }
  367. }
  368. ireg = reg1;
  369. goto print_index;
  370. }
  371. else addr = offset;
  372. if (reg1 && GET_CODE (reg1) == MULT)
  373. { breg = reg2; ireg = reg1; }
  374. else if (reg2 && GET_CODE (reg2) == MULT)
  375. { breg = reg1; ireg = reg2; }
  376. else if (reg2 || GET_CODE (addr) == MEM)
  377. { breg = reg2; ireg = reg1; }
  378. else
  379. { breg = reg1; ireg = reg2; }
  380. if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF)
  381. { int scale;
  382. if (GET_CODE (ireg) == MULT)
  383. { scale = INTVAL (XEXP (ireg, 1)) >> 1;
  384. ireg = XEXP (ireg, 0); }
  385. else scale = 0;
  386. fprintf (file, "L%d[%s:%c]",
  387. CODE_LABEL_NUMBER (XEXP (addr, 0)),
  388. reg_name[REGNO (ireg)], scales[scale]);
  389. break; }
  390. if (ireg && breg && offset == const0_rtx)
  391. if (REGNO (breg) < 8)
  392. fprintf (file, "%s", reg_name[REGNO (breg)]);
  393. else fprintf (file, "0(%s)", reg_name[REGNO (breg)]);
  394. else {
  395. if (addr != 0)
  396. {
  397. if (ireg != 0 && breg == 0
  398. && GET_CODE (offset) == CONST_INT) putc('@', file);
  399. output_addr_const (file, offset);
  400. }
  401. if (breg != 0)
  402. { if (GET_CODE (breg) != REG) abort ();
  403. if (! SEQUENT_ADDRESS_BUG)
  404. fprintf (file, "(%s)", reg_name[REGNO (breg)]);
  405. else {
  406. if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST)
  407. if (ireg) abort ();
  408. else fprintf (file, "[%s:b]", reg_name[REGNO (breg)]);
  409. else
  410. fprintf (file, "(%s)", reg_name[REGNO (breg)]);
  411. }
  412. }
  413. }
  414. print_index:
  415. if (ireg != 0)
  416. { int scale;
  417. if (GET_CODE (ireg) == MULT) {
  418. scale = INTVAL (XEXP (ireg, 1)) >> 1;
  419. ireg = XEXP (ireg, 0);
  420. }
  421. else scale = 0;
  422. if (GET_CODE (ireg) != REG) abort ();
  423. fprintf (file, "[%s:%c]",
  424. reg_name[REGNO (ireg)],
  425. scales[scale]);
  426. }
  427. break;
  428. default:
  429. output_addr_const (file, addr);
  430. }
  431. }