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 argparse 29import copy 30 31import license 32import gl_XML, glX_XML 33 34def should_use_push(registers): 35 for [reg, offset] in registers: 36 if reg[1:4] == "xmm": 37 return 0 38 39 N = len(registers) 40 return (N & 1) != 0 41 42 43def local_size(registers): 44 # The x86-64 ABI says "the value (%rsp - 8) is always a multiple of 45 # 16 when control is transfered to the function entry point." This 46 # means that the local stack usage must be (16*N)+8 for some value 47 # of N. (16*N)+8 = (8*(2N))+8 = 8*(2N+1). As long as N is odd, we 48 # meet this requirement. 49 50 N = (len(registers) | 1) 51 return 8*N 52 53 54def save_all_regs(registers): 55 adjust_stack = 0 56 if not should_use_push(registers): 57 adjust_stack = local_size(registers) 58 print '\tsubq\t$%u, %%rsp' % (adjust_stack) 59 60 for [reg, stack_offset] in registers: 61 save_reg( reg, stack_offset, adjust_stack ) 62 return 63 64 65def restore_all_regs(registers): 66 adjust_stack = 0 67 if not should_use_push(registers): 68 adjust_stack = local_size(registers) 69 70 temp = copy.deepcopy(registers) 71 while len(temp): 72 [reg, stack_offset] = temp.pop() 73 restore_reg(reg, stack_offset, adjust_stack) 74 75 if adjust_stack: 76 print '\taddq\t$%u, %%rsp' % (adjust_stack) 77 return 78 79 80def save_reg(reg, offset, use_move): 81 if use_move: 82 if offset == 0: 83 print '\tmovq\t%s, (%%rsp)' % (reg) 84 else: 85 print '\tmovq\t%s, %u(%%rsp)' % (reg, offset) 86 else: 87 print '\tpushq\t%s' % (reg) 88 89 return 90 91 92def restore_reg(reg, offset, use_move): 93 if use_move: 94 if offset == 0: 95 print '\tmovq\t(%%rsp), %s' % (reg) 96 else: 97 print '\tmovq\t%u(%%rsp), %s' % (offset, reg) 98 else: 99 print '\tpopq\t%s' % (reg) 100 101 return 102 103 104class PrintGenericStubs(gl_XML.gl_print_base): 105 106 def __init__(self): 107 gl_XML.gl_print_base.__init__(self) 108 109 self.name = "gl_x86-64_asm.py (from Mesa)" 110 self.license = license.bsd_license_template % ("(C) Copyright IBM Corporation 2005", "IBM") 111 return 112 113 114 def get_stack_size(self, f): 115 size = 0 116 for p in f.parameterIterator(): 117 size += p.get_stack_size() 118 119 return size 120 121 122 def printRealHeader(self): 123 print "/* If we build with gcc's -fvisibility=hidden flag, we'll need to change" 124 print " * the symbol visibility mode to 'default'." 125 print ' */' 126 print '' 127 print '#include "x86/assyntax.h"' 128 print '' 129 print '#ifdef __GNUC__' 130 print '# pragma GCC visibility push(default)' 131 print '# define HIDDEN(x) .hidden x' 132 print '#else' 133 print '# define HIDDEN(x)' 134 print '#endif' 135 print '' 136 print '# if defined(USE_MGL_NAMESPACE)' 137 print '# define GL_PREFIX(n) GLNAME(CONCAT(mgl,n))' 138 print '# define _glapi_Dispatch _mglapi_Dispatch' 139 print '# else' 140 print '# define GL_PREFIX(n) GLNAME(CONCAT(gl,n))' 141 print '# endif' 142 print '' 143 print '\t.text' 144 print '' 145 print '#ifdef GLX_USE_TLS' 146 print '' 147 print '_x86_64_get_dispatch:' 148 print '\tmovq\t_glapi_tls_Dispatch@GOTTPOFF(%rip), %rax' 149 print '\tmovq\t%fs:(%rax), %rax' 150 print '\tret' 151 print '\t.size\t_x86_64_get_dispatch, .-_x86_64_get_dispatch' 152 print '' 153 print '#elif defined(HAVE_PTHREAD)' 154 print '' 155 print '\t.extern\t_glapi_Dispatch' 156 print '\t.extern\t_gl_DispatchTSD' 157 print '\t.extern\tpthread_getspecific' 158 print '' 159 print '\t.p2align\t4,,15' 160 print '_x86_64_get_dispatch:' 161 print '\tmovq\t_gl_DispatchTSD@GOTPCREL(%rip), %rax' 162 print '\tmovl\t(%rax), %edi' 163 print '\tjmp\tpthread_getspecific@PLT' 164 print '' 165 print '#else' 166 print '' 167 print '\t.extern\t_glapi_get_dispatch' 168 print '' 169 print '#endif' 170 print '' 171 return 172 173 174 def printRealFooter(self): 175 print '' 176 print '#if defined (__ELF__) && defined (__linux__)' 177 print ' .section .note.GNU-stack,"",%progbits' 178 print '#endif' 179 return 180 181 182 def printFunction(self, f): 183 184 # The x86-64 ABI divides function parameters into a couple 185 # classes. For the OpenGL interface, the only ones that are 186 # relevant are INTEGER and SSE. Basically, the first 8 187 # GLfloat or GLdouble parameters are placed in %xmm0 - %xmm7, 188 # the first 6 non-GLfloat / non-GLdouble parameters are placed 189 # in registers listed in int_parameters. 190 # 191 # If more parameters than that are required, they are passed 192 # on the stack. Therefore, we just have to make sure that 193 # %esp hasn't changed when we jump to the actual function. 194 # Since we're jumping to the function (and not calling it), we 195 # have to make sure of that anyway! 196 197 int_parameters = ["%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"] 198 199 int_class = 0 200 sse_class = 0 201 stack_offset = 0 202 registers = [] 203 for p in f.parameterIterator(): 204 type_name = p.get_base_type_string() 205 206 if p.is_pointer() or (type_name != "GLfloat" and type_name != "GLdouble"): 207 if int_class < 6: 208 registers.append( [int_parameters[int_class], stack_offset] ) 209 int_class += 1 210 stack_offset += 8 211 else: 212 if sse_class < 8: 213 registers.append( ["%%xmm%u" % (sse_class), stack_offset] ) 214 sse_class += 1 215 stack_offset += 8 216 217 if ((int_class & 1) == 0) and (sse_class == 0): 218 registers.append( ["%rbp", 0] ) 219 220 221 name = f.dispatch_name() 222 223 print '\t.p2align\t4,,15' 224 print '\t.globl\tGL_PREFIX(%s)' % (name) 225 print '\t.type\tGL_PREFIX(%s), @function' % (name) 226 if not f.is_static_entry_point(f.name): 227 print '\tHIDDEN(GL_PREFIX(%s))' % (name) 228 print 'GL_PREFIX(%s):' % (name) 229 print '#if defined(GLX_USE_TLS)' 230 print '\tcall\t_x86_64_get_dispatch@PLT' 231 print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8) 232 print '\tjmp\t*%r11' 233 print '#elif defined(HAVE_PTHREAD)' 234 235 save_all_regs(registers) 236 print '\tcall\t_x86_64_get_dispatch@PLT' 237 restore_all_regs(registers) 238 239 if f.offset == 0: 240 print '\tmovq\t(%rax), %r11' 241 else: 242 print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8) 243 244 print '\tjmp\t*%r11' 245 246 print '#else' 247 print '\tmovq\t_glapi_Dispatch(%rip), %rax' 248 print '\ttestq\t%rax, %rax' 249 print '\tje\t1f' 250 print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8) 251 print '\tjmp\t*%r11' 252 print '1:' 253 254 save_all_regs(registers) 255 print '\tcall\t_glapi_get_dispatch' 256 restore_all_regs(registers) 257 258 print '\tmovq\t%u(%%rax), %%r11' % (f.offset * 8) 259 print '\tjmp\t*%r11' 260 print '#endif /* defined(GLX_USE_TLS) */' 261 262 print '\t.size\tGL_PREFIX(%s), .-GL_PREFIX(%s)' % (name, name) 263 print '' 264 return 265 266 267 def printBody(self, api): 268 for f in api.functionIterateByOffset(): 269 self.printFunction(f) 270 271 272 for f in api.functionIterateByOffset(): 273 dispatch = f.dispatch_name() 274 for n in f.entry_points: 275 if n != f.name: 276 if f.is_static_entry_point(n): 277 text = '\t.globl GL_PREFIX(%s) ; .set GL_PREFIX(%s), GL_PREFIX(%s)' % (n, n, dispatch) 278 279 if f.has_different_protocol(n): 280 print '#ifndef GLX_INDIRECT_RENDERING' 281 print text 282 print '#endif' 283 else: 284 print text 285 286 return 287 288 289def _parser(): 290 """Parse arguments and return a namespace.""" 291 parser = argparse.ArgumentParser() 292 parser.add_argument('-f', 293 default='gl_API.xml', 294 dest='filename', 295 help='An XML file describing an API') 296 return parser.parse_args() 297 298 299def main(): 300 """Main file.""" 301 args = _parser() 302 printer = PrintGenericStubs() 303 api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory()) 304 305 printer.Print(api) 306 307 308if __name__ == '__main__': 309 main() 310