1#!/usr/bin/env python
2
3# (C) Copyright IBM Corporation 2005
4# All Rights Reserved.
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# on the rights to use, copy, modify, merge, publish, distribute, sub
10# license, and/or sell copies of the Software, and to permit persons to whom
11# the Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice (including the next
14# paragraph) shall be included in all copies or substantial portions of the
15# Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24#
25# Authors:
26#    Ian Romanick <idr@us.ibm.com>
27
28import license
29import gl_XML, glX_XML
30import sys, getopt, copy
31
32def should_use_push(registers):
33	for [reg, offset] in registers:
34		if reg[1:4] == "xmm":
35			return 0
36
37	N = len(registers)
38	return (N & 1) != 0
39
40
41def local_size(registers):
42	# The x86-64 ABI says "the value (%rsp - 8) is always a multiple of
43	# 16 when control is transfered to the function entry point."  This
44	# means that the local stack usage must be (16*N)+8 for some value
45	# of N.  (16*N)+8 = (8*(2N))+8 = 8*(2N+1).  As long as N is odd, we
46	# meet this requirement.
47
48	N = (len(registers) | 1)
49	return 8*N
50
51
52def save_all_regs(registers):
53	adjust_stack = 0
54	if not should_use_push(registers):
55		adjust_stack = local_size(registers)
56		print '\tsubq\t$%u, %%rsp' % (adjust_stack)
57
58	for [reg, stack_offset] in registers:
59		save_reg( reg, stack_offset, adjust_stack )
60	return
61
62
63def restore_all_regs(registers):
64	adjust_stack = 0
65	if not should_use_push(registers):
66		adjust_stack = local_size(registers)
67
68	temp = copy.deepcopy(registers)
69	while len(temp):
70		[reg, stack_offset] = temp.pop()
71		restore_reg(reg, stack_offset, adjust_stack)
72
73	if adjust_stack:
74		print '\taddq\t$%u, %%rsp' % (adjust_stack)
75	return
76
77
78def save_reg(reg, offset, use_move):
79	if use_move:
80		if offset == 0:
81			print '\tmovq\t%s, (%%rsp)' % (reg)
82		else:
83			print '\tmovq\t%s, %u(%%rsp)' % (reg, offset)
84	else:
85		print '\tpushq\t%s' % (reg)
86
87	return
88
89
90def restore_reg(reg, offset, use_move):
91	if use_move:
92		if offset == 0:
93			print '\tmovq\t(%%rsp), %s' % (reg)
94		else:
95			print '\tmovq\t%u(%%rsp), %s' % (offset, reg)
96	else:
97		print '\tpopq\t%s' % (reg)
98
99	return
100
101
102class PrintGenericStubs(gl_XML.gl_print_base):
103
104	def __init__(self):
105		gl_XML.gl_print_base.__init__(self)
106
107		self.name = "gl_x86-64_asm.py (from Mesa)"
108		self.license = license.bsd_license_template % ("(C) Copyright IBM Corporation 2005", "IBM")
109		return
110
111
112	def get_stack_size(self, f):
113		size = 0
114		for p in f.parameterIterator():
115			size += p.get_stack_size()
116
117		return size
118
119
120	def printRealHeader(self):
121		print "/* If we build with gcc's -fvisibility=hidden flag, we'll need to change"
122		print " * the symbol visibility mode to 'default'."
123		print ' */'
124		print ''
125		print '#include "x86/assyntax.h"'
126		print ''
127		print '#ifdef __GNUC__'
128		print '#  pragma GCC visibility push(default)'
129		print '#  define HIDDEN(x) .hidden x'
130		print '#else'
131		print '#  define HIDDEN(x)'
132		print '#endif'
133		print ''
134		print '# if defined(USE_MGL_NAMESPACE)'
135		print '#  define GL_PREFIX(n) GLNAME(CONCAT(mgl,n))'
136		print '#  define _glapi_Dispatch _mglapi_Dispatch'
137		print '# else'
138		print '#  define GL_PREFIX(n) GLNAME(CONCAT(gl,n))'
139		print '# endif'
140		print ''
141		print '#if defined(HAVE_PTHREAD) || defined(WIN32)'
142		print '#  define THREADS'
143		print '#endif'
144		print ''
145		print '\t.text'
146		print ''
147		print '#ifdef GLX_USE_TLS'
148		print ''
149		print '\t.globl _x86_64_get_get_dispatch; HIDDEN(_x86_64_get_get_dispatch)'
150		print '_x86_64_get_get_dispatch:'
151		print '\tlea\t_x86_64_get_dispatch(%rip), %rax'
152		print '\tret'
153		print ''
154		print '\t.p2align\t4,,15'
155		print '_x86_64_get_dispatch:'
156		print '\tmovq\t_glapi_tls_Dispatch@GOTTPOFF(%rip), %rax'
157		print '\tmovq\t%fs:(%rax), %rax'
158		print '\tret'
159		print '\t.size\t_x86_64_get_dispatch, .-_x86_64_get_dispatch'
160		print ''
161		print '#elif defined(HAVE_PTHREAD)'
162		print ''
163		print '\t.extern\t_glapi_Dispatch'
164		print '\t.extern\t_gl_DispatchTSD'
165		print '\t.extern\tpthread_getspecific'
166		print ''
167		print '\t.p2align\t4,,15'
168		print '_x86_64_get_dispatch:'
169		print '\tmovq\t_gl_DispatchTSD@GOTPCREL(%rip), %rax'
170		print '\tmovl\t(%rax), %edi'
171		print '\tjmp\tpthread_getspecific@PLT'
172		print ''
173		print '#elif defined(THREADS)'
174		print ''
175		print '\t.extern\t_glapi_get_dispatch'
176		print ''
177		print '#endif'
178		print ''
179		return
180
181
182	def printRealFooter(self):
183		print ''
184		print '#if defined(GLX_USE_TLS) && defined(__linux__)'
185		print '	.section ".note.ABI-tag", "a"'
186		print '	.p2align 2'
187		print '	.long	1f - 0f   /* name length */'
188		print '	.long	3f - 2f   /* data length */'
189		print '	.long	1         /* note length */'
190		print '0:	.asciz "GNU"      /* vendor name */'
191		print '1:	.p2align 2'
192		print '2:	.long	0         /* note data: the ABI tag */'
193		print '	.long	2,4,20    /* Minimum kernel version w/TLS */'
194		print '3:	.p2align 2        /* pad out section */'
195		print '#endif /* GLX_USE_TLS */'
196		print ''
197		print '#if defined (__ELF__) && defined (__linux__)'
198		print '	.section .note.GNU-stack,"",%progbits'
199		print '#endif'
200		return
201
202
203	def printFunction(self, f):
204
205		# The x86-64 ABI divides function parameters into a couple
206		# classes.  For the OpenGL interface, the only ones that are
207		# relevent are INTEGER and SSE.  Basically, the first 8
208		# GLfloat or GLdouble parameters are placed in %xmm0 - %xmm7,
209		# the first 6 non-GLfloat / non-GLdouble parameters are placed
210		# in registers listed in int_parameters.
211		#
212		# If more parameters than that are required, they are passed
213		# on the stack.  Therefore, we just have to make sure that
214		# %esp hasn't changed when we jump to the actual function.
215		# Since we're jumping to the function (and not calling it), we
216		# have to make sure of that anyway!
217
218		int_parameters = ["%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"]
219
220		int_class = 0
221		sse_class = 0
222		stack_offset = 0
223		registers = []
224		for p in f.parameterIterator():
225			type_name = p.get_base_type_string()
226
227			if p.is_pointer() or (type_name != "GLfloat" and type_name != "GLdouble"):
228				if int_class < 6:
229					registers.append( [int_parameters[int_class], stack_offset] )
230					int_class += 1
231					stack_offset += 8
232			else:
233				if sse_class < 8:
234					registers.append( ["%%xmm%u" % (sse_class), stack_offset] )
235					sse_class += 1
236					stack_offset += 8
237
238		if ((int_class & 1) == 0) and (sse_class == 0):
239			registers.append( ["%rbp", 0] )
240
241
242		name = f.dispatch_name()
243
244		print '\t.p2align\t4,,15'
245		print '\t.globl\tGL_PREFIX(%s)' % (name)
246		print '\t.type\tGL_PREFIX(%s), @function' % (name)
247		if not f.is_static_entry_point(f.name):
248			print '\tHIDDEN(GL_PREFIX(%s))' % (name)
249		print 'GL_PREFIX(%s):' % (name)
250		print '#if defined(GLX_USE_TLS)'
251		print '\tcall\t_x86_64_get_dispatch@PLT'
252		print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8)
253		print '\tjmp\t*%r11'
254		print '#elif defined(HAVE_PTHREAD)'
255
256		save_all_regs(registers)
257		print '\tcall\t_x86_64_get_dispatch@PLT'
258		restore_all_regs(registers)
259
260		if f.offset == 0:
261			print '\tmovq\t(%rax), %r11'
262		else:
263			print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8)
264
265		print '\tjmp\t*%r11'
266
267		print '#else'
268		print '\tmovq\t_glapi_Dispatch(%rip), %rax'
269		print '\ttestq\t%rax, %rax'
270		print '\tje\t1f'
271		print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8)
272		print '\tjmp\t*%r11'
273		print '1:'
274
275		save_all_regs(registers)
276		print '\tcall\t_glapi_get_dispatch'
277		restore_all_regs(registers)
278
279		print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8)
280		print '\tjmp\t*%r11'
281		print '#endif /* defined(GLX_USE_TLS) */'
282
283		print '\t.size\tGL_PREFIX(%s), .-GL_PREFIX(%s)' % (name, name)
284		print ''
285		return
286
287
288	def printBody(self, api):
289		for f in api.functionIterateByOffset():
290			self.printFunction(f)
291
292
293		for f in api.functionIterateByOffset():
294			dispatch = f.dispatch_name()
295			for n in f.entry_points:
296				if n != f.name:
297					if f.is_static_entry_point(n):
298						text = '\t.globl GL_PREFIX(%s) ; .set GL_PREFIX(%s), GL_PREFIX(%s)' % (n, n, dispatch)
299
300						if f.has_different_protocol(n):
301							print '#ifndef GLX_INDIRECT_RENDERING'
302							print text
303							print '#endif'
304						else:
305							print text
306
307		return
308
309def show_usage():
310	print "Usage: %s [-f input_file_name] [-m output_mode]" % sys.argv[0]
311	sys.exit(1)
312
313if __name__ == '__main__':
314	file_name = "gl_API.xml"
315	mode = "generic"
316
317	try:
318		(args, trail) = getopt.getopt(sys.argv[1:], "m:f:")
319	except Exception,e:
320		show_usage()
321
322	for (arg,val) in args:
323		if arg == '-m':
324			mode = val
325		elif arg == "-f":
326			file_name = val
327
328	if mode == "generic":
329		printer = PrintGenericStubs()
330	else:
331		print "ERROR: Invalid mode \"%s\" specified." % mode
332		show_usage()
333
334	api = gl_XML.parse_GL_API(file_name, glX_XML.glx_item_factory())
335	printer.Print(api)
336