Index: gcc/config/i386/i386.c |
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c |
index f958b16c44d38ee1a5c98afab271b8ee6653693e..8f0111a8b3da630b15889d3f9701fc6df9ac7323 100644 |
--- a/gcc/config/i386/i386.c |
+++ b/gcc/config/i386/i386.c |
@@ -4260,6 +4260,12 @@ ix86_handle_cconv_attribute (tree *node, tree name, |
if (TARGET_64BIT) |
{ |
+ /* Usually x86-64 does not have attributes so they warn here, but |
+ we have added an attribute pnaclcall so allow that. */ |
+ if (is_attribute_p ("pnaclcall", name)) |
+ /* Ignore the other i386 attributes and return. */ |
+ return NULL_TREE; |
+ |
/* Do not warn when emulating the MS ABI. */ |
if (TREE_CODE (*node) != FUNCTION_TYPE || ix86_function_type_abi (*node)!=MS_ABI) |
warning (OPT_Wattributes, "%qs attribute ignored", |
@@ -4343,6 +4349,11 @@ ix86_comp_type_attributes (const_tree type1, const_tree type2) |
!= !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2))) |
return 0; |
+ /* Check for mismatched pnaclcall types. */ |
+ if (!lookup_attribute ("pnaclcall", TYPE_ATTRIBUTES (type1)) |
+ != !lookup_attribute ("pnaclcall", TYPE_ATTRIBUTES (type2))) |
+ return 0; |
+ |
/* Check for mismatched return types (cdecl vs stdcall). */ |
if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) |
!= !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) |
@@ -4685,6 +4696,19 @@ ix86_cfun_abi (void) |
/* regclass.c */ |
extern void init_regs (void); |
+/* Return true if the function is decorated with a pnaclcall attribute. */ |
+static bool is_pnaclcall(const_tree fntype) |
+{ |
+ return (fntype && lookup_attribute ("pnaclcall", TYPE_ATTRIBUTES (fntype))); |
+} |
+ |
+static bool ix86_cfun_pnaclcall (void) |
+{ |
+ if (! cfun ) |
+ return 0; |
+ return cfun->machine->pnaclcall; |
+} |
+ |
/* Implementation of call abi switching target hook. Specific to FNDECL |
the specific call register sets are set. See also CONDITIONAL_REGISTER_USAGE |
for more details. */ |
@@ -4692,9 +4716,15 @@ void |
ix86_call_abi_override (const_tree fndecl) |
{ |
if (fndecl == NULL_TREE) |
- cfun->machine->call_abi = DEFAULT_ABI; |
+ { |
+ cfun->machine->call_abi = DEFAULT_ABI; |
+ cfun->machine->pnaclcall = 0; |
+ } |
else |
- cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl)); |
+ { |
+ cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl)); |
+ cfun->machine->pnaclcall = is_pnaclcall (TREE_TYPE (fndecl)); |
+ } |
} |
/* MS and SYSV ABI have different set of call used registers. Avoid expensive |
@@ -4765,6 +4795,9 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ |
? (!prototype_p (fntype) || stdarg_p (fntype)) |
: !libname); |
+ if (TARGET_64BIT) |
+ cum->pnaclcall = is_pnaclcall (fntype); |
+ |
if (!TARGET_64BIT) |
{ |
/* If there are variable arguments, then we won't pass anything |
@@ -4946,7 +4979,8 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) |
static int |
classify_argument (enum machine_mode mode, const_tree type, |
- enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset) |
+ enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset, |
+ bool is_pnacl_cconv) |
{ |
HOST_WIDE_INT bytes = |
(mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); |
@@ -4966,6 +5000,10 @@ classify_argument (enum machine_mode mode, const_tree type, |
tree field; |
enum x86_64_reg_class subclasses[MAX_CLASSES]; |
+ /* Pass aggregates on the stack for PNaCl. */ |
+ if (TARGET_PNACL_CCONV || is_pnacl_cconv) |
+ return 0; |
+ |
/* On x86-64 we pass structures larger than 32 bytes on the stack. */ |
if (bytes > 32) |
return 0; |
@@ -5035,7 +5073,8 @@ classify_argument (enum machine_mode mode, const_tree type, |
num = classify_argument (TYPE_MODE (type), type, |
subclasses, |
(int_bit_position (field) |
- + bit_offset) % 256); |
+ + bit_offset) % 256, |
+ is_pnacl_cconv); |
if (!num) |
return 0; |
for (i = 0; i < num; i++) |
@@ -5055,7 +5094,8 @@ classify_argument (enum machine_mode mode, const_tree type, |
{ |
int num; |
num = classify_argument (TYPE_MODE (TREE_TYPE (type)), |
- TREE_TYPE (type), subclasses, bit_offset); |
+ TREE_TYPE (type), subclasses, bit_offset, |
+ is_pnacl_cconv); |
if (!num) |
return 0; |
@@ -5086,7 +5126,8 @@ classify_argument (enum machine_mode mode, const_tree type, |
num = classify_argument (TYPE_MODE (TREE_TYPE (field)), |
TREE_TYPE (field), subclasses, |
- bit_offset); |
+ bit_offset, |
+ is_pnacl_cconv); |
if (!num) |
return 0; |
for (i = 0; i < num; i++) |
@@ -5327,10 +5368,10 @@ classify_argument (enum machine_mode mode, const_tree type, |
class. Return 0 iff parameter should be passed in memory. */ |
static int |
examine_argument (enum machine_mode mode, const_tree type, int in_return, |
- int *int_nregs, int *sse_nregs) |
+ int *int_nregs, int *sse_nregs, bool is_pnacl_cconv) |
{ |
enum x86_64_reg_class regclass[MAX_CLASSES]; |
- int n = classify_argument (mode, type, regclass, 0); |
+ int n = classify_argument (mode, type, regclass, 0, is_pnacl_cconv); |
*int_nregs = 0; |
*sse_nregs = 0; |
@@ -5370,7 +5411,7 @@ examine_argument (enum machine_mode mode, const_tree type, int in_return, |
static rtx |
construct_container (enum machine_mode mode, enum machine_mode orig_mode, |
const_tree type, int in_return, int nintregs, int nsseregs, |
- const int *intreg, int sse_regno) |
+ const int *intreg, int sse_regno, bool is_pnacl_cconv) |
{ |
/* The following variables hold the static issued_error state. */ |
static bool issued_sse_arg_error; |
@@ -5388,11 +5429,11 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode, |
rtx exp[MAX_CLASSES]; |
rtx ret; |
- n = classify_argument (mode, type, regclass, 0); |
+ n = classify_argument (mode, type, regclass, 0, is_pnacl_cconv); |
if (!n) |
return NULL; |
if (!examine_argument (mode, type, in_return, &needed_intregs, |
- &needed_sseregs)) |
+ &needed_sseregs, is_pnacl_cconv)) |
return NULL; |
if (needed_intregs > nintregs || needed_sseregs > nsseregs) |
return NULL; |
@@ -5666,7 +5707,7 @@ function_arg_advance_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode, |
if (!named && VALID_AVX256_REG_MODE (mode)) |
return; |
- if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs)) |
+ if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs, cum->pnaclcall)) |
cum->words += words; |
else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) |
{ |
@@ -5882,7 +5923,7 @@ function_arg_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode, |
return construct_container (mode, orig_mode, type, 0, cum->nregs, |
cum->sse_nregs, |
&x86_64_int_parameter_registers [cum->regno], |
- cum->sse_regno); |
+ cum->sse_regno, cum->pnaclcall); |
} |
static rtx |
@@ -6180,7 +6221,7 @@ function_value_32 (enum machine_mode orig_mode, enum machine_mode mode, |
static rtx |
function_value_64 (enum machine_mode orig_mode, enum machine_mode mode, |
- const_tree valtype) |
+ const_tree valtype, bool is_pnacl_cconv) |
{ |
rtx ret; |
@@ -6210,7 +6251,7 @@ function_value_64 (enum machine_mode orig_mode, enum machine_mode mode, |
ret = construct_container (mode, orig_mode, valtype, 1, |
X86_64_REGPARM_MAX, X86_64_SSE_REGPARM_MAX, |
- x86_64_int_return_registers, 0); |
+ x86_64_int_return_registers, 0, is_pnacl_cconv); |
/* For zero sized structures, construct_container returns NULL, but we |
need to keep rest of compiler happy by returning meaningful value. */ |
@@ -6260,7 +6301,7 @@ ix86_function_value_1 (const_tree valtype, const_tree fntype_or_decl, |
if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI) |
return function_value_ms_64 (orig_mode, mode); |
else if (TARGET_64BIT) |
- return function_value_64 (orig_mode, mode, valtype); |
+ return function_value_64 (orig_mode, mode, valtype, is_pnaclcall (fntype)); |
else |
return function_value_32 (orig_mode, mode, fntype, fn); |
} |
@@ -6330,10 +6371,12 @@ return_in_memory_32 (const_tree type, enum machine_mode mode) |
} |
static int ATTRIBUTE_UNUSED |
-return_in_memory_64 (const_tree type, enum machine_mode mode) |
+return_in_memory_64 (const_tree type, enum machine_mode mode, |
+ bool is_pnacl_cconv) |
{ |
int needed_intregs, needed_sseregs; |
- return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs); |
+ return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs, |
+ is_pnacl_cconv); |
} |
static int ATTRIBUTE_UNUSED |
@@ -6363,7 +6406,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) |
if (ix86_function_type_abi (fntype) == MS_ABI) |
return return_in_memory_ms_64 (type, mode); |
else |
- return return_in_memory_64 (type, mode); |
+ /* NOTE: fntype was meant to be unused, but we need to know |
+ if a call was a pnaclcall. */ |
+ return return_in_memory_64 (type, mode, is_pnaclcall (fntype)); |
} |
else |
return return_in_memory_32 (type, mode); |
@@ -6382,7 +6427,7 @@ ix86_sol10_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED |
enum machine_mode mode = type_natural_mode (type, NULL); |
if (TARGET_64BIT) |
- return return_in_memory_64 (type, mode); |
+ return return_in_memory_64 (type, mode, is_pnaclcall (fntype)); |
if (mode == BLKmode) |
return 1; |
@@ -6927,7 +6972,7 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, |
container = construct_container (nat_mode, TYPE_MODE (type), |
type, 0, X86_64_REGPARM_MAX, |
X86_64_SSE_REGPARM_MAX, intreg, |
- 0); |
+ 0, ix86_cfun_pnaclcall()); |
break; |
} |
@@ -6945,7 +6990,8 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, |
lab_false = create_artificial_label (); |
lab_over = create_artificial_label (); |
- examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs); |
+ examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs, |
+ ix86_cfun_pnaclcall()); |
need_temp = (!REG_P (container) |
&& ((needed_intregs && TYPE_ALIGN (type) > 64) |
@@ -30159,6 +30205,8 @@ static const struct attribute_spec ix86_attribute_table[] = |
{ "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute }, |
/* Cdecl attribute says the callee is a normal C declaration */ |
{ "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute }, |
+ /* pnaclcall attribute says we are using the PNaCl x86_64 calling conv. */ |
+ { "pnaclcall", 0, 0, false, true, true, ix86_handle_cconv_attribute }, |
/* Regparm attribute specifies how many integer arguments are to be |
passed in registers. */ |
{ "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute }, |