#include "defs.h"
#include "gdbcore.h"
#include "inferior.h"
#include "regcache.h"
#include "value.h"
#include "gdb_string.h"
#include "ppc-tdep.h"
#undef round2
#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
CORE_ADDR
ppc_sysv_abi_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argno;
int greg;
int freg;
int vreg;
int argstkspace;
int structstkspace;
int argoffset;
int structoffset;
struct value *arg;
struct type *type;
int len;
char old_sp_buf[4];
CORE_ADDR saved_sp;
greg = struct_return ? 4 : 3;
freg = 1;
vreg = 2;
argstkspace = 0;
structstkspace = 0;
for (argno = 0; argno < nargs; argno++)
{
arg = args[argno];
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
if (freg <= 8)
freg++;
else
{
if (argstkspace & 0x4)
argstkspace += 4;
argstkspace += 8;
}
}
else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
{
if (greg > 9)
{
greg = 11;
if (argstkspace & 0x4)
argstkspace += 4;
argstkspace += 8;
}
else
{
if ((greg & 1) == 0)
greg++;
greg += 2;
}
}
else if (!TYPE_VECTOR (type))
{
if (len > 4
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
structstkspace += round2 (len, 8);
}
if (greg <= 10)
greg++;
else
argstkspace += 4;
}
else
{
if (len == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type))
{
if (vreg <= 13)
vreg++;
else
{
argstkspace += round2 (argstkspace, 16);
argstkspace += 16;
}
}
}
}
saved_sp = read_sp ();
sp -= argstkspace + structstkspace;
sp -= 8;
sp &= ~0x0f;
write_register (SP_REGNUM, sp);
store_address (old_sp_buf, 4, saved_sp);
write_memory (sp, old_sp_buf, 4);
argoffset = 8;
structoffset = argoffset + argstkspace;
freg = 1;
greg = 3;
vreg = 2;
if (struct_return)
{
char val_buf[4];
store_address (val_buf, 4, struct_addr);
memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
greg++;
}
for (argno = 0; argno < nargs; argno++)
{
arg = args[argno];
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
if (freg <= 8)
{
if (len > 8)
printf_unfiltered (
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM + freg)],
VALUE_CONTENTS (arg), len);
freg++;
}
else
{
if (argoffset & 0x4)
argoffset += 4;
write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
argoffset += 8;
}
}
else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
{
if (greg > 9)
{
greg = 11;
if (argoffset & 0x4)
argoffset += 4;
write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
argoffset += 8;
}
else
{
if ((greg & 1) == 0)
greg++;
memcpy (®isters[REGISTER_BYTE (greg)],
VALUE_CONTENTS (arg), 4);
memcpy (®isters[REGISTER_BYTE (greg + 1)],
VALUE_CONTENTS (arg) + 4, 4);
greg += 2;
}
}
else if (!TYPE_VECTOR (type))
{
char val_buf[4];
if (len > 4
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
write_memory (sp + structoffset, VALUE_CONTENTS (arg), len);
store_address (val_buf, 4, sp + structoffset);
structoffset += round2 (len, 8);
}
else
{
memset (val_buf, 0, 4);
memcpy (val_buf, VALUE_CONTENTS (arg), len);
}
if (greg <= 10)
{
memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
greg++;
}
else
{
write_memory (sp + argoffset, val_buf, 4);
argoffset += 4;
}
}
else
{
if (len == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type))
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
char *v_val_buf = alloca (16);
memset (v_val_buf, 0, 16);
memcpy (v_val_buf, VALUE_CONTENTS (arg), len);
if (vreg <= 13)
{
memcpy (®isters[REGISTER_BYTE (tdep->ppc_vr0_regnum
+ vreg)],
v_val_buf, 16);
vreg++;
}
else
{
write_memory (sp + argoffset, v_val_buf, 16);
argoffset += 16;
}
}
}
}
target_store_registers (-1);
return sp;
}
int
ppc_sysv_abi_broken_use_struct_convention (int gcc_p, struct type *value_type)
{
if (TYPE_LENGTH (value_type) == 16
&& TYPE_VECTOR (value_type))
return 0;
return generic_use_struct_convention (gcc_p, value_type);
}
int
ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
{
if (TYPE_LENGTH (value_type) == 16
&& TYPE_VECTOR (value_type))
return 0;
return (TYPE_LENGTH (value_type) > 8);
}