Home | History | Annotate | Download | only in gen
      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 (at] us.ibm.com>
     27 
     28 import argparse
     29 import copy
     30 
     31 import license
     32 import gl_XML, glX_XML
     33 
     34 def 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 
     43 def 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 
     54 def 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 
     65 def 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 
     80 def 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 
     92 def 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 
    104 class 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 
    289 def _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 
    299 def 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 
    308 if __name__ == '__main__':
    309     main()
    310