1 /* floatop.c - software operations on floats and doubles for bcc */
2
3 /* Copyright (C) 1992 Bruce Evans */
4
5 #include "bcc.h"
6 #include "gencode.h"
7 #include "reg.h"
8 #include "sc.h"
9 #include "scan.h"
10 #include "type.h"
11
12 /*-----------------------------------------------------------------------------
13 f_indirect(target leaf)
14 make the float or double target indirect if it is not already
15 return nonzero iff the result is a temp double on the base of the stack
16 -----------------------------------------------------------------------------*/
17
f_indirect(target)18 PUBLIC bool_pt f_indirect(target)
19 struct symstruct *target;
20 {
21 if (target->indcount == 0)
22 {
23 if (target->storage == CONSTANT)
24 {
25 #ifdef I80386
26 if (i386_32)
27 {
28 if (target->type->scalar & FLOAT)
29 {
30 float val;
31
32 val = *target->offset.offd;
33 push(constsym(((value_t *) &val)[0]));
34 }
35 else
36 {
37 push(constsym(((value_t *) target->offset.offd)[1]));
38 push(constsym(((value_t *) target->offset.offd)[0]));
39 }
40 }
41 else
42 #endif
43 {
44 if (target->type->scalar & FLOAT)
45 {
46 float val = *target->offset.offd;
47 push(constsym( ((unsigned short*) &val)[1] ));
48 push(constsym( ((unsigned short*) &val)[0] ));
49 }
50 else
51 {
52 push(constsym(((unsigned short*) target->offset.offd)[3]));
53 push(constsym(((unsigned short*) target->offset.offd)[2]));
54 push(constsym(((unsigned short*) target->offset.offd)[1]));
55 push(constsym(((unsigned short*) target->offset.offd)[0]));
56 }
57 }
58 }
59 else if (target->type->scalar & FLOAT)
60 pushlist(target->storage); /* XXX - floatregs */
61 else
62 pushlist(doubleregs);
63 onstack(target);
64 }
65 return target->flags == TEMP && target->type->scalar & DOUBLE
66 && target->offset.offi == sp;
67 }
68
69 /*-----------------------------------------------------------------------------
70 float1op(operation code, source leaf)
71 handles all flop unary operations except inc/dec
72 result is double on stack (or in condition codes for EQOP)
73 -----------------------------------------------------------------------------*/
74
float1op(op,source)75 PUBLIC void float1op(op, source)
76 op_pt op;
77 struct symstruct *source;
78 {
79 saveopreg();
80 pointat(source);
81 if ((op_t) op == NEGOP)
82 call("Fneg");
83 else /* op == EQOP */
84 call("Ftst");
85 outntypechar(source->type);
86 if ((op_t) op != EQOP)
87 justpushed(source);
88 restoreopreg();
89 }
90
91 /*-----------------------------------------------------------------------------
92 floatop(operation code, source leaf, target leaf)
93 handles all flop binary operations
94 result is double on stack (or in condition codes for EQOP)
95 ----------------------------------------------------------------------------*/
96
floatop(op,source,target)97 PUBLIC void floatop(op, source, target)
98 op_pt op;
99 struct symstruct *source;
100 struct symstruct *target;
101 {
102 store_t regmark;
103 bool_t sflag;
104
105 regmark = reguse;
106 saveopreg();
107 (void) f_indirect(source);
108 if (!(reguse & OPREG) && (source->storage == OPREG))
109 {
110 reguse |= source->storage;
111 saveopreg();
112 }
113 fpush(target);
114 sflag = TRUE;
115 if (source->flags != TEMP || source->offset.offi != sp + dtypesize)
116 {
117 sflag = FALSE;
118 if (source->storage == OPREG)
119 restoreopreg();
120 pointat(source);
121 }
122 switch ((op_t) op)
123 {
124 case ADDOP:
125 call("Fadd");
126 break;
127 case DIVOP:
128 call("Fdiv");
129 break;
130 case EQOP:
131 call("Fcomp");
132 sp += dtypesize; /* target is popped */
133 break; /* target symbol now invalid but is not used */
134 case MULOP:
135 call("Fmul");
136 break;
137 case SUBOP:
138 call("Fsub");
139 break;
140 }
141 if (sflag)
142 {
143 outnl();
144 sp += dtypesize; /* source is popped */
145 }
146 else
147 outntypechar(source->type);
148 onstack(target);
149 reguse = regmark; /* early so opreg is not reloaded if source */
150 restoreopreg();
151 }
152
153 /*-----------------------------------------------------------------------------
154 fpush(source leaf of scalar type)
155 converts source to double and pushes it to stack
156 OPREG must be free
157 -----------------------------------------------------------------------------*/
158
fpush(source)159 PUBLIC void fpush(source)
160 struct symstruct *source;
161 {
162 scalar_t scalar;
163
164 if ((scalar = source->type->scalar) & RSCALAR)
165 {
166 if (f_indirect(source))
167 return;
168 pointat(source);
169 }
170 else if (scalar & DLONG)
171 load(source, OPREG);
172 else
173 load(source, DREG);
174 call("Fpush");
175 if (scalar & UNSIGNED)
176 outbyte('u');
177 outntypechar(source->type);
178 justpushed(source);
179 }
180
181 /*-----------------------------------------------------------------------------
182 justpushed(target leaf)
183 records that target has just been pushed to a double on the stack
184 -----------------------------------------------------------------------------*/
185
justpushed(target)186 PUBLIC void justpushed(target)
187 struct symstruct *target;
188 {
189 sp -= dtypesize;
190 onstack(target);
191 target->type = dtype;
192 }
193