Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
293a36eb
Commit
293a36eb
authored
Oct 16, 1996
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for MIPS EABI
From-SVN: r12967
parent
03f00806
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
307 additions
and
59 deletions
+307
-59
gcc/config/mips/abi64.h
+106
-25
gcc/config/mips/mips.c
+83
-24
gcc/config/mips/mips.h
+13
-6
gcc/ginclude/va-mips.h
+105
-4
No files found.
gcc/config/mips/abi64.h
View file @
293a36eb
...
@@ -26,11 +26,14 @@ Boston, MA 02111-1307, USA. */
...
@@ -26,11 +26,14 @@ Boston, MA 02111-1307, USA. */
{ "abi=", &mips_abi_string },
{ "abi=", &mips_abi_string },
#undef STACK_BOUNDARY
#undef STACK_BOUNDARY
#define STACK_BOUNDARY (mips_abi == ABI_32 ? 64 : 128)
#define STACK_BOUNDARY \
((mips_abi == ABI_32 || mips_abi == ABI_EABI) ? 64 : 128)
#undef MIPS_STACK_ALIGN
#undef MIPS_STACK_ALIGN
#define MIPS_STACK_ALIGN(LOC) \
#define MIPS_STACK_ALIGN(LOC) \
(mips_abi == ABI_32 ? ((LOC)+7) & ~7 : ((LOC)+15) & ~15)
((mips_abi == ABI_32 || mips_abi == ABI_EABI) \
? ((LOC) + 7) & ~7 \
: ((LOC) + 15) & ~15)
#undef GP_ARG_LAST
#undef GP_ARG_LAST
#define GP_ARG_LAST (mips_abi == ABI_32 ? GP_REG_FIRST + 7 : GP_REG_FIRST + 11)
#define GP_ARG_LAST (mips_abi == ABI_32 ? GP_REG_FIRST + 7 : GP_REG_FIRST + 11)
...
@@ -78,13 +81,16 @@ Boston, MA 02111-1307, USA. */
...
@@ -78,13 +81,16 @@ Boston, MA 02111-1307, USA. */
? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
&& int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
&& int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
: (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY \
: (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY \
&& (mips_abi == ABI_32 || GET_MODE_CLASS (MODE) == MODE_INT)))\
&& (mips_abi == ABI_32 || mips_abi == ABI_EABI \
|| GET_MODE_CLASS (MODE) == MODE_INT))) \
? downward : upward))
? downward : upward))
#undef RETURN_IN_MEMORY
#undef RETURN_IN_MEMORY
#define RETURN_IN_MEMORY(TYPE) \
#define RETURN_IN_MEMORY(TYPE)
\
(mips_abi == ABI_32 \
(mips_abi == ABI_32 \
? TYPE_MODE (TYPE) == BLKmode : int_size_in_bytes (TYPE) > 16)
? TYPE_MODE (TYPE) == BLKmode \
: (int_size_in_bytes (TYPE) \
> (mips_abi == ABI_EABI ? 2 * UNITS_PER_WORD : 16)))
extern
struct
rtx_def
*
mips_function_value
();
extern
struct
rtx_def
*
mips_function_value
();
#undef FUNCTION_VALUE
#undef FUNCTION_VALUE
...
@@ -95,29 +101,78 @@ extern struct rtx_def *mips_function_value ();
...
@@ -95,29 +101,78 @@ extern struct rtx_def *mips_function_value ();
For stdarg, we do not need to save the current argument, because it
For stdarg, we do not need to save the current argument, because it
is a real argument. */
is a real argument. */
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ if (mips_abi != ABI_32 \
{ int mips_off = (! current_function_varargs) && (! (CUM).last_arg_fp); \
&& ((CUM).arg_words \
int mips_fp_off = (! current_function_varargs) && ((CUM).last_arg_fp); \
< (MAX_ARGS_IN_REGISTERS - ! current_function_varargs))) \
if ((mips_abi != ABI_32 \
&& (CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off) \
|| (mips_abi == ABI_EABI \
&& ! TARGET_SOFT_FLOAT \
&& (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off)) \
{ \
{ \
PRETEND_SIZE \
int mips_save_gp_regs = \
= (MAX_ARGS_IN_REGISTERS - (CUM).arg_words \
MAX_ARGS_IN_REGISTERS - (CUM).arg_words - mips_off; \
- ! current_function_varargs) * UNITS_PER_WORD; \
int mips_save_fp_regs = \
(mips_abi != ABI_EABI ? 0 \
: MAX_ARGS_IN_REGISTERS - (CUM).fp_arg_words - mips_fp_off); \
\
if (mips_save_gp_regs < 0) \
mips_save_gp_regs = 0; \
if (mips_save_fp_regs < 0) \
mips_save_fp_regs = 0; \
PRETEND_SIZE = ((mips_save_gp_regs * UNITS_PER_WORD) \
+ (mips_save_fp_regs * UNITS_PER_FPREG)); \
\
\
if (! (NO_RTL)) \
if (! (NO_RTL)) \
{ \
{ \
rtx mem = gen_rtx (MEM, BLKmode, virtual_incoming_args_rtx); \
if ((CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off) \
/* va_arg is an array access in this case, which causes it to \
{ \
get MEM_IN_STRUCT_P set. We must set it here so that the \
rtx ptr, mem; \
insn scheduler won't assume that these stores can't \
if (mips_abi != ABI_EABI) \
possibly overlap with the va_arg loads. */
\
ptr = virtual_incoming_args_rtx; \
if (BYTES_BIG_ENDIAN) \
else \
MEM_IN_STRUCT_P (mem) = 1; \
ptr = plus_constant (virtual_incoming_args_rtx, \
move_block_from_reg \
- (mips_save_gp_regs \
((CUM).arg_words + GP_ARG_FIRST + ! current_function_varargs, \
* UNITS_PER_WORD)); \
mem, \
mem = gen_rtx (MEM, BLKmode, ptr); \
(MAX_ARGS_IN_REGISTERS - (CUM).arg_words \
/* va_arg is an array access in this case, which causes \
- ! current_function_varargs), \
it to get MEM_IN_STRUCT_P set. We must set it here \
PRETEND_SIZE); \
so that the insn scheduler won't assume that these \
stores can't possibly overlap with the va_arg loads. */
\
if (mips_abi != ABI_EABI && BYTES_BIG_ENDIAN) \
MEM_IN_STRUCT_P (mem) = 1; \
move_block_from_reg \
((CUM).arg_words + GP_ARG_FIRST + mips_off, \
mem, \
mips_save_gp_regs, \
mips_save_gp_regs * UNITS_PER_WORD); \
} \
if (mips_abi == ABI_EABI \
&& ! TARGET_SOFT_FLOAT \
&& (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off) \
{ \
int off; \
int i; \
/* We can't use move_block_from_reg, because it will use \
the wrong mode. */
\
off = (- (mips_save_gp_regs * UNITS_PER_WORD) \
- (mips_save_fp_regs * UNITS_PER_FPREG)); \
for (i = 0; i < mips_save_fp_regs; i++) \
{ \
rtx tem = \
gen_rtx (MEM, DFmode, \
plus_constant (virtual_incoming_args_rtx, \
(off \
+ i * GET_MODE_SIZE (DFmode)))); \
emit_move_insn (tem, \
gen_rtx (REG, DFmode, \
((CUM).fp_arg_words \
+ FP_ARG_FIRST \
+ i \
+ mips_fp_off))); \
if (! TARGET_FLOAT64) \
++i; \
} \
} \
} \
} \
} \
} \
}
}
...
@@ -125,6 +180,32 @@ extern struct rtx_def *mips_function_value ();
...
@@ -125,6 +180,32 @@ extern struct rtx_def *mips_function_value ();
/* ??? Should disable for mips_abi == ABI32. */
/* ??? Should disable for mips_abi == ABI32. */
#define STRICT_ARGUMENT_NAMING
#define STRICT_ARGUMENT_NAMING
/* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is
made in memory and a pointer to the argument is passed instead of the
argument itself. The pointer is passed in whatever way is appropriate
for passing a pointer to that type. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
(mips_abi == ABI_EABI \
&& function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED))
/* A C expression that indicates when it is the called function's
responsibility to make a copy of arguments passed by invisible
reference. Normally, the caller makes a copy and passes the
address of the copy to the routine being called. When
FUNCTION_ARG_CALLEE_COPIES is defined and is nonzero, the caller
does not make a copy. Instead, it passes a pointer to the "live"
value. The called function must not modify this value. If it can
be determined that the value won't be modified, it need not make a
copy; otherwise a copy must be made.
??? The MIPS EABI says that the caller should copy in ``K&R mode.''
I don't know how to detect that here, since flag_traditional is not
a back end flag. */
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
(mips_abi == ABI_EABI && (NAMED) \
&& FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED))
/* ??? Unimplemented stuff follows. */
/* ??? Unimplemented stuff follows. */
/* ??? Add support for 16 byte/128 bit long doubles here when
/* ??? Add support for 16 byte/128 bit long doubles here when
...
...
gcc/config/mips/mips.c
View file @
293a36eb
...
@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi;
...
@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi;
/* Strings to hold which cpu and instruction set architecture to use. */
/* Strings to hold which cpu and instruction set architecture to use. */
char
*
mips_cpu_string
;
/* for -mcpu=<xxx> */
char
*
mips_cpu_string
;
/* for -mcpu=<xxx> */
char
*
mips_isa_string
;
/* for -mips{1,2,3,4} */
char
*
mips_isa_string
;
/* for -mips{1,2,3,4} */
char
*
mips_abi_string
;
/* for -mabi={o32,32,n32,n64,64} */
char
*
mips_abi_string
;
/* for -mabi={o32,32,n32,n64,64
,eabi
} */
/* If TRUE, we split addresses into their high and low parts in the RTL. */
/* If TRUE, we split addresses into their high and low parts in the RTL. */
int
mips_split_addresses
;
int
mips_split_addresses
;
...
@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode)
...
@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode)
return
TRUE
;
return
TRUE
;
/* ??? li.s does not work right with SGI's Irix 6 assembler. */
/* ??? li.s does not work right with SGI's Irix 6 assembler. */
if
(
mips_abi
!=
ABI_32
)
if
(
mips_abi
!=
ABI_32
&&
mips_abi
!=
ABI_EABI
)
return
FALSE
;
return
FALSE
;
REAL_VALUE_FROM_CONST_DOUBLE
(
d
,
op
);
REAL_VALUE_FROM_CONST_DOUBLE
(
d
,
op
);
...
@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named)
...
@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named)
break
;
break
;
case
SFmode
:
case
SFmode
:
cum
->
arg_words
++
;
if
(
mips_abi
==
ABI_EABI
&&
!
TARGET_SOFT_FLOAT
)
cum
->
fp_arg_words
++
;
else
cum
->
arg_words
++
;
break
;
break
;
case
DFmode
:
case
DFmode
:
cum
->
arg_words
+=
(
TARGET_64BIT
?
1
:
2
);
if
(
mips_abi
==
ABI_EABI
&&
!
TARGET_SOFT_FLOAT
&&
!
TARGET_SINGLE_FLOAT
)
cum
->
fp_arg_words
+=
(
TARGET_64BIT
?
1
:
2
);
else
cum
->
arg_words
+=
(
TARGET_64BIT
?
1
:
2
);
break
;
break
;
case
DImode
:
case
DImode
:
...
@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named)
...
@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named)
rtx
ret
;
rtx
ret
;
int
regbase
=
-
1
;
int
regbase
=
-
1
;
int
bias
=
0
;
int
bias
=
0
;
int
*
arg_words
=
&
cum
->
arg_words
;
int
struct_p
=
((
type
!=
(
tree
)
0
)
int
struct_p
=
((
type
!=
(
tree
)
0
)
&&
(
TREE_CODE
(
type
)
==
RECORD_TYPE
&&
(
TREE_CODE
(
type
)
==
RECORD_TYPE
||
TREE_CODE
(
type
)
==
UNION_TYPE
));
||
TREE_CODE
(
type
)
==
UNION_TYPE
));
...
@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named)
...
@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named)
cum
->
gp_reg_found
,
cum
->
arg_number
,
cum
->
arg_words
,
GET_MODE_NAME
(
mode
),
cum
->
gp_reg_found
,
cum
->
arg_number
,
cum
->
arg_words
,
GET_MODE_NAME
(
mode
),
type
,
named
);
type
,
named
);
cum
->
last_arg_fp
=
0
;
switch
(
mode
)
switch
(
mode
)
{
{
case
SFmode
:
case
SFmode
:
...
@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named)
...
@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named)
bias
=
1
;
bias
=
1
;
}
}
}
}
else
if
(
mips_abi
==
ABI_EABI
&&
!
TARGET_SOFT_FLOAT
)
{
if
(
!
TARGET_64BIT
)
cum
->
fp_arg_words
+=
cum
->
fp_arg_words
&
1
;
cum
->
last_arg_fp
=
1
;
arg_words
=
&
cum
->
fp_arg_words
;
regbase
=
FP_ARG_FIRST
;
}
else
else
regbase
=
(
TARGET_SOFT_FLOAT
||
!
named
?
GP_ARG_FIRST
:
FP_ARG_FIRST
);
regbase
=
(
TARGET_SOFT_FLOAT
||
!
named
?
GP_ARG_FIRST
:
FP_ARG_FIRST
);
break
;
break
;
case
DFmode
:
case
DFmode
:
if
(
!
TARGET_64BIT
)
if
(
!
TARGET_64BIT
)
cum
->
arg_words
+=
(
cum
->
arg_words
&
1
);
{
if
(
mips_abi
==
ABI_EABI
&&
!
TARGET_SOFT_FLOAT
&&
!
TARGET_SINGLE_FLOAT
)
cum
->
fp_arg_words
+=
cum
->
fp_arg_words
&
1
;
else
cum
->
arg_words
+=
cum
->
arg_words
&
1
;
}
if
(
mips_abi
==
ABI_32
)
if
(
mips_abi
==
ABI_32
)
regbase
=
((
cum
->
gp_reg_found
regbase
=
((
cum
->
gp_reg_found
||
TARGET_SOFT_FLOAT
||
TARGET_SOFT_FLOAT
...
@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named)
...
@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named)
||
cum
->
arg_number
>=
2
)
||
cum
->
arg_number
>=
2
)
?
GP_ARG_FIRST
?
GP_ARG_FIRST
:
FP_ARG_FIRST
);
:
FP_ARG_FIRST
);
else
if
(
mips_abi
==
ABI_EABI
&&
!
TARGET_SOFT_FLOAT
&&
!
TARGET_SINGLE_FLOAT
)
{
cum
->
last_arg_fp
=
1
;
arg_words
=
&
cum
->
fp_arg_words
;
regbase
=
FP_ARG_FIRST
;
}
else
else
regbase
=
(
TARGET_SOFT_FLOAT
||
TARGET_SINGLE_FLOAT
||
!
named
regbase
=
(
TARGET_SOFT_FLOAT
||
TARGET_SINGLE_FLOAT
||
!
named
?
GP_ARG_FIRST
:
FP_ARG_FIRST
);
?
GP_ARG_FIRST
:
FP_ARG_FIRST
);
...
@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named)
...
@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named)
/* Drops through. */
/* Drops through. */
case
BLKmode
:
case
BLKmode
:
if
(
type
!=
(
tree
)
0
&&
TYPE_ALIGN
(
type
)
>
BITS_PER_WORD
if
(
type
!=
(
tree
)
0
&&
TYPE_ALIGN
(
type
)
>
BITS_PER_WORD
&&
!
TARGET_64BIT
)
&&
!
TARGET_64BIT
&&
mips_abi
!=
ABI_EABI
)
cum
->
arg_words
+=
(
cum
->
arg_words
&
1
);
cum
->
arg_words
+=
(
cum
->
arg_words
&
1
);
regbase
=
GP_ARG_FIRST
;
regbase
=
GP_ARG_FIRST
;
break
;
break
;
...
@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named)
...
@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named)
regbase
=
GP_ARG_FIRST
;
regbase
=
GP_ARG_FIRST
;
}
}
if
(
cum
->
arg_words
>=
MAX_ARGS_IN_REGISTERS
)
if
(
*
arg_words
>=
MAX_ARGS_IN_REGISTERS
)
{
{
if
(
TARGET_DEBUG_E_MODE
)
if
(
TARGET_DEBUG_E_MODE
)
fprintf
(
stderr
,
"<stack>%s
\n
"
,
struct_p
?
", [struct]"
:
""
);
fprintf
(
stderr
,
"<stack>%s
\n
"
,
struct_p
?
", [struct]"
:
""
);
...
@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named)
...
@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named)
abort
();
abort
();
if
(
!
type
||
TREE_CODE
(
type
)
!=
RECORD_TYPE
||
mips_abi
==
ABI_32
if
(
!
type
||
TREE_CODE
(
type
)
!=
RECORD_TYPE
||
mips_abi
==
ABI_32
||
!
named
)
||
mips_abi
==
ABI_EABI
||
!
named
)
ret
=
gen_rtx
(
REG
,
mode
,
regbase
+
cum
->
arg_words
+
bias
);
ret
=
gen_rtx
(
REG
,
mode
,
regbase
+
*
arg_words
+
bias
);
else
else
{
{
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
...
@@ -3169,7 +3199,7 @@ function_arg (cum, mode, type, named)
...
@@ -3169,7 +3199,7 @@ function_arg (cum, mode, type, named)
break
;
break
;
if
(
!
field
)
if
(
!
field
)
ret
=
gen_rtx
(
REG
,
mode
,
regbase
+
cum
->
arg_words
+
bias
);
ret
=
gen_rtx
(
REG
,
mode
,
regbase
+
*
arg_words
+
bias
);
else
else
{
{
/* Now handle the special case by returning a PARALLEL
/* Now handle the special case by returning a PARALLEL
...
@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named)
...
@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named)
backend to allow DImode values in fp registers. */
backend to allow DImode values in fp registers. */
chunks
=
TREE_INT_CST_LOW
(
TYPE_SIZE
(
type
))
/
BITS_PER_WORD
;
chunks
=
TREE_INT_CST_LOW
(
TYPE_SIZE
(
type
))
/
BITS_PER_WORD
;
if
(
chunks
+
cum
->
arg_words
+
bias
>
MAX_ARGS_IN_REGISTERS
)
if
(
chunks
+
*
arg_words
+
bias
>
MAX_ARGS_IN_REGISTERS
)
chunks
=
MAX_ARGS_IN_REGISTERS
-
cum
->
arg_words
-
bias
;
chunks
=
MAX_ARGS_IN_REGISTERS
-
*
arg_words
-
bias
;
/* assign_parms checks the mode of ENTRY_PARM, so we must
/* assign_parms checks the mode of ENTRY_PARM, so we must
use the actual mode here. */
use the actual mode here. */
ret
=
gen_rtx
(
PARALLEL
,
mode
,
rtvec_alloc
(
chunks
));
ret
=
gen_rtx
(
PARALLEL
,
mode
,
rtvec_alloc
(
chunks
));
bitpos
=
0
;
bitpos
=
0
;
regno
=
regbase
+
cum
->
arg_words
+
bias
;
regno
=
regbase
+
*
arg_words
+
bias
;
field
=
TYPE_FIELDS
(
type
);
field
=
TYPE_FIELDS
(
type
);
for
(
i
=
0
;
i
<
chunks
;
i
++
)
for
(
i
=
0
;
i
<
chunks
;
i
++
)
{
{
...
@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named)
...
@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named)
}
}
if
(
TARGET_DEBUG_E_MODE
)
if
(
TARGET_DEBUG_E_MODE
)
fprintf
(
stderr
,
"%s%s
\n
"
,
reg_names
[
regbase
+
cum
->
arg_words
+
bias
],
fprintf
(
stderr
,
"%s%s
\n
"
,
reg_names
[
regbase
+
*
arg_words
+
bias
],
struct_p
?
", [struct]"
:
""
);
struct_p
?
", [struct]"
:
""
);
/* The following is a hack in order to pass 1 byte structures
/* The following is a hack in order to pass 1 byte structures
...
@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named)
...
@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named)
calling convention for now. */
calling convention for now. */
if
(
struct_p
&&
int_size_in_bytes
(
type
)
<
UNITS_PER_WORD
if
(
struct_p
&&
int_size_in_bytes
(
type
)
<
UNITS_PER_WORD
&&
!
TARGET_64BIT
)
&&
!
TARGET_64BIT
&&
mips_abi
!=
ABI_EABI
)
{
{
rtx
amount
=
GEN_INT
(
BITS_PER_WORD
rtx
amount
=
GEN_INT
(
BITS_PER_WORD
-
int_size_in_bytes
(
type
)
*
BITS_PER_UNIT
);
-
int_size_in_bytes
(
type
)
*
BITS_PER_UNIT
);
rtx
reg
=
gen_rtx
(
REG
,
word_mode
,
regbase
+
cum
->
arg_words
+
bias
);
rtx
reg
=
gen_rtx
(
REG
,
word_mode
,
regbase
+
*
arg_words
+
bias
);
if
(
TARGET_64BIT
)
if
(
TARGET_64BIT
)
cum
->
adjust
[
cum
->
num_adjusts
++
]
=
gen_ashldi3
(
reg
,
reg
,
amount
);
cum
->
adjust
[
cum
->
num_adjusts
++
]
=
gen_ashldi3
(
reg
,
reg
,
amount
);
else
else
...
@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named)
...
@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named)
if
((
mode
==
BLKmode
if
((
mode
==
BLKmode
||
GET_MODE_CLASS
(
mode
)
!=
MODE_COMPLEX_INT
||
GET_MODE_CLASS
(
mode
)
!=
MODE_COMPLEX_INT
||
GET_MODE_CLASS
(
mode
)
!=
MODE_COMPLEX_FLOAT
)
||
GET_MODE_CLASS
(
mode
)
!=
MODE_COMPLEX_FLOAT
)
&&
cum
->
arg_words
<
MAX_ARGS_IN_REGISTERS
)
&&
cum
->
arg_words
<
MAX_ARGS_IN_REGISTERS
&&
mips_abi
!=
ABI_EABI
)
{
{
int
words
;
int
words
;
if
(
mode
==
BLKmode
)
if
(
mode
==
BLKmode
)
...
@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named)
...
@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named)
}
}
else
if
(
mode
==
DImode
&&
cum
->
arg_words
==
MAX_ARGS_IN_REGISTERS
-
1
else
if
(
mode
==
DImode
&&
cum
->
arg_words
==
MAX_ARGS_IN_REGISTERS
-
1
&&
!
TARGET_64BIT
)
&&
!
TARGET_64BIT
&&
mips_abi
!=
ABI_EABI
)
{
{
if
(
TARGET_DEBUG_E_MODE
)
if
(
TARGET_DEBUG_E_MODE
)
fprintf
(
stderr
,
"function_arg_partial_nregs = 1
\n
"
);
fprintf
(
stderr
,
"function_arg_partial_nregs = 1
\n
"
);
...
@@ -3402,11 +3434,13 @@ override_options ()
...
@@ -3402,11 +3434,13 @@ override_options ()
else
if
(
!
strcmp
(
mips_abi_string
,
"64"
)
else
if
(
!
strcmp
(
mips_abi_string
,
"64"
)
||
!
strcmp
(
mips_abi_string
,
"n64"
))
||
!
strcmp
(
mips_abi_string
,
"n64"
))
mips_abi
=
ABI_64
;
mips_abi
=
ABI_64
;
else
if
(
!
strcmp
(
mips_abi_string
,
"eabi"
))
mips_abi
=
ABI_EABI
;
else
else
error
(
"bad value (%s) for -mabi= switch"
,
mips_abi_string
);
error
(
"bad value (%s) for -mabi= switch"
,
mips_abi_string
);
/* A specified ISA defaults the ABI if it was not specified. */
/* A specified ISA defaults the ABI if it was not specified. */
if
(
mips_abi_string
==
0
&&
mips_isa_string
)
if
(
mips_abi_string
==
0
&&
mips_isa_string
&&
mips_abi
!=
ABI_EABI
)
{
{
if
(
mips_isa
<=
2
)
if
(
mips_isa
<=
2
)
mips_abi
=
ABI_32
;
mips_abi
=
ABI_32
;
...
@@ -3414,7 +3448,7 @@ override_options ()
...
@@ -3414,7 +3448,7 @@ override_options ()
mips_abi
=
ABI_64
;
mips_abi
=
ABI_64
;
}
}
/* A specified ABI defaults the ISA if it was not specified. */
/* A specified ABI defaults the ISA if it was not specified. */
else
if
(
mips_isa_string
==
0
&&
mips_abi_string
)
else
if
(
mips_isa_string
==
0
&&
mips_abi_string
&&
mips_abi
!=
ABI_EABI
)
{
{
if
(
mips_abi
==
ABI_32
)
if
(
mips_abi
==
ABI_32
)
mips_isa
=
1
;
mips_isa
=
1
;
...
@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream)
...
@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream)
/* Start a section, so that the first .popsection directive is guaranteed
/* Start a section, so that the first .popsection directive is guaranteed
to have a previously defined section to pop back to. */
to have a previously defined section to pop back to. */
if
(
mips_abi
!=
ABI_32
)
if
(
mips_abi
!=
ABI_32
&&
mips_abi
!=
ABI_EABI
)
fprintf
(
stream
,
"
\t
.section
\t
.text
\n
"
);
fprintf
(
stream
,
"
\t
.section
\t
.text
\n
"
);
/* This code exists so that we can put all externs before all symbol
/* This code exists so that we can put all externs before all symbol
...
@@ -4853,7 +4887,7 @@ compute_frame_size (size)
...
@@ -4853,7 +4887,7 @@ compute_frame_size (size)
for leaf routines (total_size == extra_size) to save the gp reg.
for leaf routines (total_size == extra_size) to save the gp reg.
The gp reg is callee saved in the 64 bit ABI, so all routines must
The gp reg is callee saved in the 64 bit ABI, so all routines must
save the gp reg. */
save the gp reg. */
if
(
total_size
==
extra_size
&&
mips_abi
==
ABI_32
)
if
(
total_size
==
extra_size
&&
(
mips_abi
==
ABI_32
||
mips_abi
==
ABI_EABI
)
)
total_size
=
extra_size
=
0
;
total_size
=
extra_size
=
0
;
else
if
(
TARGET_ABICALLS
)
else
if
(
TARGET_ABICALLS
)
{
{
...
@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func)
...
@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func)
/* ??? How should we return complex float? */
/* ??? How should we return complex float? */
if
(
mclass
==
MODE_FLOAT
||
mclass
==
MODE_COMPLEX_FLOAT
)
if
(
mclass
==
MODE_FLOAT
||
mclass
==
MODE_COMPLEX_FLOAT
)
reg
=
FP_RETURN
;
reg
=
FP_RETURN
;
else
if
(
TREE_CODE
(
valtype
)
==
RECORD_TYPE
&&
mips_abi
!=
ABI_32
)
else
if
(
TREE_CODE
(
valtype
)
==
RECORD_TYPE
&&
mips_abi
!=
ABI_32
&&
mips_abi
!=
ABI_EABI
)
{
{
/* A struct with only one or two floating point fields is returned in
/* A struct with only one or two floating point fields is returned in
the floating point registers. */
the floating point registers. */
...
@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func)
...
@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func)
return
gen_rtx
(
REG
,
mode
,
reg
);
return
gen_rtx
(
REG
,
mode
,
reg
);
}
}
/* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE. Return
nonzero when an argument must be passed by reference. */
int
function_arg_pass_by_reference
(
cum
,
mode
,
type
,
named
)
CUMULATIVE_ARGS
*
cum
;
enum
machine_mode
mode
;
tree
type
;
int
named
;
{
int
size
;
if
(
mips_abi
!=
ABI_EABI
)
return
0
;
/* ??? How should SCmode be handled? */
if
(
type
==
NULL_TREE
||
mode
==
DImode
||
mode
==
DFmode
)
return
0
;
size
=
int_size_in_bytes
(
type
);
return
size
==
-
1
||
size
>
UNITS_PER_WORD
;
}
#endif
#endif
/* This function returns the register class required for a secondary
/* This function returns the register class required for a secondary
...
...
gcc/config/mips/mips.h
View file @
293a36eb
...
@@ -82,7 +82,8 @@ enum processor_type {
...
@@ -82,7 +82,8 @@ enum processor_type {
enum
mips_abi_type
{
enum
mips_abi_type
{
ABI_32
,
ABI_32
,
ABI_N32
,
ABI_N32
,
ABI_64
ABI_64
,
ABI_EABI
};
};
#ifndef MIPS_ABI_DEFAULT
#ifndef MIPS_ABI_DEFAULT
...
@@ -166,6 +167,7 @@ extern void final_prescan_insn ();
...
@@ -166,6 +167,7 @@ extern void final_prescan_insn ();
extern
struct
rtx_def
*
function_arg
();
extern
struct
rtx_def
*
function_arg
();
extern
void
function_arg_advance
();
extern
void
function_arg_advance
();
extern
int
function_arg_partial_nregs
();
extern
int
function_arg_partial_nregs
();
extern
int
function_arg_pass_by_reference
();
extern
void
function_epilogue
();
extern
void
function_epilogue
();
extern
void
function_prologue
();
extern
void
function_prologue
();
extern
void
gen_conditional_branch
();
extern
void
gen_conditional_branch
();
...
@@ -803,6 +805,8 @@ while (0)
...
@@ -803,6 +805,8 @@ while (0)
%{mgp32:-U__mips64} %{mgp64:-D__mips64} \
%{mgp32:-U__mips64} %{mgp64:-D__mips64} \
%{msingle-float:%{!msoft-float:-D__mips_single_float}} \
%{msingle-float:%{!msoft-float:-D__mips_single_float}} \
%{m4650:%{!msoft-float:-D__mips_single_float}} \
%{m4650:%{!msoft-float:-D__mips_single_float}} \
%{msoft-float:-D__mips_soft_float} \
%{mabi=eabi:-D__mips_eabi} \
%{EB:-UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -D_MIPSEB -D__MIPSEB -D__MIPSEB__ %{!ansi:-DMIPSEB}} \
%{EB:-UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -D_MIPSEB -D__MIPSEB -D__MIPSEB__ %{!ansi:-DMIPSEB}} \
%{EL:-UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -D_MIPSEL -D__MIPSEL -D__MIPSEL__ %{!ansi:-DMIPSEL}} \
%{EL:-UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -D_MIPSEL -D__MIPSEL -D__MIPSEL__ %{!ansi:-DMIPSEL}} \
%(subtarget_cpp_spec) "
%(subtarget_cpp_spec) "
...
@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info;
...
@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info;
&& ((TO) == FRAME_POINTER_REGNUM \
&& ((TO) == FRAME_POINTER_REGNUM \
|| (TO) == STACK_POINTER_REGNUM)) \
|| (TO) == STACK_POINTER_REGNUM)) \
(OFFSET) = (current_frame_info.total_size \
(OFFSET) = (current_frame_info.total_size \
- (
mips_abi != ABI_32
\
- (
(mips_abi != ABI_32 && mips_abi != ABI_EABI)
\
? current_function_pretend_args_size \
? current_function_pretend_args_size \
: 0)); \
: 0)); \
else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
...
@@ -2112,6 +2116,8 @@ typedef struct mips_args {
...
@@ -2112,6 +2116,8 @@ typedef struct mips_args {
int
gp_reg_found
;
/* whether a gp register was found yet */
int
gp_reg_found
;
/* whether a gp register was found yet */
int
arg_number
;
/* argument number */
int
arg_number
;
/* argument number */
int
arg_words
;
/* # total words the arguments take */
int
arg_words
;
/* # total words the arguments take */
int
fp_arg_words
;
/* # words for FP args (MIPS_EABI only) */
int
last_arg_fp
;
/* nonzero if last arg was FP (EABI only) */
int
num_adjusts
;
/* number of adjustments made */
int
num_adjusts
;
/* number of adjustments made */
/* Adjustments made to args pass in regs. */
/* Adjustments made to args pass in regs. */
/* ??? The size is doubled to work around a
/* ??? The size is doubled to work around a
...
@@ -2507,7 +2513,7 @@ typedef struct mips_args {
...
@@ -2507,7 +2513,7 @@ typedef struct mips_args {
/* ??? Reject combining an address with a register for the MIPS \
/* ??? Reject combining an address with a register for the MIPS \
64 bit ABI, because the SGI assembler can not handle this. */
\
64 bit ABI, because the SGI assembler can not handle this. */
\
if (!TARGET_DEBUG_A_MODE \
if (!TARGET_DEBUG_A_MODE \
&&
mips_abi == ABI_32
\
&&
(mips_abi == ABI_32 || mips_abi == ABI_EABI)
\
&& CONSTANT_ADDRESS_P (xplus1) \
&& CONSTANT_ADDRESS_P (xplus1) \
&& ! mips_split_addresses \
&& ! mips_split_addresses \
&& (!TARGET_EMBEDDED_PIC \
&& (!TARGET_EMBEDDED_PIC \
...
@@ -2537,7 +2543,7 @@ typedef struct mips_args {
...
@@ -2537,7 +2543,7 @@ typedef struct mips_args {
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
|| (GET_CODE (X) == CONST \
|| (GET_CODE (X) == CONST \
&& ! (flag_pic && pic_address_needs_scratch (X)) \
&& ! (flag_pic && pic_address_needs_scratch (X)) \
&&
mips_abi == ABI_32))
\
&&
(mips_abi == ABI_32 || mips_abi == ABI_EABI)))
\
&& (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X)))
&& (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X)))
/* Define this, so that when PIC, reload won't try to reload invalid
/* Define this, so that when PIC, reload won't try to reload invalid
...
@@ -2556,7 +2562,8 @@ typedef struct mips_args {
...
@@ -2556,7 +2562,8 @@ typedef struct mips_args {
#define LEGITIMATE_CONSTANT_P(X) \
#define LEGITIMATE_CONSTANT_P(X) \
((GET_CODE (X) != CONST_DOUBLE \
((GET_CODE (X) != CONST_DOUBLE \
|| mips_const_double_ok (X, GET_MODE (X))) \
|| mips_const_double_ok (X, GET_MODE (X))) \
&& ! (GET_CODE (X) == CONST && mips_abi != ABI_32))
&& ! (GET_CODE (X) == CONST \
&& mips_abi != ABI_32 && mips_abi != ABI_EABI))
/* A C compound statement that attempts to replace X with a valid
/* A C compound statement that attempts to replace X with a valid
memory address for an operand of mode MODE. WIN will be a C
memory address for an operand of mode MODE. WIN will be a C
...
@@ -2618,7 +2625,7 @@ typedef struct mips_args {
...
@@ -2618,7 +2625,7 @@ typedef struct mips_args {
if (GET_CODE (xinsn) == CONST \
if (GET_CODE (xinsn) == CONST \
&& ((flag_pic && pic_address_needs_scratch (xinsn)) \
&& ((flag_pic && pic_address_needs_scratch (xinsn)) \
/* ??? SGI's Irix 6 assembler can't handle CONST. */
\
/* ??? SGI's Irix 6 assembler can't handle CONST. */
\
||
mips_abi != ABI_32))
\
||
(mips_abi != ABI_32 && mips_abi != ABI_EABI)))
\
{ \
{ \
rtx ptr_reg = gen_reg_rtx (Pmode); \
rtx ptr_reg = gen_reg_rtx (Pmode); \
rtx constant = XEXP (XEXP (xinsn, 0), 1); \
rtx constant = XEXP (XEXP (xinsn, 0), 1); \
...
...
gcc/ginclude/va-mips.h
View file @
293a36eb
...
@@ -13,7 +13,51 @@
...
@@ -13,7 +13,51 @@
#ifndef __GNUC_VA_LIST
#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST
#define __GNUC_VA_LIST
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
typedef
struct
{
/* Pointer to FP regs. */
char
*
__fp_regs
;
/* Number of FP regs remaining. */
int
__fp_left
;
/* Pointer to GP regs followed by stack parameters. */
char
*
__gp_regs
;
}
__gnuc_va_list
;
#ifdef __mips64
#define __va_reg_size 8
#else
#define __va_reg_size 4
#endif
enum
{
__no_type_class
=
-
1
,
__void_type_class
,
__integer_type_class
,
__char_type_class
,
__enumeral_type_class
,
__boolean_type_class
,
__pointer_type_class
,
__reference_type_class
,
__offset_type_class
,
__real_type_class
,
__complex_type_class
,
__function_type_class
,
__method_type_class
,
__record_type_class
,
__union_type_class
,
__array_type_class
,
__string_type_class
,
__set_type_class
,
__file_type_class
,
__lang_type_class
};
#else
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
typedef
char
*
__gnuc_va_list
;
typedef
char
*
__gnuc_va_list
;
#endif
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif
/* not __GNUC_VA_LIST */
#endif
/* not __GNUC_VA_LIST */
/* If this is for internal libc use, don't define anything but
/* If this is for internal libc use, don't define anything but
...
@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list;
...
@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list;
#endif
#endif
#ifdef _STDARG_H
#ifdef _STDARG_H
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#define va_start(__AP, __LASTARG) \
(__AP.__gp_regs = ((char *) __builtin_next_arg (__LASTARG) \
- (__builtin_args_info (2) < 8 \
? (8 - __builtin_args_info (2)) * __va_reg_size \
: 0)), \
__AP.__fp_left = 8 - __builtin_args_info (3), \
__AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
#else
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#define va_start(__AP, __LASTARG) \
#define va_start(__AP, __LASTARG) \
(__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG))
(__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG))
#endif
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#else
#else
/* ! _STDARG_H */
#define va_alist __builtin_va_alist
#define va_alist __builtin_va_alist
#ifdef __mips64
#ifdef __mips64
/* This assumes that `long long int' is always a 64 bit type. */
/* This assumes that `long long int' is always a 64 bit type. */
...
@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list;
...
@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list;
#else
#else
#define va_dcl int __builtin_va_alist; __va_ellipsis
#define va_dcl int __builtin_va_alist; __va_ellipsis
#endif
#endif
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#define va_start(__AP) \
(__AP.__gp_regs = ((char *) __builtin_next_arg () \
- (__builtin_args_info (2) < 8 \
? (8 - __builtin_args_info (2)) * __va_reg_size \
: 8)), \
__AP.__fp_left = 8 - __builtin_args_info (3), \
__AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
/* Need alternate code for _MIPS_SIM_ABI64. */
/* Need alternate code for _MIPS_SIM_ABI64. */
#if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
#
el
if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
#define va_start(__AP) \
#define va_start(__AP) \
(__AP = (__gnuc_va_list) __builtin_next_arg () \
(__AP = (__gnuc_va_list) __builtin_next_arg () \
+ (__builtin_args_info (2) >= 8 ? -8 : 0))
+ (__builtin_args_info (2) >= 8 ? -8 : 0))
#else
#else
#define va_start(__AP) __AP = (char *) &__builtin_va_alist
#define va_start(__AP) __AP = (char *) &__builtin_va_alist
#endif
#endif
#endif
#endif
/* ! _STDARG_H */
#ifndef va_end
#ifndef va_end
void
va_end
(
__gnuc_va_list
);
/* Defined in libgcc.a */
void
va_end
(
__gnuc_va_list
);
/* Defined in libgcc.a */
#endif
#endif
#define va_end(__AP) ((void)0)
#define va_end(__AP) ((void)0)
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#ifdef __mips64
#define __va_next_addr(__AP, __type) \
((__builtin_classify_type (*(__type *) 0) == __real_type_class \
&& __AP.__fp_left > 0) \
? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8) \
: (__AP.__gp_regs += __va_reg_size) - __va_reg_size)
#else
#define __va_next_addr(__AP, __type) \
((__builtin_classify_type (*(__type *) 0) == __real_type_class \
&& __AP.__fp_left > 0) \
? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8) \
: (((__builtin_classify_type (* (__type *) 0) < record_type_class \
&& __alignof__ (__type) > 4) \
? __AP.__gp_regs = (__AP.__gp_regs + 8 - 1) & -8), \
(__AP.__gp_regs += __va_reg_size) - __va_reg_size))
#endif
#ifdef __MIPSEB__
#define va_arg(__AP, __type) \
((__va_rounded_size (__type) <= __va_reg_size) \
? *(__type *) (void *) (__va_next_addr (__AP, __type) \
+ __va_reg_size \
- sizeof (__type)) \
: (__builtin_classify_type (*(__type *) 0) >= __record_type_class \
? **(__type **) (void *) (__va_next_addr (__AP, __type) \
+ __va_reg_size \
- sizeof (char *)) \
: *(__type *) (void *) __va_next_addr (__AP, __type)))
#else
#define va_arg(__AP, __type) \
(__builtin_classify_type (* (__type *) 0) >= __record_type_class \
? **(__type **) (void *) __va_next_addr (__AP, __type) \
: *(__type *) (void *) __va_next_addr (__AP, __type))
#endif
#else
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
/* We cast to void * and then to TYPE * because this avoids
/* We cast to void * and then to TYPE * because this avoids
a warning about increasing the alignment requirement. */
a warning about increasing the alignment requirement. */
/* The __mips64 cases are reversed from the 32 bit cases, because the standard
/* The __mips64 cases are reversed from the 32 bit cases, because the standard
...
@@ -106,5 +206,6 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */
...
@@ -106,5 +206,6 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */
+ __va_rounded_size(__type))))[-1]
+ __va_rounded_size(__type))))[-1]
#endif
#endif
#endif
#endif
#endif
/* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif
/* defined (_STDARG_H) || defined (_VARARGS_H) */
#endif
/* defined (_STDARG_H) || defined (_VARARGS_H) */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment