Merge pull request #151 from greg-king5/fastcall

Make __fastcall__ be the default calling convention.
This commit is contained in:
Oliver Schmidt
2015-05-26 22:39:33 +02:00
24 changed files with 257 additions and 147 deletions

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 2001-2012, Ullrich von Bassewitz */
/* (C) 2001-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -46,6 +46,7 @@
#include "codeseg.h"
#include "datatype.h"
#include "error.h"
#include "global.h"
#include "reginfo.h"
#include "symtab.h"
#include "codeinfo.h"
@@ -386,33 +387,35 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
** Search for it in the list of builtin functions.
*/
if (Name[0] == '_') {
/* Search in the symbol table, skip the leading underscore */
SymEntry* E = FindGlobalSym (Name+1);
/* Did we find it in the top level table? */
/* Did we find it in the top-level table? */
if (E && IsTypeFunc (E->Type)) {
FuncDesc* D = E->V.F.Func;
/* A function may use the A or A/X registers if it is a fastcall
** function. If it is not a fastcall function but a variadic one,
** it will use the Y register (the parameter size is passed here).
** In all other cases, no registers are used. However, we assume
** that any function will destroy all registers.
/* A variadic function will use the Y register (the parameter list
** size is passed there). A fastcall function will use the A or A/X
** registers. In all other cases, no registers are used. However,
** we assume that any function will destroy all registers.
*/
if (IsQualFastcall (E->Type) && D->ParamCount > 0) {
/* Will use registers depending on the last param */
unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type);
if (LastParamSize == 1) {
*Use = REG_A;
} else if (LastParamSize == 2) {
*Use = REG_AX;
} else {
*Use = REG_EAX;
}
} else if ((D->Flags & FD_VARIADIC) != 0) {
if ((D->Flags & FD_VARIADIC) != 0) {
*Use = REG_Y;
} else if (D->ParamCount > 0 &&
(AutoCDecl ?
IsQualFastcall (E->Type) :
!IsQualCDecl (E->Type))) {
/* Will use registers depending on the last param. */
switch (CheckedSizeOf (D->LastParam->Type)) {
case 1u:
*Use = REG_A;
break;
case 2u:
*Use = REG_AX;
break;
default:
*Use = REG_EAX;
}
} else {
/* Will not use any registers */
*Use = REG_NONE;

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2012, Ullrich von Bassewitz */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -293,15 +293,15 @@ void PrintType (FILE* F, const Type* T)
/* Recursive call */
PrintType (F, T + 1);
if (T->A.L == UNSPECIFIED) {
fprintf (F, "[]");
fprintf (F, " []");
} else {
fprintf (F, "[%ld]", T->A.L);
fprintf (F, " [%ld]", T->A.L);
}
return;
case T_TYPE_PTR:
/* Recursive call */
PrintType (F, T + 1);
fprintf (F, "*");
fprintf (F, " *");
return;
case T_TYPE_FUNC:
fprintf (F, "function returning ");
@@ -659,7 +659,7 @@ Type* GetBaseElementType (Type* T)
** will return. Otherwise it will return the base element type, which means
** the element type that is not an array.
*/
{
{
while (IsTypeArray (T)) {
++T;
}

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2012, Ullrich von Bassewitz */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -603,6 +603,16 @@ INLINE int IsQualCDecl (const Type* T)
# define IsQualCDecl(T) (((T)->C & T_QUAL_CDECL) != 0)
#endif
#if defined(HAVE_INLINE)
INLINE int IsQualCConv (const Type* T)
/* Return true if the given type has a calling convention qualifier */
{
return (T->C & T_QUAL_CCONV) != 0;
}
#else
# define IsQualCConv(T) (((T)->C & T_QUAL_CCONV) != 0)
#endif
int IsVariadicFunc (const Type* T) attribute ((const));
/* Return true if this is a function type or pointer to function type with
** variable parameter list

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2013, Ullrich von Bassewitz */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -85,7 +85,7 @@ struct StructInitData {
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
/* Parse a type specificier */
/* Parse a type specifier */
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
/* Parse initialization of variables. Return the number of data bytes. */
@@ -335,18 +335,30 @@ static void FixQualifiers (Type* DataType)
T = DataType;
while (T->C != T_END) {
if (IsTypePtr (T)) {
/* Calling convention qualifier on the pointer? */
if (IsQualCConv (T)) {
/* Pull the convention off of the pointer */
Q = T[0].C & T_QUAL_CCONV;
T[0].C &= ~T_QUAL_CCONV;
/* Fastcall qualifier on the pointer? */
if (IsQualFastcall (T)) {
/* Pointer to function which is not fastcall? */
if (IsTypeFunc (T+1) && !IsQualFastcall (T+1)) {
/* Move the fastcall qualifier from the pointer to
** the function.
*/
T[0].C &= ~T_QUAL_FASTCALL;
T[1].C |= T_QUAL_FASTCALL;
/* Pointer to a function which doesn't have an explicit convention? */
if (IsTypeFunc (T + 1)) {
if (IsQualCConv (T + 1)) {
if ((T[1].C & T_QUAL_CCONV) == Q) {
Warning ("Pointer duplicates function's calling convention");
} else {
Error ("Function's and pointer's calling conventions are different");
}
} else {
if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) {
Error ("Variadic-function pointers cannot be __fastcall__");
} else {
/* Move the qualifier from the pointer to the function. */
T[1].C |= Q;
}
}
} else {
Error ("Invalid `_fastcall__' qualifier for pointer");
Error ("Not pointer to a function; can't use a calling convention");
}
}
@@ -355,8 +367,8 @@ static void FixQualifiers (Type* DataType)
if (Q == T_QUAL_NONE) {
/* No address size qualifiers specified */
if (IsTypeFunc (T+1)) {
/* Pointer to function. Use the qualifier from the function
** or the default if the function don't has one.
/* Pointer to function. Use the qualifier from the function,
** or the default if the function doesn't have one.
*/
Q = (T[1].C & T_QUAL_ADDRSIZE);
if (Q == T_QUAL_NONE) {
@@ -368,7 +380,7 @@ static void FixQualifiers (Type* DataType)
T[0].C |= Q;
} else {
/* We have address size qualifiers. If followed by a function,
** apply these also to the function.
** apply them to the function also.
*/
if (IsTypeFunc (T+1)) {
TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE);
@@ -489,7 +501,7 @@ static void ParseEnumDecl (void)
static int ParseFieldWidth (Declaration* Decl)
/* Parse an optional field width. Returns -1 if no field width is speficied,
/* Parse an optional field width. Returns -1 if no field width is specified,
** otherwise the width of the field.
*/
{
@@ -862,7 +874,7 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
/* Parse a type specificier */
/* Parse a type specifier */
{
ident Ident;
SymEntry* Entry;
@@ -1376,13 +1388,13 @@ static FuncDesc* ParseFuncDecl (void)
static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Recursively process declarators. Build a type array in reverse order. */
{
/* Read optional function or pointer qualifiers. These modify the
** identifier or token to the right. For convenience, we allow the fastcall
** qualifier also for pointers here. If it is a pointer-to-function, the
** qualifier will later be transfered to the function itself. If it's a
/* Read optional function or pointer qualifiers. They modify the
** identifier or token to the right. For convenience, we allow a calling
** convention also for pointers here. If it's a pointer-to-function, the
** qualifier later will be transfered to the function itself. If it's a
** pointer to something else, it will be flagged as an error.
*/
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_FASTCALL);
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV);
/* Pointer to something */
if (CurTok.Tok == TOK_STAR) {
@@ -1390,10 +1402,10 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Skip the star */
NextToken ();
/* Allow const, restrict and volatile qualifiers */
/* Allow const, restrict, and volatile qualifiers */
Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT);
/* Parse the type, the pointer points to */
/* Parse the type that the pointer points to */
Declarator (Spec, D, Mode);
/* Add the type */
@@ -1443,7 +1455,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* We cannot specify fastcall for variadic functions */
if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) {
Error ("Variadic functions cannot be `__fastcall__'");
Error ("Variadic functions cannot be __fastcall__");
Qualifiers &= ~T_QUAL_FASTCALL;
}

View File

@@ -1,6 +1,7 @@
/* expr.c
**
** Ullrich von Bassewitz, 21.06.1998
** 1998-06-21, Ullrich von Bassewitz
** 2015-04-19, Greg King
*/
@@ -470,9 +471,11 @@ static void FunctionCall (ExprDesc* Expr)
/* Handle function pointers transparently */
IsFuncPtr = IsTypeFuncPtr (Expr->Type);
if (IsFuncPtr) {
/* Check wether it's a fastcall function that has parameters */
IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0);
/* Check whether it's a fastcall function that has parameters */
IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && Func->ParamCount > 0 &&
(AutoCDecl ?
IsQualFastcall (Expr->Type + 1) :
!IsQualCDecl (Expr->Type + 1));
/* Things may be difficult, depending on where the function pointer
** resides. If the function pointer is an expression of some sort
@@ -517,7 +520,10 @@ static void FunctionCall (ExprDesc* Expr)
}
/* If we didn't inline the function, get fastcall info */
IsFastcall = IsQualFastcall (Expr->Type);
IsFastcall = (Func->Flags & FD_VARIADIC) == 0 &&
(AutoCDecl ?
IsQualFastcall (Expr->Type) :
!IsQualCDecl (Expr->Type));
}
/* Parse the parameter list */

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 2000-2012, Ullrich von Bassewitz */
/* (C) 2000-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -460,6 +460,9 @@ void NewFunc (SymEntry* Func)
*/
if (D->ParamCount > 0 || (D->Flags & FD_VARIADIC) != 0) {
g_importmainargs ();
/* The start-up code doesn't fast-call main(). */
Func->Type->C |= T_QUAL_CDECL;
}
/* Determine if this is a main function in a C99 environment that
@@ -478,13 +481,12 @@ void NewFunc (SymEntry* Func)
PushLiteralPool (Func);
/* If this is a fastcall function, push the last parameter onto the stack */
if (IsQualFastcall (Func->Type) && D->ParamCount > 0) {
if ((D->Flags & FD_VARIADIC) == 0 && D->ParamCount > 0 &&
(AutoCDecl ?
IsQualFastcall (Func->Type) :
!IsQualCDecl (Func->Type))) {
unsigned Flags;
/* Fastcall functions may never have an ellipsis or the compiler is buggy */
CHECK ((D->Flags & FD_VARIADIC) == 0);
/* Generate the push */
if (IsTypeFunc (D->LastParam->Type)) {
/* Pointer to function */

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2012, Ullrich von Bassewitz */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -44,6 +44,7 @@
unsigned char AddSource = 0; /* Add source lines as comments */
unsigned char AutoCDecl = 0; /* Make functions default to __cdecl__ */
unsigned char DebugInfo = 0; /* Add debug info to the obj */
unsigned char PreprocessOnly = 0; /* Just preprocess the input */
unsigned char DebugOptOutput = 0; /* Output debug stuff */

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2012, Ullrich von Bassewitz */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -52,6 +52,7 @@
/* Options */
extern unsigned char AddSource; /* Add source lines as comments */
extern unsigned char AutoCDecl; /* Make functions default to __cdecl__ */
extern unsigned char DebugInfo; /* Add debug info to the obj */
extern unsigned char PreprocessOnly; /* Just preprocess the input */
extern unsigned char DebugOptOutput; /* Output debug stuff */

View File

@@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 2000-2013, Ullrich von Bassewitz */
/* (C) 2000-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@@ -104,6 +104,7 @@ static void Usage (void)
"\n"
"Long options:\n"
" --add-source\t\t\tInclude source as comment\n"
" --all-cdecl\t\t\tMake functions default to __cdecl__\n"
" --bss-name seg\t\tSet the name of the BSS segment\n"
" --check-stack\t\t\tGenerate stack overflow checks\n"
" --code-name seg\t\tSet the name of the CODE segment\n"
@@ -350,6 +351,15 @@ static void OptAddSource (const char* Opt attribute ((unused)),
static void OptAllCDecl (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Make functions default to cdecl instead of fastcall. */
{
AutoCDecl = 1;
}
static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --bss-name option */
{
@@ -790,6 +800,7 @@ int main (int argc, char* argv[])
/* Program long options */
static const LongOpt OptTab[] = {
{ "--add-source", 0, OptAddSource },
{ "--all-cdecl", 0, OptAllCDecl },
{ "--bss-name", 1, OptBssName },
{ "--check-stack", 0, OptCheckStack },
{ "--code-name", 1, OptCodeName },

View File

@@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (C) 1998-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -37,6 +37,7 @@
/* cc65 */
#include "funcdesc.h"
#include "global.h"
#include "symtab.h"
#include "typecmp.h"
@@ -245,23 +246,36 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
return;
}
}
if (LeftType == T_TYPE_FUNC) {
/* If a calling convention wasn't set explicitly,
** then assume the default one.
*/
if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
LeftQual |= (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
if ((RightQual & T_QUAL_CCONV) == T_QUAL_NONE) {
RightQual |= (AutoCDecl || IsVariadicFunc (rhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
}
}
if (LeftQual != RightQual) {
/* On the first indirection level, different qualifiers mean
** that the types are still compatible. On the second level,
** this is a (maybe minor) error, so we create a special
** return code, since a qualifier is dropped from a pointer.
** Starting from the next level, the types are incompatible
** if the qualifiers differ.
** that the types still are compatible. On the second level,
** that is a (maybe minor) error. We create a special return-code
** if a qualifier is dropped from a pointer. But, different calling
** conventions are incompatible. Starting from the next level,
** the types are incompatible if the qualifiers differ.
*/
/* (Debugging statement) */
/* printf ("Ind = %d %06X != %06X\n", Indirections, LeftQual, RightQual); */
switch (Indirections) {
case 0:
SetResult (Result, TC_STRICT_COMPATIBLE);
break;
case 1:
/* A non const value on the right is compatible to a
/* A non-const value on the right is compatible to a
** const one to the left, same for volatile.
*/
if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
@@ -270,7 +284,11 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
} else {
SetResult (Result, TC_STRICT_COMPATIBLE);
}
break;
if (LeftType != T_TYPE_FUNC || (LeftQual & T_QUAL_CCONV) == (RightQual & T_QUAL_CCONV)) {
break;
}
/* else fall through */
default:
SetResult (Result, TC_INCOMPATIBLE);
@@ -280,7 +298,6 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
/* Check for special type elements */
switch (LeftType) {
case T_TYPE_PTR:
++Indirections;
break;