1a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* -----------------------------------------------------------------------
2a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   ffi.c - Copyright (c) 2002, 2007  Bo Thorsen <bo@suse.de>
3a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project           Copyright (c) 2008  Red Hat, Inc.
4a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
5a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   x86-64 Foreign Function Interface
6a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
7a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Permission is hereby granted, free of charge, to any person obtaining
8a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   a copy of this software and associated documentation files (the
9a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   ``Software''), to deal in the Software without restriction, including
10a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   without limitation the rights to use, copy, modify, merge, publish,
11a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   distribute, sublicense, and/or sell copies of the Software, and to
12a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   permit persons to whom the Software is furnished to do so, subject to
13a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   the following conditions:
14a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
15a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   The above copyright notice and this permission notice shall be included
16a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   in all copies or substantial portions of the Software.
17a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
18a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   DEALINGS IN THE SOFTWARE.
26a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   ----------------------------------------------------------------------- */
27a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
28a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi.h>
29a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi_common.h>
30a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
31a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdlib.h>
32a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdarg.h>
33a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
34a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#ifdef __x86_64__
35a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
36a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_GPR_REGS 6
37a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_SSE_REGS 8
38a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
39a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstruct register_args
40a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
41a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Registers for argument passing.  */
42a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  UINT64 gpr[MAX_GPR_REGS];
43a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  __int128_t sse[MAX_SSE_REGS];
44a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project};
45a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
46a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectextern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
47a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project			     void *raddr, void (*fnaddr)(void), unsigned ssecount);
48a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
49a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* All reference to register classes here is identical to the code in
50a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   gcc/config/i386/i386.c. Do *not* change one without the other.  */
51a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
52a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Register class used for passing given 64bit part of the argument.
53a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   These represent classes as documented by the PS ABI, with the exception
54a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   of SSESF, SSEDF classes, that are basically SSE class, just gcc will
55a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   use SF or DFmode move instead of DImode to avoid reformating penalties.
56a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
57a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
58a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   whenever possible (upper half does contain padding).  */
59a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectenum x86_64_reg_class
60a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  {
61a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_NO_CLASS,
62a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_INTEGER_CLASS,
63a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_INTEGERSI_CLASS,
64a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_SSE_CLASS,
65a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_SSESF_CLASS,
66a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_SSEDF_CLASS,
67a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_SSEUP_CLASS,
68a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_X87_CLASS,
69a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_X87UP_CLASS,
70a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_COMPLEX_X87_CLASS,
71a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    X86_64_MEMORY_CLASS
72a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  };
73a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
74a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_CLASSES 4
75a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
76a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define SSE_CLASS_P(X)	((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
77a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
78a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
79a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   of this code is to classify each 8bytes of incoming argument by the register
80a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   class and assign registers accordingly.  */
81a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
82a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Return the union class of CLASS1 and CLASS2.
83a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   See the x86-64 PS ABI for details.  */
84a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
85a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic enum x86_64_reg_class
86a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectmerge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
87a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
88a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #1: If both classes are equal, this is the resulting class.  */
89a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class1 == class2)
90a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return class1;
91a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
92a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
93a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     the other class.  */
94a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class1 == X86_64_NO_CLASS)
95a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return class2;
96a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class2 == X86_64_NO_CLASS)
97a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return class1;
98a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
99a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
100a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
101a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return X86_64_MEMORY_CLASS;
102a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
103a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
104a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
105a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
106a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return X86_64_INTEGERSI_CLASS;
107a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
108a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
109a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return X86_64_INTEGER_CLASS;
110a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
111a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
112a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     MEMORY is used.  */
113a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (class1 == X86_64_X87_CLASS
114a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class1 == X86_64_X87UP_CLASS
115a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class1 == X86_64_COMPLEX_X87_CLASS
116a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class2 == X86_64_X87_CLASS
117a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class2 == X86_64_X87UP_CLASS
118a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      || class2 == X86_64_COMPLEX_X87_CLASS)
119a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return X86_64_MEMORY_CLASS;
120a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
121a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Rule #6: Otherwise class SSE is used.  */
122a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return X86_64_SSE_CLASS;
123a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
124a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
125a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Classify the argument of type TYPE and mode MODE.
126a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   CLASSES will be filled by the register class used to pass each word
127a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   of the operand.  The number of words is returned.  In case the parameter
128a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   should be passed in memory, 0 is returned. As a special case for zero
129a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   sized containers, classes[0] will be NO_CLASS and 1 is returned.
130a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
131a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   See the x86-64 PS ABI for details.
132a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project*/
133a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
134a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectclassify_argument (ffi_type *type, enum x86_64_reg_class classes[],
135a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		   size_t byte_offset)
136a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
137a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  switch (type->type)
138a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
139a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_UINT8:
140a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_SINT8:
141a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_UINT16:
142a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_SINT16:
143a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_UINT32:
144a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_SINT32:
145a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_UINT64:
146a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_SINT64:
147a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_POINTER:
148a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (byte_offset + type->size <= 4)
149a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	classes[0] = X86_64_INTEGERSI_CLASS;
150a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
151a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	classes[0] = X86_64_INTEGER_CLASS;
152a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 1;
153a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_FLOAT:
154a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (byte_offset == 0)
155a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	classes[0] = X86_64_SSESF_CLASS;
156a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
157a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	classes[0] = X86_64_SSE_CLASS;
158a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 1;
159a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_DOUBLE:
160a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      classes[0] = X86_64_SSEDF_CLASS;
161a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 1;
162a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_LONGDOUBLE:
163a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      classes[0] = X86_64_X87_CLASS;
164a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      classes[1] = X86_64_X87UP_CLASS;
165a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 2;
166a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    case FFI_TYPE_STRUCT:
167a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      {
168a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	const int UNITS_PER_WORD = 8;
169a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
170a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	ffi_type **ptr;
171a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	int i;
172a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	enum x86_64_reg_class subclasses[MAX_CLASSES];
173a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
174a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	/* If the struct is larger than 16 bytes, pass it on the stack.  */
175a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	if (type->size > 16)
176a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  return 0;
177a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
178a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	for (i = 0; i < words; i++)
179a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  classes[i] = X86_64_NO_CLASS;
180a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
181a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	/* Merge the fields of structure.  */
182a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	for (ptr = type->elements; *ptr != NULL; ptr++)
183a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  {
184a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    int num;
185a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
186a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
187a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
188a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    num = classify_argument (*ptr, subclasses, byte_offset % 8);
189a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    if (num == 0)
190a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      return 0;
191a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    for (i = 0; i < num; i++)
192a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      {
193a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		int pos = byte_offset / 8;
194a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		classes[i + pos] =
195a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  merge_classes (subclasses[i], classes[i + pos]);
196a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      }
197a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
198a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    byte_offset += (*ptr)->size;
199a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  }
200a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
201a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	/* Final merger cleanup.  */
202a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	for (i = 0; i < words; i++)
203a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  {
204a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    /* If one class is MEMORY, everything should be passed in
205a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	       memory.  */
206a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    if (classes[i] == X86_64_MEMORY_CLASS)
207a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      return 0;
208a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
209a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    /* The X86_64_SSEUP_CLASS should be always preceded by
210a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	       X86_64_SSE_CLASS.  */
211a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    if (classes[i] == X86_64_SSEUP_CLASS
212a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
213a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      classes[i] = X86_64_SSE_CLASS;
214a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
215a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
216a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    if (classes[i] == X86_64_X87UP_CLASS
217a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
218a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      classes[i] = X86_64_SSE_CLASS;
219a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  }
220a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return words;
221a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      }
222a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
223a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    default:
224a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      FFI_ASSERT(0);
225a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
226a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return 0; /* Never reached.  */
227a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
228a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
229a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Examine the argument and return set number of register required in each
230a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   class.  Return zero iff parameter should be passed in memory, otherwise
231a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   the number of registers.  */
232a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
233a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
234a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectexamine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
235a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  _Bool in_return, int *pngpr, int *pnsse)
236a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
237a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int i, n, ngpr, nsse;
238a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
239a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  n = classify_argument (type, classes, 0);
240a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (n == 0)
241a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return 0;
242a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
243a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ngpr = nsse = 0;
244a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (i = 0; i < n; ++i)
245a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    switch (classes[i])
246a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      {
247a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_INTEGER_CLASS:
248a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_INTEGERSI_CLASS:
249a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	ngpr++;
250a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	break;
251a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_SSE_CLASS:
252a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_SSESF_CLASS:
253a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_SSEDF_CLASS:
254a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	nsse++;
255a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	break;
256a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_NO_CLASS:
257a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_SSEUP_CLASS:
258a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	break;
259a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_X87_CLASS:
260a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_X87UP_CLASS:
261a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      case X86_64_COMPLEX_X87_CLASS:
262a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return in_return != 0;
263a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      default:
264a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	abort ();
265a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      }
266a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
267a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  *pngpr = ngpr;
268a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  *pnsse = nsse;
269a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
270a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return n;
271a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
272a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
273a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Perform machine dependent cif processing.  */
274a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
275a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_status
276a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_prep_cif_machdep (ffi_cif *cif)
277a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
278a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
279a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  enum x86_64_reg_class classes[MAX_CLASSES];
280a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  size_t bytes;
281a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
282a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  gprcount = ssecount = 0;
283a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
284a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  flags = cif->rtype->type;
285a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (flags != FFI_TYPE_VOID)
286a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
287a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
288a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (n == 0)
289a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
290a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* The return value is passed in memory.  A pointer to that
291a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	     memory is the first argument.  Allocate a register for it.  */
292a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  gprcount++;
293a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* We don't have to do anything in asm for the return.  */
294a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  flags = FFI_TYPE_VOID;
295a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
296a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else if (flags == FFI_TYPE_STRUCT)
297a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
298a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Mark which registers the result appears in.  */
299a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  _Bool sse0 = SSE_CLASS_P (classes[0]);
300a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
301a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (sse0 && !sse1)
302a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    flags |= 1 << 8;
303a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  else if (!sse0 && sse1)
304a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    flags |= 1 << 9;
305a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  else if (sse0 && sse1)
306a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    flags |= 1 << 10;
307a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Mark the true size of the structure.  */
308a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  flags |= cif->rtype->size << 12;
309a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
310a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
311a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
312a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Go over all arguments and determine the way they should be passed.
313a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     If it's in a register and there is space for it, let that be so. If
314a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     not, add it's size to the stack byte count.  */
315a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
316a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
317a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
318a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || gprcount + ngpr > MAX_GPR_REGS
319a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || ssecount + nsse > MAX_SSE_REGS)
320a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
321a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  long align = cif->arg_types[i]->alignment;
322a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
323a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (align < 8)
324a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    align = 8;
325a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
326a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  bytes = ALIGN(bytes, align);
327a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  bytes += cif->arg_types[i]->size;
328a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
329a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
330a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
331a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  gprcount += ngpr;
332a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  ssecount += nsse;
333a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
334a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
335a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ssecount)
336a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    flags |= 1 << 11;
337a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  cif->flags = flags;
338a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  cif->bytes = bytes;
339a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
340a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return FFI_OK;
341a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
342a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
343a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid
344a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
345a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
346a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  enum x86_64_reg_class classes[MAX_CLASSES];
347a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  char *stack, *argp;
348a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ffi_type **arg_types;
349a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int gprcount, ssecount, ngpr, nsse, i, avn;
350a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  _Bool ret_in_memory;
351a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  struct register_args *reg_args;
352a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
353a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Can't call 32-bit mode from 64-bit mode.  */
354a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  FFI_ASSERT (cif->abi == FFI_UNIX64);
355a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
356a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* If the return value is a struct and we don't have a return value
357a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     address then we need to make one.  Note the setting of flags to
358a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     VOID above in ffi_prep_cif_machdep.  */
359a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
360a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		   && (cif->flags & 0xff) == FFI_TYPE_VOID);
361a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (rvalue == NULL && ret_in_memory)
362a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    rvalue = alloca (cif->rtype->size);
363a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
364a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Allocate the space for the arguments, plus 4 words of temp space.  */
365a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
366a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  reg_args = (struct register_args *) stack;
367a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  argp = stack + sizeof (struct register_args);
368a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
369a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  gprcount = ssecount = 0;
370a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
371a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* If the return value is passed in memory, add the pointer as the
372a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     first integer argument.  */
373a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ret_in_memory)
374a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    reg_args->gpr[gprcount++] = (long) rvalue;
375a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
376a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  avn = cif->nargs;
377a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  arg_types = cif->arg_types;
378a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
379a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (i = 0; i < avn; ++i)
380a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
381a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      size_t size = arg_types[i]->size;
382a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      int n;
383a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
384a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
385a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (n == 0
386a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || gprcount + ngpr > MAX_GPR_REGS
387a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || ssecount + nsse > MAX_SSE_REGS)
388a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
389a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  long align = arg_types[i]->alignment;
390a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
391a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Stack arguments are *always* at least 8 byte aligned.  */
392a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (align < 8)
393a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    align = 8;
394a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
395a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Pass this argument in memory.  */
396a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  argp = (void *) ALIGN (argp, align);
397a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  memcpy (argp, avalue[i], size);
398a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  argp += size;
399a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
400a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
401a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
402a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* The argument is passed entirely in registers.  */
403a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  char *a = (char *) avalue[i];
404a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  int j;
405a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
406a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  for (j = 0; j < n; j++, a += 8, size -= 8)
407a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    {
408a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      switch (classes[j])
409a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		{
410a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		case X86_64_INTEGER_CLASS:
411a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		case X86_64_INTEGERSI_CLASS:
412a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  reg_args->gpr[gprcount] = 0;
413a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
414a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  gprcount++;
415a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  break;
416a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		case X86_64_SSE_CLASS:
417a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		case X86_64_SSEDF_CLASS:
418a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  reg_args->sse[ssecount++] = *(UINT64 *) a;
419a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  break;
420a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		case X86_64_SSESF_CLASS:
421a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  reg_args->sse[ssecount++] = *(UINT32 *) a;
422a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  break;
423a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		default:
424a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		  abort();
425a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		}
426a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    }
427a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
428a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
429a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
430a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
431a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		   cif->flags, rvalue, fn, ssecount);
432a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
433a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
434a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
435a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectextern void ffi_closure_unix64(void);
436a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
437a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_status
438a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_prep_closure_loc (ffi_closure* closure,
439a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		      ffi_cif* cif,
440a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		      void (*fun)(ffi_cif*, void*, void**, void*),
441a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		      void *user_data,
442a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		      void *codeloc)
443a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
444a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  volatile unsigned short *tramp;
445a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
446a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  tramp = (volatile unsigned short *) &closure->tramp[0];
447a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
448a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  tramp[0] = 0xbb49;		/* mov <code>, %r11	*/
449a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  *(void * volatile *) &tramp[1] = ffi_closure_unix64;
450a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  tramp[5] = 0xba49;		/* mov <data>, %r10	*/
451a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  *(void * volatile *) &tramp[6] = codeloc;
452a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
453a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Set the carry bit iff the function uses any sse registers.
454a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     This is clc or stc, together with the first byte of the jmp.  */
455a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
456a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
457a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  tramp[11] = 0xe3ff;			/* jmp *%r11    */
458a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
459a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  closure->cif = cif;
460a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  closure->fun = fun;
461a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  closure->user_data = user_data;
462a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
463a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return FFI_OK;
464a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
465a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
466a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectint
467a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
468a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project			 struct register_args *reg_args, char *argp)
469a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
470a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ffi_cif *cif;
471a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void **avalue;
472a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ffi_type **arg_types;
473a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  long i, avn;
474a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int gprcount, ssecount, ngpr, nsse;
475a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int ret;
476a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
477a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  cif = closure->cif;
478a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  avalue = alloca(cif->nargs * sizeof(void *));
479a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  gprcount = ssecount = 0;
480a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
481a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ret = cif->rtype->type;
482a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ret != FFI_TYPE_VOID)
483a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
484a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      enum x86_64_reg_class classes[MAX_CLASSES];
485a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
486a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (n == 0)
487a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
488a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* The return value goes in memory.  Arrange for the closure
489a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	     return value to go directly back to the original caller.  */
490a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  rvalue = (void *) reg_args->gpr[gprcount++];
491a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* We don't have to do anything in asm for the return.  */
492a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  ret = FFI_TYPE_VOID;
493a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
494a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else if (ret == FFI_TYPE_STRUCT && n == 2)
495a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
496a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Mark which register the second word of the structure goes in.  */
497a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  _Bool sse0 = SSE_CLASS_P (classes[0]);
498a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  _Bool sse1 = SSE_CLASS_P (classes[1]);
499a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (!sse0 && sse1)
500a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    ret |= 1 << 8;
501a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  else if (sse0 && !sse1)
502a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    ret |= 1 << 9;
503a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
504a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
505a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
506a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  avn = cif->nargs;
507a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  arg_types = cif->arg_types;
508a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
509a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (i = 0; i < avn; ++i)
510a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
511a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      enum x86_64_reg_class classes[MAX_CLASSES];
512a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      int n;
513a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
514a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
515a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (n == 0
516a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || gprcount + ngpr > MAX_GPR_REGS
517a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || ssecount + nsse > MAX_SSE_REGS)
518a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
519a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  long align = arg_types[i]->alignment;
520a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
521a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Stack arguments are *always* at least 8 byte aligned.  */
522a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (align < 8)
523a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    align = 8;
524a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
525a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* Pass this argument in memory.  */
526a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  argp = (void *) ALIGN (argp, align);
527a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  avalue[i] = argp;
528a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  argp += arg_types[i]->size;
529a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
530a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      /* If the argument is in a single register, or two consecutive
531a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	 registers, then we can use that address directly.  */
532a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else if (n == 1
533a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	       || (n == 2
534a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		   && SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1])))
535a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
536a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  /* The argument is in a single register.  */
537a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (SSE_CLASS_P (classes[0]))
538a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    {
539a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      avalue[i] = &reg_args->sse[ssecount];
540a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      ssecount += n;
541a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    }
542a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  else
543a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    {
544a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      avalue[i] = &reg_args->gpr[gprcount];
545a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      gprcount += n;
546a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    }
547a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
548a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      /* Otherwise, allocate space to make them consecutive.  */
549a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
550a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
551a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  char *a = alloca (16);
552a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  int j;
553a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
554a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  avalue[i] = a;
555a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  for (j = 0; j < n; j++, a += 8)
556a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    {
557a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      if (SSE_CLASS_P (classes[j]))
558a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		memcpy (a, &reg_args->sse[ssecount++], 8);
559a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      else
560a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project		memcpy (a, &reg_args->gpr[gprcount++], 8);
561a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    }
562a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
563a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
564a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
565a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Invoke the closure.  */
566a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  closure->fun (cif, rvalue, avalue, closure->user_data);
567a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
568a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* Tell assembly how to perform return type promotions.  */
569a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return ret;
570a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
571a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
572a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif /* __x86_64__ */
573