Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Annotation of /sml/branches/SMLNJ/src/MLRISC/alpha32/alpha32.sml
ViewVC logotype

Annotation of /sml/branches/SMLNJ/src/MLRISC/alpha32/alpha32.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 139 - (view) (download)

1 : monnier 16 (* alpha32.sml
2 :     *
3 :     * COPYRIGHT (c) 1995 AT&T Bell Laboratories.
4 :     *
5 :     * generates machine code from the mltree.
6 :     *
7 :     *)
8 :    
9 :     (** NOTE: f29 and f30 are used as temporaries.
10 :     ** r31 is always zero.
11 :     **)
12 :     functor Alpha32
13 :     (structure Alpha32Instr : ALPHA32INSTR
14 :     structure Alpha32MLTree : MLTREE
15 :     structure Flowgen : FLOWGRAPH_GEN
16 :     structure PseudoInstrs : ALPHA32_PSEUDO_INSTR
17 :     sharing Alpha32Instr.Region = Alpha32MLTree.Region
18 :     sharing Flowgen.I = PseudoInstrs.I = Alpha32Instr
19 :     sharing Flowgen.T=Alpha32MLTree
20 : monnier 127 sharing Alpha32MLTree.Constant = Alpha32Instr.Constant
21 :     sharing Alpha32MLTree.BNames = Flowgen.B) : MLTREECOMP =
22 : monnier 16 struct
23 :     structure F = Flowgen
24 :     structure T = Alpha32MLTree
25 :     structure R = Alpha32MLTree.Region
26 :     structure I = Alpha32Instr
27 :     structure C = Alpha32Instr.C
28 :     structure LE = LabelExp
29 :     structure W32 = Word32
30 : monnier 106
31 : monnier 16 (*********************************************************
32 :    
33 :     Trap Shadows, Floating Exceptions, and Denormalized
34 :     Numbers on the DEC Alpha
35 :    
36 :     Andrew W. Appel and Lal George
37 :     Nov 28, 1995
38 :    
39 :     See section 4.7.5.1 of the Alpha Architecture Reference Manual.
40 :    
41 :     The Alpha has imprecise exceptions, meaning that if a floating
42 :     point instruction raises an IEEE exception, the exception may
43 :     not interrupt the processor until several successive instructions have
44 :     completed. ML, on the other hand, may want a "precise" model
45 :     of floating point exceptions.
46 :    
47 :     Furthermore, the Alpha hardware does not support denormalized numbers
48 :     (for "gradual underflow"). Instead, underflow always rounds to zero.
49 :     However, each floating operation (add, mult, etc.) has a trapping
50 :     variant that will raise an exception (imprecisely, of course) on
51 :     underflow; in that case, the instruction will produce a zero result
52 :     AND an exception will occur. In fact, there are several variants
53 :     of each instruction; three variants of MULT are:
54 :    
55 :     MULT s1,s2,d truncate denormalized result to zero; no exception
56 :     MULT/U s1,s2,d truncate denormalized result to zero; raise UNDERFLOW
57 :     MULT/SU s1,s2,d software completion, producing denormalized result
58 :    
59 :     The hardware treats the MULT/U and MULT/SU instructions identically,
60 :     truncating a denormalized result to zero and raising the UNDERFLOW
61 :     exception. But the operating system, on an UNDERFLOW exception,
62 :     examines the faulting instruction to see if it's an /SU form, and if so,
63 :     recalculates s1*s2, puts the right answer in d, and continues,
64 :     all without invoking the user's signal handler.
65 :    
66 :     Because most machines compute with denormalized numbers in hardware,
67 :     to maximize portability of SML programs, we use the MULT/SU form.
68 :     (and ADD/SU, SUB/SU, etc.) But to use this form successfully,
69 :     certain rules have to be followed. Basically, d cannot be the same
70 :     register as s1 or s2, because the opsys needs to be able to
71 :     recalculate the operation using the original contents of s1 and s2,
72 :     and the MULT/SU instruction will overwrite d even if it traps.
73 :    
74 :     More generally, we may want to have a sequence of floating-point
75 :     instructions. The rules for such a sequence are:
76 :    
77 :     1. The sequence should end with a TRAPB (trap barrier) instruction.
78 :     (This could be relaxed somewhat, but certainly a TRAPB would
79 :     be a good idea sometime before the next branch instruction or
80 :     update of an ML reference variable, or any other ML side effect.)
81 :     2. No instruction in the sequence should destroy any operand of itself
82 :     or of any previous instruction in the sequence.
83 :     3. No two instructions in the sequence should write the same destination
84 :     register.
85 :    
86 :     We can achieve these conditions by the following trick in the
87 :     Alpha code generator. Each instruction in the sequence will write
88 :     to a different temporary; this is guaranteed by the translation from
89 :     ML-RISC. At the beginning of the sequence, we will put a special
90 :     pseudo-instruction (we call it DEFFREG) that "defines" the destination
91 :     register of the arithmetic instruction. If there are K arithmetic
92 :     instructions in the sequence, then we'll insert K DEFFREG instructions
93 :     all at the beginning of the sequence.
94 :     Then, each arithop will not only "define" its destination temporary
95 :     but will "use" it as well. When all these instructions are fed to
96 :     the liveness analyzer, the resulting interference graph will then
97 :     have inteference edges satisfying conditions 2 and 3 above.
98 :    
99 :     Of course, DEFFREG doesn't actually generate any code. In our model
100 :     of the Alpha, every instruction generates exactly 4 bytes of code
101 :     except the "span-dependent" ones. Therefore, we'll specify DEFFREG
102 :     as a span-dependent instruction whose minimum and maximum sizes are zero.
103 :    
104 :     At the moment, we do not group arithmetic operations into sequences;
105 :     that is, each arithop will be preceded by a single DEFFREG and
106 :     followed by a TRAPB. To avoid the cost of all those TRAPB's, we
107 :     should improve this when we have time. Warning: Don't put more
108 :     than 31 instructions in the sequence, because they're all required
109 :     to write to different destination registers!
110 :    
111 :     What about multiple traps? For example, suppose a sequence of
112 :     instructions produces an Overflow and a Divide-by-Zero exception?
113 :     ML would like to know only about the earliest trap, but the hardware
114 :     will report BOTH traps to the operating system. However, as long
115 :     as the rules above are followed (and the software-completion versions
116 :     of the arithmetic instructions are used), the operating system will
117 :     have enough information to know which instruction produced the
118 :     trap. It is very probable that the operating system will report ONLY
119 :     the earlier trap to the user process, but I'm not sure.
120 :    
121 :     For a hint about what the operating system is doing in its own
122 :     trap-handler (with software completion), see section 6.3.2 of
123 :     "OpenVMS Alpha Software" (Part II of the Alpha Architecture
124 :     Manual). This stuff should apply to Unix (OSF1) as well as VMS.
125 :    
126 :     ****************************************************************)
127 :    
128 :     fun error msg = MLRiscErrorMsg.impossible ("Alpha32." ^ msg)
129 :    
130 :     val itow = Word.fromInt
131 :     val wtoi = Word.toIntX
132 :    
133 :     val emit = F.emitInstr
134 :    
135 :     val zeroR = 31
136 :     val zeroOp = I.REGop zeroR
137 :     val zeroEA = I.Direct zeroR
138 :     val argReg0 = 16
139 :    
140 :     val mem = R.memory
141 :    
142 :     fun cond T.LT = I.CC_LT | cond T.LTU = I.CC_LTU
143 :     | cond T.LE = I.CC_LE | cond T.LEU = I.CC_LEU
144 :     | cond T.EQ = I.CC_EQ | cond T.NEQ = I.CC_NEQ
145 :     | cond T.GE = I.CC_GE | cond T.GEU = I.CC_GEU
146 :     | cond T.GT = I.CC_GT | cond T.GTU = I.CC_GTU
147 :    
148 :     fun swapcc I.CC_LT = I.CC_GT | swapcc I.CC_LTU = I.CC_GTU
149 :     | swapcc I.CC_LE = I.CC_GE | swapcc I.CC_LEU = I.CC_GEU
150 :     | swapcc I.CC_EQ = I.CC_EQ | swapcc I.CC_NEQ = I.CC_NEQ
151 :     | swapcc I.CC_GT = I.CC_LT | swapcc I.CC_GEU = I.CC_LEU
152 :     | swapcc I.CC_GE = I.CC_LE | swapcc _ = error "swapcc"
153 :    
154 :     (* NOTE: stack allocation must be multiples of 16 *)
155 :     fun stackAllocate(n) =
156 :     I.OPERATE{oper=I.SUBL, ra=C.stackptrR, rb=I.IMMop n, rc=C.stackptrR}
157 :    
158 :     fun stackDeallocate(n) =
159 :     I.OPERATE{oper=I.ADDL, ra=C.stackptrR, rb=I.IMMop n, rc=C.stackptrR}
160 :    
161 :     fun loadImmed(n, base, rd) =
162 :     if ~32768 <= n andalso n < 32768 then
163 :     emit(I.LDA{r=rd, b=base, d=I.IMMop n})
164 :     else let
165 :     val w = itow n
166 :     val hi = Word.~>>(w, 0w16)
167 :     val lo = Word.andb(w, 0w65535)
168 :     val (hi', lo') =
169 :     if lo < 0w32768 then (hi, lo) else (hi+0w1, lo-0w65536)
170 :     in
171 :     emit(I.LDA{r=rd, b=base, d=I.IMMop(wtoi lo')});
172 :     emit(I.LDAH{r=rd, b=rd, d=I.IMMop(wtoi hi')})
173 :     end
174 :    
175 :     (* loadImmed32 is used to load int32 and word32 constants.
176 :     * In either case we sign extend the 32-bit value. This is compatible
177 :     * with LDL which sign extends a 32-bit valued memory location.
178 :     *)
179 : monnier 123 fun loadImmed32(0w0, base, rd) =
180 :     emit(I.OPERATE{oper=I.ADDL, ra=base, rb=zeroOp, rc=rd})
181 :     | loadImmed32(n, base, rd) = let
182 :     val low = W32.andb(n, 0w65535) (* unsigned (0 .. 65535) *)
183 :     val high = W32.~>>(n, 0w16) (* signed (~32768 .. 32768] *)
184 :     fun loadimmed(0, high) = emit(I.LDAH{r=rd, b=base, d=I.IMMop(high)})
185 :     | loadimmed(low, high) =
186 :     (emit(I.LDA{r=rd, b=base, d=I.IMMop(low)});
187 :     emit(I.LDAH{r=rd, b=rd, d=I.IMMop(high)}))
188 :     in
189 :     if W32.<(low, 0w32768) then loadimmed(W32.toInt low, W32.toIntX high)
190 :     else let (* low = (32768 .. 65535) *)
191 :     val lowsgn = W32.-(low, 0w65536) (* signed (~1 .. ~32768) *)
192 :     val highsgn = W32.+(high, 0w1) (* (~32768 .. 32768) *)
193 :     val ilow = W32.toIntX lowsgn
194 :     val ihigh = W32.toIntX highsgn
195 :     in
196 :     if ihigh <> 32768 then loadimmed(ilow, ihigh)
197 :     else let
198 :     val tmpR = C.newReg()
199 :     in
200 :     (* you gotta do what you gotta do! *)
201 :     emit(I.LDA{r=rd, b=base, d=I.IMMop(ilow)});
202 :     emit(I.OPERATE{oper=I.ADDL, ra=zeroR, rb=I.IMMop 1, rc=tmpR});
203 :     emit(I.OPERATE{oper=I.SLL, ra=tmpR, rb=I.IMMop 31, rc=tmpR});
204 :     emit(I.OPERATE{oper=I.ADDL, ra=tmpR, rb=I.REGop rd, rc=rd})
205 :     end
206 :     end
207 :     end
208 : monnier 16
209 :     fun orderedFArith (exp1, exp2, T.LR) = (fregAction exp1, fregAction exp2)
210 :     | orderedFArith (exp1, exp2, T.RL) = let
211 :     val f2 = fregAction exp2
212 :     in (fregAction exp1, f2)
213 :     end
214 :    
215 :     and stmAction exp = let
216 :     fun fbranch(_, T.FCMP(cc, exp1, exp2, order), lab) = let
217 :     val (f1, f2) = orderedFArith(exp1, exp2, order)
218 :     fun bcc(cmp, br) = let
219 : monnier 106 val tmpR = C.newFreg()
220 : monnier 16 in
221 :     emit(I.DEFFREG(tmpR));
222 :     emit(I.FOPERATE{oper=cmp, fa=f1, fb=f2, fc=tmpR});
223 :     emit(I.TRAPB);
224 :     emit(I.FBRANCH(br, tmpR, lab))
225 :     end
226 :    
227 :     fun fall(cmp1, br1, cmp2, br2) = let
228 : monnier 106 val tmpR1 = C.newFreg()
229 :     val tmpR2 = C.newFreg()
230 : monnier 16 val fallLab = Label.newLabel ""
231 :     in
232 :     emit(I.DEFFREG(tmpR1));
233 :     emit(I.FOPERATE{oper=cmp1, fa=f1, fb=f2, fc=tmpR1});
234 :     emit(I.TRAPB);
235 :     emit(I.FBRANCH(br1, tmpR1, fallLab));
236 :     emit(I.DEFFREG(tmpR2));
237 :     emit(I.FOPERATE{oper=cmp2, fa=f1, fb=f2, fc=tmpR2});
238 :     emit(I.TRAPB);
239 :     emit(I.FBRANCH(br2, tmpR2, lab));
240 :     F.defineLabel fallLab
241 :     end
242 :    
243 :     fun bcc2(cmp1, br1, cmp2, br2) = (bcc(cmp1, br1); bcc(cmp2, br2))
244 :     in
245 :     case cc
246 :     of T.== => bcc(I.CMPTEQ, I.BNE)
247 :     | T.?<> => bcc(I.CMPTEQ, I.BEQ)
248 :     | T.? => bcc(I.CMPTUN, I.BNE)
249 :     | T.<=> => bcc(I.CMPTUN, I.BEQ)
250 :     | T.> => fall(I.CMPTLE, I.BNE, I.CMPTUN, I.BEQ)
251 :     | T.>= => fall(I.CMPTLT, I.BNE, I.CMPTUN, I.BEQ)
252 :     | T.?> => bcc(I.CMPTLE, I.BEQ)
253 :     | T.?>= => bcc(I.CMPTLT, I.BEQ)
254 :     | T.< => bcc(I.CMPTLT, I.BNE)
255 :     | T.<= => bcc(I.CMPTLE, I.BNE)
256 :     | T.?< => bcc2(I.CMPTLT, I.BNE, I.CMPTUN, I.BNE)
257 :     | T.?<= => bcc2(I.CMPTLE, I.BNE, I.CMPTUN, I.BNE)
258 :     | T.<> => fall(I.CMPTEQ, I.BNE, I.CMPTUN, I.BEQ)
259 :     | T.?= => bcc2(I.CMPTEQ, I.BNE, I.CMPTUN, I.BNE)
260 :     end
261 :    
262 :     fun branch(cond, exp1, exp2, lab, order) = let
263 :     fun zapHi r = emit(I.OPERATE{oper=I.ZAP, ra=r, rb=I.IMMop 0xf0, rc=r})
264 : monnier 106 val tmpR = C.newReg()
265 : monnier 16 val (r1, o2) =
266 :     case order
267 :     of T.LR => (regAction exp1, opndAction exp2)
268 :     | T.RL => let val o2' = opndAction exp2
269 :     in
270 :     (regAction(exp1), o2')
271 :     end
272 :     fun emitBr(cmp, br) =
273 :     (emit(I.OPERATE{oper=cmp, ra=r1, rb=o2, rc=tmpR});
274 :     emit(I.BRANCH(br, tmpR, lab)))
275 :     fun emitUnsignedBr(cmp, br) =
276 :     (case (r1, o2)
277 :     of (r1, I.REGop r2) => (zapHi r1; zapHi r2; emitBr(cmp, br))
278 :     | (r1, o2) => (zapHi r1; emitBr(cmp, br))
279 :     (*esac*))
280 :     in
281 :     case cond
282 :     of I.CC_LTU => emitUnsignedBr(I.CMPULT, I.BNE)
283 :     | I.CC_LEU => emitUnsignedBr(I.CMPULE, I.BNE)
284 :     | I.CC_GTU => emitUnsignedBr(I.CMPULE, I.BEQ)
285 :     | I.CC_GEU => emitUnsignedBr(I.CMPULT, I.BEQ)
286 :     | I.CC_LT => emitBr(I.CMPLT, I.BNE)
287 :     | I.CC_LE => emitBr(I.CMPLE, I.BNE)
288 :     | I.CC_GT => emitBr(I.CMPLE, I.BEQ)
289 :     | I.CC_GE => emitBr(I.CMPLT, I.BEQ)
290 :     | I.CC_EQ => emitBr(I.CMPEQ, I.BNE)
291 :     | I.CC_NEQ => emitBr(I.CMPEQ, I.BEQ)
292 :     end
293 : monnier 106 fun copyTmp() = SOME(I.Direct(C.newReg()))
294 :     fun fcopyTmp() = SOME(I.FDirect(C.newFreg()))
295 : monnier 16 in
296 :     case exp
297 :     of T.JMP(T.LABEL(LE.LABEL lab), _) => emit(I.BRANCH(I.BR, zeroR, lab))
298 :     | T.JMP(T.LABEL _, _) => error "JMP(T.LABEL _, _)"
299 :     | T.JMP(exp, labs) =>
300 :     emit(I.JMPL({r=C.asmTmpR, b=regAction exp, d=0}, labs))
301 :     | T.BCC(_, T.CMP(T.NEQ, T.ANDB(exp, T.LI 1), T.LI 0, _), lab) =>
302 :     emit(I.BRANCH(I.BLBS, regAction exp, lab))
303 :     | T.BCC(_, T.CMP(cc, exp, T.LI n, ord), lab) =>
304 :     branch(cond cc, exp, T.LI n, lab, ord)
305 :     | T.BCC(_, T.CMP(cc, T.LI n, exp, ord), lab) =>
306 :     branch(swapcc(cond cc), exp, T.LI n, lab, ord)
307 :     | T.BCC(_, T.CMP(cc, e1, e2, ord), lab) =>
308 :     branch(cond cc, e1, e2, lab, ord)
309 :     | T.BCC(_, e, lab) => emit(I.BRANCH(I.BNE, ccAction e, lab))
310 :     | T.FBCC arg => fbranch arg
311 :     | T.CALL(exp, def, use) => let
312 :     val pv = regAction exp
313 :     val returnPtrR = 26
314 :     fun live([],acc) = acc
315 :     | live(T.GPR(T.REG r)::regs,acc) = live(regs, C.addReg(r,acc))
316 :     | live(T.CCR(T.CC cc)::regs,acc) = live(regs, C.addReg(cc,acc))
317 :     | live(T.FPR(T.FREG f)::regs,acc) = live(regs, C.addFreg(f,acc))
318 :     | live(_::regs, acc) = live(regs, acc)
319 :     in
320 :     emit(I.JSR({r=returnPtrR, b=pv, d=0},
321 :     live(def, C.addReg(returnPtrR, C.empty)),
322 :     live(use, C.addReg(pv, C.empty))))
323 :     end
324 :     | T.RET => emit(I.JMPL({r=zeroR, b=26, d=0}, []))
325 :     | T.STORE8(ea, r, region) => let
326 :     val rs = regAction r
327 :     val (rd, disp) = eaAction ea
328 : monnier 106 val t1 = C.newReg()
329 :     val t2 = C.newReg()
330 :     val t3 = C.newReg()
331 : monnier 16 in
332 :     app emit
333 :     [I.LOAD{ldOp=I.LDQ_U, r=t1, b=rd, d=disp,mem=mem},
334 :     I.LDA{r=t2, b=rd, d=disp},
335 :     I.OPERATE{oper=I.INSBL, ra=rs, rb=I.REGop(t2), rc=t3},
336 :     I.OPERATE{oper=I.MSKBL, ra=t1, rb=I.REGop(t2), rc=t1},
337 :     I.OPERATE{oper=I.BIS, ra=t1, rb=I.REGop(t3), rc=t1},
338 :     I.STORE{stOp=I.STQ_U, r=t1, b=rd, d=disp, mem=mem}]
339 :     end
340 :     | T.STORE32(ea, r, region) => let
341 :     val (b, d) = eaAction ea
342 :     in emit(I.STORE{stOp=I.STL, r=regAction r, b=b, d=d, mem=region})
343 :     end
344 :     | T.STORED(ea, f, region) => let
345 :     val (b, d) = eaAction ea
346 :     in emit(I.FSTORE{stOp=I.STT, r=fregAction f, b=b, d=d, mem=region})
347 :     end
348 :     | T.STORECC(ea, cc, region) => error "stmAction.STORECC"
349 :     | T.MV(rd, exp) => let
350 :     fun move(dst, src) = I.OPERATE{oper=I.BIS, ra=src, rb=zeroOp, rc=dst}
351 :     in
352 :     case exp
353 :     of T.REG(rs) => if rs = rd then () else emit(move(rd, rs))
354 :     | T.LI n => loadImmed(n, zeroR, rd)
355 :     | T.LI32 w => loadImmed32(w, zeroR, rd)
356 :     | _ => let val rs = regActionRd(exp, rd)
357 :     in if rs = rd then () else emit(move(rd,rs))
358 :     end
359 :     (*esac*)
360 :     end
361 :     | T.CCMV(cd, exp) => let
362 :     val cs = case exp of T.CC(r) => r | _ => ccActionCd(exp, cd)
363 :     in
364 :     if cs = cd then ()
365 :     else emit(I.OPERATE{oper=I.BIS, ra=cs, rb=zeroOp, rc=cd})
366 :     end
367 :     | T.FMV(fd, exp) => let
368 :     fun fmove(dst, src) = I.FOPERATE{oper=I.CPYS, fa=src, fb=src, fc=dst}
369 :     in
370 :     case exp
371 :     of T.FREG(fs) =>
372 :     if fs = fd then () else emit(fmove(fd, fs))
373 :     | _ => let
374 :     val fs = fregActionFd(exp, fd)
375 :     in if fs = fd then () else emit(fmove(fd, fs))
376 :     end
377 :     (*esac*)
378 :     end
379 :     | T.COPY(rds as [_], rss) =>
380 :     emit(I.COPY{dst=rds, src=rss, impl=ref NONE, tmp=NONE})
381 :     | T.COPY(rds, rss) =>
382 :     emit(I.COPY{dst=rds, src=rss, impl=ref NONE, tmp=copyTmp()})
383 :     | T.FCOPY(fds as [_], fss)=>
384 :     emit(I.FCOPY{dst=fds, src=fss, impl=ref NONE, tmp=NONE})
385 :     | T.FCOPY(fds, fss) =>
386 :     emit(I.FCOPY{dst=fds, src=fss, impl=ref NONE, tmp=fcopyTmp()})
387 :     end
388 :     and ccAction(T.CC r) = r
389 :     | ccAction(e) = ccActionCd(e, C.newCCreg())
390 :    
391 :     and ccActionCd(T.CC r, _) = r
392 :     (* enough for now ... *)
393 :     | ccActionCd(T.CMP(T.GTU, e1, e2, ord), cd) = let
394 :     val (opnd, reg) =
395 :     case ord
396 :     of T.LR => (opndAction e1, regAction e2)
397 :     | T.RL => let
398 :     val r = regAction e2
399 :     in (opndAction e1, r)
400 :     end
401 :     in
402 :     emit(I.OPERATE{oper=I.CMPULT, ra=reg, rb=opnd, rc=cd});
403 :     cd
404 :     end
405 :     | ccActionCd(T.LOADCC _, _) = error "ccAction"
406 :    
407 :     and opndAction (T.LI value) =
408 :     if value <= 255 andalso value >= 0 then I.IMMop value
409 :     else let
410 : monnier 106 val tmpR = C.newReg()
411 : monnier 16 in
412 :     loadImmed (value, zeroR, tmpR);
413 :     I.REGop tmpR
414 :     end
415 :     | opndAction(T.LI32 value) =
416 :     if Word32.<=(value, 0w255) then I.IMMop (Word32.toInt value)
417 :     else let
418 : monnier 106 val tmpR = C.newReg ()
419 : monnier 16 in
420 :     loadImmed32 (value, zeroR, tmpR);
421 :     I.REGop tmpR
422 :     end
423 :     | opndAction(T.CONST const) = I.CONSTop (const)
424 :     | opndAction exp = I.REGop (regAction exp)
425 :    
426 :     and reduceOpnd(I.IMMop i) = let
427 : monnier 106 val rd = C.newReg()
428 : monnier 16 in loadImmed(i, zeroR, rd); rd
429 :     end
430 :     | reduceOpnd(I.REGop rd) = rd
431 :     | reduceOpnd(I.CONSTop c) = regAction(T.CONST c)
432 :     | reduceOpnd(I.LABop le) = regAction(T.LABEL le)
433 :     | reduceOpnd _ = error "reduceOpnd"
434 :    
435 :     and orderedRR(e1, e2, T.LR) = (regAction e1, regAction e2)
436 :     | orderedRR(e1, e2, T.RL) = let
437 :     val r2 = regAction e2
438 :     in (regAction e1, r2)
439 :     end
440 :    
441 :     and regAction (T.REG r) = r
442 : monnier 106 | regAction exp = regActionRd(exp, C.newReg())
443 : monnier 16
444 :     and arithOperands(e1, e2, T.LR) = (regAction e1, opndAction e2)
445 :     | arithOperands(e1, e2, T.RL) = let
446 :     val opnd = opndAction e2
447 :     in (regAction e1, opnd)
448 :     end
449 :    
450 :     and regActionRd(exp, rd) = let
451 :    
452 :     fun orderedArith(oper, arith, e1, e2, ord) = let
453 :     val (reg, opnd) = arithOperands(e1, e2, ord)
454 :     in
455 :     emit(oper{oper=arith, ra=reg, rb=opnd, rc=rd});
456 :     rd
457 :     end
458 :    
459 :     fun commOrderedArith(oper, arith, e1 ,e2, ord) = let
460 :     fun f(e1 as T.LI _, e2) = orderedArith(oper, arith, e2, e1, ord)
461 :     | f(e1 as T.LI32 _, e2) = orderedArith(oper, arith, e2, e1, ord)
462 :     | f(e1, e2) = orderedArith(oper, arith, e1, e2, ord)
463 :     in
464 :     f(e1, e2)
465 :     end
466 :    
467 :    
468 :     fun orderedArithTrap arg = orderedArith arg before emit(I.TRAPB)
469 :     fun commOrderedArithTrap arg = commOrderedArith arg before emit(I.TRAPB)
470 :    
471 :     fun orderedMullTrap (e1, e2, ord, rd) = let
472 :     val (reg, opnd) = case ord
473 :     of T.LR => (regAction e1, opndAction e2)
474 :     | T.RL => let
475 :     val opnd = opndAction e2
476 :     in
477 :     (regAction e1, opnd)
478 :     end
479 :    
480 :     fun emitMulvImmed (reg, 0, rd) =
481 :     emit(I.LDA{r=rd, b=zeroR, d=I.IMMop 0})
482 :     | emitMulvImmed (reg, 1, rd) =
483 :     emit(I.OPERATE{oper=I.ADDL, ra=reg, rb=zeroOp, rc=rd})
484 :     | emitMulvImmed (reg, multiplier, rd) = let
485 :     fun log2 0w1 = 0 | log2 n = 1 + (log2 (Word.>> (n, 0w1)))
486 :    
487 :     fun exp2 n = Word.<<(0w1, n)
488 :    
489 :     fun bitIsSet (x,n) = Word.andb(x,exp2 n) <> 0w0
490 :    
491 :     fun loop (~1) = ()
492 :     | loop n =
493 :     (if bitIsSet(itow multiplier, itow n) then
494 :     emit(I.OPERATEV{oper=I.ADDLV, ra=reg, rb=I.REGop rd, rc=rd})
495 :     else ();
496 :     if n>0 then
497 :     emit(I.OPERATEV{oper=I.ADDLV, ra=rd, rb=I.REGop rd, rc=rd})
498 :     else ();
499 :     loop (n-1))
500 :     in
501 :     emit(I.OPERATEV{oper=I.ADDLV, ra=reg, rb=I.REGop reg, rc=rd});
502 :     loop ((log2 (itow multiplier)) - 1)
503 :     end
504 :     in
505 :     case opnd
506 :     of (I.IMMop multiplier) => emitMulvImmed (reg, multiplier, rd)
507 :     | _ => emit (I.OPERATEV{oper=I.MULLV , ra=reg, rb=opnd, rc=rd})
508 :     (*esac*);
509 :     emit(I.TRAPB);
510 :     rd
511 :     end
512 :    
513 :     fun opndToWord (T.LI i) = SOME (Word32.fromInt i)
514 :     | opndToWord (T.LI32 w) = SOME w
515 :     | opndToWord _ = NONE
516 :     in
517 :     case exp
518 :     of T.LI n => (loadImmed(n, zeroR, rd); rd)
519 :     | T.LI32 w => (loadImmed32(w, zeroR, rd); rd)
520 :     | T.LABEL le => (emit(I.LDA{r=rd, b=zeroR, d=I.LABop le}); rd)
521 :     | T.CONST c => (emit(I.LDA{r=rd, b=zeroR, d=I.CONSTop(c)}); rd)
522 :     | T.ADD(e, T.LABEL le)=>
523 :     (emit(I.LDA{r=rd, b=regAction(e), d=I.LABop(le)}); rd)
524 :     | T.ADD(T.LI i, e) => (loadImmed(i, regAction e, rd); rd)
525 :     | T.ADD(e, T.LI i) => (loadImmed(i, regAction e, rd); rd)
526 :     | T.ADD(T.LI32 i, e) => (loadImmed32(i, regAction e, rd); rd)
527 :     | T.ADD(e, T.LI32 i) => (loadImmed32(i, regAction e, rd); rd)
528 :     | T.ADD(T.CONST c, e) =>
529 :     (emit(I.LDA{r=rd, b=regAction e, d=I.CONSTop c}); rd)
530 :     | T.ADD(e, T.CONST c) =>
531 :     (emit(I.LDA{r=rd, b=regAction e, d=I.CONSTop c}); rd)
532 :     | T.ADD(e1, e2) => commOrderedArith(I.OPERATE, I.ADDL, e1, e2, T.LR)
533 :     | T.SUB(e1, e2, ord) => orderedArith(I.OPERATE, I.SUBL, e1, e2, ord)
534 :     | T.MULU(e1, e2) => commOrderedArith(I.OPERATE, I.MULL, e1, e2, T.LR)
535 :     | T.ADDT(e1, e2) =>
536 :     commOrderedArithTrap(I.OPERATEV, I.ADDLV, e1, e2, T.LR)
537 :     | T.SUBT(e1, e2, ord) => orderedArithTrap(I.OPERATEV, I.SUBLV, e1, e2, ord)
538 :     | T.MULT(e1, e2) => orderedMullTrap(e1, e2, T.LR, rd)
539 :     | T.ANDB(e1, e2) => let
540 :     fun opndToByteMask (SOME (0wx0:Word32.word)) = SOME 0xf
541 :     | opndToByteMask (SOME 0wx000000ff) = SOME 0xe
542 :     | opndToByteMask (SOME 0wx0000ff00) = SOME 0xd
543 :     | opndToByteMask (SOME 0wx0000ffff) = SOME 0xc
544 :     | opndToByteMask (SOME 0wx00ff0000) = SOME 0xb
545 :     | opndToByteMask (SOME 0wx00ff00ff) = SOME 0xa
546 :     | opndToByteMask (SOME 0wx00ffff00) = SOME 0x9
547 :     | opndToByteMask (SOME 0wx00ffffff) = SOME 0x8
548 :     | opndToByteMask (SOME 0wxff000000) = SOME 0x7
549 :     | opndToByteMask (SOME 0wxff0000ff) = SOME 0x6
550 :     | opndToByteMask (SOME 0wxff00ff00) = SOME 0x5
551 :     | opndToByteMask (SOME 0wxff00ffff) = SOME 0x4
552 :     | opndToByteMask (SOME 0wxffff0000) = SOME 0x3
553 :     | opndToByteMask (SOME 0wxffff00ff) = SOME 0x2
554 :     | opndToByteMask (SOME 0wxffffff00) = SOME 0x1
555 :     | opndToByteMask (SOME 0wxffffffff) = SOME 0x0
556 :     | opndToByteMask _ = NONE
557 :    
558 :     val opndToMask = opndToByteMask o opndToWord
559 :     in
560 :     case (opndToMask e1, opndToMask e2) of
561 :     (SOME mask, _) =>
562 :     orderedArith(I.OPERATE, I.ZAP, e2, T.LI mask, T.LR)
563 :     | (_, SOME mask) =>
564 :     orderedArith(I.OPERATE, I.ZAP, e1, T.LI mask, T.LR)
565 :     | _ => commOrderedArith(I.OPERATE, I.AND, e1, e2, T.LR)
566 :     end
567 :     | T.ORB(e1, e2) => commOrderedArith(I.OPERATE, I.BIS, e1, e2, T.LR)
568 :     | T.XORB(e1, e2) => commOrderedArith(I.OPERATE, I.XOR, e1, e2, T.LR)
569 :     | T.SLL(e1, e2, ord) =>
570 :     (case opndToWord e2 of
571 :     SOME 0w1 => let val r = T.REG (regAction e1)
572 :     in orderedArith(I.OPERATE, I.ADDL, r, r, T.LR) end
573 :     | SOME 0w2 => orderedArith(I.OPERATE, I.S4ADDL, e1, T.LI 0, T.LR)
574 :     | SOME 0w3 => orderedArith(I.OPERATE, I.S8ADDL, e1, T.LI 0, T.LR)
575 :     | _ => (orderedArith(I.OPERATE, I.SLL, e1, e2, T.LR);
576 :     emit(I.OPERATE{oper=I.SGNXL, ra=rd, rb=zeroOp, rc=rd});
577 :     rd)
578 :     (*esac*))
579 :     | T.SRA(e1, e2, ord) => let
580 :     val (reg, opnd) = (regAction e1, opndAction e2)
581 :     in
582 :     (* sign extend longword argument *)
583 :     emit(I.OPERATE{oper=I.SGNXL, ra=reg, rb=zeroOp, rc=reg});
584 :     emit(I.OPERATE{oper=I.SRA, ra=reg, rb=opnd, rc=rd});
585 :     rd
586 :     end
587 :     | T.SRL(e1, e2, ord) => let
588 :     val (reg, opnd) = (regAction e1, opndAction e2)
589 :     in
590 :     emit(I.OPERATE{oper=I.ZAP, ra=reg, rb=I.IMMop 0xf0, rc=reg});
591 :     emit(I.OPERATE{oper=I.SRL, ra=reg, rb=opnd, rc=rd});
592 :     rd
593 :     end
594 :     | T.DIVT arg => let
595 :     val (reg, opnd) = arithOperands arg
596 :     in
597 :     app emit (PseudoInstrs.divl({ra=reg, rb=opnd, rc=rd}, reduceOpnd));
598 :     rd
599 :     end
600 :     | T.DIVU arg => let
601 :     val (reg, opnd) = arithOperands arg
602 :     in
603 :     app emit (PseudoInstrs.divlu({ra=reg, rb=opnd, rc=rd}, reduceOpnd));
604 :     rd
605 :     end
606 :     | T.LOAD32(exp, region) => let
607 :     val (b, d) = eaAction exp
608 :     in emit(I.LOAD{ldOp=I.LDL, r=rd, b=b, d=d, mem=region}); rd
609 :     end
610 :     (* Load and sign-extend a byte from a non-aligned address *)
611 :     | T.LOAD8(exp, region) => let
612 : monnier 106 val tmpR0 = C.newReg()
613 :     val tmpR1 = C.newReg()
614 : monnier 16 val (rt, disp) = eaAction exp
615 :     in
616 :     emit(I.LOAD{ldOp=I.LDQ_U, r=tmpR0, b=rt, d=disp, mem=mem});
617 :     emit(I.LDA{r=tmpR1, b=rt, d=disp});
618 :     emit(I.OPERATE{oper=I.EXTBL, ra=tmpR0, rb=I.REGop tmpR1, rc=rd});
619 :     rd
620 :     end
621 :     | T.SEQ(e1, e2) => (stmAction e1; regAction e2)
622 :     | _ => error "regAction"
623 :     end (* regActionRd *)
624 :    
625 :     and eaAction exp = let
626 :     fun makeEA(r, n) =
627 :     if ~32768 <= n andalso n <= 32767 then (r, I.IMMop n)
628 :     else let
629 : monnier 106 val tmpR = C.newReg()
630 : monnier 16 val low = wtoi(Word.andb(itow n, 0w65535))(* unsigned low 16 bits *)
631 :     val high = n div 65536
632 :     val (lowsgn, highsgn) = (* Sign-extend *)
633 :     if low <= 32767 then (low, high) else (low -65536, high+1)
634 :     in
635 :     (emit(I.LDAH{r=tmpR, b=r, d=I.IMMop highsgn});
636 :     (tmpR, I.IMMop lowsgn))
637 :     end
638 :     in
639 :     case exp
640 :     of T.ADD(exp, T.LI n) => makeEA(regAction exp, n)
641 :     | T.ADD(T.LI n, exp) => makeEA(regAction exp, n)
642 :     | T.ADD(T.CONST c, exp) => (regAction exp, I.CONSTop(c))
643 :     | T.ADD(exp, T.CONST c) => (regAction exp, I.CONSTop(c))
644 :     | T.SUB(exp, T.LI n, _) => makeEA(regAction exp, ~n)
645 :     | exp => makeEA(regAction exp, 0)
646 :     end (* eaAction *)
647 :    
648 :     and fregAction (T.FREG f) = f
649 : monnier 106 | fregAction exp = fregActionFd(exp, C.newFreg())
650 : monnier 16
651 :     and fregActionFd(exp, fd) = let
652 :     (* macho comment goes here *)
653 :     fun doFloatArith(farith, e1, e2, fd, order) = let
654 :     val (f1, f2) = orderedFArith(e1, e2, order)
655 :     in
656 :     emit(I.DEFFREG fd);
657 :     emit(I.FOPERATEV{oper=farith, fa=f1, fb=f2, fc=fd});
658 :     emit(I.TRAPB);
659 :     fd
660 :     end
661 :     in
662 :     case exp
663 :     of T.FREG f => f
664 :     | T.FADDD(e1, e2) => doFloatArith(I.ADDT, e1, e2, fd, T.LR)
665 :     | T.FMULD(e1, e2) => doFloatArith(I.MULT, e1, e2, fd, T.LR)
666 :     | T.FSUBD(e1, e2, ord) => doFloatArith(I.SUBT, e1, e2, fd, ord)
667 :     | T.FDIVD(e1, e2, ord) => doFloatArith(I.DIVT, e1, e2, fd, ord)
668 :     | T.FABSD exp =>
669 :     (emit(I.FOPERATE{oper=I.CPYS, fa=zeroR, fb=fregAction exp, fc=fd}); fd)
670 :     | T.FNEGD exp => let
671 :     val fs = fregAction exp
672 :     in
673 :     emit(I.FOPERATE{oper=I.CPYSN, fa=fs, fb=fs, fc=fd}); fd
674 :     end
675 :     | T.CVTI2D exp => let
676 :     val opnd = opndAction exp
677 :     in
678 :     app emit (PseudoInstrs.cvti2d({opnd=opnd, fd=fd},reduceOpnd));
679 :     fd
680 :     end
681 :     | T.LOADD(exp, region) => let
682 :     val (b, d) = eaAction exp
683 :     in emit(I.FLOAD{ldOp=I.LDT, r=fd, b=b, d=d, mem=region}); fd
684 :     end
685 :     | T.FSEQ(e1, e2) => (stmAction e1; fregAction e2)
686 :     end
687 :    
688 :     fun mltreeComp mltree = let
689 :     (* condition code registers are mapped onto general registers *)
690 :     fun cc (T.CCR(T.CC cc)) = T.GPR(T.REG cc)
691 :     | cc x = x
692 :    
693 :     fun mltc(T.PSEUDO_OP pOp) = F.pseudoOp pOp
694 :     | mltc(T.DEFINELABEL lab) = F.defineLabel lab
695 :     | mltc(T.ENTRYLABEL lab) = F.entryLabel lab
696 :     | mltc(T.ORDERED mlts) = F.ordered mlts
697 :     | mltc(T.BEGINCLUSTER) = F.beginCluster()
698 :     | mltc(T.CODE stms) = app stmAction stms
699 : monnier 127 | mltc(T.BLOCK_NAME name) = F.blockName name
700 : monnier 16 | mltc(T.ENDCLUSTER regmap)= F.endCluster regmap
701 :     | mltc(T.ESCAPEBLOCK regs) = F.exitBlock (map cc regs)
702 :     in mltc mltree
703 :     end
704 :    
705 :     val mlriscComp = stmAction
706 :     end
707 :    
708 :    
709 : monnier 139 (*
710 :     * $Log: alpha32.sml,v $
711 :     * Revision 1.4 1998/06/05 23:53:57 george
712 :     * Fix for bug 1399 1361
713 :     *
714 :     * Revision 1.3 1998/05/25 15:10:44 george
715 :     * Fixed RCS keywords
716 :     *
717 :     *)

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0