1 /* longop.c - software operations on longs for bcc */
2 
3 /* Copyright (C) 1992 Bruce Evans */
4 
5 #include "bcc.h"
6 #include "byteord.h"
7 #include "gencode.h"
8 #include "reg.h"
9 #include "scan.h"
10 #include "type.h"
11 
12 /*-----------------------------------------------------------------------------
13 	longop(operation code, source leaf, target leaf)
14 	handles all binary operations on longs
15 	source and target must already have been converted to long,
16 	(except source is int for shifts) and not more than singly indirect
17 	hence they must be direct (in an index reg paired with DREG),
18 	or singly indirect (local, global, or from an index reg)
19 -----------------------------------------------------------------------------*/
20 
longop(op,source,target)21 PUBLIC void longop(op, source, target)
22 op_pt op;
23 struct symstruct *source;
24 struct symstruct *target;
25 {
26     store_pt reglist;
27     store_t regmark;
28     bool_t shiftflag;
29     scalar_t scalar;
30     offset_T spmark;
31 
32     pushlist(reglist = (regmark = reguse) & (OPREG | OPWORKREG));
33     reguse &= ~reglist;
34     spmark = sp;
35     shiftflag = FALSE;
36     scalar = target->type->scalar;
37     if ((op_t) op == SLOP || (op_t) op == SROP)
38 	shiftflag = TRUE;
39     else
40 	scalar |= source->type->scalar;
41     if ((source->indcount == 0 && !shiftflag) ||
42 	source->type->scalar & CHAR ||
43 	source->storage & (BREG | DREG | OPREG | OPWORKREG))
44     {
45 	pres2(source, target);
46 	push(source);
47     }
48     if (!shiftflag)
49 	address(source);
50     load(target, OPREG);
51     if (source->storage == CONSTANT && shiftflag)
52     {
53 	if (scalar & UNSIGNED)
54 	    target->type = ultype;
55 	if ((op_t) op == SLOP)
56 	    source->offset.offv = lslconst(source->offset.offv,
57 					   target->storage);
58 	else
59 	    source->offset.offv = lsrconst(source->offset.offv,
60 					   target->storage, scalar & UNSIGNED);
61 	if (source->offset.offv == 0)
62 	    goto shiftdone;
63     }
64 #ifdef I8088
65     /* This is ugly! But it works. I should be able to stop it being used
66      * by removing the char demotion. */
67     if (source->type->scalar & CHAR &&
68 	  !(source->storage & (BREG|DREG|DATREG1B))) {
69 	load(source, DATREG1B);
70 	outop2str("xor\tch,ch"); outnl();
71 	source->storage = DATREG1;
72     }
73 #endif
74     load(source, OPWORKREG);
75     switch ((op_t) op)
76     {
77     case ADDOP:
78 	call("ladd");
79 	break;
80     case ANDOP:
81 	call("land");
82 	break;
83     case DIVOP:
84 	call("ldiv");
85 	break;
86     case EOROP:
87 	call("leor");
88 	break;
89     case EQOP:
90 	call("lcmp");
91 	break;
92     case MODOP:
93 	call("lmod");
94 	break;
95     case MULOP:
96 	call("lmul");
97 	break;
98     case OROP:
99 	call("lor");
100 	break;
101     case SLOP:
102 	call("lsl");
103 	break;
104     case SROP:
105 	call("lsr");
106 	break;
107     case SUBOP:
108 	call("lsub");
109 	break;
110     }
111     if (scalar & UNSIGNED)
112     {
113 	outbyte('u');
114 	target->type = ultype;
115     }
116     outlongendian();
117 
118 shiftdone:
119     if ((reguse = regmark) & OPREG && op != EQOP)
120 	load(target, getindexreg());
121     if (reglist)
122     {
123 #ifdef I8088
124 	if (op == EQOP)
125 	    changesp(spmark, FALSE);
126 	else
127 #endif
128 	    modstk(spmark);
129 	poplist(reglist);
130     }
131 }
132 
133 /*-----------------------------------------------------------------------------
134 	long1op(operation code, target leaf)
135 	handles all unary operations on longs except inc/dec
136 	target must be not more than singly indirect
137 	hence it must be direct (in an index reg paired with DREG),
138 	or singly indirect (local, global, or from an index reg)
139 -----------------------------------------------------------------------------*/
140 
long1op(op,target)141 PUBLIC void long1op(op, target)
142 op_pt op;
143 struct symstruct *target;
144 {
145     pushlist(reguse & OPREG);
146     load(target, OPREG);
147     if (op == NOTOP)
148 	call("lcom");
149     else if (op == NEGOP)
150 	call("lneg");
151     else
152 	call("ltst");
153     outlongendian();
154     if (reguse & OPREG)
155     {
156 	if (op != EQOP)
157 	    load(target, getindexreg());
158 	poplist(reguse & OPREG);
159     }
160 }
161 
outlongendian()162 PUBLIC void outlongendian()
163 {
164 #ifdef MC6809
165     outbyte('_');
166 #endif
167 #if DYNAMIC_LONG_ORDER
168     if (long_big_endian)
169 #endif
170 #if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
171 	outnbyte('b');
172 #endif
173 #if DYNAMIC_LONG_ORDER
174     else
175 #endif
176 #if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
177 	outnbyte('l');
178 #endif
179 }
180