mach5.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /* $Id: mach5.c, v3.3 25-Apr-89 AJM */
  2. branch(brtyp, link, val)
  3. word_t brtyp;
  4. word_t link;
  5. valu_t val;
  6. {
  7. valu_t offset;
  8. offset = val - DOTVAL - 8; /* Allow for pipeline */
  9. if ((offset & 0xFC000000) != 0 && (offset & 0xFC000000) != 0xFC000000){
  10. serror("offset out of range");
  11. }
  12. offset = offset>>2 & 0xFFFFFF;
  13. emit4(brtyp|link|offset);
  14. return;
  15. }
  16. data(opc, ins, val, typ)
  17. long opc, ins;
  18. valu_t val;
  19. short typ;
  20. {
  21. valu_t tmpval;
  22. int adrflag = 0;
  23. if (typ == S_REG){ /* The argument is a register */
  24. emit4(opc|ins|val);
  25. return;
  26. }
  27. /* Do a bit of optimisation here, since the backend might produce instructions
  28. of the type MOV R0, R0, #0. We can ignore these. */
  29. if (((opc == ADD) || (opc == SUB)) && (val == 0)){ /* ADD or SUB 0 ? */
  30. if ((ins & 0x000F0000) == ((ins & 0x0000F000) << 4)) /* Same reg ? */
  31. return; /* Don't emit anything */
  32. }
  33. /* No optimisation, so carry on ... */
  34. ins |= 0x02000000; /* The argument is an immediate value */
  35. tmpval = val;
  36. if (opc == 0xff){ /* This is an ADR */
  37. adrflag = 1;
  38. opc = MOV;
  39. }
  40. if (typ == S_ABS){ /* An absolute value */
  41. if (calcimm(&opc, &tmpval, typ)){
  42. emit4(opc|ins|tmpval);
  43. return;
  44. }
  45. }
  46. tmpval = val;
  47. if (!adrflag){ /* Don't do this for ADRs */
  48. if (oursmall(calcimm(&opc, &tmpval, typ), 12)){
  49. emit4(opc|ins|tmpval);
  50. return;
  51. }
  52. }
  53. if (opc == MOV || opc == MVN || opc == ADD || opc == SUB){
  54. if (!bflag && pass == PASS_3){ /* Debugging info */
  55. /* warning("MOV/ADD extension"); */
  56. /* if (dflag)
  57. printf("value: %lx\n", val);*/
  58. }
  59. if (oursmall((val & 0xFFFF0000) == 0, 8)){
  60. putaddr(opc, ins, val, 2);
  61. return;
  62. }
  63. if (oursmall((val & 0xFF000000) == 0, 4)){
  64. putaddr(opc, ins, val, 3);
  65. return;
  66. }
  67. putaddr(opc, ins, val, 4);
  68. return;
  69. }
  70. if (pass == PASS_1)
  71. DOTVAL += 16; /* Worst case we can emit */
  72. else
  73. serror("immediate value out of range");
  74. return;
  75. }
  76. /* Calculate an immediate value. This is not as easy as it sounds, because
  77. the ARM uses an 8-bit value and 4-bit shift to encode the value into a
  78. 12-bit field. Unfortunately this means that some numbers may not fit at
  79. all. */
  80. calcimm(opc,val,typ)
  81. word_t *opc;
  82. valu_t *val;
  83. short typ;
  84. {
  85. int i = 0;
  86. if (typ == S_UND)
  87. return(0); /* Can't do anything with an undefined label */
  88. if ((*val & 0xFFFFFF00) == 0) /* Value is positive, but < 256, */
  89. return(1); /* so doesn't need a shift */
  90. if ((~*val & 0xFFFFFF00) == 0){ /* Value is negative, but < 256, */
  91. if (*opc == AND) /* so no shift required, only */
  92. { /* inversion */
  93. *val = ~*val;
  94. *opc = BIC;
  95. return(1);
  96. }
  97. if (*opc == MOV)
  98. {
  99. *val = ~*val;
  100. *opc = MVN;
  101. return(1);
  102. }
  103. if (*opc == ADC)
  104. {
  105. *val = ~*val;
  106. *opc = SBC;
  107. return(1);
  108. }
  109. }
  110. if ((-1**val & 0xFFFFFF00) == 0){ /* Same idea ... */
  111. if (*opc == ADD)
  112. {
  113. *val *= -1;
  114. *opc = SUB;
  115. return(1);
  116. }
  117. if (*opc == CMP)
  118. {
  119. *val *= -1;
  120. *opc = CMN;
  121. return(1);
  122. }
  123. }
  124. do{ /* Now we need to shift */
  125. rotateleft2(&*val); /* Rotate left by two bits */
  126. i++;
  127. if((*val & 0xFFFFFF00) == 0){ /* Got a value < 256 */
  128. *val = *val|i<<8; /* OR in the shift */
  129. return(1);
  130. }
  131. if ((~*val & 0xFFFFFF00) == 0){ /* If negative, carry out */
  132. if (*opc == AND) /* inversion as before */
  133. {
  134. *val = ~*val|i<<8;
  135. *opc = BIC;
  136. return(1);
  137. }
  138. if (*opc == MOV)
  139. {
  140. *val = ~*val|i<<8;
  141. *opc = MVN;
  142. return(1);
  143. }
  144. if (*opc == ADC)
  145. {
  146. *val = ~*val|i<<8;
  147. *opc = SBC;
  148. return(1);
  149. }
  150. }
  151. }while(i<15);
  152. return(0); /* Failed if can't encode it after 16 rotates */
  153. }
  154. /* Calculate an offset in an address */
  155. word_t
  156. calcoffset(val)
  157. valu_t val;
  158. {
  159. if((val & 0xFFFFF000) == 0)
  160. return(val|0x00800000);
  161. val *= -1;
  162. if((val & 0xFFFFF000) == 0)
  163. return(val);
  164. serror("offset out of range");
  165. return(0);
  166. }
  167. /* This routine deals with STR and LDR instructions */
  168. strldr(opc, ins, val)
  169. long opc, ins;
  170. valu_t val;
  171. {
  172. long reg, reg2; /* The registers we are using */
  173. long tmpval;
  174. /* If the expression was a register, then just output it and save 24
  175. bytes */
  176. if (success){
  177. emit4(opc|ins|val);
  178. return;
  179. }
  180. reg = ins & 0x0000F000; /* Extract register from instruction */
  181. if (opc == LDR){
  182. tmpval = val - DOTVAL - 8;
  183. if (oursmall((tmpval & 0xFFFFF000) == 0, 16)){ /* If it's +ve */
  184. emit4(opc|ins|tmpval|0x018F0000); /* PC rel, up bit */
  185. return;
  186. }
  187. tmpval *= -1;
  188. if (oursmall((tmpval & 0xFFFFF000) == 0, 16)){ /* If it's -ve */
  189. emit4(opc|ins|tmpval|0x010F0000); /* PC rel, no up bit */
  190. return;
  191. }
  192. if (!bflag && pass == PASS_3){ /* Debugging info */
  193. /* warning("LDR address extension"); */
  194. if (dflag)
  195. printf("value: %lx\n", val);
  196. }
  197. opc = 0x03A00000; /* Set opc for putaddr */
  198. if (oursmall((val & 0xFFFF0000) == 0, 8)){
  199. putaddr(opc, ins & 0xFFBFFFFF, val, 2);
  200. emit4(0x05100000|ins|reg<<4);
  201. return;
  202. }
  203. if (oursmall((val & 0xFF000000) == 0, 4)){
  204. putaddr(opc, ins & 0xFFBFFFFF, val, 3);
  205. emit4(0x05100000|ins|reg<<4);
  206. return;
  207. }
  208. putaddr(opc, ins & 0xFFBFFFFF, val, 4);
  209. emit4(0x05100000|ins|reg<<4);
  210. return;
  211. }
  212. /* If the failure was an STR instruction, things are a bit more complicated as
  213. we can't overwrite the register before we store its value. We therefore
  214. need to use another register as well, which must be saved and restored.
  215. This register is saved on a stack pointed to by R12. Apart from this
  216. complication, the scheme is similar to the LDR above. */
  217. if (opc == STR){
  218. reg2 = reg >> 12; /* Use R6 as the second register, */
  219. reg2 = (reg2 == 6 ? 0 : 6); /* or R0 if we can't */
  220. tmpval = val - DOTVAL - 8;
  221. if (oursmall((tmpval & 0xFFFFF000) == 0, 24)){ /* If it's +ve */
  222. emit4(opc|ins|tmpval|0x018F0000); /* PC rel, up bit */
  223. return;
  224. }
  225. tmpval *= -1;
  226. if (oursmall((tmpval & 0xFFFFF000) == 0, 24)){ /* If it's -ve */
  227. emit4(opc|ins|tmpval|0x010F0000); /* PC rel, no up bit */
  228. return;
  229. }
  230. if (!bflag && pass == PASS_3){ /* Debugging info */
  231. /* warning("STR address extension"); */
  232. if (dflag)
  233. printf("value: %lx\n", val);
  234. }
  235. opc = 0x03A00000; /* Set opc for putaddr */
  236. if (oursmall((val & 0xFFFF0000) == 0, 8)){
  237. emit4(0xE92C0000|1<<reg2);
  238. putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 2);
  239. emit4(0x05000000|ins|reg2<<16);
  240. emit4(0xE8BC0000|1<<reg2);
  241. return;
  242. }
  243. if (oursmall((val & 0xFF000000) == 0, 4)){
  244. emit4(0xE92C0000|1<<reg2);
  245. putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 3);
  246. emit4(0x05000000|ins|reg2<<16);
  247. emit4(0xE8BC0000|1<<reg2);
  248. return;
  249. }
  250. emit4(0xE92C0000|1<<reg2);
  251. putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 4);
  252. emit4(0x05000000|ins|reg2<<16);
  253. emit4(0xE8BC0000|1<<reg2);
  254. return;
  255. }
  256. }
  257. /* This routine deals with ADR instructions. The ARM does not have a
  258. 'calculate effective address' instruction, so we use ADD, SUB, MOV or
  259. MVN instead. ADR is not a genuine instruction, but is provided to make
  260. life easier. At present these are all calculated by using a MOV and
  261. successive ADDs. Even if the address will fit into a single MOV, we
  262. still use two instructions; the second is a no-op. This is to cure the
  263. optimisation problem with mobile addresses ! */
  264. calcadr(ins, reg, val, typ)
  265. word_t ins, reg;
  266. valu_t val;
  267. short typ;
  268. {
  269. valu_t tmpval = val;
  270. word_t opc = 0xff; /* Dummy opc used as a flag for data() */
  271. /* First check that the address is in range */
  272. if (val < 0)
  273. tmpval = ~tmpval; /* Invert negative addresses for check */
  274. if ((tmpval & 0xFC000000) && (typ != S_UND)){
  275. serror("adr address out of range");
  276. return;
  277. }
  278. /* Can't do it PC relative, so use an absolute MOV instead */
  279. data (opc, ins|reg<<12, val, typ);
  280. return;
  281. }
  282. word_t
  283. calcshft(val, typ, styp)
  284. valu_t val;
  285. short typ;
  286. word_t styp;
  287. {
  288. if (typ == S_UND)
  289. return(0);
  290. if (val & 0xFFFFFFE0)
  291. serror("shiftcount out of range");
  292. if (styp && !val)
  293. warning("shiftcount 0");
  294. return((val & 0x1F)<<7);
  295. }
  296. rotateleft2(x)
  297. long *x;
  298. {
  299. unsigned long bits;
  300. bits = *x & 0xC0000000;
  301. *x <<= 2 ;
  302. if (bits){
  303. bits >>= 30;
  304. *x |= bits;
  305. }
  306. return;
  307. }
  308. /*
  309. This routine overcomes the 12-bit encoding problem by outputting a number
  310. a byte at a time. For a MOV, it first uses a MOV, then successive ADDs.
  311. It will not use any more ADDs than needed to completely output the number.
  312. A similar approach is used for ADDs and SUBs.
  313. There is a problem here with optimisation in the third pass; if the
  314. instruction needed two ADDs in the second pass, but only one in the third
  315. pass, then the second ADD is replaced with a no-op. We cannot emit one
  316. less instruction, because that will upset other addresses.
  317. */
  318. putaddr(opc, ins, val, count)
  319. long opc, ins, val;
  320. int count;
  321. {
  322. long tmpval = val;
  323. long reg = ins & 0x0000F000;
  324. emit4(opc|ins|(val & 0x000000FF));
  325. tmpval = (val & 0x0000FF00) >> 8 | 0x00000C00;
  326. /* Decide what to use for the additional instructions */
  327. if (opc == 0x03a00000) /* This one is for strldr */
  328. opc = 0x02800000;
  329. if (opc == MOV)
  330. opc = ADD;
  331. if (opc == MVN)
  332. opc = SUB;
  333. if ((tmpval & 0x000000FF) != 0)
  334. emit4(opc|ins|reg<<4|tmpval);
  335. else
  336. emit4(0xF0000000); /* No-op if a zero argument */
  337. if (count == 3 || count == 4){ /* Must use three or more instructions */
  338. if ((val & 0xFFFF0000) != 0){
  339. tmpval = (val & 0x00FF0000) >> 16 | 0x00000800;
  340. emit4(opc|ins|reg<<4|tmpval);
  341. }
  342. else
  343. emit4(0xF0000000); /* No-op */
  344. }
  345. if (count == 4){ /* Must use four instructions */
  346. if ((val & 0xFF000000) != 0){
  347. tmpval = (val & 0xFF000000) >> 24 | 0x00000400;
  348. emit4(opc|ins|reg<<4|tmpval);
  349. }
  350. else
  351. emit4(0xF0000000); /* No-op */
  352. }
  353. return;
  354. }
  355. /* The following piece of code is stolen from comm7.c; it needs some minor
  356. fixes for the ARM, so it is included here rather than altering the existing
  357. code. It maintains a bit table to say whether or not an optimisation is
  358. possible. The original had some problems:
  359. (a). It assumed that the memory returned by malloc() was cleared to zero.
  360. This is true on a Sun, but not under Minix; small() should really
  361. use calloc() instead.
  362. (b). It assumed that if an optimisation was possible in pass 2, it must
  363. also be possible in pass 3, and produced an assertion error if it
  364. wasn't. This is OK for optimising things like long or short branch
  365. instructions on a 68000, but not for ADRs on the ARM. A previous
  366. optimisation may place an address out of 12-bit encoding range on
  367. pass 3, when it was in range on pass 2. However we have to be
  368. careful here .....
  369. */
  370. #define PBITTABSZ 128
  371. static char *pbittab[PBITTABSZ];
  372. oursmall(fitsmall, gain)
  373. {
  374. register bit;
  375. register char *p;
  376. if (DOTSCT == NULL)
  377. nosect();
  378. if (bflag)
  379. return(0);
  380. if (nbits == BITCHUNK) {
  381. bitindex++;
  382. nbits = 0;
  383. if (bitindex == PBITTABSZ) {
  384. static int w_given;
  385. if (pass == PASS_1 && ! w_given) {
  386. w_given = 1;
  387. warning("bit table overflow");
  388. }
  389. return(0);
  390. }
  391. if (pbittab[bitindex] == 0 && pass == PASS_1) {
  392. if ((pbittab[bitindex] = malloc(MEMINCR)) == 0) {
  393. static int w2_given;
  394. if (!w2_given) {
  395. w2_given = 1;
  396. warning("out of space for bit table");
  397. }
  398. }
  399. }
  400. if (pbittab[bitindex] == 0)
  401. return (0);
  402. }
  403. bit = 1 << (nbits&7);
  404. p = pbittab[bitindex]+(nbits>>3);
  405. nbits++;
  406. switch (pass) {
  407. case PASS_1:
  408. *p = 0;
  409. return(0);
  410. case PASS_2:
  411. if (fitsmall) {
  412. DOTGAIN += gain;
  413. *p |= bit;
  414. }
  415. return(fitsmall);
  416. case PASS_3:
  417. if (!(fitsmall || (*p & bit) == 0)){
  418. printf("line: %ld - small failed\n", lineno);
  419. printf("fitsmall: %d bit: %d\n", fitsmall, (*p & bit));
  420. if (fitsmall)
  421. return(0);
  422. else
  423. serror("This one is fatal!");
  424. }
  425. return(*p & bit);
  426. }
  427. /*NOTREACHED*/
  428. }