fix symtab.c
[deliverable/binutils-gdb.git] / gdb / ppc-sysv-tdep.c
index 300dcac6f1f685e665ce39e1c50c38109b0a2d9c..0cddf6477c6057a819514e001eb8ab00ca80fd42 100644 (file)
@@ -1,8 +1,7 @@
 /* Target-dependent code for PowerPC systems using the SVR4 ABI
    for GDB, the GNU debugger.
 
-   Copyright (C) 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2000-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "target.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "dwarf2.h"
+
+
+/* Check whether FTPYE is a (pointer to) function type that should use
+   the OpenCL vector ABI.  */
+
+static int
+ppc_sysv_use_opencl_abi (struct type *ftype)
+{
+  ftype = check_typedef (ftype);
+
+  if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+    ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+
+  return (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+         && TYPE_CALLING_CONVENTION (ftype) == DW_CC_GDB_IBM_OpenCL);
+}
 
 /* Pass the arguments in either registers, or in the stack.  Using the
    ppc sysv ABI, the first eight words of the argument list (that might
@@ -50,6 +66,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int opencl_abi = ppc_sysv_use_opencl_abi (value_type (function));
   ULONGEST saved_sp;
   int argspace = 0;            /* 0 is an initial wrong guess.  */
   int write_pass;
@@ -327,6 +344,126 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                 Hence we increase freg even when writing to memory.  */
              freg += 2;
            }
+         else if (len < 16
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY
+                  && TYPE_VECTOR (type)
+                  && opencl_abi)
+           {
+             /* OpenCL vectors shorter than 16 bytes are passed as if
+                a series of independent scalars.  */
+             struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+             int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
+
+             for (i = 0; i < nelt; i++)
+               {
+                 const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
+
+                 if (TYPE_CODE (eltype) == TYPE_CODE_FLT && !tdep->soft_float)
+                   {
+                     if (freg <= 8)
+                       {
+                         if (write_pass)
+                           {
+                             int regnum = tdep->ppc_fp0_regnum + freg;
+                             gdb_byte regval[MAX_REGISTER_SIZE];
+                             struct type *regtype
+                               = register_type (gdbarch, regnum);
+                             convert_typed_floating (elval, eltype,
+                                                     regval, regtype);
+                             regcache_cooked_write (regcache, regnum, regval);
+                           }
+                         freg++;
+                       }
+                     else
+                       {
+                         argoffset = align_up (argoffset, len);
+                         if (write_pass)
+                           write_memory (sp + argoffset, val, len);
+                         argoffset += len;
+                       }
+                   }
+                 else if (TYPE_LENGTH (eltype) == 8)
+                   {
+                     if (greg > 9)
+                       {
+                         /* Just in case GREG was 10.  */
+                         greg = 11;
+                         argoffset = align_up (argoffset, 8);
+                         if (write_pass)
+                           write_memory (sp + argoffset, elval,
+                                         TYPE_LENGTH (eltype));
+                         argoffset += 8;
+                       }
+                     else
+                       {
+                         /* Must start on an odd register - r3/r4 etc.  */
+                         if ((greg & 1) == 0)
+                           greg++;
+                         if (write_pass)
+                           {
+                             int regnum = tdep->ppc_gp0_regnum + greg;
+                             regcache_cooked_write (regcache,
+                                                    regnum + 0, elval + 0);
+                             regcache_cooked_write (regcache,
+                                                    regnum + 1, elval + 4);
+                           }
+                         greg += 2;
+                       }
+                   }
+                 else
+                   {
+                     gdb_byte word[MAX_REGISTER_SIZE];
+                     store_unsigned_integer (word, tdep->wordsize, byte_order,
+                                             unpack_long (eltype, elval));
+
+                     if (greg <= 10)
+                       {
+                         if (write_pass)
+                           regcache_cooked_write (regcache,
+                                                  tdep->ppc_gp0_regnum + greg,
+                                                  word);
+                         greg++;
+                       }
+                     else
+                       {
+                         argoffset = align_up (argoffset, tdep->wordsize);
+                         if (write_pass)
+                           write_memory (sp + argoffset, word, tdep->wordsize);
+                         argoffset += tdep->wordsize;
+                       }
+                   }
+               }
+           }
+         else if (len >= 16
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY
+                  && TYPE_VECTOR (type)
+                  && opencl_abi)
+           {
+             /* OpenCL vectors 16 bytes or longer are passed as if
+                a series of AltiVec vectors.  */
+             int i;
+
+             for (i = 0; i < len / 16; i++)
+               {
+                 const gdb_byte *elval = val + i * 16;
+
+                 if (vreg <= 13)
+                   {
+                     if (write_pass)
+                       regcache_cooked_write (regcache,
+                                              tdep->ppc_vr0_regnum + vreg,
+                                              elval);
+                     vreg++;
+                   }
+                 else
+                   {
+                     argoffset = align_up (argoffset, 16);
+                     if (write_pass)
+                       write_memory (sp + argoffset, elval, 16);
+                     argoffset += 16;
+                   }
+               }
+           }
          else if (len == 16
                   && TYPE_CODE (type) == TYPE_CODE_ARRAY
                   && TYPE_VECTOR (type)
@@ -552,13 +689,17 @@ get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype,
    when returned in general-purpose registers.  */
 
 static enum return_value_convention
-do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
-                         struct regcache *regcache, gdb_byte *readbuf,
-                         const gdb_byte *writebuf, int broken_gcc)
+do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *func_type,
+                         struct type *type, struct regcache *regcache,
+                         gdb_byte *readbuf, const gdb_byte *writebuf,
+                         int broken_gcc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
+
   gdb_assert (tdep->wordsize == 4);
+
   if (TYPE_CODE (type) == TYPE_CODE_FLT
       && TYPE_LENGTH (type) <= 8
       && !tdep->soft_float)
@@ -691,6 +832,83 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
+  /* OpenCL vectors < 16 bytes are returned as distinct
+     scalars in f1..f2 or r3..r10.  */
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type)
+      && TYPE_LENGTH (type) < 16
+      && opencl_abi)
+    {
+      struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+      int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
+
+      for (i = 0; i < nelt; i++)
+       {
+         int offset = i * TYPE_LENGTH (eltype);
+
+         if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
+           {
+             int regnum = tdep->ppc_fp0_regnum + 1 + i;
+             gdb_byte regval[MAX_REGISTER_SIZE];
+             struct type *regtype = register_type (gdbarch, regnum);
+
+             if (writebuf != NULL)
+               {
+                 convert_typed_floating (writebuf + offset, eltype,
+                                         regval, regtype);
+                 regcache_cooked_write (regcache, regnum, regval);
+               }
+             if (readbuf != NULL)
+               {
+                 regcache_cooked_read (regcache, regnum, regval);
+                 convert_typed_floating (regval, regtype,
+                                         readbuf + offset, eltype);
+               }
+           }
+         else
+           {
+             int regnum = tdep->ppc_gp0_regnum + 3 + i;
+             ULONGEST regval;
+
+             if (writebuf != NULL)
+               {
+                 regval = unpack_long (eltype, writebuf + offset);
+                 regcache_cooked_write_unsigned (regcache, regnum, regval);
+               }
+             if (readbuf != NULL)
+               {
+                 regcache_cooked_read_unsigned (regcache, regnum, &regval);
+                 store_unsigned_integer (readbuf + offset,
+                                         TYPE_LENGTH (eltype), byte_order,
+                                         regval);
+               }
+           }
+       }
+
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  /* OpenCL vectors >= 16 bytes are returned in v2..v9.  */
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type)
+      && TYPE_LENGTH (type) >= 16
+      && opencl_abi)
+    {
+      int n_regs = TYPE_LENGTH (type) / 16;
+      int i;
+
+      for (i = 0; i < n_regs; i++)
+       {
+         int offset = i * 16;
+         int regnum = tdep->ppc_vr0_regnum + 2 + i;
+
+         if (writebuf != NULL)
+           regcache_cooked_write (regcache, regnum, writebuf + offset);
+         if (readbuf != NULL)
+           regcache_cooked_read (regcache, regnum, readbuf + offset);
+       }
+
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   if (TYPE_LENGTH (type) == 16
       && TYPE_CODE (type) == TYPE_CODE_ARRAY
       && TYPE_VECTOR (type)
@@ -822,23 +1040,25 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
 }
 
 enum return_value_convention
-ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
                           struct type *valtype, struct regcache *regcache,
                           gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
-                                  writebuf, 0);
+  return do_ppc_sysv_return_value (gdbarch,
+                                  function ? value_type (function) : NULL,
+                                  valtype, regcache, readbuf, writebuf, 0);
 }
 
 enum return_value_convention
 ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
-                                 struct type *func_type,
+                                 struct value *function,
                                  struct type *valtype,
                                  struct regcache *regcache,
                                  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
-                                  writebuf, 1);
+  return do_ppc_sysv_return_value (gdbarch,
+                                  function ? value_type (function) : NULL,
+                                  valtype, regcache, readbuf, writebuf, 1);
 }
 
 /* The helper function for 64-bit SYSV push_dummy_call.  Converts the
@@ -856,13 +1076,13 @@ static int
 convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr)
 {
   struct obj_section *dot_fn_section;
-  struct minimal_symbol *dot_fn;
+  struct bound_minimal_symbol dot_fn;
   struct minimal_symbol *fn;
-  CORE_ADDR toc;
+
   /* Find the minimal symbol that corresponds to CODE_ADDR (should
      have a name of the form ".FN").  */
   dot_fn = lookup_minimal_symbol_by_pc (code_addr);
-  if (dot_fn == NULL || SYMBOL_LINKAGE_NAME (dot_fn)[0] != '.')
+  if (dot_fn.minsym == NULL || SYMBOL_LINKAGE_NAME (dot_fn.minsym)[0] != '.')
     return 0;
   /* Get the section that contains CODE_ADDR.  Need this for the
      "objfile" that it contains.  */
@@ -873,7 +1093,7 @@ convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr)
      address.  Only look for the minimal symbol in ".FN"'s object file
      - avoids problems when two object files (i.e., shared libraries)
      contain a minimal symbol with the same name.  */
-  fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
+  fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn.minsym) + 1, NULL,
                              dot_fn_section->objfile);
   if (fn == NULL)
     return 0;
@@ -882,6 +1102,83 @@ convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr)
   return 1;
 }
 
+/* Push a float in either registers, or in the stack.  Using the ppc 64 bit
+   SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic.  */
+
+static void
+ppc64_sysv_abi_push_float (struct gdbarch *gdbarch, struct regcache *regcache,
+                          struct gdbarch_tdep *tdep, struct type *type, 
+                          const bfd_byte *val, int freg, int greg,
+                          CORE_ADDR gparam)
+{
+  gdb_byte regval[MAX_REGISTER_SIZE];
+  const gdb_byte *p;
+
+  if (TYPE_LENGTH (type) <= 8)
+    {
+      /* Version 1.7 of the 64-bit PowerPC ELF ABI says:
+
+        "Single precision floating point values are mapped to
+        the first word in a single doubleword."
+
+        And version 1.9 says:
+
+        "Single precision floating point values are mapped to
+        the second word in a single doubleword."
+
+        GDB then writes single precision floating point values
+        at both words in a doubleword, to support both ABIs.  */
+      if (TYPE_LENGTH (type) == 4)
+       {
+         memcpy (regval, val, 4);
+         memcpy (regval + 4, val, 4);
+         p = regval;
+       }
+      else
+       p = val;
+
+      /* Write value in the stack's parameter save area.  */
+      write_memory (gparam, p, 8);
+
+      /* Floats and Doubles go in f1 .. f13.  They also consume a left aligned
+        GREG, and can end up in memory.  */
+      if (freg <= 13)
+       {
+         struct type *regtype;
+
+         regtype = register_type (gdbarch, tdep->ppc_fp0_regnum + freg);
+         convert_typed_floating (val, type, regval, regtype);
+         regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval);
+       }
+      if (greg <= 10)
+       regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval);
+    }
+  else
+    {
+      /* IBM long double stored in two doublewords of the
+        parameter save area and corresponding registers.  */
+      if (!tdep->soft_float && freg <= 13)
+       {
+         regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val);
+         if (freg <= 12)
+           regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1,
+                                  val + 8);
+       }
+      if (greg <= 10)
+       {
+         regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val);
+         if (greg <= 9)
+           regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1,
+                                  val + 8);
+       }
+      write_memory (gparam, val, TYPE_LENGTH (type));
+    }
+}
+
 /* Pass the arguments in either registers, or in the stack.  Using the
    ppc 64 bit SysV ABI.
 
@@ -899,9 +1196,13 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
   CORE_ADDR func_addr = find_function_addr (function, NULL);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int opencl_abi = ppc_sysv_use_opencl_abi (value_type (function));
   ULONGEST back_chain;
   /* See for-loop comment below.  */
   int write_pass;
+  /* Size of the by-reference parameter copy region, the final value is
+     computed in the for-loop below.  */
+  LONGEST refparam_size = 0;
   /* Size of the general parameter region, the final value is computed
      in the for-loop below.  */
   LONGEST gparam_size = 0;
@@ -947,19 +1248,26 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
       /* The address, at which the next general purpose parameter
          (integer, struct, float, vector, ...) should be saved.  */
       CORE_ADDR gparam;
+      /* The address, at which the next by-reference parameter
+        (non-Altivec vector, variably-sized type) should be saved.  */
+      CORE_ADDR refparam;
 
       if (!write_pass)
        {
-         /* During the first pass, GPARAM is more like an offset
-            (start address zero) than an address.  That way it
-            accumulates the total stack space required.  */
+         /* During the first pass, GPARAM and REFPARAM are more like
+            offsets (start address zero) than addresses.  That way
+            they accumulate the total stack space each region
+            requires.  */
          gparam = 0;
+         refparam = 0;
        }
       else
        {
-         /* Decrement the stack pointer making space for the on-stack
-            stack parameters.  Set gparam to that region.  */
-         gparam = align_down (sp - gparam_size, 16);
+         /* Decrement the stack pointer making space for the Altivec
+            and general on-stack parameters.  Set refparam and gparam
+            to their corresponding regions.  */
+         refparam = align_down (sp - refparam_size, 16);
+         gparam = align_down (refparam - gparam_size, 16);
          /* Add in space for the TOC, link editor double word,
             compiler double word, LR save area, CR save area.  */
          sp = align_down (gparam - 48, 16);
@@ -988,53 +1296,9 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
 
          if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
            {
-             /* Floats and Doubles go in f1 .. f13.  They also
-                consume a left aligned GREG,, and can end up in
-                memory.  */
              if (write_pass)
-               {
-                 gdb_byte regval[MAX_REGISTER_SIZE];
-                 const gdb_byte *p;
-
-                 /* Version 1.7 of the 64-bit PowerPC ELF ABI says:
-
-                    "Single precision floating point values are mapped to
-                    the first word in a single doubleword."
-
-                    And version 1.9 says:
-
-                    "Single precision floating point values are mapped to
-                    the second word in a single doubleword."
-
-                    GDB then writes single precision floating point values
-                    at both words in a doubleword, to support both ABIs.  */
-                 if (TYPE_LENGTH (type) == 4)
-                   {
-                     memcpy (regval, val, 4);
-                     memcpy (regval + 4, val, 4);
-                     p = regval;
-                   }
-                 else
-                   p = val;
-
-                 /* Write value in the stack's parameter save area.  */
-                 write_memory (gparam, p, 8);
-
-                 if (freg <= 13)
-                   {
-                     struct type *regtype
-                        = register_type (gdbarch, tdep->ppc_fp0_regnum);
-
-                     convert_typed_floating (val, type, regval, regtype);
-                     regcache_cooked_write (regcache,
-                                             tdep->ppc_fp0_regnum + freg,
-                                            regval);
-                   }
-                 if (greg <= 10)
-                   regcache_cooked_write (regcache,
-                                          tdep->ppc_gp0_regnum + greg,
-                                          regval);
-               }
+                 ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
+                                            val, freg, greg, gparam);
 
              freg++;
              greg++;
@@ -1046,35 +1310,58 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
                   && (gdbarch_long_double_format (gdbarch)
                       == floatformats_ibm_long_double))
            {
-             /* IBM long double stored in two doublewords of the
-                parameter save area and corresponding registers.  */
              if (write_pass)
+               ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
+                                          val, freg, greg, gparam);
+             freg += 2;
+             greg += 2;
+             gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+           }
+         else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
+             && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16))
+           {
+             int i;
+
+             for (i = 0; i < 2; i++)
                {
-                 if (!tdep->soft_float && freg <= 13)
-                   {
-                     regcache_cooked_write (regcache,
-                                             tdep->ppc_fp0_regnum + freg,
-                                            val);
-                     if (freg <= 12)
-                       regcache_cooked_write (regcache,
-                                              tdep->ppc_fp0_regnum + freg + 1,
-                                              val + 8);
-                   }
-                 if (greg <= 10)
+                 if (write_pass)
                    {
-                     regcache_cooked_write (regcache,
-                                            tdep->ppc_gp0_regnum + greg,
-                                            val);
-                     if (greg <= 9)
-                       regcache_cooked_write (regcache,
-                                              tdep->ppc_gp0_regnum + greg + 1,
-                                              val + 8);
+                     struct type *target_type;
+
+                     target_type = check_typedef (TYPE_TARGET_TYPE (type));
+                     ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
+                                                target_type, val + i *
+                                                TYPE_LENGTH (target_type),
+                                                freg, greg, gparam);
                    }
-                 write_memory (gparam, val, TYPE_LENGTH (type));
+                 freg++;
+                 greg++;
+                 /* Always consume parameter stack space.  */
+                 gparam = align_up (gparam + 8, tdep->wordsize);
+               }
+           }
+         else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
+                  && TYPE_LENGTH (type) == 32
+                  && (gdbarch_long_double_format (gdbarch)
+                      == floatformats_ibm_long_double))
+           {
+             int i;
+
+             for (i = 0; i < 2; i++)
+               {
+                 struct type *target_type;
+
+                 target_type = check_typedef (TYPE_TARGET_TYPE (type));
+                 if (write_pass)
+                   ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
+                                              target_type, val + i *
+                                              TYPE_LENGTH (target_type),
+                                              freg, greg, gparam);
+                 freg += 2;
+                 greg += 2;
+                 gparam = align_up (gparam + TYPE_LENGTH (target_type),
+                                    tdep->wordsize);
                }
-             freg += 2;
-             greg += 2;
-             gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
            }
          else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT
                   && TYPE_LENGTH (type) <= 8)
@@ -1133,9 +1420,112 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
              greg += 2;
              gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
            }
+         else if (TYPE_LENGTH (type) < 16
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY
+                  && TYPE_VECTOR (type)
+                  && opencl_abi)
+           {
+             /* OpenCL vectors shorter than 16 bytes are passed as if
+                a series of independent scalars.  */
+             struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+             int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
+
+             for (i = 0; i < nelt; i++)
+               {
+                 const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
+
+                 if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
+                   {
+                     if (write_pass)
+                       {
+                         gdb_byte regval[MAX_REGISTER_SIZE];
+                         const gdb_byte *p;
+
+                         if (TYPE_LENGTH (eltype) == 4)
+                           {
+                             memcpy (regval, elval, 4);
+                             memcpy (regval + 4, elval, 4);
+                             p = regval;
+                           }
+                         else
+                           p = elval;
+
+                         write_memory (gparam, p, 8);
+
+                         if (freg <= 13)
+                           {
+                             int regnum = tdep->ppc_fp0_regnum + freg;
+                             struct type *regtype
+                               = register_type (gdbarch, regnum);
+
+                             convert_typed_floating (elval, eltype,
+                                                     regval, regtype);
+                             regcache_cooked_write (regcache, regnum, regval);
+                           }
+
+                         if (greg <= 10)
+                           regcache_cooked_write (regcache,
+                                                  tdep->ppc_gp0_regnum + greg,
+                                                  regval);
+                       }
+
+                     freg++;
+                     greg++;
+                     gparam = align_up (gparam + 8, tdep->wordsize);
+                   }
+                 else
+                   {
+                     if (write_pass)
+                       {
+                         ULONGEST word = unpack_long (eltype, elval);
+                         if (greg <= 10)
+                           regcache_cooked_write_unsigned
+                             (regcache, tdep->ppc_gp0_regnum + greg, word);
+
+                         write_memory_unsigned_integer
+                           (gparam, tdep->wordsize, byte_order, word);
+                       }
+
+                     greg++;
+                     gparam = align_up (gparam + TYPE_LENGTH (eltype),
+                                        tdep->wordsize);
+                   }
+               }
+           }
+         else if (TYPE_LENGTH (type) >= 16
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY
+                  && TYPE_VECTOR (type)
+                  && opencl_abi)
+           {
+             /* OpenCL vectors 16 bytes or longer are passed as if
+                a series of AltiVec vectors.  */
+             int i;
+
+             for (i = 0; i < TYPE_LENGTH (type) / 16; i++)
+               {
+                 const gdb_byte *elval = val + i * 16;
+
+                 gparam = align_up (gparam, 16);
+                 greg += greg & 1;
+
+                 if (write_pass)
+                   {
+                     if (vreg <= 13)
+                       regcache_cooked_write (regcache,
+                                              tdep->ppc_vr0_regnum + vreg,
+                                              elval);
+
+                     write_memory (gparam, elval, 16);
+                   }
+
+                 greg += 2;
+                 vreg++;
+                 gparam += 16;
+               }
+           }
          else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
                   && TYPE_CODE (type) == TYPE_CODE_ARRAY
-                  && tdep->ppc_vr0_regnum >= 0)
+                  && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
            {
              /* In the Altivec ABI, vectors go in the vector registers
                 v2 .. v13, as well as the parameter area -- always at
@@ -1157,6 +1547,30 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
              vreg++;
              gparam += 16;
            }
+         else if (TYPE_LENGTH (type) >= 16 && TYPE_VECTOR (type)
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+           {
+             /* Non-Altivec vectors are passed by reference.  */
+
+             /* Copy value onto the stack ...  */
+             refparam = align_up (refparam, 16);
+             if (write_pass)
+               write_memory (refparam, val, TYPE_LENGTH (type));
+
+             /* ... and pass a pointer to the copy as parameter.  */
+             if (write_pass)
+               {
+                 if (greg <= 10)
+                   regcache_cooked_write_unsigned (regcache,
+                                                   tdep->ppc_gp0_regnum +
+                                                   greg, refparam);
+                 write_memory_unsigned_integer (gparam, tdep->wordsize,
+                                                byte_order, refparam);
+               }
+             greg++;
+             gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+             refparam = align_up (refparam + TYPE_LENGTH (type), tdep->wordsize);
+           }
          else if ((TYPE_CODE (type) == TYPE_CODE_INT
                    || TYPE_CODE (type) == TYPE_CODE_ENUM
                    || TYPE_CODE (type) == TYPE_CODE_BOOL
@@ -1298,8 +1712,9 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
 
       if (!write_pass)
        {
-         /* Save the true region sizes ready for the second pass.
-            Make certain that the general parameter save area is at
+         /* Save the true region sizes ready for the second pass.  */
+         refparam_size = refparam;
+         /* Make certain that the general parameter save area is at
             least the minimum 8 registers (or doublewords) in size.  */
          if (greg < 8)
            gparam_size = 8 * tdep->wordsize;
@@ -1352,12 +1767,14 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
    location; when READBUF is non-NULL, fill the buffer from the
    corresponding register return-value location.  */
 enum return_value_convention
-ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
                             struct type *valtype, struct regcache *regcache,
                             gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct type *func_type = function ? value_type (function) : NULL;
+  int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
 
   /* This function exists to support a calling convention that
      requires floating-point registers.  It shouldn't be used on
@@ -1420,6 +1837,83 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
        regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
+  /* OpenCL vectors < 16 bytes are returned as distinct
+     scalars in f1..f2 or r3..r10.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (valtype)
+      && TYPE_LENGTH (valtype) < 16
+      && opencl_abi)
+    {
+      struct type *eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
+      int i, nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
+
+      for (i = 0; i < nelt; i++)
+       {
+         int offset = i * TYPE_LENGTH (eltype);
+
+         if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
+           {
+             int regnum = tdep->ppc_fp0_regnum + 1 + i;
+             gdb_byte regval[MAX_REGISTER_SIZE];
+             struct type *regtype = register_type (gdbarch, regnum);
+
+             if (writebuf != NULL)
+               {
+                 convert_typed_floating (writebuf + offset, eltype,
+                                         regval, regtype);
+                 regcache_cooked_write (regcache, regnum, regval);
+               }
+             if (readbuf != NULL)
+               {
+                 regcache_cooked_read (regcache, regnum, regval);
+                 convert_typed_floating (regval, regtype,
+                                         readbuf + offset, eltype);
+               }
+           }
+         else
+           {
+             int regnum = tdep->ppc_gp0_regnum + 3 + i;
+             ULONGEST regval;
+
+             if (writebuf != NULL)
+               {
+                 regval = unpack_long (eltype, writebuf + offset);
+                 regcache_cooked_write_unsigned (regcache, regnum, regval);
+               }
+             if (readbuf != NULL)
+               {
+                 regcache_cooked_read_unsigned (regcache, regnum, &regval);
+                 store_unsigned_integer (readbuf + offset,
+                                         TYPE_LENGTH (eltype), byte_order,
+                                         regval);
+               }
+           }
+       }
+
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  /* OpenCL vectors >= 16 bytes are returned in v2..v9.  */
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (valtype)
+      && TYPE_LENGTH (valtype) >= 16
+      && opencl_abi)
+    {
+      int n_regs = TYPE_LENGTH (valtype) / 16;
+      int i;
+
+      for (i = 0; i < n_regs; i++)
+       {
+         int offset = i * 16;
+         int regnum = tdep->ppc_vr0_regnum + 2 + i;
+
+         if (writebuf != NULL)
+           regcache_cooked_write (regcache, regnum, writebuf + offset);
+         if (readbuf != NULL)
+           regcache_cooked_read (regcache, regnum, readbuf + offset);
+       }
+
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   /* Array type has more than one use.  */
   if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
     {
@@ -1440,7 +1934,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
        }
       /* A VMX vector is returned in v2.  */
       if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
-        && TYPE_VECTOR (valtype) && tdep->ppc_vr0_regnum >= 0)
+         && TYPE_VECTOR (valtype)
+         && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
         {
           if (readbuf)
             regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
@@ -1482,11 +1977,13 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
              gdb_byte regval[MAX_REGISTER_SIZE];
              struct type *regtype =
                register_type (gdbarch, tdep->ppc_fp0_regnum);
+             struct type *target_type;
+             target_type = check_typedef (TYPE_TARGET_TYPE (valtype));
              if (writebuf != NULL)
                {
                  convert_typed_floating ((const bfd_byte *) writebuf +
-                                         i * (TYPE_LENGTH (valtype) / 2),
-                                         valtype, regval, regtype);
+                                         i * TYPE_LENGTH (target_type), 
+                                         target_type, regval, regtype);
                  regcache_cooked_write (regcache,
                                          tdep->ppc_fp0_regnum + 1 + i,
                                         regval);
@@ -1498,8 +1995,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
                                         regval);
                  convert_typed_floating (regval, regtype,
                                          (bfd_byte *) readbuf +
-                                         i * (TYPE_LENGTH (valtype) / 2),
-                                         valtype);
+                                         i * TYPE_LENGTH (target_type),
+                                         target_type);
                }
            }
        }
This page took 0.033658 seconds and 4 git commands to generate.