widl: Output register parameter assignments on ARM platforms.

This commit is contained in:
Alexandre Julliard 2024-04-16 18:09:52 +02:00
parent 30a7054879
commit 235f76594e

View file

@ -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 )