Module: wine Branch: master Commit: 235f76594e1aec4b37014ff2e37b5a487b1df33e URL: https://gitlab.winehq.org/wine/wine/-/commit/235f76594e1aec4b37014ff2e37b5a4...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Apr 16 18:09:52 2024 +0200
widl: Output register parameter assignments on ARM platforms.
---
tools/widl/typegen.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 169 insertions(+), 8 deletions(-)
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index 063080bd9de..6f362bc1d8d 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -1372,6 +1372,129 @@ int is_interpreted_func( const type_t *iface, const var_t *func ) return interpreted_mode; }
+/* replace consecutive params code by a repeat sequence: 0x9d code<1> repeat_count<2> */ +static unsigned int compress_params_array( unsigned char *params, unsigned int count ) +{ + unsigned int i, j; + + for (i = 0; i + 4 <= count; i++) + { + for (j = 1; i + j < count; j++) if (params[i + j] != params[i]) break; + if (j < 4) continue; + params[i] = 0x9d; + params[i + 2] = j & 0xff; + params[i + 3] = j >> 8; + memmove( params + i + 4, params + i + j, count - (i + j) ); + count -= j - 4; + i += 3; + } + return count; +} + +/* fill the parameters array for the procedure extra data on ARM platforms */ +static unsigned int fill_params_array( const type_t *iface, const var_t *func, + unsigned char *params, unsigned int count ) +{ + unsigned int reg_count = 0, float_count = 0, double_count = 0, stack_pos = 0, offset = 0; + var_list_t *args = type_function_get_args( func->declspec.type ); + enum type_basic_type type; + unsigned int size, pos, align; + var_t *var; + + memset( params, 0x9f /* padding */, count ); + + if (is_object( iface )) + { + params[0] = 0x80 + reg_count++; + offset += pointer_size; + } + + if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry ) + { + type = TYPE_BASIC_LONG; + if (type_get_type( var->declspec.type ) == TYPE_BASIC) + type = type_basic_get_type( var->declspec.type ); + + size = get_stack_size( var, &align, NULL ); + offset = ROUND_SIZE( offset, align ); + pos = offset / pointer_size; + + if (target.cpu == CPU_ARM64) + { + switch (type) + { + case TYPE_BASIC_FLOAT: + case TYPE_BASIC_DOUBLE: + if (double_count >= 8) break; + params[pos] = 0x88 + double_count++; + offset += size; + continue; + + default: + reg_count = ROUND_SIZE( reg_count, align / pointer_size ); + if (reg_count > 8 - size / pointer_size) break; + while (size) + { + params[pos++] = 0x80 + reg_count++; + offset += pointer_size; + size -= pointer_size; + } + continue; + } + } + else /* CPU_ARM */ + { + switch (type) + { + case TYPE_BASIC_FLOAT: + if (!(float_count % 2)) float_count = max( float_count, double_count * 2 ); + if (float_count >= 16) + { + stack_pos = ROUND_SIZE( stack_pos, align ); + params[pos] = 0x100 - (offset - stack_pos) / pointer_size; + stack_pos += size; + } + else + { + params[pos] = 0x84 + float_count++; + } + offset += size; + continue; + + case TYPE_BASIC_DOUBLE: + double_count = max( double_count, (float_count + 1) / 2 ); + if (double_count >= 8) break; + params[pos] = 0x84 + 2 * double_count; + params[pos + 1] = 0x84 + 2 * double_count + 1; + double_count++; + offset += size; + continue; + + default: + reg_count = ROUND_SIZE( reg_count, align / pointer_size ); + if (reg_count <= 4 - size / pointer_size || !stack_pos) + { + while (size && reg_count < 4) + { + params[pos++] = 0x80 + reg_count++; + offset += pointer_size; + size -= pointer_size; + } + } + break; + } + } + + stack_pos = ROUND_SIZE( stack_pos, align ); + memset( params + pos, 0x100 - (offset - stack_pos) / pointer_size, size / pointer_size ); + stack_pos += size; + offset += size; + } + + while (count && params[count - 1] == 0x9f) count--; + return count; +} + static void write_proc_func_interp( FILE *file, int indent, const type_t *iface, const var_t *func, unsigned int *offset, unsigned short num_proc ) @@ -1390,6 +1513,7 @@ static void write_proc_func_interp( FILE *file, int indent, const type_t *iface, unsigned int stack_size = 0; unsigned int stack_offset = 0; unsigned int stack_align; + unsigned int extra_size = 0; unsigned short param_num = 0; unsigned short handle_stack_offset = 0; unsigned short handle_param_num = 0; @@ -1477,16 +1601,21 @@ static void write_proc_func_interp( FILE *file, int indent, const type_t *iface, print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %u */\n", size, size ); print_file( file, indent, "0x%02x,\n", oi2_flags ); print_file( file, indent, "0x%02x,\t/* %u params */\n", nb_args, nb_args ); - print_file( file, indent, "0x%02x,\n", pointer_size == 8 ? 10 : 8 ); - print_file( file, indent, "0x%02x,\n", ext_flags ); - print_file( file, indent, "NdrFcShort(0x0),\n" ); /* server corr hint */ - print_file( file, indent, "NdrFcShort(0x0),\n" ); /* client corr hint */ - print_file( file, indent, "NdrFcShort(0x0),\n" ); /* FIXME: notify index */ - *offset += 14; - if (pointer_size == 8) + *offset += 6; + extra_size = 8; + + switch (target.cpu) + { + case CPU_x86_64: { unsigned short pos = 0, fpu_mask = 0;
+ extra_size += 2; + print_file( file, indent, "0x%02x,\n", extra_size ); + print_file( file, indent, "0x%02x,\n", ext_flags ); + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* server corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* client corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* FIXME: notify index */ if (is_object( iface )) pos += 2; if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry ) { @@ -1503,8 +1632,40 @@ static void write_proc_func_interp( FILE *file, int indent, const type_t *iface, if (pos >= 16) break; } print_file( file, indent, "NdrFcShort(0x%x),\n", fpu_mask ); /* floating point mask */ - *offset += 2; + break; + } + case CPU_ARM: + case CPU_ARM64: + { + unsigned int i, len, count = stack_size / pointer_size; + unsigned char *params = xmalloc( count ); + + count = fill_params_array( iface, func, params, count ); + len = compress_params_array( params, count ); + + extra_size += 3 + len + !(len % 2); + print_file( file, indent, "0x%02x,\n", extra_size ); + print_file( file, indent, "0x%02x,\n", ext_flags ); + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* server corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* client corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* FIXME: notify index */ + print_file( file, indent, "NdrFcShort(0x%02x),\n", count ); + print_file( file, indent, "0x%02x,\n", len ); + for (i = 0; i < len; i++) print_file( file, indent, "0x%02x,\n", params[i] ); + if (!(len % 2)) print_file( file, indent, "0x00,\n" ); + free( params ); + break; + } + case CPU_i386: + default: + print_file( file, indent, "0x%02x,\n", extra_size ); + print_file( file, indent, "0x%02x,\n", ext_flags ); + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* server corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* client corr hint */ + print_file( file, indent, "NdrFcShort(0x0),\n" ); /* FIXME: notify index */ + break; } + *offset += extra_size;
/* emit argument data */ if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )