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