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