|
|
1.1 root 1: /* $Id: rc-x86-subs-asm.S,v 1.2 2009/09/07 15:25:23 fredette Exp $ */
2:
3: /* libtme/host/x86/rc-x86-subs-asm.S - hand-coded x86 host recode subs: */
4:
5: /*
6: * Copyright (c) 2007 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: .text
37:
38: .ascii "$Id: rc-x86-subs-asm.S,v 1.2 2009/09/07 15:25:23 fredette Exp $"
39:
40: # concatenation:
41: #
42: #if ((defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)) && !defined(UNIXCPP)) || defined(ANSICPP)
43: #define __TME_CONCAT(a,b) a ## b
44: #define _TME_CONCAT(a,b) __TME_CONCAT(a,b)
45: #else
46: #define _TME_CONCAT(a,b) a/**/b
47: #endif
48:
49: #ifdef __x86_64__
50: #define TME_RECODE_SIZE_HOST 6
51: #define TME_RECODE_BITS_HOST(x) _TME_CONCAT(x, 64)
52: #define TME_RECODE_BITS_DOUBLE_HOST(x) _TME_CONCAT(x, 128)
53: #define TME_RECODE_X86_OPN(x) _TME_CONCAT(x, q)
54: #define TME_RECODE_X86_REGN(x) _TME_CONCAT(%r, x)
55: #define TME_RECODE_X86_REG_HOST_SUBS_DST_N %r12
56: #define TME_RECODE_X86_REG_HOST_SUBS_DST_L %r12d
57: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_N %rbp
58: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_L %ebp
59: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_W %bp
60: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_B %bpl
61: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_P1_N %rax
62: #else /* !__x86_64__ */
63: #define TME_RECODE_SIZE_HOST 5
64: #define TME_RECODE_BITS_HOST(x) _TME_CONCAT(x, 32)
65: #define TME_RECODE_BITS_DOUBLE_HOST(x) _TME_CONCAT(x, 64)
66: #define TME_RECODE_X86_OPN(x) _TME_CONCAT(x, l)
67: #define TME_RECODE_X86_REGN(x) _TME_CONCAT(%e, x)
68: #define TME_RECODE_X86_REG_HOST_SUBS_DST_N %edi
69: #define TME_RECODE_X86_REG_HOST_SUBS_DST_L %edi
70: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_N %ebp
71: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_L %ebp
72: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_W %bp
73: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1_P1_N %eax
74: #endif /* !__x86_64__ */
75:
76: # this macro does a double-host-size shift:
77: #
78: .macro tme_recode_x86_double_shift name shift shiftd reg_first reg_second arith=0
79: .align 16
80: .globl \name
81: \name:
82:
83: # branch if the most-significant half of the shift count in
84: # src1 is nonzero, swapping the least-significant half of the
85: # shift count in src1 with the scratch c register in the
86: # meantime. we will swap them back after the shift.
87: #
88: # NB: we do the swaps with the c register instead of just
89: # overwriting it, to cooperate with subs that keep the
90: # most-significant half of src0 in the c register:
91: #
92: TME_RECODE_X86_OPN(test) TME_RECODE_X86_REG_HOST_SUBS_SRC1_P1_N, TME_RECODE_X86_REG_HOST_SUBS_SRC1_P1_N
93: TME_RECODE_X86_OPN(xchg) TME_RECODE_X86_REG_HOST_SUBS_SRC1_N, TME_RECODE_X86_REGN(cx)
94: jnz .L_double_shift_2_\@
95:
96: # branch if the shift count is greater than the host size:
97: #
98: TME_RECODE_X86_OPN(cmp) $(1 << TME_RECODE_SIZE_HOST), TME_RECODE_X86_REGN(cx)
99: jae .L_double_shift_1_\@
100:
101: # do the double-precision shift:
102: #
103: \shiftd %cl, \reg_second, \reg_first
104: \shift %cl, \reg_second
105: TME_RECODE_X86_OPN(xchg) TME_RECODE_X86_REG_HOST_SUBS_SRC1_N, TME_RECODE_X86_REGN(cx)
106: ret
107:
108: .L_double_shift_1_\@:
109:
110: # branch if the shift count is greater than or equal to the
111: # double-host size:
112: #
113: TME_RECODE_X86_OPN(cmp) $2*(1 << TME_RECODE_SIZE_HOST), TME_RECODE_X86_REGN(cx)
114: jae .L_double_shift_2_\@
115:
116: # first do a host-size shift by doing a register move and
117: # then a clear for a logical shift, or a copy of the most
118: # significant bit of the second register down into all other
119: # bits:
120: #
121: TME_RECODE_X86_OPN(mov) \reg_second, \reg_first
122: .if \arith
123: TME_RECODE_X86_OPN(shl) $1, \reg_second
124: TME_RECODE_X86_OPN(sbb) \reg_second, \reg_second
125: .else
126: TME_RECODE_X86_OPN(xor) \reg_second, \reg_second
127: .endif
128:
129: # do the remainder of the shift as a host-size shift (which
130: # masks the count in %cl to the host size):
131: #
132: \shift %cl, \reg_first
133: TME_RECODE_X86_OPN(xchg) TME_RECODE_X86_REG_HOST_SUBS_SRC1_N, TME_RECODE_X86_REGN(cx)
134: ret
135:
136: # the shift count is greater than the double-host-size. for a
137: # logical shift, clear both registers. for an arithmetic shift,
138: # copy the most significant bit of the second register down into
139: # all bits in both registers:
140: #
141: .L_double_shift_2_\@:
142: .if \arith
143: TME_RECODE_X86_OPN(shl) $1, \reg_second
144: TME_RECODE_X86_OPN(sbb) \reg_second, \reg_second
145: TME_RECODE_X86_OPN(mov) \reg_second, \reg_first
146: .else
147: TME_RECODE_X86_OPN(xor) \reg_first, \reg_first
148: TME_RECODE_X86_OPN(xor) \reg_second, \reg_second
149: .endif
150: TME_RECODE_X86_OPN(xchg) TME_RECODE_X86_REG_HOST_SUBS_SRC1_N, TME_RECODE_X86_REGN(cx)
151: ret
152: .endm
153:
154: # this macro does a host-size or smaller shift:
155: #
156: .macro tme_recode_x86_shift insn size shift
157: .align 16
158: .globl tme_recode_x86_\insn\size
159: tme_recode_x86_\insn\size:
160:
161: # _if this is a right shift smaller than host size, first
162: # zero-extend or sign-extend the destination to host size,
163: # so we can do a 32-bit shift, or branch to
164: # _tme_recode_x86_shift_arithmetic_all (which assumes that
165: # the destination is host size):
166: #
167: .ifnc \insn,shll
168: .if \size < TME_RECODE_BITS_HOST(/**/)
169:
170: # _if this is an 8-bit shift on an ia32 host, we can't encode
171: # %dil for a movzbl or movsbl, so we do an and for a movzbl and
172: # a movsbl through the c register:
173: #
174: .ifeq (TME_RECODE_BITS_HOST(/**/) - 32) | (\size - 8)
175: .ifc \insn,shra
176: movl %edi, %ecx
177: movsbl %cl, %edi
178: .else
179: andl $0xff, %edi
180: .endif
181: .else
182:
183: # otherwise, emit a movz or movs instruction to extend
184: # the destination in TME_RECODE_X86_REG_HOST_SUBS_DST:
185: #
186: .ifeq \size - 32
187: # the x86_64 32-bit extensions are different:
188: #
189: .ifc \insn,shra
190: movslq TME_RECODE_X86_REG_HOST_SUBS_DST_L, TME_RECODE_X86_REG_HOST_SUBS_DST_N
191: .else
192: movl TME_RECODE_X86_REG_HOST_SUBS_DST_L, TME_RECODE_X86_REG_HOST_SUBS_DST_L
193: .endif
194: .else
195: #ifdef __x86_64__
196: .byte 0x48 + (1 << 0) + (1 << 2) # TME_RECODE_X86_REX_R(TME_RECODE_SIZE_64, %r12) + TME_RECODE_X86_REX_B(0, %r12)
197: #endif /* __x86_64__ */
198: .byte 0x0f # TME_RECODE_X86_OPCODE_ESC_0F
199: .ifc \insn,shra
200: .byte 0xbf - ((\size / 8) & 1) # TME_RECODE_X86_OPCODE0F_MOVS_Ew_Gv or TME_RECODE_X86_OPCODE0F_MOVS_Eb_Gv
201: .else
202: .byte 0xb7 - ((\size / 8) & 1) # TME_RECODE_X86_OPCODE0F_MOVZ_Ew_Gv or TME_RECODE_X86_OPCODE0F_MOVZ_Eb_Gv
203: .endif
204: #ifdef __x86_64__
205: .byte (0xc0 + (12 % 8)) + ((12 % 8) << 3) # %r12, %r12
206: #else /* !__x86_64__ */
207: .byte (0xc0 + 7) + (7 << 3) # %edi, %edi
208: #endif /* __x86_64__ */
209: .endif
210: .endif
211: .endif
212: .endif
213:
214: # compare the shift count in TME_RECODE_X86_REG_HOST_SUBS_SRC1
215: # to the size:
216: #
217: .ifeq \size - 64
218: cmpq $\size, TME_RECODE_X86_REG_HOST_SUBS_SRC1_N
219: .else
220: .ifeq \size - 32
221: cmpl $\size, TME_RECODE_X86_REG_HOST_SUBS_SRC1_L
222: .else
223: .ifeq \size - 16
224: cmpw $\size, TME_RECODE_X86_REG_HOST_SUBS_SRC1_W
225: .else
226: .ifeq \size - 8
227: #ifdef TME_RECODE_X86_REG_HOST_SUBS_SRC1_B
228: cmpb $\size, TME_RECODE_X86_REG_HOST_SUBS_SRC1_B
229: #else
230: movl TME_RECODE_X86_REG_HOST_SUBS_SRC1_L, %ecx
231: cmpb $\size, %cl
232: #endif
233: .endif
234: .endif
235: .endif
236: .endif
237:
238: # put the shift count into the c register. this has already
239: # been done if this is an 8-bit shift on an ia32 host:
240: #
241: .ifne (TME_RECODE_BITS_HOST(/**/) - 32) | (\size - 8)
242: movl TME_RECODE_X86_REG_HOST_SUBS_SRC1_L, %ecx
243: .endif
244:
245: # _if the shift count is greater than or equal to the size,
246: # for an arithmetic shift copy the most-significant bit down
247: # into all other bits, otherwise do a clear:
248: #
249: .ifc \insn,shra
250: jae _tme_recode_x86_shift_arithmetic_all
251: .else
252: jae _tme_recode_x86_shift_logical_all
253: .endif
254:
255: # otherwise, do the shift:
256: #
257: .ifeq (\size - 64)
258: \shift %cl, TME_RECODE_X86_REG_HOST_SUBS_DST_N
259: .else
260: \shift %cl, TME_RECODE_X86_REG_HOST_SUBS_DST_L
261: .endif
262: ret
263: .endm
264:
265: # the shifts:
266: #
267: #ifdef __x86_64__
268: tme_recode_x86_double_shift tme_recode_x86_shll128 shlq shldq %r13 %r12
269: tme_recode_x86_double_shift tme_recode_x86_shrl128 shrq shrdq %r12 %r13
270: tme_recode_x86_double_shift tme_recode_x86_shra128 sarq shrdq %r12 %r13 1
271: tme_recode_x86_shift shll 64 shlq
272: tme_recode_x86_shift shrl 64 shrq
273: tme_recode_x86_shift shra 64 sarq
274: #else /* !__x86_64__ */
275: tme_recode_x86_double_shift tme_recode_x86_shll64 shll shldl %esi %edi
276: tme_recode_x86_double_shift tme_recode_x86_shrl64 shrl shrdl %edi %esi
277: tme_recode_x86_double_shift tme_recode_x86_shra64 sarl shrdl %edi %esi 1
278: #endif /* !__x86_64__ */
279: tme_recode_x86_shift shll 32 shll
280: tme_recode_x86_shift shrl 32 shrl
281: tme_recode_x86_shift shra 32 sarl
282: tme_recode_x86_shift shll 16 shll
283: tme_recode_x86_shift shrl 16 shrl
284: tme_recode_x86_shift shra 16 sarl
285: tme_recode_x86_shift shll 8 shll
286: tme_recode_x86_shift shrl 8 shrl
287: tme_recode_x86_shift shra 8 sarl
288:
289: _tme_recode_x86_shift_arithmetic_all:
290: TME_RECODE_X86_OPN(add) TME_RECODE_X86_REG_HOST_SUBS_DST_N, TME_RECODE_X86_REG_HOST_SUBS_DST_N
291: TME_RECODE_X86_OPN(sbb) TME_RECODE_X86_REG_HOST_SUBS_DST_N, TME_RECODE_X86_REG_HOST_SUBS_DST_N
292: ret
293:
294: _tme_recode_x86_shift_logical_all:
295: TME_RECODE_X86_OPN(xor) TME_RECODE_X86_REG_HOST_SUBS_DST_N, TME_RECODE_X86_REG_HOST_SUBS_DST_N
296: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.