Pristine Ack-5.5
[Ack-5.5.git] / mach / i386 / as / mach5.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 #define RCSID5 "$Id: mach5.c,v 1.8 1994/06/24 07:25:30 ceriel Exp $"
6
7 /*
8  * INTEL 80386 special routines
9  */
10
11 ea_1_16(param)
12 {
13         reg_1 &= 0377;
14         if ((reg_1 & 070) || (param & ~070)) {
15                 serror("bad operand");
16         }
17         emit1(reg_1 | param);
18         switch(reg_1 >> 6) {
19         case 0:
20                 if (reg_1 == 6 || (reg_1 & 040)) {
21 #ifdef RELOCATION
22                         RELOMOVE(relonami, rel_1);
23                         newrelo(exp_1.typ, RELO2);
24 #endif
25                         emit2(exp_1.val);
26                 }
27                 break;
28         case 1:
29                 emit1(exp_1.val);
30                 break;
31         case 2:
32 #ifdef RELOCATION
33                 RELOMOVE(relonami, rel_1);
34                 newrelo(exp_1.typ, RELO2);
35 #endif
36                 emit2(exp_1.val);
37                 break;
38         }
39 }
40
41 ea_1(param) {
42         if (! address_long) {
43                 ea_1_16(param);
44                 return;
45         }
46         if (is_expr(reg_1)) {
47                 serror("bad operand");
48                 return;
49         }
50         if (is_reg(reg_1)) {
51                 emit1(0300 | param | (reg_1&07));
52                 return;
53         }
54         if (rm_1 == 04) {
55                 /* sib field use here */
56                 emit1(mod_1 << 6 | param | 04);
57                 emit1(sib_1 | reg_1);
58         }
59         else emit1(mod_1<<6 | param | (reg_1&07));
60         if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
61                 /* ??? should this be protected by a call to "small" ??? */
62 #ifdef RELOCATION
63                 RELOMOVE(relonami, rel_1);
64                 newrelo(exp_1.typ, RELO4);
65 #endif
66                 emit4((long)(exp_1.val));
67         }
68         else if (mod_1 == 1) {
69                 emit1((int)(exp_1.val));
70         }
71 }
72
73 ea_2(param) {
74
75         op_1 = op_2;
76         RELOMOVE(rel_1, rel_2);
77         ea_1(param);
78 }
79
80 int
81 checkscale(val)
82         valu_t val;
83 {
84         int v = val;
85
86         if (! address_long) {
87                 serror("scaling not allowed in 16-bit mode");
88                 return 0;
89         }
90         if (v != val) v = 0;
91         switch(v) {
92         case 1:
93                 return 0;
94         case 2:
95                 return 1 << 6;
96         case 4:
97                 return 2 << 6;
98         case 8:
99                 return 3 << 6;
100         default:
101                 serror("bad scale");
102                 return 0;
103         }
104         /*NOTREACHED*/
105 }
106
107 reverse() {
108         struct operand op;
109 #ifdef RELOCATION
110         int r = rel_1;
111
112         rel_1 = rel_2; rel_2 = r;
113 #endif
114         op = op_1; op_1 = op_2; op_2 = op;
115 }
116
117 badsyntax() {
118
119         serror("bad operands");
120 }
121
122 regsize(sz)
123         int sz;
124 {
125         register int bit;
126
127         bit = (sz&1) ? 0 : IS_R8;
128         if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
129             (is_reg(reg_2) && (reg_2 & IS_R8) != bit)) 
130                 serror("register error");
131         if (! address_long) {
132                 reg_1 &= ~010;
133                 reg_2 &= ~010;
134         }
135 }
136
137 indexed() {
138         if (address_long) {
139                 mod_2 = 0;
140                 if (sib_2 == -1)
141                         serror("register error");
142                 if (rm_2 == 0 && reg_2 == 4) {
143                         /* base register sp, no index register; use
144                            indexed mode without index register
145                         */
146                         rm_2 = 04;
147                         sib_2 = 044;
148                 }
149                 if (reg_2 == 015) {
150                         reg_2 = 05;
151                         return;
152                 }
153                 if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
154                         if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
155                         }
156                         else mod_2 = 01;
157                 }
158                 else    if (small(0, 1)) {
159                 }
160                 else mod_2 = 02;
161         }
162         else {
163                 if (reg_2 & ~7)
164                         serror("register error");
165                 if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
166                         if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
167                         }
168                         else reg_2 |= 0100;
169                 }
170                 else if (small(0, 1)) {
171                 }
172                 else reg_2 |= 0200;
173         }
174 }
175
176 ebranch(opc,exp)
177         register int opc;
178         expr_t exp;
179 {
180         /*      Conditional branching; Full displacements are available
181                 on the 80386, so the welknown trick with the reverse branch
182                 over a jump is not needed here.
183                 The only complication here is with the address size, which
184                 can be set with a prefix. In this case, the user gets what
185                 he asked for.
186         */
187         register int sm;
188         register long dist;
189         int saving = address_long ? 4 : 2;
190
191         if (opc == 0353) saving--;
192         dist = exp.val - (DOTVAL + 2);
193         if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
194                 dist -= DOTGAIN;
195         sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
196         if ((exp.typ & ~S_DOT) != DOTTYP)
197                 sm = 0;
198         if ((sm = small(sm,saving)) == 0) {
199                 if (opc == 0353) {
200                         emit1(0xe9);
201                 }
202                 else {
203                         emit1(0xF);
204                         emit1(opc | 0x80);
205                 }
206                 dist -= saving;
207                 exp.val = dist;
208                 adsize_exp(exp, RELPC);
209         }
210         else {
211                 if (opc == 0353) {
212                         emit1(opc);
213                 }
214                 else {
215                         emit1(opc | 0x70);
216                 }
217                 emit1((int)dist);
218         }
219 }
220
221 branch(opc,exp)
222         register int opc;
223         expr_t exp;
224 {
225         /*      LOOP, JCXZ, etc. branch instructions.
226                 Here, the offset just must fit in a byte.
227         */
228         register long dist;
229
230         dist = exp.val - (DOTVAL + 2);
231         if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
232                 dist -= DOTGAIN;
233         fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
234         emit1(opc);
235         emit1((int)dist);
236 }
237
238 pushop(opc)
239         register int opc;
240 {
241
242         regsize(1);
243         if (is_segreg(reg_1)) {
244                 /* segment register */
245                 if ((reg_1 & 07) <= 3)
246                         emit1(6 | opc | (reg_1&7)<<3);
247                 else {
248                         emit1(0xF);
249                         emit1(0200 | opc | ((reg_1&7)<<3));
250                 }
251         } else if (is_reg(reg_1)) {
252                 /* normal register */
253                 emit1(0120 | opc<<3 | (reg_1&7));
254         } else if (opc == 0) {
255                 if (is_expr(reg_1)) {
256                         if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
257                                   operand_long ? 3 : 1)) {
258                                 emit1(0152);
259                                 emit1((int)(exp_1.val));
260                         }
261                         else {
262                                 emit1(0150);
263                                 RELOMOVE(relonami, rel_1);
264                                 opsize_exp(exp_1, 1);
265                         }
266                 }
267                 else {
268                         emit1(0377); ea_1(6<<3);
269                 }
270         } else {
271                 emit1(0217); ea_1(0<<3);
272         }
273 }
274
275 opsize_exp(exp, nobyte)
276         expr_t exp;
277 {
278         if (! nobyte) {
279 #ifdef RELOCATION
280                 newrelo(exp.typ, RELO1);
281 #endif
282                 emit1((int)(exp.val));
283         }
284         else if (operand_long) {
285 #ifdef RELOCATION
286                 newrelo(exp.typ, RELO4);
287 #endif
288                 emit4((long)(exp.val));
289         }
290         else {
291 #ifdef RELOCATION
292                 newrelo(exp.typ, RELO2);
293 #endif
294                 emit2((int)(exp.val));
295         }
296 }
297
298 adsize_exp(exp, relpc)
299         expr_t exp;
300 {
301         if (address_long) {
302 #ifdef RELOCATION
303                 newrelo(exp.typ, RELO4 | relpc);
304 #endif
305                 emit4((long)(exp.val));
306         }
307         else {
308 #ifdef RELOCATION
309                 newrelo(exp.typ, RELO2 | relpc);
310 #endif
311                 emit2((int)(exp.val));
312         }
313 }
314
315 addop(opc) 
316         register int opc;
317 {
318
319         regsize(opc);
320         if (is_reg(reg_2)) {
321                 /*      Add register to register or memory */
322                 emit1(opc); ea_1((reg_2&7)<<3);
323         } else if (is_acc(reg_1) && is_expr(reg_2)) {
324                 /*      Add immediate to accumulator */
325                 emit1(opc | 4);
326                 RELOMOVE(relonami, rel_2);
327                 opsize_exp(exp_2, (opc&1));
328         } else if (is_expr(reg_2)) {
329                 /*      Add immediate to register or memory */
330                 if ((opc&1) == 0) {
331                         emit1(0200);
332                 } else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
333                                    operand_long ? 3 : 1)) {
334                         emit1(0201);
335                 } else {
336                         emit1(0203); opc &= ~1;
337                 }
338                 ea_1(opc & 070);
339                 RELOMOVE(relonami, rel_2);
340                 opsize_exp(exp_2, (opc&1));
341         } else if (is_reg(reg_1)) {
342                 /*      Add register or memory to register */
343                 emit1(opc | 2);
344                 ea_2((reg_1&7)<<3);
345         } else
346                 badsyntax();
347 }
348
349 rolop(opc)
350         register int opc;
351 {
352         register int oreg;
353
354         oreg = reg_2;
355         reg_2 = reg_1;
356         regsize(opc);
357         if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
358                 /* cl register */
359                 emit1(0322 | (opc&1)); ea_1(opc&070);
360         } else if (is_expr(oreg)) {
361             if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
362                 /* shift by 1 */
363                 emit1(0320 | (opc&1)); ea_1(opc&070);
364             } else {
365                 /* shift by byte count */
366                 emit1(0300 | (opc & 1)); 
367                 ea_1(opc & 070);
368 #ifdef RELOCATION
369                 RELOMOVE(relonami, rel_2);
370                 newrelo(exp_2.typ, RELO1);
371 #endif
372                 emit1((int)(exp_2.val));
373             }
374         }
375         else
376                 badsyntax();
377 }
378
379 incop(opc)
380         register int opc;
381 {
382
383         regsize(opc);
384         if ((opc&1) && is_reg(reg_1)) {
385                 /* word register */
386                 emit1(0100 | (opc&010) | (reg_1&7));
387         } else {
388                 emit1(0376 | (opc&1));
389                 ea_1(opc & 010);
390         }
391 }
392
393 callop(opc) 
394         register int opc;
395 {
396
397         regsize(1);
398         if (is_expr(reg_1)) {
399                 if (opc == (040+(0351<<8))) {
400                         RELOMOVE(relonami, rel_1);
401                         ebranch(0353,exp_1);
402                 } else {
403                         exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
404                         emit1(opc>>8);
405                         RELOMOVE(relonami, rel_1);
406                         adsize_exp(exp_1, RELPC);
407                 }
408         } else {
409                 emit1(0377); ea_1(opc&070);
410         }
411 }
412
413 xchg(opc)
414         register int opc;
415 {
416
417         regsize(opc);
418         if (! is_reg(reg_1) || is_acc(reg_2)) {
419                 reverse();
420         }
421         if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
422                 emit1(0220 | (reg_2&7));
423         } else if (is_reg(reg_1)) {
424                 emit1(0206 | opc); ea_2((reg_1&7)<<3);
425         } else
426                 badsyntax();
427 }
428
429 test(opc)
430         register int opc;
431 {
432
433         regsize(opc);
434         if (is_reg(reg_2) || is_expr(reg_1))
435                 reverse();
436         if (is_expr(reg_2)) {
437                 if (is_acc(reg_1)) {
438                         emit1(0250 | opc);
439                         RELOMOVE(relonami, rel_2);
440                         opsize_exp(exp_2, (opc&1));
441                 }
442                 else {
443                         emit1(0366 | opc);
444                         ea_1(0<<3);
445                         RELOMOVE(relonami, rel_2);
446                         opsize_exp(exp_2, (opc&1));
447                 }
448         } else if (is_reg(reg_1)) {
449                 emit1(0204 | opc); ea_2((reg_1&7)<<3);
450         } else
451                 badsyntax();
452 }
453
454 mov(opc)
455         register int opc;
456 {
457
458         regsize(opc);
459         if (is_segreg(reg_1)) {
460                 /* to segment register */
461                 emit1(0216); ea_2((reg_1&07)<<3);
462         } else if (is_segreg(reg_2)) {
463                 /* from segment register */
464                 emit1(0214); ea_1((reg_2&07)<<3);
465         } else if (is_expr(reg_2)) {
466                 /* from immediate */
467                 if (is_reg(reg_1)) {
468                         /* to register */
469                         emit1(0260 | opc<<3 | (reg_1&7)); 
470                 } else {
471                         /* to memory */
472                         emit1(0306 | opc); ea_1(0<<3); 
473                 }
474                 RELOMOVE(relonami, rel_2);
475                 opsize_exp(exp_2, (opc&1));
476         } else if (rm_1 == 05 && is_acc(reg_2)) {
477                 /* from accumulator to memory  (displacement) */
478                 emit1(0242 | opc);
479                 RELOMOVE(relonami, rel_1);
480                 adsize_exp(exp_1, 0);
481         } else if (rm_2 == 05 && is_acc(reg_1)) {
482                 /* from memory (displacement) to accumulator */
483                 emit1(0240 | opc);
484                 RELOMOVE(relonami, rel_2);
485                 adsize_exp(exp_2, 0);
486         } else if (is_reg(reg_2)) {
487                 /* from register to memory or register */
488                 emit1(0210 | opc); ea_1((reg_2&07)<<3);
489         } else if (is_reg(reg_1)) {
490                 /* from memory or register to register */
491                 emit1(0212 | opc); ea_2((reg_1&07)<<3);
492         } else
493                 badsyntax();
494 }
495
496 extshft(opc, reg)
497         int opc;
498 {
499         int oreg2 = reg_2;
500
501         reg_2 = reg_1;
502         regsize(1);
503
504         emit1(0xF);
505         if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
506                 /* cl register */
507                 emit1(opc|1);
508                 ea_1(reg << 3);
509         }
510         else if (is_expr(oreg2)) {
511                 emit1(opc);
512                 ea_1(reg << 3);
513 #ifdef RELOCATION
514                 RELOMOVE(relonami, rel_2);
515                 newrelo(exp_2.typ, RELO1);
516 #endif
517                 emit1((int)(exp_2.val));
518         }
519         else    badsyntax();
520 }
521
522 bittestop(opc)
523         int opc;
524 {
525         regsize(1);
526         emit1(0xF);
527         if (is_expr(reg_2)) {
528                 emit1(0272);
529                 ea_1(opc << 3);
530 #ifdef RELOCATION
531                 RELOMOVE(relonami, rel_2);
532                 newrelo(exp_2.typ, RELO1);
533 #endif
534                 emit1((int)(exp_2.val));
535         }
536         else if (is_reg(reg_2)) {
537                 emit1(0203 | (opc<<3));
538                 ea_1((reg_2&7)<<3);
539         }
540         else    badsyntax();
541 }
542
543 imul(reg)
544         int reg;
545 {
546         /*      This instruction is more elaborate on the 80386. Its most
547                 general form is:
548                         imul reg, reg_or_mem, immediate.
549                 This is the form processed here.
550         */
551         regsize(1);
552         if (is_expr(reg_1)) {
553                 /* To also handle
554                         imul reg, immediate, reg_or_mem
555                 */
556                 reverse();
557         }
558         if (is_expr(reg_2)) {
559                 /* The immediate form; two cases: */
560                 if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
561                           operand_long ? 3 : 1)) {
562                         /* case 1: 1 byte encoding of immediate */
563                         emit1(0153);
564                         ea_1((reg & 07) << 3);
565                         emit1((int)(exp_2.val));
566                 }
567                 else {
568                         /* case 2: WORD or DWORD encoding of immediate */
569                         emit1(0151);
570                         ea_1((reg & 07) << 3);
571                         RELOMOVE(relonami, rel_2);
572                         opsize_exp(exp_2, 1);
573                 }
574         }
575         else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
576                 /* the "reg" field and the "reg_or_mem" field are the same,
577                    and the 3rd operand is not an immediate ...
578                 */
579                 if (reg == 0) {
580                         /* how lucky we are, the target is the ax register */
581                         /* However, we cannot make an optimization for f.i.
582                                 imul eax, blablabla
583                            because the latter does not affect edx, whereas
584                                 imul blablabla
585                            does! Therefore, "reg" is or-ed with 0x10 in the
586                            former case, so that the test above fails.
587                         */
588                         emit1(0367);
589                         ea_2(050);
590                 }
591                 else {
592                         /* another register ... */
593                         emit1(0xF);
594                         emit1(0257);
595                         ea_2((reg & 07) << 3);
596                 }
597         }
598         else badsyntax();
599 }