Initial snarf.
[shack.git] / arch / x86 / util / x86_fpstack.ml
blob5751cdedea2d4ce01055fad9c4e7de1fd29c61cf
1 (*
2 Rewrite FP pseudo-registers to use real stack registers
3 Copyright (C) 2001 Justin David Smith, Caltech
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 NOTE: this code assumes no transients are atop the
23 stack upon entering any block, i.e. on entering the
24 block the stack ONLY contains the allocated registers
25 fp0..fp5.
29 (* Useful junk *)
30 open Format
31 open Symbol
32 open Frame_type
33 open X86_exn
34 open X86_inst_type
35 open X86_frame_type
36 open X86_frame
37 open X86_util
40 (*** Utilities ***)
43 (* fpclassify
44 Classifies this instruction. Only used internally, see the
45 next two functions for a general (and better) overview. *)
46 let fpclassify = function
47 FLD _
48 | FILD _
49 | FILD64 _
50 | FMOV _
51 | FCALL _ ->
52 true, 1
54 (* Normal store operations *)
55 | FSTP _
56 | FISTP _
57 | FISTP64 _ ->
58 true, -1
60 (* Arithmetic operations *)
61 | FADDP
62 | FSUBP
63 | FMULP
64 | FDIVP
65 | FSUBRP
66 | FDIVRP ->
67 true, -1
68 | FCHS
69 | FADD _
70 | FSUB _
71 | FMUL _
72 | FDIV _
73 | FSUBR _
74 | FDIVR _
75 | FPREM
76 | FSIN
77 | FCOS
78 | FPATAN
79 | FSQRT ->
80 true, 0
82 (* Comparison pops nil, once, or twice *)
83 | FUCOM ->
84 true, 0
85 | FUCOMP ->
86 true, -1
87 | FUCOMPP ->
88 true, -2
90 (* Misc. floating-point ops *)
91 | FST _
92 | FIST _
93 | FMOVP _
94 | FXCH _ ->
95 true, 0
97 (* FSTSW doesn't use the stack *)
98 | FINIT
99 | FSTCW _
100 | FLDCW _
101 | FSTSW ->
102 false, 0
104 (* Non-FP operations *)
105 | MOV _
106 | MOVS _
107 | MOVZ _
108 | MOVD _
109 | MOVQ _
110 | RMOVS _
111 | LEA _
112 | NOT _
113 | NEG _
114 | INC _
115 | DEC _
116 | ADD _
117 | ADC _
118 | SUB _
119 | SBB _
120 | MUL _
121 | IMUL _
122 | DIV _
123 | IDIV _
124 | CLTD
125 | AND _
126 | OR _
127 | XOR _
128 | SAL _
129 | SAR _
130 | SHL _
131 | SHR _
132 | SHLD _
133 | SHRD _
134 | PUSH _
135 | POP _
136 | CALL _
137 | RET
138 | CMP _
139 | TEST _
140 | JMP _
141 | FJMP _
142 | IJMP _
143 | JCC _
144 | SET _
145 | RES _
146 | COW _
147 | RESP _
148 | CommentFIR _
149 | CommentMIR _
150 | CommentInst _
151 | CommentString _
152 | NOP ->
153 false, 0
156 (* inst_uses_fpstack
157 Returns true if the given instruction uses registers from the
158 floating-point stack (either explicitly or implicitly). These
159 instructions cannot be so easily moved around. *)
160 let inst_uses_fpstack inst =
161 let fpstack, _ = fpclassify inst in
162 fpstack
165 (* fpstack_tos_delta
166 This instruction returns the change in the TOS pointer after
167 executing the named floating-point instruction. If the value
168 is zero, no change is made; if positive, values are pushed on
169 to the stack; if negative, the stack is popped. *)
170 let fpstack_tos_delta inst =
171 let _, delta = fpclassify inst in
172 delta
175 (*** Rewrite FP Pseudo-regs as FPStack ***)
178 (* rewrite_operand
179 Rewrites the stack pseudo-registers with real FPStack
180 operands that are adjusted to consider temporary values
181 pushed onto the top of the stack.
183 let rewrite_operand tos op =
184 match op with
185 FloatRegister r ->
186 let sym_eq (reg, _) = Symbol.eq reg r in
187 if List.exists sym_eq fpmap then
188 let index = Int32.of_int (tos + (snd (List.find sym_eq fpmap))) in
189 FPStack index
190 else
192 | ImmediateNumber _
193 | ImmediateLabel _
194 | Register _
195 | MMXRegister _
196 | FPStack _
197 | MemReg _
198 | MemRegOff _
199 | MemRegRegOffMul _
200 | SpillRegister _ ->
204 (* rewrite_inst
205 Rewrite operands in an instruction. This function
206 returns the revised instruction as well as the new
207 TOS, or new number of temporaries sitting at the top
208 of the floating-point stack after this operation. *)
209 let rec rewrite_insts tos insts =
210 let modify_tos delta tos insts =
211 if delta <> 0 then
212 let tos = tos + delta in
213 let inst = CommentString (sprintf "Modified TOS: now %d" tos) in
214 inst :: rewrite_insts tos insts
215 else
216 rewrite_insts tos insts
218 match insts with
219 [] ->
221 | inst :: insts ->
222 let inst = map_operands (rewrite_operand tos) inst in
223 let delta = fpstack_tos_delta inst in
224 inst :: modify_tos delta tos insts
227 (* rewrite_block
228 Rewrites a block of instructions. The block is assumed to
229 start out with tos = 0, or no temporary values on the floating
230 point stack (only the permanent values). *)
231 let rewrite_block block =
232 let insts = block.block_code in
233 let insts = rewrite_insts 0 insts in
234 { block with block_code = insts }
237 (* expand_fmov_insts
238 This function expands out FMOV and FMOVP instructions into
239 FLD and FST/FSTP instructions. This is important to run
240 /before/ we rewrite since we currently assume the TOS ptr
241 is revised at most once per instruction in the above code. *)
242 let rec expand_fmov_insts = function
243 FMOVP (dpre, dst, spre, src) :: insts ->
244 FLD (spre, src) :: FSTP (dpre, dst) :: expand_fmov_insts insts
245 | FMOV (dpre, dst, spre, src) :: insts ->
246 FLD (spre, src) :: FST (dpre, dst) :: expand_fmov_insts insts
247 | inst :: insts ->
248 inst :: expand_fmov_insts insts
249 | [] ->
253 (* expand_fmov_block
254 See above, this works on a block at a time. *)
255 let expand_fmov_block block =
256 let insts = block.block_code in
257 let insts = expand_fmov_insts insts in
258 { block with block_code = insts }
261 (* rewrite_prog
262 Rewrites the entire program. *)
263 let rewrite_prog prog =
264 let blocks = prog.asm_blocks in
265 let blocks = Trace.map expand_fmov_block blocks in
266 let blocks = Trace.map rewrite_block blocks in
267 { prog with asm_blocks = blocks }
269 let rewrite_prog = Fir_state.profile "X86_fpstack.rewrite_prog" rewrite_prog