|
|
1.1 root 1: /* $Id: sparc-rc-insns.c,v 1.8 2010/06/05 17:00:47 fredette Exp $ */
2:
3: /* ic/sparc/sparc-rc-insns.c - SPARC recode instruction support: */
4:
5: /*
6: * Copyright (c) 2008 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #if TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32
37:
38: _TME_RCSID("$Id: sparc-rc-insns.c,v 1.8 2010/06/05 17:00:47 fredette Exp $");
39:
40: /* macros: */
41:
42: /* the sparc instruction recoder is mostly driven by the 32-bit
43: control value kept in the sparc_recode variable. this value
44: includes various fields and flags, and is initially taken from the
45: sparc instruction's entry in _tme_sparc_recode_insn_opmap[]. this
46: entry provides only the least significant 16 bits; other
47: more-significant bits may be added as recoding proceeds: */
48:
49: /* the opcode for the recode instruction: */
50: #define TME_SPARC_RECODE_INSN_OPCODE(x) ((tme_uint8_t) (x))
51: #define TME_SPARC_RECODE_INSN_OPCODE_MASK (0xff)
52:
53: /* if set, the PC and PC_next registers must be valid for this sparc
54: instruction, either because the sparc instruction itself needs them
55: to be valid, or because the situation calls for them to be valid
56: (for example, when TME_SPARC_RECODE_INSN_LAST is also set): */
57: #define TME_SPARC_RECODE_INSN_UPDATE_PCS (1 << 8)
58:
59: /* if set, this sparc instruction will be the last one recoded in this
60: instructions thunk: */
61: #define TME_SPARC_RECODE_INSN_LAST (1 << 9)
62:
63: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is set, these flags are set
64: if this sparc instruction doesn't take rs2/simm13 and/or rs1 source
65: operands: */
66: #define TME_SPARC_RECODE_INSN_NO_RS2 (1 << 10)
67: #define TME_SPARC_RECODE_INSN_NO_RS1 (1 << 11)
68:
69: /* when the recode opcode is TME_RECODE_OPCODE_GUEST, this flag is set
70: if this sparc instruction doesn't write any sparc register visible
71: to recode: */
72: #define TME_SPARC_RECODE_INSN_NO_RD (1 << 12)
73:
74: /* if set, the TME_SPARC_IREG_INSN register must be valid for this
75: sparc instruction, usually because it uses a generic assist
76: function that needs the instruction word: */
77: #define TME_SPARC_RECODE_INSN_UPDATE_INSN (1 << 13)
78:
79: /* if set, this is a shift instruction: */
80: #define TME_SPARC_RECODE_INSN_SHIFT (1 << 14)
81:
82: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is clear, this is set if
83: this sparc instruction needs TME_RECODE_FLAG_CARRY set with the
84: %icc.C flag: */
85: #define TME_SPARC_RECODE_INSN_DEFC (TME_SPARC_RECODE_INSN_NO_RS2)
86:
87: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is clear, this is set if
88: this sparc instruction updates the sparc condition codes: */
89: #define TME_SPARC_RECODE_INSN_CC (TME_SPARC_RECODE_INSN_NO_RS1)
90:
91: /* NB: the following sparc_recode flags cannot be used in the 16-bit
92: _tme_sparc_recode_insn_opmap[]: */
93:
94: /* if set, this suppresses the normal recoding of the sparc
95: instruction itself (although any TME_SPARC_RECODE_INSN_UPDATE_PCS
96: will still be done): */
97: #define TME_SPARC_RECODE_INSN_NONE (1 << 16)
98:
99: /* if set, this is a v9 32-bit right shift: */
100: #define TME_SPARC_RECODE_INSN_SHIFT_RIGHT (1 << 17)
101:
102: /* if set, after the normal recoding of the sparc instruction, a
103: recode endif will be emitted: */
104: #define TME_SPARC_RECODE_INSN_NEED_ENDIF (1 << 18)
105:
106: /* when TME_SPARC_RECODE_INSN_LAST is set, this is any recode chain
107: information for the instructions thunk: */
108: #define TME_SPARC_RECODE_CHAIN_INFO(x) ((x) << 19)
109: #if (TME_RECODE_CHAIN_INFO_UNCONDITIONAL | TME_RECODE_CHAIN_INFO_CONDITIONAL | TME_RECODE_CHAIN_INFO_NEAR | TME_RECODE_CHAIN_INFO_FAR | TME_RECODE_CHAIN_INFO_JUMP | TME_RECODE_CHAIN_INFO_RETURN | TME_RECODE_CHAIN_INFO_CALL) > 0x1f
110: #error "TME_RECODE_CHAIN_INFO_ values changed"
111: #endif
112:
113: /* these are composite values used in
114: _tme_sparc_recode_insn_opmap[]: */
115:
116: /* this sparc instruction needs an assist: */
117: #define TME_SPARC_RECODE_INSN_ASSIST \
118: (TME_RECODE_OPCODE_GUEST \
119: | TME_SPARC_RECODE_INSN_UPDATE_INSN)
120:
121: /* this sparc instruction needs an assist, and can trap: */
122: #define TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \
123: (TME_SPARC_RECODE_INSN_ASSIST \
124: | TME_SPARC_RECODE_INSN_UPDATE_PCS)
125:
126: /* this sparc instruction needs an assist, can trap, and the assist
127: function does not need source operands from the rs1 and rs2/simm13
128: fields: */
129: #define TME_SPARC_RECODE_INSN_ASSIST_FULL \
130: (TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \
131: | TME_SPARC_RECODE_INSN_NO_RS2 \
132: | TME_SPARC_RECODE_INSN_NO_RS1)
133:
134: /* this sparc instruction is undefined: */
135: #define TME_SPARC_RECODE_INSN_UNDEF TME_SPARC_RECODE_INSN_ASSIST_FULL
136:
137: /* this sparc instruction is a load: */
138: #define TME_SPARC_RECODE_INSN_LD \
139: (TME_SPARC_RECODE_INSN_UPDATE_PCS \
140: | TME_RECODE_OPCODE_RW)
141:
142: /* this sparc instruction is a store: */
143: #define TME_SPARC_RECODE_INSN_ST \
144: (TME_SPARC_RECODE_INSN_UPDATE_PCS \
145: | TME_RECODE_OPCODE_RW)
146:
147: /* this sparc instruction is a load alternate: */
148: #define TME_SPARC_RECODE_INSN_LDA \
149: (TME_SPARC_VERSION(ic) < 9 \
150: ? TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \
151: : TME_SPARC_RECODE_INSN_LD)
152:
153: /* rename various things by the architecture size: */
154: #define tme_sparc_idle_type_pc _TME_SPARC_RECODE_SIZE(tme_sparc_idle_type_pc,/**/)
155: #define _tme_sparc_recode_insn_opmap _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_opmap)
156: #define _tme_sparc_execute_opmap _TME_SPARC_RECODE_SIZE(_tme_sparc,_execute_opmap)
157: #define tme_sparc_recode_insn_current _TME_SPARC_RECODE_SIZE(tme_sparc,_recode_insn_current)
158: #define tme_sparc_recode_insn_assist_redispatch _TME_SPARC_RECODE_SIZE(tme_sparc,_recode_insn_assist_redispatch)
159: #define _tme_sparc_recode_insn_assist _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist)
160: #define _tme_sparc_recode_insn_assist_full _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_full)
161: #define _tme_sparc_recode_insn_assist_jmpl _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_jmpl)
162: #define _tme_sparc_recode_insn_assist_unimpl _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_unimpl)
163: #define _tme_sparc_recode_insns_total _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insns_total)
164: #define _tme_sparc_recode_insn_branch_delay_bad _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_branch_delay_bad)
165: #define _tme_sparc_recode_recode _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_recode)
166:
167: #endif /* TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 */
168:
169: /* this maps format three opcodes into sparc recode controls: */
170: static const tme_uint16_t _tme_sparc_recode_insn_opmap[128] = {
171:
172: /* op=2: arithmetic, logical, shift, and remaining: */
173:
174: /* 000000 */ TME_RECODE_OPCODE_ADD,
175: /* 000001 */ TME_RECODE_OPCODE_AND,
176: /* 000010 */ TME_RECODE_OPCODE_OR,
177: /* 000011 */ TME_RECODE_OPCODE_XOR,
178: /* 000100 */ TME_RECODE_OPCODE_SUB,
179: /* 000101 */ TME_RECODE_OPCODE_ANDN,
180: /* 000110 */ TME_RECODE_OPCODE_ORN,
181: /* 000111 */ TME_RECODE_OPCODE_XORN,
182: /* 001000 */ TME_RECODE_OPCODE_ADDC | TME_SPARC_RECODE_INSN_DEFC,
183: #if TME_SPARC_VERSION(ic) < 9
184: /* 001001 */ TME_SPARC_RECODE_INSN_UNDEF,
185: #else /* TME_SPARC_VERSION(ic) >= 9 */
186: /* 101001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: mulx */
187: #endif /* TME_SPARC_VERSION(ic) >= 9 */
188: /* 001010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* umul */
189: /* 001011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* smul */
190: /* 001100 */ TME_RECODE_OPCODE_SUBC | TME_SPARC_RECODE_INSN_DEFC,
191: #if TME_SPARC_VERSION(ic) < 9
192: /* 001101 */ TME_SPARC_RECODE_INSN_UNDEF,
193: #else /* TME_SPARC_VERSION(ic) >= 9 */
194: /* 001101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: udivx */
195: #endif /* TME_SPARC_VERSION(ic) >= 9 */
196: /* 001110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* udiv */
197: /* 001111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* sdiv */
198: /* 010000 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ADD,
199: /* 010001 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_AND,
200: /* 010010 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_OR,
201: /* 010011 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_XOR,
202: /* 010100 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_SUB,
203: /* 010101 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ANDN,
204: /* 010110 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ORN,
205: /* 010111 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_XORN,
206: /* 011000 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ADDC | TME_SPARC_RECODE_INSN_DEFC,
207: /* 011001 */ TME_SPARC_RECODE_INSN_UNDEF,
208: /* 011010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* umulcc */
209: /* 011011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* smulcc */
210: /* 011100 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_SUBC | TME_SPARC_RECODE_INSN_DEFC,
211: /* 011101 */ TME_SPARC_RECODE_INSN_UNDEF,
212: /* 011110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* udivcc */
213: /* 011111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* sdivcc */
214: /* 100000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* taddcc */
215: /* 100001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* tsubcc */
216: /* 100010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* taddcctv */
217: /* 100011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* tsubcctv */
218: /* 100100 */ TME_SPARC_RECODE_INSN_ASSIST, /* mulscc */
219: /* 100101 */ TME_RECODE_OPCODE_SHLL | TME_SPARC_RECODE_INSN_SHIFT,
220: /* 100110 */ TME_RECODE_OPCODE_SHRL | TME_SPARC_RECODE_INSN_SHIFT,
221: /* 100111 */ TME_RECODE_OPCODE_SHRA | TME_SPARC_RECODE_INSN_SHIFT,
222: /* 101000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdasr */
223: #if TME_SPARC_VERSION(ic) < 9
224: /* 101001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdpsr */
225: #else /* TME_SPARC_VERSION(ic) >= 9 */
226: /* 101001 */ TME_SPARC_RECODE_INSN_UNDEF,
227: #endif /* TME_SPARC_VERSION(ic) >= 9 */
228: /* 101010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdwim (v9: rdpr) */
229: /* 101011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdtbr (v9: flushw) */
230: #if TME_SPARC_VERSION(ic) < 9
231: /* 101100 */ TME_SPARC_RECODE_INSN_UNDEF,
232: /* 101101 */ TME_SPARC_RECODE_INSN_UNDEF,
233: /* 101110 */ TME_SPARC_RECODE_INSN_UNDEF,
234: /* 101111 */ TME_SPARC_RECODE_INSN_UNDEF,
235: #else /* TME_SPARC_VERSION(ic) >= 9 */
236: /* 101100 */ 0, /* v9: movcc (handled specially) */
237: /* 101101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: sdivx */
238: /* 101110 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* v9: popc */
239: /* 101111 */ 0, /* v9: movr (handled specially) */
240: #endif /* TME_SPARC_VERSION(ic) >= 9 */
241: /* 110000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrasr */
242: #if TME_SPARC_VERSION(ic) < 9
243: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrpsr */
244: #else /* TME_SPARC_VERSION(ic) >= 9 */
245: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: saved/restored */
246: #endif /* TME_SPARC_VERSION(ic) >= 9 */
247: /* 110010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrwim (v9: wrpr) */
248: #if TME_SPARC_VERSION(ic) < 9
249: /* 110011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrtbr */
250: #else /* TME_SPARC_VERSION(ic) >= 9 */
251: /* 110011 */ TME_SPARC_RECODE_INSN_UNDEF,
252: #endif /* TME_SPARC_VERSION(ic) >= 9 */
253: /* 110100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* fpop1 */
254: /* 110101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* fpop2 */
255: /* 110110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* cpop1 (v9: impdep1) */
256: /* 110111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* cpop2 (v9: impdep2) */
257: /* 111000 */ 0, /* jmpl (handled specially) */
258: /* 111001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST, /* rett (v9: return) */
259: /* 111010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* ticc */
260: /* 111011 */ TME_SPARC_RECODE_INSN_ASSIST | TME_SPARC_RECODE_INSN_NO_RD, /* flush */
261: /* 111100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* save */
262: /* 111101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* restore */
263: #if TME_SPARC_VERSION(ic) < 9
264: /* 111110 */ TME_SPARC_RECODE_INSN_UNDEF,
265: #else /* TME_SPARC_VERSION(ic) >= 9 */
266: /* 111110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST, /* v9: done/retry */
267: #endif /* TME_SPARC_VERSION(ic) >= 9 */
268: /* 111111 */ TME_SPARC_RECODE_INSN_UNDEF,
269:
270: /* op=3: memory instructions: */
271:
272: /* 000000 */ TME_SPARC_RECODE_INSN_LD, /* ld (v9: lduw) */
273: /* 000001 */ TME_SPARC_RECODE_INSN_LD, /* ldub */
274: /* 000010 */ TME_SPARC_RECODE_INSN_LD, /* lduh */
275: /* 000011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldd */
276: /* 000100 */ TME_SPARC_RECODE_INSN_ST, /* st (v9: stw) */
277: /* 000101 */ TME_SPARC_RECODE_INSN_ST, /* stb */
278: /* 000110 */ TME_SPARC_RECODE_INSN_ST, /* sth */
279: /* 000111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* std */
280: #if TME_SPARC_VERSION(ic) < 9
281: /* 001000 */ TME_SPARC_RECODE_INSN_UNDEF,
282: #else /* TME_SPARC_VERSION(ic) >= 9 */
283: /* 001000 */ TME_SPARC_RECODE_INSN_LD, /* v9: ldsw */
284: #endif /* TME_SPARC_VERSION(ic) >= 9 */
285: /* 001001 */ TME_SPARC_RECODE_INSN_LD, /* ldsb */
286: /* 001010 */ TME_SPARC_RECODE_INSN_LD, /* ldsh */
287: #if TME_SPARC_VERSION(ic) < 9
288: /* 001011 */ TME_SPARC_RECODE_INSN_UNDEF,
289: #else /* TME_SPARC_VERSION(ic) >= 9 */
290: /* 001011 */ TME_SPARC_RECODE_INSN_LD, /* v9: ldx */
291: #endif /* TME_SPARC_VERSION(ic) >= 9 */
292: /* 001100 */ TME_SPARC_RECODE_INSN_UNDEF,
293: /* 001101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldstub */
294: #if TME_SPARC_VERSION(ic) < 9
295: /* 001110 */ TME_SPARC_RECODE_INSN_UNDEF,
296: #else /* TME_SPARC_VERSION(ic) >= 9 */
297: /* 001110 */ TME_SPARC_RECODE_INSN_ST, /* v9: stx */
298: #endif /* TME_SPARC_VERSION(ic) >= 9 */
299: /* 001111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* swap */
300: /* 010000 */ TME_SPARC_RECODE_INSN_LDA, /* lda (v9: lduwa) */
301: /* 010001 */ TME_SPARC_RECODE_INSN_LDA, /* lduba */
302: /* 010010 */ TME_SPARC_RECODE_INSN_LDA, /* lduha */
303: /* 010011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldda */
304: /* 010100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* sta (v9: stwa) */
305: /* 010101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stba */
306: /* 010110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stha */
307: /* 010111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stda */
308: #if TME_SPARC_VERSION(ic) < 9
309: /* 011000 */ TME_SPARC_RECODE_INSN_UNDEF,
310: #else /* TME_SPARC_VERSION(ic) >= 9 */
311: /* 011000 */ TME_SPARC_RECODE_INSN_LDA, /* v9: ldswa*/
312: #endif /* TME_SPARC_VERSION(ic) >= 9 */
313: /* 011001 */ TME_SPARC_RECODE_INSN_LDA, /* ldsba */
314: /* 011010 */ TME_SPARC_RECODE_INSN_LDA, /* ldsha */
315: #if TME_SPARC_VERSION(ic) < 9
316: /* 011011 */ TME_SPARC_RECODE_INSN_UNDEF,
317: #else /* TME_SPARC_VERSION(ic) >= 9 */
318: /* 001011 */ TME_SPARC_RECODE_INSN_LDA, /* v9: ldxa*/
319: #endif /* TME_SPARC_VERSION(ic) >= 9 */
320: /* 011100 */ TME_SPARC_RECODE_INSN_UNDEF,
321: /* 011101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldstuba */
322: #if TME_SPARC_VERSION(ic) < 9
323: /* 011110 */ TME_SPARC_RECODE_INSN_UNDEF,
324: #else /* TME_SPARC_VERSION(ic) >= 9 */
325: /* 001110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* v9: stxa */
326: #endif /* TME_SPARC_VERSION(ic) >= 9 */
327: /* 011111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* swapa */
328: /* 100000 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldf */
329: /* 100001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldfsr */
330: #if TME_SPARC_VERSION(ic) < 9
331: /* 100010 */ TME_SPARC_RECODE_INSN_UNDEF,
332: #else /* TME_SPARC_VERSION(ic) >= 9 */
333: /* 100010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: ldqf */
334: #endif /* TME_SPARC_VERSION(ic) >= 9 */
335: /* 100011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* lddf */
336: /* 100100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stf */
337: /* 100101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stfsr */
338: /* 100110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdfq */
339: /* 100111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdf */
340: /* 101000 */ TME_SPARC_RECODE_INSN_UNDEF,
341: /* 101001 */ TME_SPARC_RECODE_INSN_UNDEF,
342: /* 101010 */ TME_SPARC_RECODE_INSN_UNDEF,
343: /* 101011 */ TME_SPARC_RECODE_INSN_UNDEF,
344: /* 101100 */ TME_SPARC_RECODE_INSN_UNDEF,
345: #if TME_SPARC_VERSION(ic) < 9
346: /* 101101 */ TME_SPARC_RECODE_INSN_UNDEF,
347: #else /* TME_SPARC_VERSION(ic) >= 9 */
348: /* 101101 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* v9: prefetch */
349: #endif /* TME_SPARC_VERSION(ic) >= 9 */
350: /* 101110 */ TME_SPARC_RECODE_INSN_UNDEF,
351: /* 101111 */ TME_SPARC_RECODE_INSN_UNDEF,
352: /* 110000 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldc (v9: ldfa) */
353: #if TME_SPARC_VERSION(ic) < 9
354: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldcsr */
355: /* 110010 */ TME_SPARC_RECODE_INSN_UNDEF,
356: #else /* TME_SPARC_VERSION(ic) >= 9 */
357: /* 110001 */ TME_SPARC_RECODE_INSN_UNDEF,
358: /* 110010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: ldqfa */
359: #endif /* TME_SPARC_VERSION(ic) >= 9 */
360: /* 110011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* lddc (v9: lddfa) */
361: /* 110100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stc (v9: stfa) */
362: #if TME_SPARC_VERSION(ic) < 9
363: /* 110101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stcsr */
364: #else /* TME_SPARC_VERSION(ic) >= 9 */
365: /* 110101 */ TME_SPARC_RECODE_INSN_UNDEF,
366: #endif /* TME_SPARC_VERSION(ic) >= 9 */
367: /* 110110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdcq (v9: stqfa) */
368: /* 110111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdc (v9: stdfa) */
369: /* 111000 */ TME_SPARC_RECODE_INSN_UNDEF,
370: /* 111001 */ TME_SPARC_RECODE_INSN_UNDEF,
371: /* 111010 */ TME_SPARC_RECODE_INSN_UNDEF,
372: /* 111011 */ TME_SPARC_RECODE_INSN_UNDEF,
373: #if TME_SPARC_VERSION(ic) < 9
374: /* 111100 */ TME_SPARC_RECODE_INSN_UNDEF,
375: /* 111101 */ TME_SPARC_RECODE_INSN_UNDEF,
376: /* 111110 */ TME_SPARC_RECODE_INSN_UNDEF,
377: #else /* TME_SPARC_VERSION(ic) >= 9 */
378: /* 111100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: casa */
379: /* 111101 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* v9: prefetch */
380: /* 111110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: casxa */
381: #endif /* TME_SPARC_VERSION(ic) >= 9 */
382: /* 111111 */ TME_SPARC_RECODE_INSN_UNDEF,
383: };
384:
385: /* this returns the current instruction: */
386: tme_uint32_t
387: tme_sparc_recode_insn_current(const struct tme_sparc *ic)
388: {
389: const struct tme_token *itlb_current_token;
390: const struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *recode_itlb_current;
391: const struct tme_sparc_tlb *itlb_current;
392: tme_uint32_t page_offset;
393: const tme_shared tme_uint32_t *_sparc_insn;
394: tme_uint32_t sparc_insn;
395:
396: /* in a cooperative threading system, the current ITLB entry must be
397: valid. in a noncooperative threading system, some master may be
398: in the process of invalidating the current ITLB entry: */
399: itlb_current_token = ic->_tme_sparc_itlb_current_token;
400: assert (!TME_THREADS_COOPERATIVE || tme_token_is_valid(itlb_current_token));
401:
402: /* get the current recode ITLB entry: */
403: recode_itlb_current
404: = ((struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *)
405: (((const char *) itlb_current_token)
406: - (((char *) &(((struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *) 0)->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_token)))
407: - (char *) 0)));
408:
409: /* the current ITLB entry must cover the current context,
410: instruction ASI and PC, and allow fast reading: */
411: itlb_current = &ic->tme_sparc_tlbs[(recode_itlb_current - &ic->_TME_SPARC_RECODE_SIZE(tme_sparc_recode_tlb,s)[0])];
412: assert ((itlb_current->tme_sparc_tlb_context > ic->tme_sparc_memory_context_max
413: || itlb_current->tme_sparc_tlb_context == ic->tme_sparc_memory_context_default)
414: && TME_SPARC_TLB_ASI_MASK_OK(itlb_current, ic->tme_sparc_asi_mask_insn)
415: && itlb_current->tme_sparc_tlb_addr_first <= ic->tme_sparc_ireg(TME_SPARC_IREG_PC)
416: && ic->tme_sparc_ireg(TME_SPARC_IREG_PC) <= itlb_current->tme_sparc_tlb_addr_last
417: && itlb_current->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF);
418:
419: /* fetch the instruction: */
420: page_offset = recode_itlb_current->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_page);
421: page_offset ^= (tme_uint32_t) ic->tme_sparc_ireg(TME_SPARC_IREG_PC);
422: assert ((page_offset >> ic->tme_sparc_tlb_page_size_log2) == 0);
423: _sparc_insn
424: = ((const tme_shared tme_uint32_t *)
425: (recode_itlb_current->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_memory)
426: + page_offset));
427: sparc_insn
428: = tme_memory_bus_read32(_sparc_insn,
429: (tme_rwlock_t *) NULL,
430: sizeof(tme_uint32_t),
431: sizeof(tme_sparc_ireg_t));
432: sparc_insn = tme_betoh_u32(sparc_insn);
433:
434: return (sparc_insn);
435: }
436:
437: /* this checks for conditions that require a redispatch out of recode
438: instruction thunks: */
439: tme_recode_uguest_t
440: tme_sparc_recode_insn_assist_redispatch(struct tme_sparc *ic)
441: {
442: int redispatch_required;
443:
444: /* if the instruction TLB entry for this PC is invalid, or doesn't
445: cover the PC and context and ASI, or doesn't allow fast reading,
446: or isn't covered by any cacheable, or the page containing this PC
447: isn't still cache-valid (i.e., its contents have changed since we
448: cached recoded instructions for it), a redispatch is required: */
449: /* NB: we check for the current PC, even though it's for an
450: instruction that has already completed.
451:
452: if PC and PC_next are on the same page, this does the right
453: thing. if PC and PC_next are on different pages, and the PC page
454: requires a redispatch but the PC_next page does not, this will
455: cause a needless redispatch. if PC and PC_next are on different
456: pages, and the PC page doesn't require a redispatch but the
457: PC_next page does, that will get handled by either
458: _TME_SPARC_EXECUTE_NAME()/tme_sparc_recode() or the host chain
459: out/chain in, because the current instructions thunk can't
460: cover both PC and PC_next.
461:
462: so, checking for the current PC never does the wrong thing, and
463: is useful for at least _tme_sparc_recode_ls_assist_ld(), which
464: must redispatch after executing a ld instruction that might be
465: different from the ld instruction at the time the instructions
466: thunk was recoded - because if the destination register has been
467: changed in the new instruction, if
468: _tme_sparc_recode_ls_assist_ld() did return to the instructions
469: thunk, it would incorrectly take the return value for the
470: destination register in the original instruction: */
471: redispatch_required
472: = (_tme_sparc_recode_chain_src_key(ic,
473: ic->tme_sparc_ireg(TME_SPARC_IREG_PC))
474: == TME_SPARC_RECODE_SRC_KEY_UNDEF);
475:
476: /* if the instruction burst has been set to zero by a
477: TME_BUS_CYCLE_SYNCHRONOUS_EVENT, a redispatch is required: */
478: redispatch_required |= (ic->_tme_sparc_instruction_burst_remaining == 0);
479:
480: /* if a redispatch is required: */
481: if (__tme_predict_false(redispatch_required)) {
482:
483: /* do the redispatch: */
484: tme_sparc_redispatch(ic);
485: }
486:
487: return (0);
488: }
489:
490: /* the assist functions for format three instructions reference the
491: opmap in struct tme_sparc: */
492:
493: /* the assist function for TME_SPARC_RECODE_INSN_ASSIST and
494: TME_SPARC_RECODE_INSN_ASSIST_CANTRAP instructions: */
495: static tme_recode_uguest_t
496: _tme_sparc_recode_insn_assist(struct tme_ic *_ic,
497: tme_recode_uguest_t rs1,
498: tme_recode_uguest_t rs2)
499: {
500: struct tme_sparc *ic;
501: tme_uint32_t sparc_insn;
502: tme_uint32_t sparc_opcode;
503: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic)
504: tme_sparc_ireg_t rs1_buffer;
505: tme_sparc_ireg_t rs2_buffer;
506: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) */
507: tme_sparc_ireg_t *_rs1;
508: tme_sparc_ireg_t *_rs2;
509: tme_sparc_ireg_t rd;
510:
511: /* recover our ic: */
512: ic = (struct tme_sparc *) _ic;
513:
514: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist);
515:
516: /* set PC_next_next from PC_next: */
517: /* NB that this sets PC_next_next to garbage unless this instruction
518: was a TME_SPARC_RECODE_INSN_ASSIST_CANTRAP: */
519: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT)
520: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT)
521: + sizeof(tme_uint32_t));
522:
523: /* copy the instruction from the internal register into its normal
524: position: */
525: sparc_insn = ic->tme_sparc_ireg(TME_SPARC_IREG_INSN);
526: ic->_tme_sparc_insn = sparc_insn;
527:
528: /* form the opcode index: */
529: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19));
530: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40);
531: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]);
532:
533: /* run the instruction: */
534: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic)
535: rs1_buffer = rs1;
536: rs2_buffer = rs2;
537: _rs1 = &rs1_buffer;
538: _rs2 = &rs2_buffer;
539: #else /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */
540: _rs1 = &rs1;
541: _rs2 = &rs2;
542: #endif /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */
543: #ifdef _TME_SPARC_RECODE_VERIFY
544: rd = 0;
545: #endif /* _TME_SPARC_RECODE_VERIFY */
546: (*ic->_tme_sparc_execute_opmap[sparc_opcode])
547: (ic, _rs1, _rs2, &rd);
548:
549: /* return the result: */
550: return (rd);
551: }
552:
553: /* the assist function for TME_SPARC_RECODE_INSN_ASSIST_FULL
554: instructions: */
555: static tme_recode_uguest_t
556: _tme_sparc_recode_insn_assist_full(struct tme_ic *_ic,
557: tme_recode_uguest_t _rs1,
558: tme_recode_uguest_t _rs2)
559: {
560: struct tme_sparc *ic;
561: tme_uint32_t sparc_insn;
562: unsigned int reg_rs1;
563: unsigned int reg_rs2;
564: unsigned int reg_rd;
565: tme_uint32_t sparc_opcode;
566:
567: /* recover our ic: */
568: ic = (struct tme_sparc *) _ic;
569:
570: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_full);
571:
572: /* set PC_next_next from PC_next: */
573: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT)
574: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT)
575: + sizeof(tme_uint32_t));
576:
577: /* copy the instruction from the internal register into its normal
578: position: */
579: sparc_insn = ic->tme_sparc_ireg(TME_SPARC_IREG_INSN);
580: ic->_tme_sparc_insn = sparc_insn;
581:
582: /* if the i bit is zero: */
583: if (__tme_predict_true((sparc_insn & TME_BIT(13)) == 0)) {
584:
585: /* decode rs2: */
586: reg_rs2 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2);
587: TME_SPARC_REG_INDEX(ic, reg_rs2);
588: }
589:
590: /* otherwise, the i bit is one: */
591: else {
592:
593: /* decode simm13: */
594: ic->tme_sparc_ireg(TME_SPARC_IREG_TMP(0)) = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff);
595: reg_rs2 = TME_SPARC_IREG_TMP(0);
596: }
597:
598: /* decode rs1: */
599: reg_rs1 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1);
600: TME_SPARC_REG_INDEX(ic, reg_rs1);
601:
602: /* decode rd: */
603: reg_rd = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD);
604: TME_SPARC_REG_INDEX(ic, reg_rd);
605:
606: /* form the opcode index: */
607: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19));
608: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40);
609: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]);
610:
611: /* run the instruction: */
612: (*ic->_tme_sparc_execute_opmap[sparc_opcode])
613: (ic,
614: &ic->tme_sparc_ireg(reg_rs1),
615: &ic->tme_sparc_ireg(reg_rs2),
616: &ic->tme_sparc_ireg(reg_rd));
617:
618: /* set %g0 to zero, in case the instruction changed it: */
619: ic->tme_sparc_ireg(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G0) = 0;
620:
621: /* return no result */
622: return (tme_sparc_recode_insn_assist_redispatch(ic));
623:
624: /* unused: */
625: _rs1 = 0;
626: _rs2 = 0;
627: }
628:
629: /* the assist function for jmpl instructions: */
630: static tme_recode_uguest_t
631: _tme_sparc_recode_insn_assist_jmpl(struct tme_ic *_ic,
632: tme_recode_uguest_t rs1,
633: tme_recode_uguest_t rs2)
634: {
635: struct tme_sparc *ic;
636: tme_sparc_ireg_t pc_next_next;
637: tme_uint32_t ls_faults;
638:
639: /* recover our ic: */
640: ic = (struct tme_sparc *) _ic;
641:
642: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[0x38 /* jmpl */]);
643:
644: /* get the target address: */
645: pc_next_next = ((tme_sparc_ireg_t) rs1) + (tme_sparc_ireg_t) rs2;
646:
647: /* assume that the target address will not fault: */
648: ls_faults = TME_SPARC_LS_FAULT_NONE;
649:
650: #if TME_SPARC_VERSION(ic) >= 9
651:
652: /* mask the target address: */
653: pc_next_next &= ic->tme_sparc_address_mask;
654:
655: /* if the target address is in a virtual address hole: */
656: if (__tme_predict_false((pc_next_next
657: + ic->tme_sparc64_ireg_va_hole_start)
658: > ((ic->tme_sparc64_ireg_va_hole_start * 2) - 1))) {
659:
660: /* the target address is out of range: */
661: ls_faults += TME_SPARC64_LS_FAULT_VA_RANGE_NNPC;
662: }
663:
664: #endif /* TME_SPARC_VERSION(ic) >= 9 */
665:
666: /* if the target address is not 32-bit aligned: */
667: if (__tme_predict_false((((tme_uint32_t) pc_next_next) % sizeof(tme_uint32_t)) != 0)) {
668:
669: /* the target address is misaligned: */
670: ls_faults += TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED;
671: }
672:
673: /* if the target address has faulted: */
674: if (__tme_predict_false(ls_faults != TME_SPARC_LS_FAULT_NONE)) {
675:
676: /* set PC_next from PC: */
677: /* NB: we don't need to set PC_next_next, because we're
678: faulting: */
679: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT)
680: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC)
681: + sizeof(tme_uint32_t));
682:
683: /* in case a CPU-specific trap function needs it, store a dummy
684: jmpl instruction: */
685: ic->_tme_sparc_insn
686: = ((((tme_uint32_t) 2) << 30)
687: + (0x38 << 19) /* jmpl */
688: );
689:
690: /* fault: */
691: tme_sparc_nnpc_trap(ic, ls_faults);
692: }
693:
694: /* return the target address: */
695: return (pc_next_next);
696: }
697:
698: /* the assist function for unimplemented instructions: */
699: static tme_recode_uguest_t
700: _tme_sparc_recode_insn_assist_unimpl(struct tme_ic *_ic,
701: tme_recode_uguest_t _rs1,
702: tme_recode_uguest_t _rs2)
703: {
704: struct tme_sparc *ic;
705:
706: /* recover our ic: */
707: ic = (struct tme_sparc *) _ic;
708:
709: /* set PC_next_next from PC_next: */
710: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT)
711: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT)
712: + sizeof(tme_uint32_t));
713:
714: /* trap: */
715: #if TME_SPARC_VERSION(ic) < 9
716: tme_sparc32_trap(ic, TME_SPARC32_TRAP_illegal_instruction);
717: #else /* TME_SPARC_VERSION(ic) >= 9 */
718: tme_sparc64_trap(ic, TME_SPARC64_TRAP_illegal_instruction);
719: #endif /* TME_SPARC_VERSION(ic) >= 9 */
720:
721: /* return no result */
722: return (0);
723:
724: /* unused: */
725: _rs1 = 0;
726: _rs2 = 0;
727: }
728:
729: #ifdef _TME_SPARC_STATS
730: static tme_recode_uguest_t
731: _tme_sparc_recode_insns_total(struct tme_ic *_ic,
732: tme_recode_uguest_t _rs1,
733: tme_recode_uguest_t _rs2)
734: {
735: TME_SPARC_STAT_N(((struct tme_sparc *) _ic),
736: tme_sparc_stats_recode_insns_total,
737: (tme_uint32_t) _rs2);
738: return (0);
739: }
740: #endif /* _TME_SPARC_STATS */
741:
742: /* this returns nonzero if the given instruction can't be recoded in a
743: branch delay slot. in general, an instruction can't be recoded in
744: a branch delay slot if it may set PC_next_next without doing a
745: redispatch, or if it may use a recode if/endif: */
746: static int
747: _tme_sparc_recode_insn_branch_delay_bad(tme_uint32_t sparc_insn)
748: {
749: unsigned int sparc_opcode;
750:
751: /* if this is a format three instruction, and op is three: */
752: if (sparc_insn >= 0xc0000000) {
753:
754: /* all of the instructions with op equal to three can be recoded
755: in a branch delay slot: */
756: return (FALSE);
757: }
758:
759: /* otherwise, if this is a format three instruction, and op is
760: two: */
761: else if (sparc_insn >= 0x80000000) {
762:
763: /* form the opcode index: */
764: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19));
765:
766: /* instructions that may set PC_next_next without doing a
767: redispatch, and instructions that may use a recode if/endif
768: can't be recoded in a branch delay slot: */
769: return (sparc_opcode == 0x38 /* jmpl */
770: || (TME_SPARC_VERSION(ic) >= 9
771: && (sparc_opcode == 0x2c /* v9: movcc */
772: || sparc_opcode == 0x2f))); /* v9: movr */
773: }
774:
775: /* otherwise, if this is a format two instruction: */
776: else if (__tme_predict_true(sparc_insn < 0x40000000)) {
777:
778: /* except for sethi instructions, format two instructions can't be
779: recoded in a branch delay slot - the other implemented format
780: two instructions are all branches that set PC_next_next: */
781: return ((sparc_insn & (0x7 << 22)) != (0x4 << 22));
782: }
783:
784: /* otherwise, this is a format three instruction: */
785: else {
786:
787: /* we can't recode call instructions in branch delay slots, since
788: they set PC_next_next: */
789: return (TRUE);
790: }
791: }
792:
793: /* the sparc instruction recoder: */
794: static tme_recode_thunk_off_t
795: _tme_sparc_recode_recode(struct tme_sparc *ic,
796: const struct tme_sparc_tlb *itlb)
797: {
798: tme_uint32_t page_size;
799: unsigned int reg_guest_pc;
800: unsigned int recode_size_address;
801: struct tme_recode_insn *recode_insn;
802: struct tme_recode_insn *recode_insns_last_start;
803: tme_sparc_ireg_t pc_next;
804: tme_uint32_t sparc_insn_next;
805: tme_uint32_t sparc_insn_count;
806: tme_uint32_t pc_advance;
807: tme_uint32_t sparc_recode;
808: tme_sparc_ireg_t itlb_addr_last;
809: tme_recode_uguest_t (*sparc_assist) _TME_P((struct tme_ic *, tme_recode_uguest_t, tme_recode_uguest_t));
810: tme_uint32_t sparc_insn;
811: tme_uint32_t sparc_opcode;
812: int recode_operand;
813: tme_sparc_ireg_t imm;
814: unsigned int shift_count_mask;
815: unsigned int cond;
816: const struct tme_recode_conds_thunk *conds_thunk;
817: tme_int32_t branch_displacement_raw;
818: tme_sparc_ireg_t branch_displacement;
819: const struct tme_recode_flags_thunk *flags_thunk;
820: int recode_operand_address;
821: tme_uint32_t chain_info;
822:
823: /* get the page size: */
824: page_size = (((tme_uint32_t) 1) << ic->tme_sparc_tlb_page_size_log2);
825:
826: /* on entry to this function, PC has already been updated to be the
827: first instruction. on entry to an instructions thunk, PC hasn't
828: been updated yet, and PC_next is the first instruction: */
829: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
830:
831: /* assume that addresses are guest size: */
832: recode_size_address = TME_SPARC_RECODE_SIZE(ic);
833:
834: /* if this is a v9 CPU and PSTATE.AM is set: */
835: if (TME_SPARC_VERSION(ic) >= 9
836: && (ic->tme_sparc64_ireg_pstate
837: & TME_SPARC64_PSTATE_AM)) {
838:
839: /* addresses are only 32 bits wide: */
840: recode_size_address = TME_RECODE_SIZE_32;
841: }
842:
843: /* start at the beginning of the recode instructions buffer: */
844: recode_insn = &ic->tme_sparc_recode_insns[0];
845:
846: /* calculate the worst-case position in the recode instructions
847: buffer, past which we may not be able to recode another sparc
848: instruction. this is actually an upper bound on the worst case,
849: found by counting the number of "recode_insn++" statements in
850: this function, and multiplying that by two so that branch
851: instructions can loop to recode a branch delay slot: */
852: recode_insns_last_start = &ic->tme_sparc_recode_insns[TME_ARRAY_ELS(ic->tme_sparc_recode_insns) - (35 * 2)];
853:
854: /* fetch the first instruction as the next instruction: */
855: pc_next = ic->tme_sparc_ireg(TME_SPARC_IREG_PC);
856: sparc_insn_next
857: = tme_memory_bus_read32(((const tme_shared tme_uint32_t *)
858: (itlb->tme_sparc_tlb_emulator_off_read
859: + pc_next)),
860: itlb->tme_sparc_tlb_bus_rwlock,
861: sizeof(tme_uint32_t),
862: sizeof(tme_sparc_ireg_t));
863: sparc_insn_next = tme_betoh_u32(sparc_insn_next);
864: sparc_insn_count = 0;
865:
866: /* the next instruction will be the first instruction: */
867: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn_next);
868:
869: /* clear the recode information: */
870: sparc_recode = 0;
871:
872: /* if PC is at the last instruction address before tme_sparc_ireg_t
873: wrapping: */
874: /* NB: we don't consider the v9 address mask here, because we only
875: need to protect against the pc_next local variable itself
876: wrapping its tme_sparc_ireg_t. if the v9 address mask is set for
877: 32 bits and PC is 0xfffffffc, pc_next will not wrap to zero -
878: instead it will advance to 0x100000000, but we also won't
879: continue to recode because that address is on a different
880: page: */
881: assert (TME_SPARC_VERSION(ic) < 9
882: || (pc_next < ic->tme_sparc_address_mask));
883: if (__tme_predict_false(pc_next
884: == (tme_sparc_ireg_t) (0 - (tme_sparc_ireg_t) sizeof(tme_uint32_t)))) {
885:
886: /* recode is impossible here: */
887: return (0);
888: }
889:
890: /* stop recoding after the last instruction on the page, or right
891: before the last instruction before tme_sparc_ireg_t wrapping,
892: whichever comes first: */
893: itlb_addr_last
894: = ((pc_next
895: | (page_size - 1))
896: - (sizeof(tme_uint32_t) - 1));
897: if (__tme_predict_false(itlb_addr_last
898: == (tme_sparc_ireg_t) (0 - (tme_sparc_ireg_t) sizeof(tme_uint32_t)))) {
899: itlb_addr_last -= sizeof(tme_uint32_t);
900: }
901: assert (itlb_addr_last >= pc_next);
902: assert (itlb->tme_sparc_tlb_addr_last >= itlb_addr_last);
903:
904: /* loop recoding instructions: */
905: for (;;) {
906:
907: /* reset the assist function: */
908: sparc_assist = _tme_sparc_recode_insn_assist;
909:
910: /* make the next instruction the current instruction: */
911: pc_advance += sizeof(sparc_insn);
912: sparc_insn = sparc_insn_next;
913: sparc_insn_count++;
914:
915: /* advance the PC of the next instruction: */
916: pc_next += sizeof(sparc_insn);
917:
918: /* if the PC of the next instruction is still in this
919: page: */
920: if (__tme_predict_true(pc_next <= itlb_addr_last)) {
921:
922: /* fetch the next instruction: */
923: sparc_insn_next
924: = tme_memory_bus_read32(((const tme_shared tme_uint32_t *)
925: (itlb->tme_sparc_tlb_emulator_off_read
926: + pc_next)),
927: itlb->tme_sparc_tlb_bus_rwlock,
928: sizeof(tme_uint32_t),
929: sizeof(tme_sparc_ireg_t));
930: sparc_insn_next = tme_betoh_u32(sparc_insn_next);
931: }
932:
933: /* otherwise, the instruction TLB entry doesn't cover the PC of
934: the next instruction: */
935: else {
936:
937: /* the current instruction is the last instruction, and we need
938: to update the PC registers: */
939: sparc_recode |= TME_SPARC_RECODE_INSN_LAST | TME_SPARC_RECODE_INSN_UPDATE_PCS;
940:
941: /* in case the current instruction is a control transfer
942: instruction, poison the next instruction to look like another
943: control transfer instruction. we use a call instruction: */
944: sparc_insn_next = 0x40000000;
945: }
946:
947: /* if this is a format three instruction (op is two or three): */
948: if (__tme_predict_true(sparc_insn >= 0x80000000)) {
949:
950: /* form the opcode index: */
951: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19));
952: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40);
953:
954: /* add in the recode information for this instruction: */
955: sparc_recode |= _tme_sparc_recode_insn_opmap[sparc_opcode];
956:
957: /* if this is a jmpl instruction: */
958: if (__tme_predict_false(sparc_opcode == 0x38)) {
959:
960: /* if the next instruction can't be recoded when it's in a
961: branch delay slot (usually because it's also a control
962: transfer instruction): */
963: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) {
964:
965: /* if we haven't recoded any instructions yet, recode is
966: impossible here: */
967: if (recode_insn == &ic->tme_sparc_recode_insns[0]) {
968: return (0);
969: }
970:
971: /* stop recoding immediately, leaving the updated PC
972: pointing to the instruction before the jmpl: */
973: assert (pc_advance >= sizeof(sparc_insn));
974: pc_advance -= sizeof(sparc_insn);
975: sparc_insn_count--;
976: sparc_recode
977: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS
978: | TME_SPARC_RECODE_INSN_NONE
979: | TME_SPARC_RECODE_INSN_LAST);
980: }
981:
982: /* otherwise, the next instruction can be recoded when it's in
983: a branch delay slot: */
984: else {
985:
986: /* if PC doesn't already point to the jmpl instruction: */
987: if (pc_advance != 0
988: || reg_guest_pc != TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)) {
989:
990: /* advance PC to the jmpl instruction: */
991: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
992: recode_insn->tme_recode_insn_size = recode_size_address;
993: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc;
994: recode_insn->tme_recode_insn_operand_src[1]
995: = (pc_advance == 0
996: ? TME_RECODE_OPERAND_ZERO
997: : TME_RECODE_OPERAND_IMM);
998: recode_insn->tme_recode_insn_imm_uguest = pc_advance;
999: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1000: recode_insn->tme_recode_insn_flags_thunk = NULL;
1001: recode_insn++;
1002: }
1003:
1004: /* if rs1 is %i7 or %o7, assume that this jmpl is doing a
1005: return, otherwise assume that this jmpl is doing a
1006: call. either way, the branch delay slot will be the
1007: last instruction: */
1008: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1));
1009: sparc_recode
1010: |= ((((recode_operand
1011: - TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0))
1012: & 15 /* %o7 */)
1013: == 15 /* %o7 */)
1014: ? (TME_SPARC_RECODE_INSN_LAST
1015: + TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_RETURN
1016: + TME_RECODE_CHAIN_INFO_FAR
1017: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
1018: : (TME_SPARC_RECODE_INSN_LAST
1019: + TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_CALL
1020: + TME_RECODE_CHAIN_INFO_FAR
1021: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL)));
1022:
1023: /* call the jmpl assist function. if this doesn't trap, it
1024: returns the target address for PC_next_next, which we put
1025: directly into PC_next: */
1026: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST;
1027: recode_insn->tme_recode_insn_size = recode_size_address;
1028: recode_insn->tme_recode_insn_operand_src[0]
1029: = (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)
1030: ? TME_RECODE_OPERAND_ZERO
1031: : recode_operand);
1032: if (__tme_predict_true(sparc_insn & TME_BIT(13))) {
1033: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1034: recode_insn->tme_recode_insn_imm_uguest
1035: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff);
1036: }
1037: else {
1038: recode_insn->tme_recode_insn_operand_src[1]
1039: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2));
1040: }
1041: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1042: recode_insn->tme_recode_insn_guest_func = _tme_sparc_recode_insn_assist_jmpl;
1043: recode_insn++;
1044:
1045: /* assume that rd is %g0: */
1046: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1047:
1048: /* decode rd: */
1049: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD));
1050:
1051: /* if rd is not %g0: */
1052: if (recode_operand != TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) {
1053:
1054: /* we will soon be able to find the PC of the jmpl in rd: */
1055: reg_guest_pc = recode_operand;
1056:
1057: /* write the PC of the jmpl into the destination register: */
1058: /* NB: we don't use recode_size_address here because we need to
1059: update the entire destination register: */
1060: recode_insn->tme_recode_insn_operand_dst = recode_operand;
1061: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1062: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1063: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1064: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1065: recode_insn->tme_recode_insn_flags_thunk = NULL;
1066: recode_insn++;
1067: }
1068:
1069: /* advance PC to the branch delay slot: */
1070: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1071: recode_insn->tme_recode_insn_size = recode_size_address;
1072: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc;
1073: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1074: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn);
1075: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1076: recode_insn->tme_recode_insn_flags_thunk = NULL;
1077: recode_insn++;
1078: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn);
1079: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1080:
1081: /* loop now to fetch and recode the instruction in the branch
1082: delay slot: */
1083: continue;
1084: }
1085: }
1086:
1087: /* otherwise, if this is a v9 movcc instruction: */
1088: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9
1089: && sparc_opcode == 0x2c)) {
1090:
1091: /* if cc2 is clear, or if cc1 is set, this is not an integer
1092: movcc: */
1093: if (__tme_predict_false((sparc_insn
1094: & (TME_BIT(18)
1095: | TME_BIT(11)))
1096: != TME_BIT(18))) {
1097:
1098: /* this instruction needs a full assist: */
1099: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL;
1100: }
1101:
1102: /* otherwise, this is an integer movcc: */
1103: else {
1104:
1105: /* get the condition field: */
1106: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 14));
1107:
1108: /* get the conditions thunk to test: */
1109: conds_thunk
1110: = ((sparc_insn & TME_BIT(12))
1111: ? ic->tme_sparc_recode_conds_thunk_xcc
1112: : ic->tme_sparc_recode_conds_thunk_icc);
1113:
1114: /* define the first recode flag with the condition: */
1115: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC;
1116: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT);
1117: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT);
1118: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG(0);
1119: recode_insn->tme_recode_insn_conds_thunk = conds_thunk;
1120: recode_insn++;
1121:
1122: /* emit the if to test the first recode carry flag: */
1123: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF;
1124: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG(0);
1125: recode_insn++;
1126:
1127: /* move the source operand to the destination register: */
1128: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1129: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1130: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1131: if (sparc_insn & TME_BIT(13)) {
1132: recode_insn->tme_recode_insn_imm_uguest
1133: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x7ff);
1134: recode_operand = TME_RECODE_OPERAND_IMM;
1135: }
1136: else {
1137: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2));
1138: }
1139: recode_insn->tme_recode_insn_operand_src[1] = recode_operand;
1140: recode_insn->tme_recode_insn_operand_dst
1141: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD));
1142: recode_insn->tme_recode_insn_flags_thunk = NULL;
1143: recode_insn++;
1144:
1145: /* emit the endif: */
1146: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF;
1147: recode_insn++;
1148:
1149: /* suppress any instructions below: */
1150: sparc_recode |= TME_SPARC_RECODE_INSN_NONE;
1151: }
1152: }
1153:
1154: /* otherwise, if this is a v9 movr instruction: */
1155: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9
1156: && sparc_opcode == 0x2f)) {
1157:
1158: /* get the condition field: */
1159: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x7 << 10));
1160:
1161: /* this shifts the "not" bit in the condition up from bit
1162: two to bit three, to match the other branches: */
1163: cond = (cond + 4) & (TME_SPARC_COND_NOT | 3);
1164:
1165: /* if this is an unimplemented movr: */
1166: if (__tme_predict_false(!TME_SPARC_COND_IS_CONDITIONAL(cond))) {
1167:
1168: /* this instruction needs a full assist: */
1169: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL;
1170: }
1171:
1172: /* otherwise, this is an implemented movr: */
1173: else {
1174:
1175: /* test the register and set the internal "rcc" flags: */
1176: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1));
1177: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND;
1178: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1179: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1180: recode_insn->tme_recode_insn_operand_src[1] = recode_operand;
1181: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL;
1182: recode_insn->tme_recode_insn_flags_thunk = ic->tme_sparc_recode_flags_thunk_rcc;
1183: recode_insn++;
1184:
1185: /* define the first recode flag with the condition: */
1186: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC;
1187: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT);
1188: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT);
1189: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG(0);
1190: recode_insn->tme_recode_insn_conds_thunk = ic->tme_sparc_recode_conds_thunk_rcc;
1191: recode_insn++;
1192:
1193: /* emit the if to test the first recode carry flag: */
1194: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF;
1195: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG(0);
1196: recode_insn++;
1197:
1198: /* move the source operand to the destination register: */
1199: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1200: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1201: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1202: if (sparc_insn & TME_BIT(13)) {
1203: recode_insn->tme_recode_insn_imm_uguest
1204: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x3ff);
1205: recode_operand = TME_RECODE_OPERAND_IMM;
1206: }
1207: else {
1208: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2));
1209: }
1210: recode_insn->tme_recode_insn_operand_src[1] = recode_operand;
1211: recode_insn->tme_recode_insn_operand_dst
1212: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD));
1213: recode_insn->tme_recode_insn_flags_thunk = NULL;
1214: recode_insn++;
1215:
1216: /* emit the endif: */
1217: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF;
1218: recode_insn++;
1219:
1220: /* suppress any instructions below: */
1221: sparc_recode |= TME_SPARC_RECODE_INSN_NONE;
1222: }
1223: }
1224:
1225: /* otherwise, if this is a v9 ld*a instruction: */
1226: /* NB: all of the simple ld and st instructions that we handle
1227: here, have bit 21 (bit 2 in the opcode) set for a st, and
1228: clear for a ld: */
1229: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9
1230: && TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_RW
1231: && ((sparc_opcode
1232: & (TME_BIT(4)
1233: + TME_BIT(2)))
1234: == (TME_BIT(4)
1235: + !TME_BIT(2))))) {
1236:
1237: /* if the i bit is clear, and the immediate ASI is not
1238: ASI_PRIMARY_NOFAULT or ASI_PRIMARY_NOFAULT_LITTLE: */
1239: if ((sparc_insn & TME_BIT(13)) == 0
1240: && (TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xff << 5))
1241: != (TME_SPARC64_ASI_FLAG_UNRESTRICTED
1242: + ((ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_CLE)
1243: ? TME_SPARC64_ASI_FLAG_LITTLE
1244: : !TME_SPARC64_ASI_FLAG_LITTLE)
1245: + TME_SPARC64_ASI_FLAG_NO_FAULT))) {
1246:
1247: /* this instruction can't be a simple ld instruction: */
1248: sparc_recode
1249: ^= (TME_SPARC_RECODE_INSN_LDA
1250: ^ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP);
1251: }
1252: }
1253:
1254: /* if this instruction needs a full assist: */
1255: if ((sparc_recode
1256: & (TME_SPARC_RECODE_INSN_OPCODE_MASK
1257: | TME_SPARC_RECODE_INSN_NO_RS2
1258: | TME_SPARC_RECODE_INSN_NO_RS1))
1259: == (TME_RECODE_OPCODE_GUEST
1260: | TME_SPARC_RECODE_INSN_NO_RS2
1261: | TME_SPARC_RECODE_INSN_NO_RS1)) {
1262:
1263: /* set the full assist function: */
1264: sparc_assist = _tme_sparc_recode_insn_assist_full;
1265: }
1266: }
1267:
1268: /* otherwise, if this is a format two instruction: */
1269: else if (__tme_predict_true(sparc_insn < 0x40000000)) {
1270:
1271: /* dispatch on op2: */
1272: switch (TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x7 << 22))) {
1273:
1274: default:
1275: case 0: /* UNIMP: */
1276: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST;
1277: sparc_assist = _tme_sparc_recode_insn_assist_unimpl;
1278: break;
1279:
1280: #if TME_SPARC_VERSION(ic) >= 9
1281: case 1: /* BPcc */
1282: case 3: /* BPr */
1283: #endif /* TME_SPARC_VERSION(ic) >= 9 */
1284: case 2: /* Bicc: */
1285:
1286: /* if the next instruction can't be recoded when it's in a
1287: branch delay slot (usually because it's also a control
1288: transfer instruction): */
1289: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) {
1290:
1291: /* if we haven't recoded any instructions yet, recode is
1292: impossible here: */
1293: if (recode_insn == &ic->tme_sparc_recode_insns[0]) {
1294: return (0);
1295: }
1296:
1297: /* stop recoding immediately, leaving the updated PC
1298: pointing to the instruction before the jmpl: */
1299: assert (pc_advance >= sizeof(sparc_insn));
1300: pc_advance -= sizeof(sparc_insn);
1301: sparc_insn_count--;
1302: sparc_recode
1303: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS
1304: | TME_SPARC_RECODE_INSN_NONE
1305: | TME_SPARC_RECODE_INSN_LAST);
1306: break;
1307: }
1308:
1309: /* get the condition field: */
1310: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 25));
1311:
1312: /* assume that this branch instruction tests a condition in
1313: the icc flags: */
1314: conds_thunk = ic->tme_sparc_recode_conds_thunk_icc;
1315:
1316: /* if this is a BPr or a BPcc: */
1317: if (TME_SPARC_VERSION(ic) >= 9
1318: && (sparc_insn & (0x1 << 22))) {
1319:
1320: /* if this is a BPr: */
1321: if (sparc_insn & (0x2 << 22)) {
1322:
1323: /* if this is an unimplemented BPr instruction: */
1324: if (__tme_predict_false((sparc_insn & (1 << 28)) != 0
1325: || (sparc_insn & (3 << 25)) == 0)) {
1326:
1327: /* do a full assist and stop recoding: */
1328: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST;
1329: sparc_assist = _tme_sparc_recode_insn_assist_unimpl;
1330: break;
1331: }
1332:
1333: /* test the register and set the internal "rcc" flags: */
1334: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1));
1335: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND;
1336: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1337: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1338: recode_insn->tme_recode_insn_operand_src[1] = recode_operand;
1339: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL;
1340: recode_insn->tme_recode_insn_flags_thunk = ic->tme_sparc_recode_flags_thunk_rcc;
1341: recode_insn++;
1342:
1343: /* this shifts the "not" bit in the condition up from bit
1344: two to bit three, to match the other branches: */
1345: cond = (cond + 4) & (TME_SPARC_COND_NOT | 3);
1346:
1347: /* we need to test the condition in the internal "rcc" flags: */
1348: conds_thunk = ic->tme_sparc_recode_conds_thunk_rcc;
1349:
1350: /* get the raw branch displacement: */
1351: branch_displacement_raw
1352: = ((tme_int16_t)
1353: (((sparc_insn & (0x3 << 20)) >> 6)
1354: | (sparc_insn & 0x3fff)));
1355: }
1356:
1357: /* otherwise, this is a BPcc: */
1358: else {
1359:
1360: /* if this is an unimplemented BPcc instruction: */
1361: if (__tme_predict_false((sparc_insn & (1 << 20)) != 0)) {
1362:
1363: /* do a full assist and stop recoding: */
1364: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST;
1365: sparc_assist = _tme_sparc_recode_insn_assist_unimpl;
1366: break;
1367: }
1368:
1369: /* if this BPcc is testing the xcc flags: */
1370: if (sparc_insn & (1 << 21)) {
1371: conds_thunk = ic->tme_sparc_recode_conds_thunk_xcc;
1372: }
1373:
1374: /* get the raw branch displacement: */
1375: branch_displacement_raw
1376: = ((tme_int32_t)
1377: TME_FIELD_MASK_EXTRACTS(sparc_insn, 0x0007ffff));
1378: }
1379: }
1380:
1381: /* otherwise, this is a Bicc: */
1382: else {
1383:
1384: /* get the raw branch displacement: */
1385: branch_displacement_raw
1386: = ((tme_int32_t)
1387: TME_FIELD_MASK_EXTRACTS(sparc_insn, 0x003fffff));
1388: }
1389:
1390: /* fully sign-extend the branch displacement: */
1391: branch_displacement
1392: = ((tme_sparc_ireg_t)
1393: (tme_recode_guest_t)
1394: branch_displacement_raw);
1395:
1396: /* advance PC to the branch delay slot: */
1397: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1398: recode_insn->tme_recode_insn_size = recode_size_address;
1399: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc;
1400: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1401: recode_insn->tme_recode_insn_imm_uguest = pc_advance + sizeof(sparc_insn);
1402: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1403: recode_insn->tme_recode_insn_flags_thunk = NULL;
1404: recode_insn++;
1405: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn);
1406: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1407:
1408: /* if this isn't a branch always: */
1409: if (cond != (TME_SPARC_COND_NOT | TME_SPARC_COND_N)) {
1410:
1411: /* assuming that the branch won't be taken, set PC_next to
1412: the instruction following the branch delay slot: */
1413: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1414: recode_insn->tme_recode_insn_size = recode_size_address;
1415: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1416: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1417: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn);
1418: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1419: recode_insn->tme_recode_insn_flags_thunk = NULL;
1420: recode_insn++;
1421: }
1422:
1423: /* if this is a conditional branch: */
1424: if (TME_SPARC_COND_IS_CONDITIONAL(cond)) {
1425:
1426: /* define the recode jump flag with the condition: */
1427: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC;
1428: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT);
1429: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT);
1430: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG_JUMP;
1431: recode_insn->tme_recode_insn_conds_thunk = conds_thunk;
1432: recode_insn++;
1433:
1434: /* emit the if to test the recode jump flag: */
1435: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF;
1436: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG_JUMP;
1437: recode_insn++;
1438: }
1439:
1440: /* if this isn't a branch never: */
1441: if (cond != TME_SPARC_COND_N) {
1442:
1443: /* if this branch target is within this same page, this chain
1444: can be near, otherwise it must be far: */
1445: if ((((pc_next - sizeof(sparc_insn))
1446: + (branch_displacement * sizeof(sparc_insn)))
1447: ^ (pc_next - sizeof(sparc_insn)))
1448: < page_size) {
1449: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_NEAR);
1450: }
1451: else {
1452: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_FAR);
1453: }
1454:
1455: /* if this is a branch always: */
1456: if (cond == (TME_SPARC_COND_NOT | TME_SPARC_COND_N)) {
1457:
1458: /* the branch delay slot will be the last instruction, and
1459: after that we need an unconditional jump: */
1460: sparc_recode
1461: |= (TME_SPARC_RECODE_INSN_LAST
1462: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_JUMP
1463: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL));
1464:
1465: /* set PC_next to the branch target, using the address of
1466: the branch delay slot already in PC (which is one
1467: instruction away from the PC of the branch, to which
1468: the branch displacement is relative): */
1469: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1470: branch_displacement -= 1;
1471: }
1472:
1473: /* otherwise, this is a conditional branch: */
1474: else {
1475:
1476: /* the branch delay slot will be the last instruction, and
1477: after that we need an conditional jump: */
1478: sparc_recode
1479: |= (TME_SPARC_RECODE_INSN_LAST
1480: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_JUMP
1481: + TME_RECODE_CHAIN_INFO_CONDITIONAL));
1482:
1483: /* change PC_next to the branch target, from the
1484: instruction following the branch delay slot already in
1485: PC_next (which is two instructions away from the PC of
1486: the branch, to which the branch displacement is
1487: relative): */
1488: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1489: branch_displacement -= 2;
1490: }
1491:
1492: /* set PC_next to the branch target: */
1493: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1494: recode_insn->tme_recode_insn_size = recode_size_address;
1495: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1496: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1497: recode_insn->tme_recode_insn_imm_uguest = branch_displacement * sizeof(sparc_insn);
1498: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1499: recode_insn->tme_recode_insn_flags_thunk = NULL;
1500: recode_insn++;
1501: }
1502:
1503: /* if this is a conditional branch: */
1504: if (TME_SPARC_COND_IS_CONDITIONAL(cond)) {
1505:
1506: /* if this conditional branch never annuls the branch delay
1507: slot: */
1508: if ((sparc_insn & TME_BIT(29)) == 0) {
1509:
1510: /* emit the endif: */
1511: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF;
1512: recode_insn++;
1513: }
1514:
1515: /* otherwise, this conditional branch annuls the branch
1516: delay slot if the branch is not taken: */
1517: else {
1518:
1519: /* we need to emit the endif after we emit the
1520: instructions for the branch delay slot: */
1521: sparc_recode |= TME_SPARC_RECODE_INSN_NEED_ENDIF;
1522: }
1523: }
1524:
1525: /* otherwise, this is an unconditional branch: */
1526: else {
1527:
1528: /* if the branch delay slot is annulled: */
1529: if (sparc_insn & TME_BIT(29)) {
1530:
1531: /* don't bother to recode the instruction in the branch
1532: delay slot: */
1533: sparc_recode |= TME_SPARC_RECODE_INSN_NONE;
1534: }
1535: }
1536:
1537: /* if this is a branch to . instruction: */
1538: if (__tme_predict_false(branch_displacement_raw == 0)) {
1539:
1540: /* if this isn't a branch never, and this isn't an
1541: unconditional branch that annuls, and the branch with its
1542: delay instruction are a supported timing loop: */
1543: if (cond != TME_SPARC_COND_N
1544: && (sparc_recode & TME_SPARC_RECODE_INSN_NONE) == 0
1545: && tme_sparc_timing_loop_ok(sparc_insn,
1546: sparc_insn_next)) {
1547:
1548: /* store the branch delay instruction in the instruction register: */
1549: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1550: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32;
1551: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1552: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1553: recode_insn->tme_recode_insn_imm_u32 = sparc_insn_next;
1554: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_INSN);
1555: recode_insn->tme_recode_insn_flags_thunk = NULL;
1556: recode_insn++;
1557:
1558: /* call the timing loop assist function: */
1559: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST;
1560: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32;
1561: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_IMM;
1562: recode_insn->tme_recode_insn_imm_u32 = sparc_insn;
1563: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_ZERO;
1564: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL;
1565: recode_insn->tme_recode_insn_guest_func = tme_sparc_timing_loop_assist;
1566: recode_insn++;
1567:
1568: /* the branch delay instruction must be the last instruction: */
1569: assert (sparc_recode & TME_SPARC_RECODE_INSN_LAST);
1570:
1571: /* advance to the branch delay instruction: */
1572: assert (((tme_uint32_t) (pc_advance + sizeof(sparc_insn))) == 0
1573: && reg_guest_pc == TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC));
1574: pc_advance = 0;
1575:
1576: /* suppress the branch delay instruction: */
1577: sparc_recode |= TME_SPARC_RECODE_INSN_NONE;
1578:
1579: /* do *not* loop now to fetch and recode the instruction
1580: in the branch delay slot: */
1581: break;
1582: }
1583: }
1584:
1585: /* loop now to fetch and recode the instruction in the branch
1586: delay slot: */
1587: continue;
1588:
1589: case 4: /* SETHI: */
1590:
1591: /* unless this instruction is suppressed, load the constant
1592: into the register: */
1593: if (!(sparc_recode & TME_SPARC_RECODE_INSN_NONE)) {
1594: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD));
1595: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1596: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1597: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1598: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1599: recode_insn->tme_recode_insn_imm_u32 = (tme_uint32_t) (sparc_insn << 10);
1600: recode_insn->tme_recode_insn_operand_dst = recode_operand;
1601: recode_insn->tme_recode_insn_flags_thunk = NULL;
1602: recode_insn++;
1603: }
1604:
1605: /* suppress any instructions below: */
1606: sparc_recode |= TME_SPARC_RECODE_INSN_NONE;
1607: break;
1608:
1609: #if TME_SPARC_VERSION(ic) >= 9
1610: case 5: /* FBPfcc */
1611: #endif /* TME_SPARC_VERSION(ic) >= 9 */
1612: case 6: /* FBfcc: */
1613:
1614: /* if we haven't recoded any instructions yet, recode is
1615: impossible here: */
1616: if (recode_insn == &ic->tme_sparc_recode_insns[0]) {
1617: return (0);
1618: }
1619:
1620: /* stop recoding immediately, leaving the updated PC
1621: pointing to the instruction before the jmpl: */
1622: assert (pc_advance >= sizeof(sparc_insn));
1623: pc_advance -= sizeof(sparc_insn);
1624: sparc_insn_count--;
1625: sparc_recode
1626: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS
1627: | TME_SPARC_RECODE_INSN_NONE
1628: | TME_SPARC_RECODE_INSN_LAST);
1629: break;
1630: }
1631: }
1632:
1633: /* otherwise, this is a format one instruction: */
1634: else {
1635:
1636: /* if the next instruction can't be recoded when it's in a
1637: branch delay slot (usually because it's also a control
1638: transfer instruction): */
1639: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) {
1640:
1641: /* if we haven't recoded any instructions yet, recode is
1642: impossible here: */
1643: if (recode_insn == &ic->tme_sparc_recode_insns[0]) {
1644: return (0);
1645: }
1646:
1647: /* stop recoding immediately, leaving the updated PC
1648: pointing to the instruction before the jmpl: */
1649: assert (pc_advance >= sizeof(sparc_insn));
1650: pc_advance -= sizeof(sparc_insn);
1651: sparc_insn_count--;
1652: sparc_recode
1653: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS
1654: | TME_SPARC_RECODE_INSN_NONE
1655: | TME_SPARC_RECODE_INSN_LAST);
1656: }
1657:
1658: /* otherwise, the next instruction can be recoded when it's in a
1659: branch delay slot: */
1660: else {
1661:
1662: /* write the PC of the CALL into r[15]: */
1663: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1664: recode_insn->tme_recode_insn_size = recode_size_address;
1665: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc;
1666: recode_insn->tme_recode_insn_operand_src[1]
1667: = (pc_advance == 0
1668: ? TME_RECODE_OPERAND_ZERO
1669: : TME_RECODE_OPERAND_IMM);
1670: recode_insn->tme_recode_insn_imm_uguest = pc_advance;
1671: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(15);
1672: recode_insn->tme_recode_insn_flags_thunk = NULL;
1673: recode_insn++;
1674:
1675: /* if the PC is not guest size: */
1676: if (recode_size_address < TME_SPARC_RECODE_SIZE(ic)) {
1677:
1678: /* zero-extend r[15] to guest size: */
1679: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_EXTZ;
1680: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1681: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(15);
1682: recode_insn->tme_recode_insn_operand_src[1] = recode_size_address;
1683: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(15);
1684: recode_insn->tme_recode_insn_flags_thunk = NULL;
1685: recode_insn++;
1686: }
1687:
1688: /* advance PC to the branch delay slot: */
1689: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1690: recode_insn->tme_recode_insn_size = recode_size_address;
1691: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(15);
1692: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1693: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn);
1694: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1695: recode_insn->tme_recode_insn_flags_thunk = NULL;
1696: recode_insn++;
1697: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn);
1698: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1699:
1700: /* write the target of the call into PC_next. NB that we have
1701: to account for the fact that PC already points to the
1702: branch delay slot, but the displacement is relative to the
1703: PC of the call instruction: */
1704: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1705: recode_insn->tme_recode_insn_size = recode_size_address;
1706: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1707: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1708: recode_insn->tme_recode_insn_imm_uguest
1709: = ((tme_sparc_ireg_t)
1710: (((tme_recode_guest_t)
1711: (tme_int32_t)
1712: (sparc_insn << 2))
1713: - sizeof(sparc_insn)));
1714: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1715: recode_insn->tme_recode_insn_flags_thunk = NULL;
1716: recode_insn++;
1717:
1718: /* the branch delay slot will be the last instruction, and
1719: after that we need an unconditional call: */
1720: sparc_recode
1721: |= (TME_SPARC_RECODE_INSN_LAST
1722: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_CALL
1723: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL));
1724:
1725: /* if the call target is within this same page,
1726: the call can be near, otherwise the call must be far: */
1727: if ((((pc_next - sizeof(sparc_insn))
1728: + ((tme_sparc_ireg_t)
1729: (tme_recode_guest_t)
1730: (tme_int32_t)
1731: (sparc_insn << 2)))
1732: ^ (pc_next - sizeof(sparc_insn)))
1733: < page_size) {
1734: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_NEAR);
1735: }
1736: else {
1737: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_FAR);
1738: }
1739:
1740: continue;
1741: }
1742: }
1743:
1744: /* if we might not have enough space for recode insns for the next
1745: instruction: */
1746: if (__tme_predict_false(recode_insn >= recode_insns_last_start)) {
1747:
1748: /* this will be the last instruction, and we need to update the
1749: PCs: */
1750: sparc_recode |= TME_SPARC_RECODE_INSN_UPDATE_PCS | TME_SPARC_RECODE_INSN_LAST;
1751: }
1752:
1753: /* if this is the last instruction, we must be updating PC and
1754: PC_next: */
1755: assert ((sparc_recode & TME_SPARC_RECODE_INSN_LAST) == 0
1756: || (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_PCS)
1757: || (pc_advance == 0
1758: && reg_guest_pc == TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)));
1759:
1760: /* if we need PC and PC_next to be valid for this instruction: */
1761: if (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_PCS) {
1762:
1763: /* if we need to update PC and PC_next: */
1764: if (pc_advance > 0
1765: || reg_guest_pc != TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)) {
1766:
1767: /* advance PC: */
1768: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1769: recode_insn->tme_recode_insn_size = recode_size_address;
1770: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc;
1771: recode_insn->tme_recode_insn_operand_src[1]
1772: = (pc_advance == 0
1773: ? TME_RECODE_OPERAND_ZERO
1774: : TME_RECODE_OPERAND_IMM);
1775: recode_insn->tme_recode_insn_imm_uguest = pc_advance;
1776: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1777: recode_insn->tme_recode_insn_flags_thunk = NULL;
1778: recode_insn++;
1779: pc_advance = 0;
1780: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1781:
1782: /* set PC_next: */
1783: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1784: recode_insn->tme_recode_insn_size = recode_size_address;
1785: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC);
1786: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1787: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn);
1788: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT);
1789: recode_insn->tme_recode_insn_flags_thunk = NULL;
1790: recode_insn++;
1791: }
1792: }
1793:
1794: /* if this instruction hasn't been suppressed: */
1795: if (__tme_predict_true((sparc_recode & TME_SPARC_RECODE_INSN_NONE) == 0)) {
1796:
1797: /* if this instruction always or sometimes needs an assist: */
1798: if (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_INSN) {
1799:
1800: /* store the instruction in the instruction register: */
1801: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
1802: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32;
1803: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
1804: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1805: recode_insn->tme_recode_insn_imm_u32 = sparc_insn;
1806: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_INSN);
1807: recode_insn->tme_recode_insn_flags_thunk = NULL;
1808: recode_insn++;
1809:
1810: /* if this instruction doesn't take rs2: */
1811: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RS2) {
1812:
1813: /* clear the i bit and rs2, to force the second source
1814: operand to be %g0, or zero: */
1815: sparc_insn &= ~(TME_BIT(13) | TME_SPARC_FORMAT3_MASK_RS2);
1816: }
1817:
1818: /* if this instruction doesn't take rs1: */
1819: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RS1) {
1820:
1821: /* clear rs1, to force the first source operand to be %g0,
1822: or zero: */
1823: sparc_insn &= ~TME_SPARC_FORMAT3_MASK_RS1;
1824: }
1825: }
1826:
1827: /* otherwise, this instruction doesn't need an assist: */
1828: else {
1829:
1830: /* if this is an addx, addxcc, subx, or subxcc instruction: */
1831: if (sparc_recode & TME_SPARC_RECODE_INSN_DEFC) {
1832:
1833: /* define the recode carry flag with the icc C flag: */
1834: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC;
1835: recode_insn->tme_recode_insn_operand_src[0] = TME_SPARC_COND_CS;
1836: recode_insn->tme_recode_insn_operand_src[1] = 0;
1837: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG_CARRY;
1838: recode_insn->tme_recode_insn_conds_thunk = ic->tme_sparc_recode_conds_thunk_icc;
1839: recode_insn++;
1840: }
1841:
1842: /* because we set the flags thunk on the recode instruction
1843: now, this instruction can't be a shift (because a shift may
1844: make more than one recode instruction): */
1845: assert ((sparc_recode
1846: & (TME_SPARC_RECODE_INSN_CC
1847: | TME_SPARC_RECODE_INSN_SHIFT))
1848: != (TME_SPARC_RECODE_INSN_CC
1849: | TME_SPARC_RECODE_INSN_SHIFT));
1850:
1851: /* assume that this instruction doesn't update flags: */
1852: flags_thunk = NULL;
1853:
1854: /* if this instruction updates flags: */
1855: if (sparc_recode & TME_SPARC_RECODE_INSN_CC) {
1856:
1857: /* set the right flags thunk for this instruction. NB that
1858: the least significant two bits of op3 are zero only for
1859: the additive instructions, and bit two of op3 is set only
1860: for a subtraction instruction: */
1861: flags_thunk
1862: = ((sparc_insn & (0x3 << 19)) == 0
1863: ? ((sparc_insn & (0x4 << 19))
1864: ? ic->tme_sparc_recode_flags_thunk_sub
1865: : ic->tme_sparc_recode_flags_thunk_add)
1866: : ic->tme_sparc_recode_flags_thunk_logical);
1867: }
1868:
1869: /* set any flags thunk on this instruction: */
1870: recode_insn->tme_recode_insn_flags_thunk = flags_thunk;
1871: }
1872:
1873: /* assume that if this is a shift, it's a 32-bit shift: */
1874: shift_count_mask = 32 - 1;
1875:
1876: /* if this is a v9 shift: */
1877: if (TME_SPARC_VERSION(ic) >= 9
1878: && (sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) {
1879:
1880: /* if this is a 64-bit shift: */
1881: if (sparc_insn & TME_BIT(12)) {
1882:
1883: /* this is a 64-bit shift: */
1884: shift_count_mask = 64 - 1;
1885: }
1886:
1887: /* otherwise, this is a 32-bit shift: */
1888: else {
1889:
1890: /* if this is a right shift: */
1891: if (sparc_insn & TME_BIT(20)) {
1892:
1893: /* remember that this is a right shift: */
1894: sparc_recode |= TME_SPARC_RECODE_INSN_SHIFT_RIGHT;
1895:
1896: /* decode rs1: */
1897: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1));
1898:
1899: /* extend rs1 into the second temporary register. if this
1900: is a shift right arithmetic, sign extend, else zero
1901: extend: */
1902: recode_insn->tme_recode_insn_opcode
1903: = ((sparc_insn & TME_BIT(19))
1904: ? TME_RECODE_OPCODE_EXTS
1905: : TME_RECODE_OPCODE_EXTZ);
1906: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1907: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1908: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_SIZE_32;
1909: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(1));
1910: recode_insn++;
1911:
1912: /* NB that the flags thunk for the final instruction was
1913: already set above (to NULL, because sparc shift
1914: instructions do not affect any condition codes), so we
1915: have to do the same since we advanced to the next
1916: instruction: */
1917: recode_insn->tme_recode_insn_flags_thunk = NULL;
1918: }
1919: }
1920: }
1921:
1922: /* if the i bit is one: */
1923: if (sparc_insn & TME_BIT(13)) {
1924:
1925: /* decode simm13: */
1926: imm = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff);
1927:
1928: /* if this is a shift instruction: */
1929: if (__tme_predict_false(sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) {
1930:
1931: /* mask the immediate with the shift count mask: */
1932: imm &= shift_count_mask;
1933: }
1934:
1935: /* if the immediate is zero, the second source operand is zero,
1936: otherwise the second source operand is the immediate: */
1937: recode_insn->tme_recode_insn_imm_uguest = imm;
1938: recode_operand
1939: = (imm == 0
1940: ? TME_RECODE_OPERAND_ZERO
1941: : TME_RECODE_OPERAND_IMM);
1942: }
1943:
1944: /* otherwise, the i bit is zero: */
1945: else {
1946:
1947: /* decode rs2: */
1948: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2));
1949: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) {
1950: recode_operand = TME_RECODE_OPERAND_ZERO;
1951: }
1952:
1953: /* if this is a shift instruction: */
1954: if (__tme_predict_false(sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) {
1955:
1956: /* make a temporary copy of the register with shift count,
1957: masked with the shift count mask, and use the temporary
1958: register as the second source operand: */
1959: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND;
1960: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
1961: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1962: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
1963: recode_insn->tme_recode_insn_imm_uguest = shift_count_mask;
1964: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(0));
1965: recode_insn->tme_recode_insn_operand_dst = recode_operand;
1966: recode_insn++;
1967:
1968: /* NB that the flags thunk for the final instruction was
1969: already set above (to NULL, because sparc shift
1970: instructions do not affect any condition codes), so we
1971: have to do the same since we advanced to the next
1972: instruction: */
1973: recode_insn->tme_recode_insn_flags_thunk = NULL;
1974: }
1975: }
1976:
1977: /* set the second source operand: */
1978: recode_insn->tme_recode_insn_operand_src[1] = recode_operand;
1979:
1980: /* decode rs1: */
1981: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1));
1982: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) {
1983: recode_operand = TME_RECODE_OPERAND_ZERO;
1984: }
1985:
1986: /* if this is a v9 32-bit right shift: */
1987: if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9
1988: && (sparc_recode & TME_SPARC_RECODE_INSN_SHIFT_RIGHT))) {
1989:
1990: /* the first source operand is actually in the second
1991: temporary register: */
1992: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(1));
1993: }
1994:
1995: /* set the first source operand: */
1996: recode_insn->tme_recode_insn_operand_src[0] = recode_operand;
1997:
1998: /* decode rd: */
1999: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD));
2000: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) {
2001: recode_operand = TME_RECODE_OPERAND_NULL;
2002: }
2003:
2004: /* if this is a simple ld or st instruction: */
2005: if (TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_RW) {
2006:
2007: /* assume that the first source operand is %g0, which makes
2008: the second source operand the guest address: */
2009: recode_operand_address = recode_insn->tme_recode_insn_operand_src[1];
2010:
2011: /* if the second source operand is %g0: */
2012: if (recode_operand_address == TME_RECODE_OPERAND_ZERO) {
2013:
2014: /* nothing to do; the guest address is the first source
2015: operand, which is already in
2016: recode_insn->tme_recode_insn_operand_src[0]: */
2017: }
2018:
2019: /* otherwise, the second source operand is not %g0: */
2020: else {
2021:
2022: /* if the first source operand is not %g0: */
2023: if (recode_insn->tme_recode_insn_operand_src[0] != TME_RECODE_OPERAND_ZERO) {
2024:
2025: /* add the two parts of the guest address into the
2026: temporary register: */
2027: recode_operand_address = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(0));
2028: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD;
2029: recode_insn->tme_recode_insn_size = recode_size_address;
2030: recode_insn->tme_recode_insn_operand_dst = recode_operand_address;
2031: recode_insn->tme_recode_insn_flags_thunk = NULL;
2032: recode_insn++;
2033: }
2034:
2035: /* set the guest address as the first source operand: */
2036: recode_insn->tme_recode_insn_operand_src[0] = recode_operand_address;
2037: }
2038:
2039: /* if this is a st instruction: */
2040: /* NB: all of the simple ld and st instructions that we handle
2041: here, have bit 21 set for a st, and clear for a ld: */
2042: if (sparc_insn & (4 << 19)) {
2043:
2044: /* the second source operand is the register being
2045: stored: */
2046: recode_insn->tme_recode_insn_operand_src[1]
2047: = ((TME_RECODE_OPERAND_NULL != TME_RECODE_OPERAND_ZERO
2048: && recode_operand == TME_RECODE_OPERAND_NULL)
2049: ? TME_RECODE_OPERAND_ZERO
2050: : recode_operand);
2051:
2052: /* the destination operand must be the recode %null: */
2053: recode_operand = TME_RECODE_OPERAND_NULL;
2054: }
2055:
2056: /* otherwise, this is an ld instruction: */
2057: else {
2058:
2059: /* the second source operand must be zero: */
2060: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_ZERO;
2061: }
2062:
2063: /* set the read/write thunk: */
2064: assert (TME_SPARC_VERSION(ic) >= 9 || (sparc_insn & (16 << 19)) == 0);
2065: recode_insn->tme_recode_insn_rw_thunk
2066: = ic->tme_sparc_recode_rw_thunks
2067: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic,
2068: (TME_SPARC_RECODE_SIZE(ic)
2069: - (TME_SPARC_VERSION(ic) >= 9
2070: && (ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_AM))),
2071: ((TME_SPARC_VERSION(ic) >= 9
2072: && (ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_CLE))
2073: ? TME_ENDIAN_LITTLE
2074: : TME_ENDIAN_BIG),
2075: (TME_SPARC_VERSION(ic) >= 9
2076: && (sparc_insn & (16 << 19))),
2077: TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 19)))];
2078: }
2079:
2080: /* otherwise, if this instruction needs an assist: */
2081: else if (TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_GUEST) {
2082:
2083: /* set the assist function: */
2084: recode_insn->tme_recode_insn_guest_func = sparc_assist;
2085:
2086: /* if this instruction needs a full assist: */
2087: if ((sparc_recode
2088: & (TME_SPARC_RECODE_INSN_NO_RS2
2089: | TME_SPARC_RECODE_INSN_NO_RS1))
2090: == (TME_SPARC_RECODE_INSN_NO_RS2
2091: | TME_SPARC_RECODE_INSN_NO_RS1)) {
2092:
2093: /* the source operands can be the recode %undef, since the
2094: full assist functions don't use the source operands: */
2095: assert (sparc_assist == _tme_sparc_recode_insn_assist_full
2096: || sparc_assist == _tme_sparc_recode_insn_assist_unimpl
2097: );
2098: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_UNDEF;
2099: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_UNDEF;
2100:
2101: /* assume that this instruction is not also marked
2102: TME_SPARC_RECODE_INSN_NO_RD, and force the destination
2103: operand to be the recode %null, to indicate that the
2104: assist can change any of the recode-visible ic state: */
2105: recode_operand = TME_RECODE_OPERAND_NULL;
2106: }
2107:
2108: /* if this instruction's rd field doesn't encode a destination
2109: general register: */
2110: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RD) {
2111:
2112: /* force the destination operand to be the fixed %g0: */
2113: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0);
2114: }
2115: }
2116:
2117: /* set the destination operand: */
2118: recode_insn->tme_recode_insn_operand_dst = recode_operand;
2119:
2120: /* set the size: */
2121: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
2122:
2123: /* set the opcode: */
2124: recode_insn->tme_recode_insn_opcode = TME_SPARC_RECODE_INSN_OPCODE(sparc_recode);
2125:
2126: /* we have finished this instruction: */
2127: recode_insn++;
2128: }
2129:
2130: /* if we need to, emit an endif: */
2131: if (sparc_recode & TME_SPARC_RECODE_INSN_NEED_ENDIF) {
2132: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF;
2133: recode_insn++;
2134: #ifndef NDEBUG
2135: sparc_recode &= ~TME_SPARC_RECODE_INSN_NEED_ENDIF;
2136: #endif
2137: }
2138:
2139: /* if this was the last instruction: */
2140: if (sparc_recode & TME_SPARC_RECODE_INSN_LAST) {
2141: break;
2142: }
2143:
2144: /* clear sparc_recode: */
2145: sparc_recode = 0;
2146: }
2147:
2148: /* make sure we didn't forget an endif: */
2149: assert ((sparc_recode & TME_SPARC_RECODE_INSN_NEED_ENDIF) == 0);
2150:
2151: #ifdef _TME_SPARC_STATS
2152: /* update the recode instructions total: */
2153: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST;
2154: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic);
2155: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
2156: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM;
2157: recode_insn->tme_recode_insn_imm_u32 = sparc_insn_count;
2158: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0);
2159: recode_insn->tme_recode_insn_guest_func = _tme_sparc_recode_insns_total;
2160: recode_insn++;
2161: #endif /* _TME_SPARC_STATS */
2162:
2163: /* set the end of the instructions: */
2164: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_insns_end = recode_insn;
2165:
2166: /* get the chain information: */
2167: chain_info
2168: = ((sparc_recode
2169: / TME_SPARC_RECODE_CHAIN_INFO(1))
2170: & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
2171: | TME_RECODE_CHAIN_INFO_CONDITIONAL
2172: | TME_RECODE_CHAIN_INFO_NEAR
2173: | TME_RECODE_CHAIN_INFO_FAR
2174: | TME_RECODE_CHAIN_INFO_JUMP
2175: | TME_RECODE_CHAIN_INFO_RETURN
2176: | TME_RECODE_CHAIN_INFO_CALL
2177: ));
2178:
2179: /* if there is no chain information: */
2180: if (chain_info == 0) {
2181:
2182: /* if the next PC is on the same page, make a chain jump near
2183: unconditional, otherwise make a chain jump far
2184: unconditional: */
2185: if (pc_next <= itlb_addr_last) {
2186: chain_info += TME_RECODE_CHAIN_INFO_NEAR;
2187: }
2188: else {
2189: chain_info += TME_RECODE_CHAIN_INFO_FAR;
2190: }
2191: chain_info
2192: += (TME_RECODE_CHAIN_INFO_JUMP
2193: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL);
2194: }
2195:
2196: /* otherwise, there is chain information. if the chain is
2197: conditional: */
2198: else if ((chain_info
2199: & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
2200: | TME_RECODE_CHAIN_INFO_CONDITIONAL))
2201: != TME_RECODE_CHAIN_INFO_UNCONDITIONAL) {
2202:
2203: /* if the alternate PC is on the same page, the alternate target
2204: can be near, otherwise it must be far: */
2205: if (pc_next <= itlb_addr_last) {
2206: chain_info += TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR;
2207: }
2208: else {
2209: chain_info += TME_RECODE_CHAIN_INFO_ALTERNATE_FAR;
2210: }
2211: }
2212:
2213: /* set the chain information: */
2214: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_chain_info = chain_info;
2215:
2216: /* make sure we didn't overflow the instructions buffer: */
2217: assert (recode_insn <= &ic->tme_sparc_recode_insns[TME_ARRAY_ELS(ic->tme_sparc_recode_insns)]);
2218:
2219: /* recode these instructions: */
2220: return (tme_recode_insns_thunk(ic->tme_sparc_recode_ic,
2221: &ic->tme_sparc_recode_insns_group));
2222: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.