|
|
1.1 root 1: (* Copyright 1989 by AT&T Bell Laboratories *)
2: (* sparcinstr.sml
3: *
4: * J.H. Reppy
5: * Cornell University
6: * Ithaca, NY 14853
7: * [email protected]
8: *
9: * HISTORY:
10: * 11/20/89 created
11: *)
12:
13: structure SparcInstr =
14: struct
15:
16: open BaseCoder
17:
18: datatype register = REG of int
19: datatype fregister = FREG of int
20:
21: datatype labelexp
22: = LABELexp of { (* An offset relative to a label. The value of a *)
23: base : label, (* label expression is ((dst - base) + offset). *)
24: dst : label,
25: offset : int
26: }
27:
28: datatype operand
29: = REGrand of register (* A register value *)
30: | IMrand of int (* A small integer constant (13 bits) *)
31: | LABrand of labelexp (* A small valued label expression (13 bits) *)
32: | HIrand of labelexp (* The high 22 bits of a label expression *)
33: | LOrand of labelexp (* The low 10 bits of a label expression *)
34:
35: datatype condition = EQL | NEQ | GTR | GEQ | LSS | LEQ
36:
37: datatype instruction
38: = I_nop
39: | I_ld of ops3 (* ld: load word *)
40: | I_ldb of ops3 (* ldb: load byte (unsigned) *)
41: | I_ldf of fmemops (* ldf: load floating-point register *)
42: | I_st of ops3 (* st: store word *)
43: | I_stb of ops3 (* stb: store byte *)
44: | I_stf of fmemops (* stf: store floating-point register *)
45: | I_sethi of (operand * register) (* sethi *)
46: | I_ba of label (* branch always *)
47: | I_bcc of (condition * label)
48: | I_fbcc of (condition * label)
49: | I_jmpl of ops3 (* jmpl: jump and link *)
50: | I_add of ops3 (* add *)
51: | I_addcc of ops3 (* add and set condition codes *)
52: | I_taddcctv of ops3 (* tagged add with overflow trap *)
53: | I_sub of ops3
54: | I_subcc of ops3 (* subtract and set condition codes *)
55: | I_sll of ops3
56: | I_sra of ops3
57: | I_and of ops3
58: | I_andcc of ops3 (* logical and and set condition codes *)
59: | I_or of ops3
60: | I_xor of ops3
61: | I_not of (register * register)
62: | I_tvs (* tvs: trap on integer overflow *)
63: | I_fadd of fops3 (* floating-point addition *)
64: | I_fsub of fops3 (* floating-point subtraction *)
65: | I_fmul of fops3 (* floating-point multiplication *)
66: | I_fdiv of fops3 (* floating-point division *)
67: | I_fneg of fops2 (* floating-point negation *)
68: | I_fcmp of fops2 (* floating-point comparison *)
69: withtype ops3 = (register * operand * register)
70: and fmemops = (register * operand * fregister)
71: and fops3 = (fregister * fregister * fregister)
72: and fops2 = (fregister * fregister)
73:
74: datatype ikind = IK_NOP | IK_JUMP | IK_INSTR
75:
76: fun instrKind (I_nop) = IK_NOP
77: | instrKind (I_ba _) = IK_JUMP
78: | instrKind (I_bcc _) = IK_JUMP
79: | instrKind (I_fbcc _) = IK_JUMP
80: | instrKind (I_jmpl _) = IK_JUMP
81: | instrKind _ = IK_INSTR
82:
83: val nop = I_nop
84:
85:
86:
87: (** Span dependent instructions **
88: * The implementation of these instructions depends on the value of the
89: * label expressions. The last register argument is a temporary register
90: * to be used in address computations (if necessary).
91: *)
92:
93: datatype sdi
94: = SetBaseAddr of (bool ref * register * labelexp * register)
95: | LoadAddr of (labelexp * register * register)
96: | Load of (labelexp * register * register)
97: | LoadF of (labelexp * fregister * register)
98:
99: fun minSize (SetBaseAddr _) = 0
100: | minSize (LoadF _) = 8
101: | minSize _ = 4
102:
103: local
104: (* Sizes of SDIs *)
105: val sz0max = (true, 0) and sz12max = (true, 12)
106: val sz16max = (true, 16) and sz20max = (true, 20)
107: val sz4 = (false, 4) and sz8 = (false, 8) and sz12 = (false, 12)
108: in
109:
110: (* Return the size of the various span-dependent instructions. This should
111: * be consistent with expand in "sparccoder.sml" *)
112: fun sizeOf I = let
113: fun span (LABELexp{base, dst, offset}) =
114: ((addrOf dst) + offset) - (addrOf base)
115: fun sizeOf' labexp = let
116: val x = span labexp
117: in
118: if (x < ~4096) orelse (4095 < x) then sz12max else sz4
119: end
120: in
121: case I
122: of SetBaseAddr(ref false, _, _, _) => sz0max
123: | SetBaseAddr(ref true, _, labexp, _) => let
124: val x = span labexp
125: in if (4095 < x)
126: then if (8190 < x)
127: then sz16max
128: else sz12 (* use two subtract immediates *)
129: else if (x < ~4096)
130: then sz16max
131: else sz8
132: end
133: | LoadAddr(labexp, _, _) => sizeOf' labexp
134: | Load(labexp, _, _) => sizeOf' labexp
135: | LoadF(labexp, _, _) => let
136: val x = span labexp
137: in
138: if (x < ~4092) orelse (4092 <= x) then sz20max else sz8
139: end
140: end
141:
142: end (* local *)
143:
144: local
145: val baseReg = REG 27 (* %i3 *)
146: val zeroR = REG 0 (* %g0 *)
147: val zeroRand = REGrand zeroR
148: in
149:
150: (* expand SDIs into real instruction sequences. *)
151: fun expand (SetBaseAddr(ref false, _, _, _), 0) = []
152: | expand (SetBaseAddr(ref true, contReg, labexp, _), 8) = [
153: I_ld(contReg, IMrand 0, baseReg),
154: I_sub(baseReg, LABrand labexp, baseReg)]
155: | expand (SetBaseAddr(ref true, contReg, LABELexp{base, dst, offset}, _), 12) = let
156: val n = if (((addrOf dst) - (addrOf base)) < 0) then ~4096 else 4095
157: val labexp = LABELexp{base=base, dst=dst, offset=offset - n}
158: in [
159: I_ld(contReg, zeroRand, baseReg),
160: I_sub(baseReg, IMrand n, baseReg),
161: I_sub(baseReg, LABrand labexp, baseReg)]
162: end
163: | expand (SetBaseAddr(ref true, contReg, labexp, tmpR), 16) = [
164: I_ld(contReg, zeroRand, baseReg),
165: I_sethi(HIrand labexp, tmpR),
166: I_or(tmpR, LOrand labexp, tmpR),
167: I_sub(baseReg, REGrand tmpR, baseReg)]
168: | expand (LoadAddr(labexp, dst, _), 4) = [I_add(baseReg, LABrand(labexp), dst)]
169: | expand (LoadAddr(labexp, dst, tmpR), 12) = [
170: I_sethi(HIrand labexp, tmpR),
171: I_or(tmpR, LOrand labexp, tmpR),
172: I_add(baseReg, REGrand tmpR, dst)]
173: | expand (Load(labexp, dst, _), 4) = [I_ld(baseReg, LABrand(labexp), dst)]
174: | expand (Load(labexp, dst, tmpR), 12) = [
175: I_sethi(HIrand(labexp), tmpR),
176: I_or(tmpR, LOrand labexp, tmpR),
177: I_ld(baseReg, REGrand tmpR, dst)]
178: | expand (LoadF(labexp as LABELexp{base, dst, offset}, FREG i, _), 8) = [
179: I_ldf(baseReg, LABrand(labexp), FREG i),
180: I_ldf(baseReg, LABrand(LABELexp{base=base, dst=dst, offset=offset+4}),
181: FREG(i+1))]
182: | expand (LoadF(labexp, FREG i, tmpR), 20) = [
183: I_sethi(HIrand(labexp), tmpR),
184: I_or(tmpR, LOrand(labexp), tmpR),
185: I_add(baseReg, REGrand tmpR, tmpR),
186: I_ldf(tmpR, zeroRand, FREG i),
187: I_ldf(tmpR, IMrand 4, FREG(i+1)) ]
188:
189: end (* local *)
190:
191:
192: (** Resource usage **
193: *
194: * The sparc resources are the condition codes, floating-point condition codes,
195: * registers %r1-%r31, floating-point registers (viewed as a single resource)
196: * and memory. We treat %g6 (the dataptr) specially. We assume that %g6 is
197: * only used in 'add', 'taddcctv', 'st', 'stf', and 'or' (move) instructions.
198: * We use %g6 to denote the "allocation" resource. This interferes in a
199: * non-standard way with the memory resource and with itself. Store instructions
200: * using %g6 as a base register don't define the memory resource, but the
201: * move of %g6 (using 'or') to another register is an implicit definition of
202: * the memory resource (since it makes the allocation visible), the move also
203: * defines the allocation resource, since it should only occur after the record
204: * has been initialized. There is an implicit use dependency between the
205: * 'tvs' instruction and the exnptr register.
206: *)
207:
208: val numRegs = 31 (* %r1-%r31 *)
209:
210: val numResources = (* registers + fp regs + mem, cond codes, fp cond codes *)
211: (numRegs + 4)
212:
213: local
214: val memRId = 0
215: val memR = [memRId]
216: fun addRegR (REG 0, lst) = lst
217: | addRegR (REG i, lst) = (i :: lst)
218: fun regR r = addRegR(r, nil)
219: val allocRId = 6 and allocR = [6]
220: val exnptrRId = 7
221: val fregsRId = (numRegs + 1)
222: val ccRId = (fregsRId + 1)
223: val fccRId = (ccRId + 1)
224: val fregsR = [fregsRId]
225: val ccR = [ccRId] and fccR = [fccRId]
226: fun rUseDef3 (a, REGrand b, c) = (addRegR(a, regR b), regR c)
227: | rUseDef3 (a, _, c) = (regR a, regR c)
228: fun rUseDef3cc (a, REGrand b, c) = (addRegR(a, regR b), ccRId :: (regR c))
229: | rUseDef3cc (a, _, c) = (regR a, ccRId :: (regR c))
230: val fregUseDef = (fregsR, fregsR)
231: val allR = let
232: fun f (~1, l) = l | f (i, l) = f(i-1, i::l)
233: in
234: f (numResources-1, nil)
235: end
236: in
237:
238: fun rUseDef (I_nop) = ([], [])
239: | rUseDef (I_ld args) = let val (u, d) = rUseDef3 args in (memRId :: u, d) end
240: | rUseDef (I_ldb args) = let val (u, d) = rUseDef3 args in (memRId :: u, d) end
241: | rUseDef (I_ldf(a, REGrand b, c)) = (memRId :: addRegR(a, regR b), fregsR)
242: | rUseDef (I_ldf(a, _, c)) = (memRId :: regR a, fregsR)
243: | rUseDef (I_st(REG 6, REGrand b, c)) = (6 :: addRegR(b, regR c), [])
244: | rUseDef (I_st(REG 6, _, c)) = (6 :: (regR c), [])
245: | rUseDef (I_st(a, REGrand b, c)) = (addRegR(a, addRegR(b, regR c)), memR)
246: | rUseDef (I_st(a, _, c)) = (addRegR(a, regR c), memR)
247: | rUseDef (I_stb(a, REGrand b, c)) = (addRegR(a, addRegR(b, regR c)), memR)
248: | rUseDef (I_stb(a, _, c)) = (addRegR(a, regR c), memR)
249: | rUseDef (I_stf(REG 6, REGrand b, c)) = (6 :: addRegR(b, fregsR), [])
250: | rUseDef (I_stf(REG 6, _, c)) = (6 :: fregsR, [])
251: | rUseDef (I_stf(a, REGrand b, c)) = (addRegR(a, addRegR(b, fregsR)), memR)
252: | rUseDef (I_stf(a, _, c)) = (addRegR(a, fregsR), memR)
253: | rUseDef (I_sethi(_, r)) = ([], regR r)
254: | rUseDef (I_ba _) = ([], [])
255: | rUseDef (I_bcc _) = (ccR, [])
256: | rUseDef (I_fbcc _) = (fccR, [])
257: | rUseDef (I_jmpl args) = rUseDef3 args
258: | rUseDef (I_add args) = rUseDef3 args
259: | rUseDef (I_addcc args) = rUseDef3cc args
260: | rUseDef (I_taddcctv _) = (allR, allR) (* GC limit check *)
261: | rUseDef (I_sub args) = rUseDef3 args
262: | rUseDef (I_subcc args) = rUseDef3cc args
263: | rUseDef (I_sll args) = rUseDef3 args
264: | rUseDef (I_sra args) = rUseDef3 args
265: | rUseDef (I_and args) = rUseDef3 args
266: | rUseDef (I_andcc args) = rUseDef3cc args
267: | rUseDef (I_or(_, REGrand(REG 6), REG c)) = (* this completes the allocation *)
268: ([6], [6, c, memRId])
269: | rUseDef (I_or args) = rUseDef3 args
270: | rUseDef (I_xor args) = rUseDef3 args
271: | rUseDef (I_not(a, b)) = (regR a, regR b)
272: | rUseDef (I_tvs) = ([ccRId, exnptrRId], [])
273: | rUseDef (I_fadd args) = fregUseDef
274: | rUseDef (I_fsub args) = fregUseDef
275: | rUseDef (I_fmul args) = fregUseDef
276: | rUseDef (I_fdiv args) = fregUseDef
277: | rUseDef (I_fneg(a, b)) = fregUseDef
278: | rUseDef (I_fcmp(a, b)) = (fregsR, fccR)
279:
280: local
281: fun uses (r, I) = let
282: fun uses3 (REG a, REGrand(REG b), _) = ((r = a) orelse (r = b))
283: | uses3 (REG a, _, _) = (r = a)
284: fun st_uses (REG a, REGrand(REG b), REG c) =
285: ((r = a) orelse (r = b) orelse (r = c))
286: | st_uses (REG a, _, REG c) = ((r = a) orelse (r = c))
287: in
288: case I
289: of (I_ld args) => uses3 args
290: | (I_ldb args) => uses3 args
291: | (I_ldf (REG a, REGrand(REG b), _)) => ((r = a) orelse (r = b))
292: | (I_ldf (REG a, _, _)) => (r = a)
293: | (I_st args) => st_uses args
294: | (I_stb args) => st_uses args
295: | (I_stf (REG a, REGrand(REG b), _)) => ((r = a) orelse (r = b))
296: | (I_stf (REG a, _, _)) => (r = a)
297: | (I_jmpl args) => uses3 args
298: | (I_add args) => uses3 args
299: | (I_addcc args) => uses3 args
300: | (I_taddcctv _) => true (* GC limit check *)
301: | (I_sub args) => uses3 args
302: | (I_subcc args) => uses3 args
303: | (I_sll args) => uses3 args
304: | (I_sra args) => uses3 args
305: | (I_and args) => uses3 args
306: | (I_andcc args) => uses3 args
307: | (I_or args) => uses3 args
308: | (I_xor args) => uses3 args
309: | (I_not(REG a, _)) => (r = a)
310: | (I_tvs) => (r = exnptrRId)
311: | _ => false
312: end
313: in
314: fun hazard (I_ld(_, _, REG dst), I) = uses (dst, I)
315: | hazard (I_ldb(_, _, REG dst), I) = uses (dst, I)
316: | hazard (I_ldf _, I) = (case I of (I_stf _) => true
317: | (I_fadd _) => true | (I_fsub _) => true | (I_fmul _) => true
318: | (I_fdiv _) => true | (I_fneg _) => true | (I_fcmp _) => true
319: | _ => false)
320: | hazard (I, I_stf _) = (case I
321: of (I_fadd _) => true | (I_fsub _) => true | (I_fmul _) => true
322: | (I_fdiv _) => true | (I_fneg _) => true | (I_fcmp _) => true
323: | _ => false)
324: | hazard _ = false
325: end (* local *)
326: end (* local *)
327:
328: fun needsNop (I_fcmp _, I_fbcc _) = true
329: | needsNop _ = false
330:
331: end (* SparcInstr *)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.