Squashed 'dmd2/' content from commit 10017d5

git-subtree-dir: dmd2
git-subtree-split: 10017d50eaaff4ecdc37a0153b6c37ea0b004c81
This commit is contained in:
Alexey Prokhin
2012-04-05 11:10:48 +04:00
commit caad8cde58
241 changed files with 233638 additions and 0 deletions

412
access.c Normal file
View File

@@ -0,0 +1,412 @@
// Copyright (c) 1999-2012 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "root.h"
#include "rmem.h"
#include "enum.h"
#include "aggregate.h"
#include "init.h"
#include "attrib.h"
#include "scope.h"
#include "id.h"
#include "mtype.h"
#include "declaration.h"
#include "aggregate.h"
#include "expression.h"
#include "module.h"
#define LOG 0
/* Code to do access checks
*/
int hasPackageAccess(Scope *sc, Dsymbol *s);
/****************************************
* Return PROT access for Dsymbol smember in this declaration.
*/
enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
{
return PROTpublic;
}
enum PROT StructDeclaration::getAccess(Dsymbol *smember)
{
enum PROT access_ret = PROTnone;
#if LOG
printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
toChars(), smember->toChars());
#endif
if (smember->toParent() == this)
{
access_ret = smember->prot();
}
else if (smember->isDeclaration()->isStatic())
{
access_ret = smember->prot();
}
return access_ret;
}
enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
{
enum PROT access_ret = PROTnone;
#if LOG
printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
toChars(), smember->toChars());
#endif
if (smember->toParent() == this)
{
access_ret = smember->prot();
}
else
{
if (smember->isDeclaration()->isStatic())
{
access_ret = smember->prot();
}
for (size_t i = 0; i < baseclasses->dim; i++)
{ BaseClass *b = (*baseclasses)[i];
enum PROT access = b->base->getAccess(smember);
switch (access)
{
case PROTnone:
break;
case PROTprivate:
access_ret = PROTnone; // private members of base class not accessible
break;
case PROTpackage:
case PROTprotected:
case PROTpublic:
case PROTexport:
// If access is to be tightened
if (b->protection < access)
access = b->protection;
// Pick path with loosest access
if (access > access_ret)
access_ret = access;
break;
default:
assert(0);
}
}
}
#if LOG
printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
toChars(), smember->toChars(), access_ret);
#endif
return access_ret;
}
/********************************************************
* Helper function for ClassDeclaration::accessCheck()
* Returns:
* 0 no access
* 1 access
*/
static int accessCheckX(
Dsymbol *smember,
Dsymbol *sfunc,
AggregateDeclaration *dthis,
AggregateDeclaration *cdscope)
{
assert(dthis);
#if 0
printf("accessCheckX for %s.%s in function %s() in scope %s\n",
dthis->toChars(), smember->toChars(),
sfunc ? sfunc->toChars() : "NULL",
cdscope ? cdscope->toChars() : "NULL");
#endif
if (dthis->hasPrivateAccess(sfunc) ||
dthis->isFriendOf(cdscope))
{
if (smember->toParent() == dthis)
return 1;
else
{
ClassDeclaration *cdthis = dthis->isClassDeclaration();
if (cdthis)
{
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
{ BaseClass *b = (*cdthis->baseclasses)[i];
enum PROT access = b->base->getAccess(smember);
if (access >= PROTprotected ||
accessCheckX(smember, sfunc, b->base, cdscope)
)
return 1;
}
}
}
}
else
{
if (smember->toParent() != dthis)
{
ClassDeclaration *cdthis = dthis->isClassDeclaration();
if (cdthis)
{
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
{ BaseClass *b = (*cdthis->baseclasses)[i];
if (accessCheckX(smember, sfunc, b->base, cdscope))
return 1;
}
}
}
}
return 0;
}
/*******************************
* Do access check for member of this class, this class being the
* type of the 'this' pointer used to access smember.
*/
void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
{
int result;
FuncDeclaration *f = sc->func;
AggregateDeclaration *cdscope = sc->getStructClassScope();
enum PROT access;
#if LOG
printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
toChars(), smember->toChars(),
f ? f->toChars() : NULL,
cdscope ? cdscope->toChars() : NULL);
#endif
Dsymbol *smemberparent = smember->toParent();
if (!smemberparent || !smemberparent->isAggregateDeclaration())
{
#if LOG
printf("not an aggregate member\n");
#endif
return; // then it is accessible
}
// BUG: should enable this check
//assert(smember->parent->isBaseOf(this, NULL));
if (smemberparent == this)
{ enum PROT access2 = smember->prot();
result = access2 >= PROTpublic ||
hasPrivateAccess(f) ||
isFriendOf(cdscope) ||
(access2 == PROTpackage && hasPackageAccess(sc, this));
#if LOG
printf("result1 = %d\n", result);
#endif
}
else if ((access = this->getAccess(smember)) >= PROTpublic)
{
result = 1;
#if LOG
printf("result2 = %d\n", result);
#endif
}
else if (access == PROTpackage && hasPackageAccess(sc, this))
{
result = 1;
#if LOG
printf("result3 = %d\n", result);
#endif
}
else
{
result = accessCheckX(smember, f, this, cdscope);
#if LOG
printf("result4 = %d\n", result);
#endif
}
if (!result)
{
error(loc, "member %s is not accessible", smember->toChars());
}
}
/****************************************
* Determine if this is the same or friend of cd.
*/
int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
{
#if LOG
printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
#endif
if (this == cd)
return 1;
// Friends if both are in the same module
//if (toParent() == cd->toParent())
if (cd && getAccessModule() == cd->getAccessModule())
{
#if LOG
printf("\tin same module\n");
#endif
return 1;
}
#if LOG
printf("\tnot friend\n");
#endif
return 0;
}
/****************************************
* Determine if scope sc has package level access to s.
*/
int hasPackageAccess(Scope *sc, Dsymbol *s)
{
#if LOG
printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
#endif
for (; s; s = s->parent)
{
if (s->isPackage() && !s->isModule())
break;
}
#if LOG
if (s)
printf("\tthis is in package '%s'\n", s->toChars());
#endif
if (s && s == sc->module->parent)
{
#if LOG
printf("\ts is in same package as sc\n");
#endif
return 1;
}
#if LOG
printf("\tno package access\n");
#endif
return 0;
}
/**********************************
* Determine if smember has access to private members of this declaration.
*/
int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
{
if (smember)
{ AggregateDeclaration *cd = NULL;
Dsymbol *smemberparent = smember->toParent();
if (smemberparent)
cd = smemberparent->isAggregateDeclaration();
#if LOG
printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
toChars(), smember->toChars());
#endif
if (this == cd) // smember is a member of this class
{
#if LOG
printf("\tyes 1\n");
#endif
return 1; // so we get private access
}
// If both are members of the same module, grant access
while (1)
{ Dsymbol *sp = smember->toParent();
if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
smember = sp;
else
break;
}
if (!cd && toParent() == smember->toParent())
{
#if LOG
printf("\tyes 2\n");
#endif
return 1;
}
if (!cd && getAccessModule() == smember->getAccessModule())
{
#if LOG
printf("\tyes 3\n");
#endif
return 1;
}
}
#if LOG
printf("\tno\n");
#endif
return 0;
}
/****************************************
* Check access to d for expression e.d
*/
void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
{
#if LOG
if (e)
{ printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
printf("\te->type = %s\n", e->type->toChars());
}
else
{
printf("accessCheck(%s)\n", d->toPrettyChars());
}
#endif
if (!e)
{
if (d->prot() == PROTprivate && d->getAccessModule() != sc->module ||
d->prot() == PROTpackage && !hasPackageAccess(sc, d))
{
error(loc, "%s %s is not accessible from module %s",
d->kind(), d->toPrettyChars(), sc->module->toChars());
}
}
else if (e->type->ty == Tclass)
{ // Do access check
ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
if (e->op == TOKsuper)
{
ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
if (cd2)
cd = cd2;
}
cd->accessCheck(loc, sc, d);
}
else if (e->type->ty == Tstruct)
{ // Do access check
StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
cd->accessCheck(loc, sc, d);
}
}

320
aggregate.h Normal file
View File

@@ -0,0 +1,320 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#ifndef DMD_AGGREGATE_H
#define DMD_AGGREGATE_H
#ifdef __DMC__
#pragma once
#endif /* __DMC__ */
#include "root.h"
#include "dsymbol.h"
struct Identifier;
struct Type;
struct TypeFunction;
struct Expression;
struct FuncDeclaration;
struct CtorDeclaration;
struct DtorDeclaration;
struct InvariantDeclaration;
struct NewDeclaration;
struct DeleteDeclaration;
struct InterfaceDeclaration;
struct TypeInfoClassDeclaration;
struct VarDeclaration;
struct dt_t;
struct AggregateDeclaration : ScopeDsymbol
{
Type *type;
StorageClass storage_class;
enum PROT protection;
Type *handle; // 'this' type
unsigned structsize; // size of struct
unsigned alignsize; // size of struct for alignment purposes
unsigned structalign; // struct member alignment in effect
int hasUnions; // set if aggregate has overlapping fields
VarDeclarations fields; // VarDeclaration fields
unsigned sizeok; // set when structsize contains valid data
// 0: no size
// 1: size is correct
// 2: cannot determine size; fwd referenced
Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
bool isdeprecated; // !=0 if deprecated
#if DMDV2
int isnested; // !=0 if is nested
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
#endif
// Special member functions
InvariantDeclaration *inv; // invariant
NewDeclaration *aggNew; // allocator
DeleteDeclaration *aggDelete; // deallocator
#if DMDV2
//CtorDeclaration *ctor;
Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
CtorDeclaration *defaultCtor; // default constructor
Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
bool noDefaultCtor; // no default construction
#endif
FuncDeclarations dtors; // Array of destructors
FuncDeclaration *dtor; // aggregate destructor
#ifdef IN_GCC
Array methods; // flat list of all methods for debug information
#endif
AggregateDeclaration(Loc loc, Identifier *id);
void semantic2(Scope *sc);
void semantic3(Scope *sc);
void inlineScan();
unsigned size(Loc loc);
static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
Type *getType();
void addField(Scope *sc, VarDeclaration *v);
int firstFieldInUnion(int indx); // first field in union that includes indx
int numFieldsInUnion(int firstIndex); // #fields in union starting at index
int isDeprecated(); // is aggregate deprecated?
FuncDeclaration *buildDtor(Scope *sc);
int isNested();
int isExport();
void emitComment(Scope *sc);
void toJsonBuffer(OutBuffer *buf);
void toDocBuffer(OutBuffer *buf);
// For access checking
virtual PROT getAccess(Dsymbol *smember); // determine access to smember
int isFriendOf(AggregateDeclaration *cd);
int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class?
void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
enum PROT prot();
// Back end
Symbol *stag; // tag symbol for debug data
Symbol *sinit;
Symbol *toInitializer();
AggregateDeclaration *isAggregateDeclaration() { return this; }
};
struct AnonymousAggregateDeclaration : AggregateDeclaration
{
AnonymousAggregateDeclaration()
: AggregateDeclaration(0, NULL)
{
}
AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
};
struct StructDeclaration : AggregateDeclaration
{
int zeroInit; // !=0 if initialize with 0 fill
#if DMDV2
int hasIdentityAssign; // !=0 if has identity opAssign
int hasIdentityEquals; // !=0 if has identity opEquals
FuncDeclaration *cpctor; // generated copy-constructor, if any
FuncDeclarations postblits; // Array of postblit functions
FuncDeclaration *postblit; // aggregate postblit
FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
static FuncDeclaration *xerreq; // object.xopEquals
#endif
StructDeclaration(Loc loc, Identifier *id);
Dsymbol *syntaxCopy(Dsymbol *s);
void semantic(Scope *sc);
Dsymbol *search(Loc, Identifier *ident, int flags);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
char *mangle();
const char *kind();
void finalizeSize();
#if DMDV1
Expression *cloneMembers();
#endif
#if DMDV2
int needOpAssign();
int needOpEquals();
FuncDeclaration *buildOpAssign(Scope *sc);
FuncDeclaration *buildOpEquals(Scope *sc);
FuncDeclaration *buildPostBlit(Scope *sc);
FuncDeclaration *buildCpCtor(Scope *sc);
FuncDeclaration *buildXopEquals(Scope *sc);
#endif
void toDocBuffer(OutBuffer *buf);
PROT getAccess(Dsymbol *smember); // determine access to smember
void toObjFile(int multiobj); // compile to .obj file
void toDt(dt_t **pdt);
void toDebug(); // to symbolic debug info
StructDeclaration *isStructDeclaration() { return this; }
};
struct UnionDeclaration : StructDeclaration
{
UnionDeclaration(Loc loc, Identifier *id);
Dsymbol *syntaxCopy(Dsymbol *s);
const char *kind();
UnionDeclaration *isUnionDeclaration() { return this; }
};
struct BaseClass
{
Type *type; // (before semantic processing)
enum PROT protection; // protection for the base interface
ClassDeclaration *base;
int offset; // 'this' pointer offset
FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's
// making up the vtbl[]
size_t baseInterfaces_dim;
BaseClass *baseInterfaces; // if BaseClass is an interface, these
// are a copy of the InterfaceDeclaration::interfaces
BaseClass();
BaseClass(Type *type, enum PROT protection);
int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
void copyBaseInterfaces(BaseClasses *);
};
#if DMDV2
#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
#else
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
#endif
struct ClassDeclaration : AggregateDeclaration
{
static ClassDeclaration *object;
static ClassDeclaration *classinfo;
static ClassDeclaration *throwable;
static ClassDeclaration *exception;
static ClassDeclaration *errorException;
ClassDeclaration *baseClass; // NULL only if this is Object
#if DMDV1
CtorDeclaration *ctor;
CtorDeclaration *defaultCtor; // default constructor
#endif
FuncDeclaration *staticCtor;
FuncDeclaration *staticDtor;
Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
BaseClasses *baseclasses; // Array of BaseClass's; first is super,
// rest are Interface's
size_t interfaces_dim;
BaseClass **interfaces; // interfaces[interfaces_dim] for this class
// (does not include baseClass)
BaseClasses *vtblInterfaces; // array of base interfaces that have
// their own vtbl[]
TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
int com; // !=0 if this is a COM class (meaning
// it derives from IUnknown)
int isscope; // !=0 if this is an auto class
int isabstract; // !=0 if abstract class
#if DMDV1
int isnested; // !=0 if is nested
VarDeclaration *vthis; // 'this' parameter if this class is nested
#endif
int inuse; // to prevent recursive attempts
ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
Dsymbol *syntaxCopy(Dsymbol *s);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
int isBaseOf2(ClassDeclaration *cd);
#define OFFSET_RUNTIME 0x76543210
virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
virtual int isBaseInfoComplete();
Dsymbol *search(Loc, Identifier *ident, int flags);
Dsymbol *searchBase(Loc, Identifier *ident);
#if DMDV2
int isFuncHidden(FuncDeclaration *fd);
#endif
FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
void interfaceSemantic(Scope *sc);
#if DMDV1
int isNested();
#endif
int isCOMclass();
virtual int isCOMinterface();
#if DMDV2
virtual int isCPPinterface();
#endif
int isAbstract();
virtual int vtblOffset();
const char *kind();
char *mangle();
void toDocBuffer(OutBuffer *buf);
PROT getAccess(Dsymbol *smember); // determine access to smember
void addLocalClass(ClassDeclarations *);
// Back end
void toObjFile(int multiobj); // compile to .obj file
void toDebug();
unsigned baseVtblOffset(BaseClass *bc);
Symbol *toSymbol();
Symbol *toVtblSymbol();
void toDt(dt_t **pdt);
void toDt2(dt_t **pdt, ClassDeclaration *cd);
Symbol *vtblsym;
ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
};
struct InterfaceDeclaration : ClassDeclaration
{
#if DMDV2
int cpp; // !=0 if this is a C++ interface
#endif
InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
Dsymbol *syntaxCopy(Dsymbol *s);
void semantic(Scope *sc);
int isBaseOf(ClassDeclaration *cd, int *poffset);
int isBaseOf(BaseClass *bc, int *poffset);
const char *kind();
int isBaseInfoComplete();
int vtblOffset();
#if DMDV2
int isCPPinterface();
#endif
virtual int isCOMinterface();
void toObjFile(int multiobj); // compile to .obj file
Symbol *toSymbol();
InterfaceDeclaration *isInterfaceDeclaration() { return this; }
};
#endif /* DMD_AGGREGATE_H */

79
aliasthis.c Normal file
View File

@@ -0,0 +1,79 @@
// Compiler implementation of the D programming language
// Copyright (c) 2009-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "mars.h"
#include "identifier.h"
#include "aliasthis.h"
#include "scope.h"
#include "aggregate.h"
#include "dsymbol.h"
#if DMDV2
AliasThis::AliasThis(Loc loc, Identifier *ident)
: Dsymbol(NULL) // it's anonymous (no identifier)
{
this->loc = loc;
this->ident = ident;
}
Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
{
assert(!s);
/* Since there is no semantic information stored here,
* we don't need to copy it.
*/
return this;
}
void AliasThis::semantic(Scope *sc)
{
Dsymbol *parent = sc->parent;
if (parent)
parent = parent->pastMixin();
AggregateDeclaration *ad = NULL;
if (parent)
ad = parent->isAggregateDeclaration();
if (ad)
{
assert(ad->members);
Dsymbol *s = ad->search(loc, ident, 0);
if (!s)
{ s = sc->search(loc, ident, 0);
if (s)
::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
else
::error(loc, "undefined identifier %s", ident->toChars());
}
else if (ad->aliasthis && s != ad->aliasthis)
error("there can be only one alias this");
ad->aliasthis = s;
}
else
error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere");
}
const char *AliasThis::kind()
{
return "alias this";
}
void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("alias ");
buf->writestring(ident->toChars());
buf->writestring(" this;\n");
}
#endif

41
aliasthis.h Normal file
View File

@@ -0,0 +1,41 @@
// Compiler implementation of the D programming language
// Copyright (c) 2009-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#ifndef DMD_ALIASTHIS_H
#define DMD_ALIASTHIS_H
#ifdef __DMC__
#pragma once
#endif /* __DMC__ */
#include "mars.h"
#include "dsymbol.h"
/**************************************************************/
#if DMDV2
struct AliasThis : Dsymbol
{
// alias Identifier this;
Identifier *ident;
AliasThis(Loc loc, Identifier *ident);
Dsymbol *syntaxCopy(Dsymbol *);
void semantic(Scope *sc);
const char *kind();
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
AliasThis *isAliasThis() { return this; }
};
#endif
#endif

165
apply.c Normal file
View File

@@ -0,0 +1,165 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "mars.h"
#include "expression.h"
/**************************************
* An Expression tree walker that will visit each Expression e in the tree,
* in depth-first evaluation order, and call fp(e,param) on it.
* fp() signals whether the walking continues with its return value:
* Returns:
* 0 continue
* 1 done
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
* Creating an iterator for this would be much more complex.
*/
typedef int (*fp_t)(Expression *, void *);
int Expression::apply(fp_t fp, void *param)
{
return (*fp)(this, param);
}
/******************************
* Perform apply() on an array of Expressions.
*/
int arrayExpressionApply(Expressions *a, fp_t fp, void *param)
{
//printf("arrayExpressionApply(%p)\n", a);
if (a)
{
for (size_t i = 0; i < a->dim; i++)
{ Expression *e = (*a)[i];
if (e)
{
if (e->apply(fp, param))
return 1;
}
}
}
return 0;
}
int NewExp::apply(int (*fp)(Expression *, void *), void *param)
{
//printf("NewExp::apply(): %s\n", toChars());
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
arrayExpressionApply(newargs, fp, param) ||
arrayExpressionApply(arguments, fp, param) ||
(*fp)(this, param));
}
int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param)
{
//printf("NewAnonClassExp::apply(): %s\n", toChars());
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
arrayExpressionApply(newargs, fp, param) ||
arrayExpressionApply(arguments, fp, param) ||
(*fp)(this, param));
}
int UnaExp::apply(fp_t fp, void *param)
{
return e1->apply(fp, param) ||
(*fp)(this, param);
}
int BinExp::apply(fp_t fp, void *param)
{
return e1->apply(fp, param) ||
e2->apply(fp, param) ||
(*fp)(this, param);
}
int AssertExp::apply(fp_t fp, void *param)
{
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
return e1->apply(fp, param) ||
(msg ? msg->apply(fp, param) : 0) ||
(*fp)(this, param);
}
int CallExp::apply(fp_t fp, void *param)
{
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
return e1->apply(fp, param) ||
arrayExpressionApply(arguments, fp, param) ||
(*fp)(this, param);
}
int ArrayExp::apply(fp_t fp, void *param)
{
//printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars());
return e1->apply(fp, param) ||
arrayExpressionApply(arguments, fp, param) ||
(*fp)(this, param);
}
int SliceExp::apply(fp_t fp, void *param)
{
return e1->apply(fp, param) ||
(lwr ? lwr->apply(fp, param) : 0) ||
(upr ? upr->apply(fp, param) : 0) ||
(*fp)(this, param);
}
int ArrayLiteralExp::apply(fp_t fp, void *param)
{
return arrayExpressionApply(elements, fp, param) ||
(*fp)(this, param);
}
int AssocArrayLiteralExp::apply(fp_t fp, void *param)
{
return arrayExpressionApply(keys, fp, param) ||
arrayExpressionApply(values, fp, param) ||
(*fp)(this, param);
}
int StructLiteralExp::apply(fp_t fp, void *param)
{
return arrayExpressionApply(elements, fp, param) ||
(*fp)(this, param);
}
int TupleExp::apply(fp_t fp, void *param)
{
return arrayExpressionApply(exps, fp, param) ||
(*fp)(this, param);
}
int CondExp::apply(fp_t fp, void *param)
{
return econd->apply(fp, param) ||
e1->apply(fp, param) ||
e2->apply(fp, param) ||
(*fp)(this, param);
}

193
argtypes.c Normal file
View File

@@ -0,0 +1,193 @@
// Compiler implementation of the D programming language
// Copyright (c) 2010-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.c
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "mars.h"
#include "dsymbol.h"
#include "mtype.h"
#include "scope.h"
#include "init.h"
#include "expression.h"
#include "attrib.h"
#include "declaration.h"
#include "template.h"
#include "id.h"
#include "enum.h"
#include "import.h"
#include "aggregate.h"
#include "hdrgen.h"
/****************************************************
* This breaks a type down into 'simpler' types that can be passed to a function
* in registers, and returned in registers.
* It's highly platform dependent.
* Returning a tuple of zero length means the type cannot be passed/returned in registers.
*/
TypeTuple *Type::toArgTypes()
{
return NULL; // not valid for a parameter
}
TypeTuple *TypeBasic::toArgTypes()
{ Type *t1 = NULL;
Type *t2 = NULL;
switch (ty)
{
case Tvoid:
return NULL;
case Tbool:
case Tint8:
case Tuns8:
case Tint16:
case Tuns16:
case Tint32:
case Tuns32:
case Tfloat32:
case Tint64:
case Tuns64:
case Tfloat64:
case Tfloat80:
t1 = this;
break;
case Timaginary32:
t1 = Type::tfloat32;
break;
case Timaginary64:
t1 = Type::tfloat64;
break;
case Timaginary80:
t1 = Type::tfloat80;
break;
case Tcomplex32:
if (global.params.is64bit)
t1 = Type::tfloat64; // weird, eh?
else
{
t1 = Type::tfloat64;
t2 = Type::tfloat64;
}
break;
case Tcomplex64:
t1 = Type::tfloat64;
t2 = Type::tfloat64;
break;
case Tcomplex80:
t1 = Type::tfloat80;
t2 = Type::tfloat80;
break;
case Tascii:
t1 = Type::tuns8;
break;
case Twchar:
t1 = Type::tuns16;
break;
case Tdchar:
t1 = Type::tuns32;
break;
default: assert(0);
}
TypeTuple *t;
if (t1)
{
if (t2)
t = new TypeTuple(t1, t2);
else
t = new TypeTuple(t1);
}
else
t = new TypeTuple();
return t;
}
TypeTuple *TypeVector::toArgTypes()
{
return new TypeTuple(Type::tfloat64);
}
TypeTuple *TypeSArray::toArgTypes()
{
#if DMDV2
return new TypeTuple(); // pass on the stack for efficiency
#else
return new TypeTuple(Type::tvoidptr);
#endif
}
TypeTuple *TypeDArray::toArgTypes()
{
return new TypeTuple(); // pass on the stack for efficiency
}
TypeTuple *TypeAArray::toArgTypes()
{
return new TypeTuple(Type::tvoidptr);
}
TypeTuple *TypePointer::toArgTypes()
{
return new TypeTuple(this);
}
TypeTuple *TypeDelegate::toArgTypes()
{
return new TypeTuple(); // pass on the stack for efficiency
}
TypeTuple *TypeStruct::toArgTypes()
{
d_uns64 sz = size(0);
assert(sz < 0xFFFFFFFF);
switch ((unsigned)sz)
{
case 1:
return new TypeTuple(Type::tint8);
case 2:
return new TypeTuple(Type::tint16);
case 4:
return new TypeTuple(Type::tint32);
case 8:
return new TypeTuple(Type::tint64);
}
return new TypeTuple(); // pass on the stack
}
TypeTuple *TypeEnum::toArgTypes()
{
return toBasetype()->toArgTypes();
}
TypeTuple *TypeTypedef::toArgTypes()
{
return sym->basetype->toArgTypes();
}
TypeTuple *TypeClass::toArgTypes()
{
return new TypeTuple(Type::tvoidptr);
}

648
arrayop.c Normal file
View File

@@ -0,0 +1,648 @@
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "rmem.h"
#include "aav.h"
#include "expression.h"
#include "statement.h"
#include "mtype.h"
#include "declaration.h"
#include "scope.h"
#include "id.h"
#include "module.h"
#include "init.h"
extern int binary(const char *p , const char **tab, int high);
/**************************************
* Hash table of array op functions already generated or known about.
*/
AA *arrayfuncs;
/**********************************************
* Check that there are no uses of arrays without [].
*/
bool isArrayOpValid(Expression *e)
{
if (e->op == TOKslice)
return true;
Type *tb = e->type->toBasetype();
if ( (tb->ty == Tarray) || (tb->ty == Tsarray) )
{
switch (e->op)
{
case TOKadd:
case TOKmin:
case TOKmul:
case TOKdiv:
case TOKmod:
case TOKxor:
case TOKand:
case TOKor:
case TOKassign:
case TOKaddass:
case TOKminass:
case TOKmulass:
case TOKdivass:
case TOKmodass:
case TOKxorass:
case TOKandass:
case TOKorass:
#if DMDV2
case TOKpow:
case TOKpowass:
#endif
return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2);
case TOKcall:
return false; // TODO: Decide if [] is required after arrayop calls.
case TOKneg:
case TOKtilde:
return isArrayOpValid(((UnaExp *)e)->e1);
default:
return false;
}
}
return true;
}
/***********************************
* Construct the array operation expression.
*/
Expression *BinExp::arrayOp(Scope *sc)
{
//printf("BinExp::arrayOp() %s\n", toChars());
Type *tb = type->toBasetype();
assert(tb->ty == Tarray || tb->ty == Tsarray);
if (tb->nextOf()->toBasetype()->ty == Tvoid)
{
error("Cannot perform array operations on void[] arrays");
return new ErrorExp();
}
if (!isArrayOpValid(e2))
{
e2->error("invalid array operation %s (did you forget a [] ?)", toChars());
return new ErrorExp();
}
Expressions *arguments = new Expressions();
/* The expression to generate an array operation for is mangled
* into a name to use as the array operation function name.
* Mangle in the operands and operators in RPN order, and type.
*/
OutBuffer buf;
buf.writestring("_array");
buildArrayIdent(&buf, arguments);
buf.writeByte('_');
/* Append deco of array element type
*/
#if DMDV2
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
#else
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
#endif
size_t namelen = buf.offset;
buf.writeByte(0);
char *name = buf.toChars();
Identifier *ident = Lexer::idPool(name);
/* Look up name in hash table
*/
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident);
FuncDeclaration *fd = (FuncDeclaration *)*pfd;
if (!fd)
{
/* Some of the array op functions are written as library functions,
* presumably to optimize them with special CPU vector instructions.
* List those library functions here, in alpha order.
*/
static const char *libArrayopFuncs[] =
{
"_arrayExpSliceAddass_a",
"_arrayExpSliceAddass_d", // T[]+=T
"_arrayExpSliceAddass_f", // T[]+=T
"_arrayExpSliceAddass_g",
"_arrayExpSliceAddass_h",
"_arrayExpSliceAddass_i",
"_arrayExpSliceAddass_k",
"_arrayExpSliceAddass_s",
"_arrayExpSliceAddass_t",
"_arrayExpSliceAddass_u",
"_arrayExpSliceAddass_w",
"_arrayExpSliceDivass_d", // T[]/=T
"_arrayExpSliceDivass_f", // T[]/=T
"_arrayExpSliceMinSliceAssign_a",
"_arrayExpSliceMinSliceAssign_d", // T[]=T-T[]
"_arrayExpSliceMinSliceAssign_f", // T[]=T-T[]
"_arrayExpSliceMinSliceAssign_g",
"_arrayExpSliceMinSliceAssign_h",
"_arrayExpSliceMinSliceAssign_i",
"_arrayExpSliceMinSliceAssign_k",
"_arrayExpSliceMinSliceAssign_s",
"_arrayExpSliceMinSliceAssign_t",
"_arrayExpSliceMinSliceAssign_u",
"_arrayExpSliceMinSliceAssign_w",
"_arrayExpSliceMinass_a",
"_arrayExpSliceMinass_d", // T[]-=T
"_arrayExpSliceMinass_f", // T[]-=T
"_arrayExpSliceMinass_g",
"_arrayExpSliceMinass_h",
"_arrayExpSliceMinass_i",
"_arrayExpSliceMinass_k",
"_arrayExpSliceMinass_s",
"_arrayExpSliceMinass_t",
"_arrayExpSliceMinass_u",
"_arrayExpSliceMinass_w",
"_arrayExpSliceMulass_d", // T[]*=T
"_arrayExpSliceMulass_f", // T[]*=T
"_arrayExpSliceMulass_i",
"_arrayExpSliceMulass_k",
"_arrayExpSliceMulass_s",
"_arrayExpSliceMulass_t",
"_arrayExpSliceMulass_u",
"_arrayExpSliceMulass_w",
"_arraySliceExpAddSliceAssign_a",
"_arraySliceExpAddSliceAssign_d", // T[]=T[]+T
"_arraySliceExpAddSliceAssign_f", // T[]=T[]+T
"_arraySliceExpAddSliceAssign_g",
"_arraySliceExpAddSliceAssign_h",
"_arraySliceExpAddSliceAssign_i",
"_arraySliceExpAddSliceAssign_k",
"_arraySliceExpAddSliceAssign_s",
"_arraySliceExpAddSliceAssign_t",
"_arraySliceExpAddSliceAssign_u",
"_arraySliceExpAddSliceAssign_w",
"_arraySliceExpDivSliceAssign_d", // T[]=T[]/T
"_arraySliceExpDivSliceAssign_f", // T[]=T[]/T
"_arraySliceExpMinSliceAssign_a",
"_arraySliceExpMinSliceAssign_d", // T[]=T[]-T
"_arraySliceExpMinSliceAssign_f", // T[]=T[]-T
"_arraySliceExpMinSliceAssign_g",
"_arraySliceExpMinSliceAssign_h",
"_arraySliceExpMinSliceAssign_i",
"_arraySliceExpMinSliceAssign_k",
"_arraySliceExpMinSliceAssign_s",
"_arraySliceExpMinSliceAssign_t",
"_arraySliceExpMinSliceAssign_u",
"_arraySliceExpMinSliceAssign_w",
"_arraySliceExpMulSliceAddass_d", // T[] += T[]*T
"_arraySliceExpMulSliceAddass_f",
"_arraySliceExpMulSliceAddass_r",
"_arraySliceExpMulSliceAssign_d", // T[]=T[]*T
"_arraySliceExpMulSliceAssign_f", // T[]=T[]*T
"_arraySliceExpMulSliceAssign_i",
"_arraySliceExpMulSliceAssign_k",
"_arraySliceExpMulSliceAssign_s",
"_arraySliceExpMulSliceAssign_t",
"_arraySliceExpMulSliceAssign_u",
"_arraySliceExpMulSliceAssign_w",
"_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T
"_arraySliceExpMulSliceMinass_f",
"_arraySliceExpMulSliceMinass_r",
"_arraySliceSliceAddSliceAssign_a",
"_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
"_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
"_arraySliceSliceAddSliceAssign_g",
"_arraySliceSliceAddSliceAssign_h",
"_arraySliceSliceAddSliceAssign_i",
"_arraySliceSliceAddSliceAssign_k",
"_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
"_arraySliceSliceAddSliceAssign_s",
"_arraySliceSliceAddSliceAssign_t",
"_arraySliceSliceAddSliceAssign_u",
"_arraySliceSliceAddSliceAssign_w",
"_arraySliceSliceAddass_a",
"_arraySliceSliceAddass_d", // T[]+=T[]
"_arraySliceSliceAddass_f", // T[]+=T[]
"_arraySliceSliceAddass_g",
"_arraySliceSliceAddass_h",
"_arraySliceSliceAddass_i",
"_arraySliceSliceAddass_k",
"_arraySliceSliceAddass_s",
"_arraySliceSliceAddass_t",
"_arraySliceSliceAddass_u",
"_arraySliceSliceAddass_w",
"_arraySliceSliceMinSliceAssign_a",
"_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
"_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
"_arraySliceSliceMinSliceAssign_g",
"_arraySliceSliceMinSliceAssign_h",
"_arraySliceSliceMinSliceAssign_i",
"_arraySliceSliceMinSliceAssign_k",
"_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
"_arraySliceSliceMinSliceAssign_s",
"_arraySliceSliceMinSliceAssign_t",
"_arraySliceSliceMinSliceAssign_u",
"_arraySliceSliceMinSliceAssign_w",
"_arraySliceSliceMinass_a",
"_arraySliceSliceMinass_d", // T[]-=T[]
"_arraySliceSliceMinass_f", // T[]-=T[]
"_arraySliceSliceMinass_g",
"_arraySliceSliceMinass_h",
"_arraySliceSliceMinass_i",
"_arraySliceSliceMinass_k",
"_arraySliceSliceMinass_s",
"_arraySliceSliceMinass_t",
"_arraySliceSliceMinass_u",
"_arraySliceSliceMinass_w",
"_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
"_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
"_arraySliceSliceMulSliceAssign_i",
"_arraySliceSliceMulSliceAssign_k",
"_arraySliceSliceMulSliceAssign_s",
"_arraySliceSliceMulSliceAssign_t",
"_arraySliceSliceMulSliceAssign_u",
"_arraySliceSliceMulSliceAssign_w",
"_arraySliceSliceMulass_d", // T[]*=T[]
"_arraySliceSliceMulass_f", // T[]*=T[]
"_arraySliceSliceMulass_i",
"_arraySliceSliceMulass_k",
"_arraySliceSliceMulass_s",
"_arraySliceSliceMulass_t",
"_arraySliceSliceMulass_u",
"_arraySliceSliceMulass_w",
};
int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
if (i == -1)
{
#ifdef DEBUG // Make sure our array is alphabetized
for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
{
if (strcmp(name, libArrayopFuncs[i]) == 0)
assert(0);
}
#endif
/* Not in library, so generate it.
* Construct the function body:
* foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
* loopbody;
* return p;
*/
Parameters *fparams = new Parameters();
Expression *loopbody = buildArrayLoop(fparams);
Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
#if DMDV1
// for (size_t i = 0; i < p.length; i++)
Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
Statement *s1 = new ForStatement(0,
new DeclarationStatement(0, d),
new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
new ExpStatement(0, loopbody));
#else
// foreach (i; 0 .. p.length)
Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
new Parameter(0, NULL, Id::p, NULL),
new IntegerExp(0, 0, Type::tint32),
new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
new ExpStatement(0, loopbody));
#endif
Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
//printf("s2: %s\n", s2->toChars());
Statement *fbody = new CompoundStatement(0, s1, s2);
/* Construct the function
*/
TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
//printf("ftype: %s\n", ftype->toChars());
fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype);
fd->fbody = fbody;
fd->protection = PROTpublic;
fd->linkage = LINKc;
fd->isArrayOp = 1;
sc->module->importedFrom->members->push(fd);
sc = sc->push();
sc->parent = sc->module->importedFrom;
sc->stc = 0;
sc->linkage = LINKc;
fd->semantic(sc);
fd->semantic2(sc);
fd->semantic3(sc);
sc->pop();
}
else
{ /* In library, refer to it.
*/
fd = FuncDeclaration::genCfunc(type, ident);
}
*pfd = fd; // cache symbol in hash table
}
/* Call the function fd(arguments)
*/
Expression *ec = new VarExp(0, fd);
Expression *e = new CallExp(loc, ec, arguments);
e->type = type;
return e;
}
/******************************************
* Construct the identifier for the array operation function,
* and build the argument list to pass to it.
*/
void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
buf->writestring("Exp");
arguments->shift(this);
}
void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
Type *tb = type->toBasetype();
if (tb->ty == Tarray || tb->ty == Tsarray)
{
e1->buildArrayIdent(buf, arguments);
}
else
Expression::buildArrayIdent(buf, arguments);
}
void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
buf->writestring("Slice");
arguments->shift(this);
}
void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
/* Evaluate assign expressions right to left
*/
e2->buildArrayIdent(buf, arguments);
e1->buildArrayIdent(buf, arguments);
buf->writestring("Assign");
}
#define X(Str) \
void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
{ \
/* Evaluate assign expressions right to left \
*/ \
e2->buildArrayIdent(buf, arguments); \
e1->buildArrayIdent(buf, arguments); \
buf->writestring(#Str); \
buf->writestring("ass"); \
}
X(Add)
X(Min)
X(Mul)
X(Div)
X(Mod)
X(Xor)
X(And)
X(Or)
#if DMDV2
X(Pow)
#endif
#undef X
void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
e1->buildArrayIdent(buf, arguments);
buf->writestring("Neg");
}
void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
{
e1->buildArrayIdent(buf, arguments);
buf->writestring("Com");
}
#define X(Str) \
void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
{ \
/* Evaluate assign expressions left to right \
*/ \
e1->buildArrayIdent(buf, arguments); \
e2->buildArrayIdent(buf, arguments); \
buf->writestring(#Str); \
}
X(Add)
X(Min)
X(Mul)
X(Div)
X(Mod)
X(Xor)
X(And)
X(Or)
#if DMDV2
X(Pow)
#endif
#undef X
/******************************************
* Construct the inner loop for the array operation function,
* and build the parameter list.
*/
Expression *Expression::buildArrayLoop(Parameters *fparams)
{
Identifier *id = Identifier::generateId("c", fparams->dim);
Parameter *param = new Parameter(0, type, id, NULL);
fparams->shift(param);
Expression *e = new IdentifierExp(0, id);
return e;
}
Expression *CastExp::buildArrayLoop(Parameters *fparams)
{
Type *tb = type->toBasetype();
if (tb->ty == Tarray || tb->ty == Tsarray)
{
return e1->buildArrayLoop(fparams);
}
else
return Expression::buildArrayLoop(fparams);
}
Expression *SliceExp::buildArrayLoop(Parameters *fparams)
{
Identifier *id = Identifier::generateId("p", fparams->dim);
Parameter *param = new Parameter(STCconst, type, id, NULL);
fparams->shift(param);
Expression *e = new IdentifierExp(0, id);
Expressions *arguments = new Expressions();
Expression *index = new IdentifierExp(0, Id::p);
arguments->push(index);
e = new ArrayExp(0, e, arguments);
return e;
}
Expression *AssignExp::buildArrayLoop(Parameters *fparams)
{
/* Evaluate assign expressions right to left
*/
Expression *ex2 = e2->buildArrayLoop(fparams);
#if DMDV2
/* Need the cast because:
* b = c + p[i];
* where b is a byte fails because (c + p[i]) is an int
* which cannot be implicitly cast to byte.
*/
ex2 = new CastExp(0, ex2, e1->type->nextOf());
#endif
Expression *ex1 = e1->buildArrayLoop(fparams);
Parameter *param = (*fparams)[0];
param->storageClass = 0;
Expression *e = new AssignExp(0, ex1, ex2);
return e;
}
#define X(Str) \
Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \
{ \
/* Evaluate assign expressions right to left \
*/ \
Expression *ex2 = e2->buildArrayLoop(fparams); \
Expression *ex1 = e1->buildArrayLoop(fparams); \
Parameter *param = (*fparams)[0]; \
param->storageClass = 0; \
Expression *e = new Str##AssignExp(loc, ex1, ex2); \
return e; \
}
X(Add)
X(Min)
X(Mul)
X(Div)
X(Mod)
X(Xor)
X(And)
X(Or)
#if DMDV2
X(Pow)
#endif
#undef X
Expression *NegExp::buildArrayLoop(Parameters *fparams)
{
Expression *ex1 = e1->buildArrayLoop(fparams);
Expression *e = new NegExp(0, ex1);
return e;
}
Expression *ComExp::buildArrayLoop(Parameters *fparams)
{
Expression *ex1 = e1->buildArrayLoop(fparams);
Expression *e = new ComExp(0, ex1);
return e;
}
#define X(Str) \
Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \
{ \
/* Evaluate assign expressions left to right \
*/ \
Expression *ex1 = e1->buildArrayLoop(fparams); \
Expression *ex2 = e2->buildArrayLoop(fparams); \
Expression *e = new Str##Exp(0, ex1, ex2); \
return e; \
}
X(Add)
X(Min)
X(Mul)
X(Div)
X(Mod)
X(Xor)
X(And)
X(Or)
#if DMDV2
X(Pow)
#endif
#undef X
/***********************************************
* Test if operand is a valid array op operand.
*/
int Expression::isArrayOperand()
{
//printf("Expression::isArrayOperand() %s\n", toChars());
if (op == TOKslice)
return 1;
if (type->toBasetype()->ty == Tarray)
{
switch (op)
{
case TOKadd:
case TOKmin:
case TOKmul:
case TOKdiv:
case TOKmod:
case TOKxor:
case TOKand:
case TOKor:
case TOKassign:
case TOKaddass:
case TOKminass:
case TOKmulass:
case TOKdivass:
case TOKmodass:
case TOKxorass:
case TOKandass:
case TOKorass:
#if DMDV2
case TOKpow:
case TOKpowass:
#endif
case TOKneg:
case TOKtilde:
return 1;
default:
break;
}
}
return 0;
}

77
arraytypes.h Normal file
View File

@@ -0,0 +1,77 @@
// Compiler implementation of the D programming language
// Copyright (c) 2006-2007 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#ifndef DMD_ARRAYTYPES_H
#define DMD_ARRAYTYPES_H
#ifdef __DMC__
#pragma once
#endif /* __DMC__ */
#include "root.h"
typedef ArrayBase<struct TemplateParameter> TemplateParameters;
typedef ArrayBase<struct Expression> Expressions;
typedef ArrayBase<struct Statement> Statements;
typedef ArrayBase<struct BaseClass> BaseClasses;
typedef ArrayBase<struct ClassDeclaration> ClassDeclarations;
typedef ArrayBase<struct Dsymbol> Dsymbols;
typedef ArrayBase<struct Object> Objects;
typedef ArrayBase<struct FuncDeclaration> FuncDeclarations;
typedef ArrayBase<struct Parameter> Parameters;
typedef ArrayBase<struct Identifier> Identifiers;
typedef ArrayBase<struct Initializer> Initializers;
typedef ArrayBase<struct VarDeclaration> VarDeclarations;
typedef ArrayBase<struct Type> Types;
typedef ArrayBase<struct ScopeDsymbol> ScopeDsymbols;
typedef ArrayBase<struct Catch> Catches;
typedef ArrayBase<struct StaticDtorDeclaration> StaticDtorDeclarations;
typedef ArrayBase<struct SharedStaticDtorDeclaration> SharedStaticDtorDeclarations;
typedef ArrayBase<struct AliasDeclaration> AliasDeclarations;
typedef ArrayBase<struct Module> Modules;
typedef ArrayBase<struct File> Files;
typedef ArrayBase<struct CaseStatement> CaseStatements;
typedef ArrayBase<struct CompoundStatement> CompoundStatements;
typedef ArrayBase<struct GotoCaseStatement> GotoCaseStatements;
typedef ArrayBase<struct TemplateInstance> TemplateInstances;
//typedef ArrayBase<char> Strings;
typedef ArrayBase<void> Voids;
typedef ArrayBase<struct block> Blocks;
typedef ArrayBase<struct Symbol> Symbols;
#endif

117
artistic.txt Normal file
View File

@@ -0,0 +1,117 @@
The "Artistic License"
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
Definitions:
"Package" refers to the collection of files distributed by the
Copyright Holder, and derivatives of that collection of files
created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes
of the Copyright Holder as specified below.
"Copyright Holder" is whoever is named in the copyright or
copyrights for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the
basis of media cost, duplication charges, time of people involved,
and so on. (You will not be required to justify it to the
Copyright Holder, but only to the computing community at large
as a market that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it
under the same conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way, provided
that you insert a prominent notice in each changed file stating how and
when you changed that file, and provided that you do at least ONE of the
following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or placing the modifications on a major archive
site such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or organization.
c) rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page for each non-standard executable that clearly
documents how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent), together
with instructions on where to get the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial) software
distribution provided that you do not advertise this Package as a
product of your own. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
6. The source code and object code supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever generated
them, and may be sold commercially, and may be aggregated with this
Package.
7. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
8. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End

1524
attrib.c Normal file

File diff suppressed because it is too large Load Diff

189
attrib.h Normal file
View File

@@ -0,0 +1,189 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#ifndef DMD_ATTRIB_H
#define DMD_ATTRIB_H
#ifdef __DMC__
#pragma once
#endif /* __DMC__ */
#include "dsymbol.h"
struct Expression;
struct Statement;
struct LabelDsymbol;
struct Initializer;
struct Module;
struct Condition;
struct HdrGenState;
/**************************************************************/
struct AttribDeclaration : Dsymbol
{
Dsymbols *decl; // array of Dsymbol's
AttribDeclaration(Dsymbols *decl);
virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s);
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
void setScopeNewSc(Scope *sc,
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
unsigned structalign);
void semanticNewSc(Scope *sc,
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
unsigned structalign);
void semantic(Scope *sc);
void semantic2(Scope *sc);
void semantic3(Scope *sc);
void inlineScan();
void addComment(unsigned char *comment);
void emitComment(Scope *sc);
const char *kind();
int oneMember(Dsymbol **ps, Identifier *ident);
int hasPointers();
bool hasStaticCtorOrDtor();
void checkCtorConstInit();
void addLocalClass(ClassDeclarations *);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
void toJsonBuffer(OutBuffer *buf);
AttribDeclaration *isAttribDeclaration() { return this; }
void toObjFile(int multiobj); // compile to .obj file
int cvMember(unsigned char *p);
};
struct StorageClassDeclaration: AttribDeclaration
{
StorageClass stc;
StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void setScope(Scope *sc);
void semantic(Scope *sc);
int oneMember(Dsymbol **ps, Identifier *ident);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
static void stcToCBuffer(OutBuffer *buf, StorageClass stc);
};
struct LinkDeclaration : AttribDeclaration
{
enum LINK linkage;
LinkDeclaration(enum LINK p, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void setScope(Scope *sc);
void semantic(Scope *sc);
void semantic3(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
char *toChars();
};
struct ProtDeclaration : AttribDeclaration
{
enum PROT protection;
ProtDeclaration(enum PROT p, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void importAll(Scope *sc);
void setScope(Scope *sc);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
static void protectionToCBuffer(OutBuffer *buf, enum PROT protection);
};
struct AlignDeclaration : AttribDeclaration
{
unsigned salign;
AlignDeclaration(unsigned sa, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void setScope(Scope *sc);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
};
struct AnonDeclaration : AttribDeclaration
{
int isunion;
int sem; // 1 if successful semantic()
AnonDeclaration(Loc loc, int isunion, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
const char *kind();
};
struct PragmaDeclaration : AttribDeclaration
{
Expressions *args; // array of Expression's
PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void semantic(Scope *sc);
void setScope(Scope *sc);
int oneMember(Dsymbol **ps, Identifier *ident);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
const char *kind();
void toObjFile(int multiobj); // compile to .obj file
};
struct ConditionalDeclaration : AttribDeclaration
{
Condition *condition;
Dsymbols *elsedecl; // array of Dsymbol's for else block
ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
Dsymbol *syntaxCopy(Dsymbol *s);
int oneMember(Dsymbol **ps, Identifier *ident);
void emitComment(Scope *sc);
Dsymbols *include(Scope *sc, ScopeDsymbol *s);
void addComment(unsigned char *comment);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
void toJsonBuffer(OutBuffer *buf);
void importAll(Scope *sc);
void setScope(Scope *sc);
};
struct StaticIfDeclaration : ConditionalDeclaration
{
ScopeDsymbol *sd;
int addisdone;
StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
Dsymbol *syntaxCopy(Dsymbol *s);
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
void semantic(Scope *sc);
void importAll(Scope *sc);
void setScope(Scope *sc);
const char *kind();
};
// Mixin declarations
struct CompileDeclaration : AttribDeclaration
{
Expression *exp;
ScopeDsymbol *sd;
int compiled;
CompileDeclaration(Loc loc, Expression *exp);
Dsymbol *syntaxCopy(Dsymbol *s);
int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
void compileIt(Scope *sc);
void semantic(Scope *sc);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
};
#endif /* DMD_ATTRIB_H */

498
backend/aa.c Normal file
View File

@@ -0,0 +1,498 @@
// Copyright (c) 2000-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "tinfo.h"
#include "aa.h"
// Implementation of associative array
// Auto-rehash and pre-allocate - Dave Fladebo
static unsigned long prime_list[] =
{
97UL, 389UL,
1543UL, 6151UL,
24593UL, 98317UL,
393241UL, 1572869UL,
6291469UL, 25165843UL,
100663319UL, 402653189UL,
1610612741UL, 4294967291UL
};
/**********************************
* Align to next pointer boundary, so value
* will be aligned.
*/
size_t aligntsize(size_t tsize)
{
// Is pointer alignment on the x64 4 bytes or 8?
return (tsize + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1);
}
/**********************************
* Constructor.
*/
AArray::AArray(TypeInfo *keyti, size_t valuesize)
{
this->keyti = keyti;
this->valuesize = valuesize;
this->nodes = 0;
this->buckets = NULL;
this->buckets_length = 0;
}
/**********************************
* Destructor.
*/
void delnodes(aaA* e)
{ aaA* en;
do
{
if (e->left)
{ if (!e->right)
{ en = e;
e = e->left;
delete en;
continue;
}
delnodes(e->left);
}
en = e;
e = e->right;
delete en;
} while (e != NULL);
}
AArray::~AArray()
{
if (buckets)
{
for (size_t i = 0; i < buckets_length; i++)
{ aaA* e = buckets[i];
if (e)
delnodes(e); // recursively free all nodes
}
delete [] buckets;
}
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* AArray::get(void *pkey)
{
//printf("AArray::get()\n");
size_t i;
aaA* e;
size_t keysize = aligntsize(keyti->tsize());
if (!buckets_length)
{
typedef aaA* aaAp;
buckets_length = prime_list[0];
buckets = new aaAp[buckets_length];
memset(buckets, 0, buckets_length * sizeof(buckets[0]));
}
hash_t key_hash = keyti->getHash(pkey);
i = key_hash % buckets_length;
//printf("key_hash = %x, buckets_length = %d, i = %d\n", key_hash, buckets_length, i);
aaA** pe = &buckets[i];
while ((e = *pe) != NULL)
{ int c;
c = key_hash - e->hash;
if (c == 0)
{
c = keyti->compare(pkey, e + 1);
if (c == 0)
goto Lret;
}
if (c < 0)
pe = &e->left;
else
pe = &e->right;
}
// Not found, create new elem
//printf("create new one\n");
e = (aaA *) new char[sizeof(aaA) + keysize + valuesize];
memcpy(e + 1, pkey, keysize);
memset((unsigned char *)(e + 1) + keysize, 0, valuesize);
e->hash = key_hash;
e->left = NULL;
e->right = NULL;
*pe = e;
++nodes;
//printf("length = %d, nodes = %d\n", buckets_length, nodes);
if (nodes > buckets_length * 4)
{
//printf("rehash()\n");
rehash();
}
Lret:
return (void *)((char *)(e + 1) + keysize);
}
/*************************************************
* Determine if key is in aa.
* Returns:
* NULL not in aa
* !=NULL in aa, return pointer to value
*/
void* AArray::in(void *pkey)
{
//printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
size_t len = buckets_length;
if (len)
{
hash_t key_hash = keyti->getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
aaA *e = buckets[i];
while (e != NULL)
{ int c;
c = key_hash - e->hash;
if (c == 0)
{
c = keyti->compare(pkey, e + 1);
if (c == 0)
return (char *)(e + 1) + aligntsize(keyti->tsize());
}
if (c < 0)
e = e->left;
else
e = e->right;
}
}
// Not found
return NULL;
}
/*************************************************
* Delete key entry in aa[].
* If key is not in aa[], do nothing.
*/
void AArray::del(void *pkey)
{
aaA* e;
if (buckets_length)
{
hash_t key_hash = keyti->getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % buckets_length;
aaA** pe = &buckets[i];
while ((e = *pe) != NULL) // NULL means not found
{ int c;
c = key_hash - e->hash;
if (c == 0)
{
c = keyti->compare(pkey, e + 1);
if (c == 0)
{
if (!e->left && !e->right)
{
*pe = NULL;
}
else if (e->left && !e->right)
{
*pe = e->left;
e->left = NULL;
}
else if (!e->left && e->right)
{
*pe = e->right;
e->right = NULL;
}
else
{
*pe = e->left;
e->left = NULL;
do
pe = &(*pe)->right;
while (*pe);
*pe = e->right;
e->right = NULL;
}
nodes--;
delete[] e;
break;
}
}
if (c < 0)
pe = &e->left;
else
pe = &e->right;
}
}
}
/********************************************
* Produce array of keys from aa.
*/
void *AArray::keys()
{
void *p = NULL;
if (nodes)
{
size_t keysize = keyti->tsize();
typedef char* charp;
p = (void *)new charp[nodes * keysize];
void *q = p;
for (size_t i = 0; i < buckets_length; i++)
{ aaA* e = buckets[i];
if (e)
q = keys_x(e, q, keysize);
}
}
return p;
}
void *AArray::keys_x(aaA* e, void *p, size_t keysize)
{
do
{
memcpy(p, e + 1, keysize);
if (e->left)
{ if (!e->right)
{ e = e->left;
continue;
}
p = keys_x(e->left, p, keysize);
}
e = e->right;
} while (e != NULL);
return p;
}
/********************************************
* Produce array of values from aa.
*/
void *AArray::values()
{
void *p = NULL;
if (nodes)
{
p = (void *)new char[nodes * valuesize];
void *q = p;
for (size_t i = 0; i < buckets_length; i++)
{ aaA *e = buckets[i];
if (e)
q = values_x(e, q);
}
}
return p;
}
void *AArray::values_x(aaA *e, void *p)
{
size_t keysize = keyti->tsize();
do
{
memcpy(p,
(char *)(e + 1) + keysize,
valuesize);
p = (void *)((char *)p + valuesize);
if (e->left)
{ if (!e->right)
{ e = e->left;
continue;
}
p = values_x(e->left, p);
}
e = e->right;
} while (e != NULL);
return p;
}
/********************************************
* Rehash an array.
*/
void AArray::rehash()
{
//printf("Rehash\n");
if (buckets_length)
{
size_t len = nodes;
if (len)
{ size_t i;
aaA** newbuckets;
size_t newbuckets_length;
for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++)
{
if (len <= prime_list[i])
break;
}
newbuckets_length = prime_list[i];
typedef aaA* aaAp;
newbuckets = new aaAp[newbuckets_length];
memset(newbuckets, 0, newbuckets_length * sizeof(newbuckets[0]));
for (i = 0; i < buckets_length; i++)
{ aaA *e = buckets[i];
if (e)
rehash_x(e, newbuckets, newbuckets_length);
}
delete[] buckets;
buckets = newbuckets;
buckets_length = newbuckets_length;
}
}
}
void AArray::rehash_x(aaA* olde, aaA** newbuckets, size_t newbuckets_length)
{
while (1)
{
aaA* left = olde->left;
aaA* right = olde->right;
olde->left = NULL;
olde->right = NULL;
aaA* e;
//printf("rehash %p\n", olde);
hash_t key_hash = olde->hash;
size_t i = key_hash % newbuckets_length;
aaA** pe = &newbuckets[i];
while ((e = *pe) != NULL)
{ int c;
//printf("\te = %p, e->left = %p, e->right = %p\n", e, e->left, e->right);
assert(e->left != e);
assert(e->right != e);
c = key_hash - e->hash;
if (c == 0)
c = keyti->compare(olde + 1, e + 1);
if (c < 0)
pe = &e->left;
else if (c > 0)
pe = &e->right;
else
assert(0);
}
*pe = olde;
if (right)
{
if (!left)
{ olde = right;
continue;
}
rehash_x(right, newbuckets, newbuckets_length);
}
if (!left)
break;
olde = left;
}
}
/*********************************************
* For each element in the AArray,
* call dg(void *parameter, void *pkey, void *pvalue)
* If dg returns !=0, stop and return that value.
*/
typedef int (*dg2_t)(void *, void *, void *);
int AArray::apply(void *parameter, dg2_t dg)
{ int result = 0;
//printf("_aaApply(aa = %p, keysize = %d, dg = %p)\n", this, keyti->tsize(), dg);
if (nodes)
{
size_t keysize = aligntsize(keyti->tsize());
for (size_t i = 0; i < buckets_length; i++)
{ aaA* e = buckets[i];
if (e)
{
result = apply_x(e, dg, keysize, parameter);
if (result)
break;
}
}
}
return result;
}
int AArray::apply_x(aaA* e, dg2_t dg, size_t keysize, void *parameter)
{ int result;
do
{
//printf("apply_x(e = %p, dg = %p)\n", e, dg);
result = (*dg)(parameter, e + 1, (char *)(e + 1) + keysize);
if (result)
break;
if (e->right)
{ if (!e->left)
{
e = e->right;
continue;
}
result = apply_x(e->right, dg, keysize, parameter);
if (result)
break;
}
e = e->left;
} while (e);
return result;
}

109
backend/aa.h Normal file
View File

@@ -0,0 +1,109 @@
// Copyright (c) 2006-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#ifndef AA_H
#define AA_H
#include <stdlib.h>
#include "tinfo.h"
struct aaA
{
aaA *left;
aaA *right;
hash_t hash;
/* key */
/* value */
};
struct AArray
{
TypeInfo *keyti;
size_t valuesize;
size_t nodes;
aaA** buckets;
size_t buckets_length;
AArray(TypeInfo *keyti, size_t valuesize);
~AArray();
size_t length()
{
return nodes;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* get(void *pkey);
void* get(char *string) { return get(&string); }
/*************************************************
* Determine if key is in aa.
* Returns:
* null not in aa
* !=null in aa, return pointer to value
*/
void* in(void *pkey);
void* in(char *string) { return in(&string); }
/*************************************************
* Delete key entry in aa[].
* If key is not in aa[], do nothing.
*/
void del(void *pkey);
/********************************************
* Produce array of keys from aa.
*/
void *keys();
/********************************************
* Produce array of values from aa.
*/
void *values();
/********************************************
* Rehash an array.
*/
void rehash();
/*********************************************
* For each element in the AArray,
* call dg(void *parameter, void *pkey, void *pvalue)
* If dg returns !=0, stop and return that value.
*/
typedef int (*dg2_t)(void *, void *, void *);
int apply(void *parameter, dg2_t dg);
private:
void *keys_x(aaA* e, void *p, size_t keysize);
void *values_x(aaA *e, void *p);
void rehash_x(aaA* olde, aaA** newbuckets, size_t newbuckets_length);
int apply_x(aaA* e, dg2_t dg, size_t keysize, void *parameter);
};
#endif

80
backend/backend.txt Normal file
View File

@@ -0,0 +1,80 @@
Files in the Back End
=====================
aa.c simple hash table
aa.h header for simple hash table
bcomplex.c our own complex number implementation because we can't rely on host C compiler
bcomplex.h header for our own complex numbers
blockopt.c manage and simple optimizations on graphs of basic blocks
cc.h main header file for back end
cdef.h configuration
cdeflnx.h configuration for linux
cg.c global variables for code generator
cg87.c x87 FPU code generation
cgcod.c main loop for code generator
cgcs.c compute common subexpressions for non-optimized code generation
cgcv.c CodeView symbol debug info generation
cgcv.h header for cgcv.c
cgelem.c local optimizations of elem trees
cgen.c generate/manage linked list of code instructions
cgobj.c generate OMF object files
cgreg.c register allocator
cgsched.c instruction scheduler
cod1.c code gen
cod2.c code gen
cod3.c code gen
cod4.c code gen
cod5.c code gen
code.c memory management for code instructions
code.h define registers, register masks, and the CPU instruction linked list
cppman.c C++ name mangling
cv4.h CodeView symbolic debug info declarations
debug.c pretty printing for debug builds
dt.c static data for later output to object file
dt.h API for dt.c
dwarf.c generate DWARF symbolic debug info
dwarf.h API for dwarf.c
dwarf2.h Dwarf 3 spec declarations
ee.c handle IDDE debugger expression evaluation
el.c expression trees (intermediate code)
el.h header for el.c
elfobj.c generate ELF object files
evalu8.c constant folding
exh.h exception handling support
gdag.c Directed acyclic graphs and global optimizer common subexpressions
gflow.c global data flow analysis
global.h declarations for back end
glocal.c global optimizations
gloop.c global loop optimizations
go.c global optimizer main loop
go.h global optimizer declarations
gother.c other global optimizations
html.c support for embedding source code in html
html.h header for html.c
iasm.h declarations for inline assembler
mach.h declarations for Mach-O object file format
machobj.c generate Mach-O object files
md5.c implementation of MD5 message digest
md5.h API for md5.c
melf.h declarations for ELF file format
newman.c "new" C++ name mangling scheme
nteh.c Windows structured exception handling support
oper.h operators for expression tree
optabgen.c generate tables for back end
os.c some operating system specific support
out.c write data definitions to object file
outbuf.c resizeable buffer
outbuf.h API for resizeable buffer
ptrntab.c instruction tables for inline assembler
rtlsym.c initialize for compiler 'helper' runtime functions
rtlsym.h compiler 'helper' runtime functions
strtold.c our own version of strtold() because we cannot rely on C's
symbol.c symbols for the back end
tassert.h our own assert macro (to reduce code size)
tinfo.h specialization of hash table aa.c
ti_achar.c specialization of hash tables for array of chars
token.h C/C++ tokens
ty.h type masks
type.c back end type
type.h header for type.c
var.c global variables

292
backend/bcomplex.c Normal file
View File

@@ -0,0 +1,292 @@
// public domain
#include <math.h>
#include "bcomplex.h"
/*********************************************************/
Complex_ld Complex_ld::div(Complex_ld &x, Complex_ld &y)
{
Complex_ld q;
long double r;
long double den;
if (fabs(y.re) < fabs(y.im))
{
r = y.re / y.im;
den = y.im + r * y.re;
q.re = (x.re * r + x.im) / den;
q.im = (x.im * r - x.re) / den;
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
q.re = (x.re + r * x.im) / den;
q.im = (x.im - r * x.re) / den;
}
return q;
}
Complex_ld Complex_ld::mul(Complex_ld &x, Complex_ld &y)
{
Complex_ld p;
p.re = x.re * y.re - x.im * y.im;
p.im = x.im * y.re + x.re * y.im;
return p;
}
long double Complex_ld::abs(Complex_ld &z)
{
long double x,y,ans,temp;
x = fabs(z.re);
y = fabs(z.im);
if (x == 0)
ans = y;
else if (y == 0)
ans = x;
else if (x > y)
{
temp = y / x;
ans = x * sqrt(1 + temp * temp);
}
else
{
temp = x / y;
ans = y * sqrt(1 + temp * temp);
}
return ans;
}
Complex_ld Complex_ld::sqrtc(Complex_ld &z)
{
Complex_ld c;
long double x,y,w,r;
if (z.re == 0 && z.im == 0)
{
c.re = 0;
c.im = 0;
}
else
{
x = fabs(z.re);
y = fabs(z.im);
if (x >= y)
{
r = y / x;
w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
}
else
{
r = x / y;
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
}
if (z.re >= 0)
{
c.re = w;
c.im = z.im / (w + w);
}
else
{
c.im = (z.im >= 0) ? w : -w;
c.re = z.im / (c.im + c.im);
}
}
return c;
}
/*********************************************************/
Complex_d Complex_d::div(Complex_d &x, Complex_d &y)
{
Complex_d q;
long double r;
long double den;
if (fabs(y.re) < fabs(y.im))
{
r = y.re / y.im;
den = y.im + r * y.re;
q.re = (x.re * r + x.im) / den;
q.im = (x.im * r - x.re) / den;
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
q.re = (x.re + r * x.im) / den;
q.im = (x.im - r * x.re) / den;
}
return q;
}
Complex_d Complex_d::mul(Complex_d &x, Complex_d &y)
{
Complex_d p;
p.re = x.re * y.re - x.im * y.im;
p.im = x.im * y.re + x.re * y.im;
return p;
}
long double Complex_d::abs(Complex_d &z)
{
long double x,y,ans,temp;
x = fabs(z.re);
y = fabs(z.im);
if (x == 0)
ans = y;
else if (y == 0)
ans = x;
else if (x > y)
{
temp = y / x;
ans = x * sqrt(1 + temp * temp);
}
else
{
temp = x / y;
ans = y * sqrt(1 + temp * temp);
}
return ans;
}
Complex_d Complex_d::sqrtc(Complex_d &z)
{
Complex_d c;
long double x,y,w,r;
if (z.re == 0 && z.im == 0)
{
c.re = 0;
c.im = 0;
}
else
{
x = fabs(z.re);
y = fabs(z.im);
if (x >= y)
{
r = y / x;
w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
}
else
{
r = x / y;
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
}
if (z.re >= 0)
{
c.re = w;
c.im = z.im / (w + w);
}
else
{
c.im = (z.im >= 0) ? w : -w;
c.re = z.im / (c.im + c.im);
}
}
return c;
}
/*********************************************************/
Complex_f Complex_f::div(Complex_f &x, Complex_f &y)
{
Complex_f q;
long double r;
long double den;
if (fabs(y.re) < fabs(y.im))
{
r = y.re / y.im;
den = y.im + r * y.re;
q.re = (x.re * r + x.im) / den;
q.im = (x.im * r - x.re) / den;
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
q.re = (x.re + r * x.im) / den;
q.im = (x.im - r * x.re) / den;
}
return q;
}
Complex_f Complex_f::mul(Complex_f &x, Complex_f &y)
{
Complex_f p;
p.re = x.re * y.re - x.im * y.im;
p.im = x.im * y.re + x.re * y.im;
return p;
}
long double Complex_f::abs(Complex_f &z)
{
long double x,y,ans,temp;
x = fabs(z.re);
y = fabs(z.im);
if (x == 0)
ans = y;
else if (y == 0)
ans = x;
else if (x > y)
{
temp = y / x;
ans = x * sqrt(1 + temp * temp);
}
else
{
temp = x / y;
ans = y * sqrt(1 + temp * temp);
}
return ans;
}
Complex_f Complex_f::sqrtc(Complex_f &z)
{
Complex_f c;
long double x,y,w,r;
if (z.re == 0 && z.im == 0)
{
c.re = 0;
c.im = 0;
}
else
{
x = fabs(z.re);
y = fabs(z.im);
if (x >= y)
{
r = y / x;
w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
}
else
{
r = x / y;
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
}
if (z.re >= 0)
{
c.re = w;
c.im = z.im / (w + w);
}
else
{
c.im = (z.im >= 0) ? w : -w;
c.re = z.im / (c.im + c.im);
}
}
return c;
}

36
backend/bcomplex.h Normal file
View File

@@ -0,0 +1,36 @@
// public domain
#ifndef BCOMPLEX_H
#define BCOMPLEX_H 1
// Avoid interfering with system <complex.h> and other
// such; roll our own for reliable bootstrapping
struct Complex_f
{ float re, im;
static Complex_f div(Complex_f &x, Complex_f &y);
static Complex_f mul(Complex_f &x, Complex_f &y);
static long double abs(Complex_f &z);
static Complex_f sqrtc(Complex_f &z);
};
struct Complex_d
{ double re, im;
static Complex_d div(Complex_d &x, Complex_d &y);
static Complex_d mul(Complex_d &x, Complex_d &y);
static long double abs(Complex_d &z);
static Complex_d sqrtc(Complex_d &z);
};
struct Complex_ld
{ long double re, im;
static Complex_ld div(Complex_ld &x, Complex_ld &y);
static Complex_ld mul(Complex_ld &x, Complex_ld &y);
static long double abs(Complex_ld &z);
static Complex_ld sqrtc(Complex_ld &z);
};
#endif

2204
backend/blockopt.c Normal file

File diff suppressed because it is too large Load Diff

1557
backend/cc.h Normal file

File diff suppressed because it is too large Load Diff

1104
backend/cdef.h Normal file

File diff suppressed because it is too large Load Diff

85
backend/cdeflnx.h Normal file
View File

@@ -0,0 +1,85 @@
// Copyright (C) ?-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#include <time.h>
#define M_UNIX 1
#define IMPLIED_PRAGMA_ONCE 1
#define MEMMODELS 1
#if __GNUC__
#define __SC__ 0
#define _MSC_VER 0
#endif
#define ERRSTREAM stderr
#define isleadbyte(c) 0
#define __cdecl __attribute__ ((__cdecl__))
#define _cdecl __attribute__ ((__cdecl__))
#define __stdcall __attribute__ ((__stdcall__))
#define __pascal
#define __near
#define _near
#define __far
#define _far
#define __ss
#define __cs
#if SCPP
// Need to define the token enum before any refs
#define TOKENS_ONLY 1
#include "token.h"
#undef TOKEN_H
#undef TOKENS_ONLY
#define TOKENS_ONLY 0
#endif
//
// Error messages generated by msgsx.c
//
//#include "msgs2.h"
char * strupr(char *);
//
// Attributes
//
// Types of attributes
#define ATTR_LINKMOD 0x0001 // link modifier
#define ATTR_TYPEMOD 0x0002 // basic type modifier
#define ATTR_FUNCINFO 0x0004 // function information
#define ATTR_DATAINFO 0x0008 // data information
#define ATTR_TRANSU 0x0010 // transparent union
#define ATTR_IGNORED 0x0020 // attribute can be ignored
#define ATTR_WARNING 0x0040 // attribute was ignored
#define ATTR_SEGMENT 0x0080 // segment secified
// attribute location in code
#define ALOC_DECSTART 0x001 // start of declaration
#define ALOC_SYMDEF 0x002 // symbol defined
#define ALOC_PARAM 0x004 // follows function parameter
#define ALOC_FUNC 0x008 // follows function declaration
#define ATTR_LINK_MODIFIERS (mTYconst|mTYvolatile|mTYcdecl|mTYstdcall)
#define ATTR_CAN_IGNORE(a) \
(((a) & (ATTR_LINKMOD|ATTR_TYPEMOD|ATTR_FUNCINFO|ATTR_DATAINFO|ATTR_TRANSU)) == 0)
#define LNX_CHECK_ATTRIBUTES(a,x) assert(((a) & ~(x|ATTR_IGNORED|ATTR_WARNING)) == 0)
#if SCPP
#include "optdata.h"
#endif
#define TRIGRAPHS (ANSI || OPT_IS_SET(OPTtrigraphs))

61
backend/cg.c Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (C) 1984-1995 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include "cc.h"
#include "global.h"
#include "code.h"
#include "type.h"
#include "filespec.h"
///////////////////// GLOBALS /////////////////////
#include "fltables.c"
targ_size_t Poffset; /* size of func parameter variables */
targ_size_t framehandleroffset; // offset of C++ frame handler
#if TARGET_OSX
targ_size_t localgotoffset; // offset of where localgot refers to
#endif
int cseg = CODE; // current code segment
// (negative values mean it is the negative
// of the public name index of a COMDAT)
/* Stack offsets */
targ_size_t localsize, /* amt subtracted from SP for local vars */
Toff, /* base for temporaries */
Poff,Aoff; // comsubexps, params, regs, autos
/* The following are initialized for the 8088. cod3_set32() or cod3_set64()
* will change them as appropriate.
*/
int BPRM = 6; /* R/M value for [BP] or [EBP] */
regm_t fregsaved = mBP | mSI | mDI; // mask of registers saved across
// function calls
// (add in mBX for I32)
regm_t FLOATREGS = FLOATREGS_16;
regm_t FLOATREGS2 = FLOATREGS2_16;
regm_t DOUBLEREGS = DOUBLEREGS_16;
symbol *localgot; // reference to GOT for this function
symbol *tls_get_addr_sym; // function __tls_get_addr
#if TARGET_OSX
int STACKALIGN = 16;
#else
int STACKALIGN = 0;
#endif

3638
backend/cg87.c Normal file

File diff suppressed because it is too large Load Diff

2527
backend/cgcod.c Normal file

File diff suppressed because it is too large Load Diff

683
backend/cgcs.c Normal file
View File

@@ -0,0 +1,683 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2012 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <time.h>
#include "cc.h"
#include "oper.h"
#include "global.h"
#include "code.h"
#include "type.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
/*********************************
* Struct for each elem:
* Helem pointer to elem
* Hhash hash value for the elem
*/
typedef struct HCS
{ elem *Helem;
unsigned Hhash;
} hcs;
static hcs *hcstab = NULL; /* array of hcs's */
static unsigned hcsmax = 0; /* max index into hcstab[] */
static unsigned hcstop; /* # of entries in hcstab[] */
static unsigned touchstari;
static unsigned touchfunci[2];
// Use a bit vector for quick check if expression is possibly in hcstab[].
// This results in much faster compiles when hcstab[] gets big.
static vec_t csvec; // vector of used entries
#define CSVECDIM 16001 //8009 //3001 // dimension of csvec (should be prime)
STATIC void ecom(elem **);
STATIC unsigned cs_comphash(elem *);
STATIC void addhcstab(elem *,int);
STATIC void touchlvalue(elem *);
STATIC void touchfunc(int);
STATIC void touchstar(void);
STATIC void touchaccess(elem *);
/*******************************
* Eliminate common subexpressions across extended basic blocks.
* String together as many blocks as we can.
*/
void comsubs()
{ register block *bl,*blc,*bln;
register int n; /* # of blocks to treat as one */
//static int xx;
//printf("comsubs() %d\n", ++xx);
//debugx = (xx == 37);
#ifdef DEBUG
if (debugx) dbg_printf("comsubs(%p)\n",startblock);
#endif
// No longer do we just compute Bcount. We now eliminate unreachable
// blocks.
block_compbcount(); // eliminate unreachable blocks
#if SCPP
if (errcnt)
return;
#endif
if (!csvec)
{
csvec = vec_calloc(CSVECDIM);
}
for (bl = startblock; bl; bl = bln)
{
bln = bl->Bnext;
if (!bl->Belem)
continue; /* if no expression or no parents */
// Count up n, the number of blocks in this extended basic block (EBB)
n = 1; // always at least one block in EBB
blc = bl;
while (bln && list_nitems(bln->Bpred) == 1 &&
((blc->BC == BCiftrue &&
list_block(list_next(blc->Bsucc)) == bln) ||
(blc->BC == BCgoto && list_block(blc->Bsucc) == bln)
) &&
bln->BC != BCasm // no CSE's extending across ASM blocks
)
{
n++; // add block to EBB
blc = bln;
bln = blc->Bnext;
}
vec_clear(csvec);
hcstop = 0;
touchstari = 0;
touchfunci[0] = 0;
touchfunci[1] = 0;
bln = bl;
while (n--) // while more blocks in EBB
{
#ifdef DEBUG
if (debugx)
dbg_printf("cses for block %p\n",bln);
#endif
if (bln->Belem)
ecom(&bln->Belem); // do the tree
bln = bln->Bnext;
}
}
#ifdef DEBUG
if (debugx)
dbg_printf("done with comsubs()\n");
#endif
}
/*******************************
*/
void cgcs_term()
{
vec_free(csvec);
csvec = NULL;
#ifdef DEBUG
debugw && dbg_printf("freeing hcstab\n");
#endif
#if TX86
util_free(hcstab);
#else
MEM_PARF_FREE(hcstab);
#endif
hcstab = NULL;
hcsmax = 0;
}
/*************************
* Eliminate common subexpressions for an element.
*/
STATIC void ecom(elem **pe)
{ int i,op,hcstopsave;
unsigned hash;
elem *e,*ehash;
tym_t tym;
e = *pe;
assert(e);
elem_debug(e);
#ifdef DEBUG
assert(e->Ecount == 0);
//assert(e->Ecomsub == 0);
#endif
tym = tybasic(e->Ety);
op = e->Eoper;
switch (op)
{
case OPconst:
case OPvar:
case OPrelconst:
break;
case OPstreq:
case OPpostinc:
case OPpostdec:
case OPeq:
case OPaddass:
case OPminass:
case OPmulass:
case OPdivass:
case OPmodass:
case OPshrass:
case OPashrass:
case OPshlass:
case OPandass:
case OPxorass:
case OPorass:
#if TX86
/* Reverse order of evaluation for double op=. This is so that */
/* the pushing of the address of the second operand is easier. */
/* However, with the 8087 we don't need the kludge. */
if (op != OPeq && tym == TYdouble && !config.inline8087)
{ if (EOP(e->E1))
ecom(&e->E1->E1);
ecom(&e->E2);
}
else
#endif
{
/* Don't mark the increment of an i++ or i-- as a CSE, if it */
/* can be done with an INC or DEC instruction. */
if (!(OTpost(op) && elemisone(e->E2)))
ecom(&e->E2); /* evaluate 2nd operand first */
case OPnegass:
if (EOP(e->E1)) /* if lvalue is an operator */
{
#ifdef DEBUG
if (e->E1->Eoper != OPind)
elem_print(e);
#endif
assert(e->E1->Eoper == OPind);
ecom(&(e->E1->E1));
}
}
touchlvalue(e->E1);
if (!OTpost(op)) /* lvalue of i++ or i-- is not a cse*/
{
hash = cs_comphash(e->E1);
vec_setbit(hash % CSVECDIM,csvec);
addhcstab(e->E1,hash); // add lvalue to hcstab[]
}
return;
case OPbtc:
case OPbts:
case OPbtr:
ecom(&e->E1);
ecom(&e->E2);
touchfunc(0); // indirect assignment
return;
case OPandand:
case OPoror:
ecom(&e->E1);
hcstopsave = hcstop;
ecom(&e->E2);
hcstop = hcstopsave; /* no common subs by E2 */
return; /* if comsub then logexp() will */
/* break */
case OPcond:
ecom(&e->E1);
hcstopsave = hcstop;
ecom(&e->E2->E1); /* left condition */
hcstop = hcstopsave; /* no common subs by E2 */
ecom(&e->E2->E2); /* right condition */
hcstop = hcstopsave; /* no common subs by E2 */
return; /* can't be a common sub */
case OPcall:
case OPcallns:
ecom(&e->E2); /* eval right first */
/* FALL-THROUGH */
case OPucall:
case OPucallns:
ecom(&e->E1);
touchfunc(1);
return;
case OPstrpar: /* so we don't break logexp() */
#if TX86
case OPinp: /* never CSE the I/O instruction itself */
#endif
ecom(&e->E1);
/* FALL-THROUGH */
case OPasm:
case OPstrthis: // don't CSE these
case OPframeptr:
case OPgot:
case OPctor:
case OPdtor:
case OPdctor:
case OPmark:
return;
case OPddtor:
return;
case OPparam:
#if TX86
case OPoutp:
#endif
ecom(&e->E1);
case OPinfo:
ecom(&e->E2);
return;
case OPcomma:
case OPremquo:
ecom(&e->E1);
ecom(&e->E2);
break;
#if TARGET_SEGMENTED
case OPvp_fp:
case OPcvp_fp:
ecom(&e->E1);
touchaccess(e);
break;
#endif
case OPind:
ecom(&e->E1);
/* Generally, CSEing a *(double *) results in worse code */
if (tyfloating(tym))
return;
break;
#if TX86
case OPstrcpy:
case OPstrcat:
case OPmemcpy:
case OPmemset:
ecom(&e->E2);
case OPsetjmp:
ecom(&e->E1);
touchfunc(0);
return;
#endif
default: /* other operators */
#if TX86
#ifdef DEBUG
if (!EBIN(e)) WROP(e->Eoper);
#endif
assert(EBIN(e));
case OPadd:
case OPmin:
case OPmul:
case OPdiv:
case OPor:
case OPxor:
case OPand:
case OPeqeq:
case OPne:
case OPscale:
case OPyl2x:
case OPyl2xp1:
ecom(&e->E1);
ecom(&e->E2);
break;
#else
#ifdef DEBUG
if (!EOP(e)) WROP(e->Eoper);
#endif
assert(EOP(e));
ecom(&e->E1);
if (EBIN(e))
ecom(&e->E2); /* eval left first */
break;
#endif
case OPstring:
case OPaddr:
case OPbit:
#ifdef DEBUG
WROP(e->Eoper);
elem_print(e);
#endif
assert(0); /* optelem() should have removed these */
/* NOTREACHED */
// Explicitly list all the unary ops for speed
case OPnot: case OPcom: case OPneg: case OPuadd:
case OPabs: case OPsqrt: case OPrndtol: case OPsin: case OPcos: case OPrint:
case OPpreinc: case OPpredec:
case OPbool: case OPstrlen: case OPs16_32: case OPu16_32:
case OPd_s32: case OPd_u32:
case OPs32_d: case OPu32_d: case OPd_s16: case OPs16_d: case OP32_16:
case OPd_f: case OPf_d:
case OPd_ld: case OPld_d:
case OPc_r: case OPc_i:
case OPu8_16: case OPs8_16: case OP16_8:
case OPu32_64: case OPs32_64: case OP64_32: case OPmsw:
case OPu64_128: case OPs64_128: case OP128_64:
case OPd_s64: case OPs64_d: case OPd_u64: case OPu64_d:
case OPstrctor: case OPu16_d: case OPd_u16:
case OParrow:
case OPvoid: case OPnullcheck:
case OPbsf: case OPbsr: case OPbswap: case OPvector:
case OPld_u64:
#if TARGET_SEGMENTED
case OPoffset: case OPnp_fp: case OPnp_f16p: case OPf16p_np:
#endif
ecom(&e->E1);
break;
case OPhalt:
return;
}
/* don't CSE structures or unions or volatile stuff */
if (tym == TYstruct ||
tym == TYvoid ||
e->Ety & mTYvolatile
#if TX86
|| tyxmmreg(tym)
// don't CSE doubles if inline 8087 code (code generator can't handle it)
|| (tyfloating(tym) && config.inline8087)
#endif
)
return;
hash = cs_comphash(e); /* must be AFTER leaves are done */
/* Search for a match in hcstab[].
* Search backwards, as most likely matches will be towards the end
* of the list.
*/
#ifdef DEBUG
if (debugx) dbg_printf("elem: %p hash: %6d\n",e,hash);
#endif
int csveci = hash % CSVECDIM;
if (vec_testbit(csveci,csvec))
{
for (i = hcstop; i--;)
{
#ifdef DEBUG
if (debugx)
dbg_printf("i: %2d Hhash: %6d Helem: %p\n",
i,hcstab[i].Hhash,hcstab[i].Helem);
#endif
if (hash == hcstab[i].Hhash && (ehash = hcstab[i].Helem) != NULL)
{
/* if elems are the same and we still have room for more */
if (el_match(e,ehash) && ehash->Ecount < 0xFF)
{
/* Make sure leaves are also common subexpressions
* to avoid false matches.
*/
if (!OTleaf(op))
{
if (!e->E1->Ecount)
continue;
if (OTbinary(op) && !e->E2->Ecount)
continue;
}
ehash->Ecount++;
*pe = ehash;
#ifdef DEBUG
if (debugx)
dbg_printf("**MATCH** %p with %p\n",e,*pe);
#endif
el_free(e);
return;
}
}
}
}
else
vec_setbit(csveci,csvec);
addhcstab(e,hash); // add this elem to hcstab[]
}
/**************************
* Compute hash function for elem e.
*/
STATIC unsigned cs_comphash(elem *e)
{ register int hash;
unsigned op;
elem_debug(e);
op = e->Eoper;
#if TX86
hash = (e->Ety & (mTYbasic | mTYconst | mTYvolatile)) + (op << 8);
#else
hash = e->Ety + op;
#endif
if (!OTleaf(op))
{ hash += (size_t) e->E1;
if (OTbinary(op))
hash += (size_t) e->E2;
}
else
{ hash += e->EV.Vint;
if (op == OPvar || op == OPrelconst)
hash += (size_t) e->EV.sp.Vsym;
}
return hash;
}
/****************************
* Add an elem to the common subexpression table.
* Recompute hash if it is 0.
*/
STATIC void addhcstab(elem *e,int hash)
{ unsigned h = hcstop;
if (h >= hcsmax) /* need to reallocate table */
{
assert(h == hcsmax);
// With 32 bit compiles, we've got memory to burn
hcsmax += (__INTSIZE == 4) ? (hcsmax + 128) : 100;
assert(h < hcsmax);
#if TX86
hcstab = (hcs *) util_realloc(hcstab,hcsmax,sizeof(hcs));
#else
hcstab = (hcs *) MEM_PARF_REALLOC(hcstab,hcsmax*sizeof(hcs));
#endif
//printf("hcstab = %p; hcstop = %d, hcsmax = %d\n",hcstab,hcstop,hcsmax);
}
hcstab[h].Helem = e;
hcstab[h].Hhash = hash;
hcstop++;
}
/***************************
* "touch" the elem.
* If it is a pointer, "touch" all the suspects
* who could be pointed to.
* Eliminate common subs that are indirect loads.
*/
STATIC void touchlvalue(elem *e)
{ register int i;
if (e->Eoper == OPind) /* if indirect store */
{
/* NOTE: Some types of array assignments do not need
* to touch all variables. (Like a[5], where a is an
* array instead of a pointer.)
*/
touchfunc(0);
return;
}
for (i = hcstop; --i >= 0;)
{ if (hcstab[i].Helem &&
hcstab[i].Helem->EV.sp.Vsym == e->EV.sp.Vsym)
hcstab[i].Helem = NULL;
}
assert(e->Eoper == OPvar || e->Eoper == OPrelconst);
switch (e->EV.sp.Vsym->Sclass)
{
case SCregpar:
case SCregister:
case SCtmp:
case SCpseudo:
break;
case SCauto:
case SCparameter:
case SCfastpar:
case SCbprel:
if (e->EV.sp.Vsym->Sflags & SFLunambig)
break;
/* FALL-THROUGH */
case SCstatic:
case SCextern:
case SCglobal:
case SClocstat:
case SCcomdat:
case SCinline:
case SCsinline:
case SCeinline:
case SCcomdef:
touchstar();
break;
default:
#ifdef DEBUG
elem_print(e);
symbol_print(e->EV.sp.Vsym);
#endif
assert(0);
}
}
/**************************
* "touch" variables that could be changed by a function call or
* an indirect assignment.
* Eliminate any subexpressions that are "starred" (they need to
* be recomputed).
* Input:
* flag If !=0, then this is a function call.
* If 0, then this is an indirect assignment.
*/
STATIC void touchfunc(int flag)
{ register hcs *pe,*petop;
register elem *he;
//printf("touchfunc(%d)\n", flag);
petop = &hcstab[hcstop];
//pe = &hcstab[0]; printf("pe = %p, petop = %p\n",pe,petop);
for (pe = &hcstab[0]; pe < petop; pe++)
//for (pe = &hcstab[touchfunci[flag]]; pe < petop; pe++)
{ he = pe->Helem;
if (!he)
continue;
switch (he->Eoper)
{
case OPvar:
switch (he->EV.sp.Vsym->Sclass)
{
case SCregpar:
case SCregister:
case SCtmp:
break;
case SCauto:
case SCparameter:
case SCfastpar:
case SCbprel:
//printf("he = '%s'\n", he->EV.sp.Vsym->Sident);
if (he->EV.sp.Vsym->Sflags & SFLunambig)
break;
/* FALL-THROUGH */
case SCstatic:
case SCextern:
case SCcomdef:
case SCglobal:
case SClocstat:
case SCcomdat:
case SCpseudo:
case SCinline:
case SCsinline:
case SCeinline:
if (!(he->EV.sp.Vsym->ty() & mTYconst))
goto L1;
break;
default:
debug(WRclass((enum SC)he->EV.sp.Vsym->Sclass));
assert(0);
}
break;
case OPind:
#if TX86
case OPstrlen:
case OPstrcmp:
case OPmemcmp:
case OPbt:
#endif
goto L1;
#if TARGET_SEGMENTED
case OPvp_fp:
case OPcvp_fp:
if (flag == 0) /* function calls destroy vptrfptr's, */
break; /* not indirect assignments */
#endif
L1:
pe->Helem = NULL;
break;
}
}
touchfunci[flag] = hcstop;
}
/*******************************
* Eliminate all common subexpressions that
* do any indirection ("starred" elems).
*/
STATIC void touchstar()
{ register int i;
register elem *e;
for (i = touchstari; i < hcstop; i++)
{ e = hcstab[i].Helem;
if (e && (e->Eoper == OPind || e->Eoper == OPbt) /*&& !(e->Ety & mTYconst)*/)
hcstab[i].Helem = NULL;
}
touchstari = hcstop;
}
#if TARGET_SEGMENTED
/*****************************************
* Eliminate any common subexpressions that could be modified
* if a handle pointer access occurs.
*/
STATIC void touchaccess(elem *ev)
{ register int i;
register elem *e;
ev = ev->E1;
for (i = 0; i < hcstop; i++)
{ e = hcstab[i].Helem;
/* Invalidate any previous handle pointer accesses that */
/* are not accesses of ev. */
if (e && (e->Eoper == OPvp_fp || e->Eoper == OPcvp_fp) && e->E1 != ev)
hcstab[i].Helem = NULL;
}
}
#endif
#endif // !SPP

2705
backend/cgcv.c Normal file

File diff suppressed because it is too large Load Diff

76
backend/cgcv.h Normal file
View File

@@ -0,0 +1,76 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/* Header for cgcv.c */
#ifndef CGCV_H
#define CGCV_H
//#pragma once
extern char *ftdbname;
void cv_init ( void );
unsigned cv_typidx ( type *t );
void cv_outsym ( Symbol *s );
void cv_func ( Symbol *s );
void cv_term ( void );
unsigned long cv4_struct(Classsym *,int);
/* =================== Added for MARS compiler ========================= */
typedef unsigned long idx_t; // type of type index
/* Data structure for a type record */
#pragma pack(1)
typedef struct DEBTYP_T
{
unsigned prev; // previous debtyp_t with same hash
unsigned short length; // length of following array
unsigned char data[2]; // variable size array
} debtyp_t;
#pragma pack()
struct Cgcv
{
long signature;
symlist_t list; // deferred list of symbols to output
idx_t deb_offset; // offset added to type index
unsigned sz_idx; // size of stored type index
int LCFDoffset;
int LCFDpointer;
int FD_code; // frame for references to code
};
extern Cgcv cgcv;
debtyp_t * debtyp_alloc(unsigned length);
int cv_stringbytes(const char *name);
inline unsigned cv4_numericbytes(targ_size_t value);
void cv4_storenumeric(unsigned char *p,targ_size_t value);
idx_t cv_debtyp ( debtyp_t *d );
int cv_namestring ( unsigned char *p , const char *name );
unsigned cv4_typidx(type *t);
idx_t cv4_arglist(type *t,unsigned *pnparam);
unsigned char cv4_callconv(type *t);
#define TOIDX(a,b) ((cgcv.sz_idx == 4) ? TOLONG(a,b) : TOWORD(a,b))
#define DEBSYM 5 /* segment of symbol info */
#define DEBTYP 6 /* segment of type info */
#endif

4522
backend/cgelem.c Normal file

File diff suppressed because it is too large Load Diff

781
backend/cgen.c Normal file
View File

@@ -0,0 +1,781 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "el.h"
#include "oper.h"
#include "code.h"
#include "type.h"
#include "global.h"
#include "aa.h"
#include "dt.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
/*************************************
* Handy function to answer the question: who the heck is generating this piece of code?
*/
inline void ccheck(code *cs)
{
// if (cs->Iop == LEA && (cs->Irm & 0x3F) == 0x34 && cs->Isib == 7) *(char*)0=0;
// if (cs->Iop == 0x31) *(char*)0=0;
// if (cs->Irm == 0x3D) *(char*)0=0;
}
/*****************************
* Find last code in list.
*/
code *code_last(code *c)
{
if (c)
{ while (c->next)
c = c->next;
}
return c;
}
/*****************************
* Set flag bits on last code in list.
*/
void code_orflag(code *c,unsigned flag)
{
if (flag && c)
{ while (c->next)
c = c->next;
c->Iflags |= flag;
}
}
/*****************************
* Set rex bits on last code in list.
*/
void code_orrex(code *c,unsigned rex)
{
if (rex && c)
{ while (c->next)
c = c->next;
c->Irex |= rex;
}
}
/**************************************
* Set the opcode fields in cs.
*/
code *setOpcode(code *c, code *cs, unsigned op)
{
cs->Iop = op;
return c;
}
/*****************************
* Concatenate two code lists together. Return pointer to result.
*/
#if TX86 && __INTSIZE == 4 && __SC__
__declspec(naked) code * __pascal cat(code *c1,code *c2)
{
_asm
{
mov EAX,c1-4[ESP]
mov ECX,c2-4[ESP]
test EAX,EAX
jne L6D
mov EAX,ECX
ret 8
L6D: mov EDX,EAX
cmp dword ptr [EAX],0
je L7B
L74: mov EDX,[EDX]
cmp dword ptr [EDX],0
jne L74
L7B: mov [EDX],ECX
ret 8
}
}
#else
code * __pascal cat(code *c1,code *c2)
{ code **pc;
if (!c1)
return c2;
for (pc = &code_next(c1); *pc; pc = &code_next(*pc))
;
*pc = c2;
return c1;
}
#endif
code * cat3(code *c1,code *c2,code *c3)
{ code **pc;
for (pc = &c1; *pc; pc = &code_next(*pc))
;
for (*pc = c2; *pc; pc = &code_next(*pc))
;
*pc = c3;
return c1;
}
code * cat4(code *c1,code *c2,code *c3,code *c4)
{ code **pc;
for (pc = &c1; *pc; pc = &code_next(*pc))
;
for (*pc = c2; *pc; pc = &code_next(*pc))
;
for (*pc = c3; *pc; pc = &code_next(*pc))
;
*pc = c4;
return c1;
}
code * cat6(code *c1,code *c2,code *c3,code *c4,code *c5,code *c6)
{ return cat(cat4(c1,c2,c3,c4),cat(c5,c6)); }
/*****************************
* Add code to end of linked list.
* Note that unused operands are garbage.
* gen1() and gen2() are shortcut routines.
* Input:
* c -> linked list that code is to be added to end of
* cs -> data for the code
* Returns:
* pointer to start of code list
*/
code *gen(code *c,code *cs)
{ code *ce,*cstart;
unsigned reg;
#ifdef DEBUG /* this is a high usage routine */
assert(cs);
#endif
assert(I64 || cs->Irex == 0);
ce = code_calloc();
*ce = *cs;
//printf("ce = %p %02x\n", ce, ce->Iop);
ccheck(ce);
if (config.flags4 & CFG4optimized &&
(ce->Iop == 0x81 || ce->Iop == 0x80) &&
ce->IFL2 == FLconst &&
reghasvalue((ce->Iop == 0x80) ? BYTEREGS : ALLREGS,I64 ? ce->IEV2.Vsize_t : ce->IEV2.Vlong,&reg) &&
!(ce->Iflags & CFopsize && I16)
)
{ // See if we can replace immediate instruction with register instruction
static unsigned char regop[8] =
{ 0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38 };
//printf("replacing 0x%02x, val = x%lx\n",ce->Iop,ce->IEV2.Vlong);
ce->Iop = regop[(ce->Irm & modregrm(0,7,0)) >> 3] | (ce->Iop & 1);
code_newreg(ce, reg);
}
code_next(ce) = CNIL;
if (c)
{ cstart = c;
while (code_next(c)) c = code_next(c); /* find end of list */
code_next(c) = ce; /* link into list */
return cstart;
}
return ce;
}
code *gen1(code *c,unsigned op)
{ code *ce,*cstart;
ce = code_calloc();
ce->Iop = op;
ccheck(ce);
assert(op != LEA);
if (c)
{ cstart = c;
while (code_next(c)) c = code_next(c); /* find end of list */
code_next(c) = ce; /* link into list */
return cstart;
}
return ce;
}
code *gen2(code *c,unsigned op,unsigned rm)
{ code *ce,*cstart;
cstart = ce = code_calloc();
/*cxcalloc++;*/
ce->Iop = op;
ce->Iea = rm;
ccheck(ce);
if (c)
{ cstart = c;
while (code_next(c)) c = code_next(c); /* find end of list */
code_next(c) = ce; /* link into list */
}
return cstart;
}
code *gen2sib(code *c,unsigned op,unsigned rm,unsigned sib)
{ code *ce,*cstart;
cstart = ce = code_calloc();
/*cxcalloc++;*/
ce->Iop = op;
ce->Irm = rm;
ce->Isib = sib;
ce->Irex = (rm | (sib & (REX_B << 16))) >> 16;
if (sib & (REX_R << 16))
ce->Irex |= REX_X;
ccheck(ce);
if (c)
{ cstart = c;
while (code_next(c)) c = code_next(c); /* find end of list */
code_next(c) = ce; /* link into list */
}
return cstart;
}
/********************************
* Generate an ASM sequence.
*/
code *genasm(code *c,char *s,unsigned slen)
{ code *ce;
ce = code_calloc();
ce->Iop = ASM;
ce->IFL1 = FLasm;
ce->IEV1.as.len = slen;
ce->IEV1.as.bytes = (char *) mem_malloc(slen);
memcpy(ce->IEV1.as.bytes,s,slen);
return cat(c,ce);
}
code *gencs(code *c,unsigned op,unsigned ea,unsigned FL2,symbol *s)
{ code cs;
cs.Iop = op;
cs.Iea = ea;
ccheck(&cs);
cs.Iflags = 0;
cs.IFL2 = FL2;
cs.IEVsym2 = s;
cs.IEVoffset2 = 0;
return gen(c,&cs);
}
code *genc2(code *c,unsigned op,unsigned ea,targ_size_t EV2)
{ code cs;
cs.Iop = op;
cs.Iea = ea;
ccheck(&cs);
cs.Iflags = CFoff;
cs.IFL2 = FLconst;
cs.IEV2.Vsize_t = EV2;
return gen(c,&cs);
}
/*****************
* Generate code.
*/
code *genc1(code *c,unsigned op,unsigned ea,unsigned FL1,targ_size_t EV1)
{ code cs;
assert(FL1 < FLMAX);
cs.Iop = op;
cs.Iflags = CFoff;
cs.Iea = ea;
ccheck(&cs);
cs.IFL1 = FL1;
cs.IEV1.Vsize_t = EV1;
return gen(c,&cs);
}
/*****************
* Generate code.
*/
code *genc(code *c,unsigned op,unsigned ea,unsigned FL1,targ_size_t EV1,unsigned FL2,targ_size_t EV2)
{ code cs;
assert(FL1 < FLMAX);
cs.Iop = op;
cs.Iea = ea;
ccheck(&cs);
cs.Iflags = CFoff;
cs.IFL1 = FL1;
cs.IEV1.Vsize_t = EV1;
assert(FL2 < FLMAX);
cs.IFL2 = FL2;
cs.IEV2.Vsize_t = EV2;
return gen(c,&cs);
}
/********************************
* Generate 'instruction' which is actually a line number.
*/
code *genlinnum(code *c,Srcpos srcpos)
{ code cs;
#if 0
srcpos.print("genlinnum");
#endif
cs.Iop = ESCAPE | ESClinnum;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = 0;
cs.IFL2 = 0;
cs.IEV1.Vsrcpos = srcpos;
return gen(c,&cs);
}
/******************************
* Append line number to existing code.
*/
void cgen_linnum(code **pc,Srcpos srcpos)
{
*pc = genlinnum(*pc,srcpos);
}
/*****************************
* Prepend line number to existing code.
*/
void cgen_prelinnum(code **pc,Srcpos srcpos)
{
*pc = cat(genlinnum(NULL,srcpos),*pc);
}
/********************************
* Generate 'instruction' which tells the address resolver that the stack has
* changed.
*/
code *genadjesp(code *c, int offset)
{ code cs;
if (!I16 && offset)
{
cs.Iop = ESCAPE | ESCadjesp;
cs.Iflags = 0;
cs.Irex = 0;
cs.IEV1.Vint = offset;
return gen(c,&cs);
}
else
return c;
}
/********************************
* Generate 'instruction' which tells the scheduler that the fpu stack has
* changed.
*/
code *genadjfpu(code *c, int offset)
{ code cs;
if (!I16 && offset)
{
cs.Iop = ESCAPE | ESCadjfpu;
cs.Iflags = 0;
cs.Irex = 0;
cs.IEV1.Vint = offset;
return gen(c,&cs);
}
else
return c;
}
/********************************
* Generate 'nop'
*/
code *gennop(code *c)
{
return gen1(c,NOP);
}
/****************************************
* Clean stack after call to codelem().
*/
code *gencodelem(code *c,elem *e,regm_t *pretregs,bool constflag)
{
if (e)
{
unsigned stackpushsave;
int stackcleansave;
stackpushsave = stackpush;
stackcleansave = cgstate.stackclean;
cgstate.stackclean = 0; // defer cleaning of stack
c = cat(c,codelem(e,pretregs,constflag));
assert(cgstate.stackclean == 0);
cgstate.stackclean = stackcleansave;
c = genstackclean(c,stackpush - stackpushsave,*pretregs); // do defered cleaning
}
return c;
}
/**********************************
* Determine if one of the registers in regm has value in it.
* If so, return !=0 and set *preg to which register it is.
*/
bool reghasvalue(regm_t regm,targ_size_t value,unsigned *preg)
{
//printf("reghasvalue(%s, %llx)\n", regm_str(regm), (unsigned long long)value);
/* See if another register has the right value */
unsigned r = 0;
for (regm_t mreg = regcon.immed.mval; mreg; mreg >>= 1)
{
if (mreg & regm & 1 && regcon.immed.value[r] == value)
{ *preg = r;
return TRUE;
}
r++;
regm >>= 1;
}
return FALSE;
}
/**************************************
* Load a register from the mask regm with value.
* Output:
* *preg the register selected
*/
code *regwithvalue(code *c,regm_t regm,targ_size_t value,unsigned *preg,regm_t flags)
{ unsigned reg;
if (!preg)
preg = &reg;
/* If we don't already have a register with the right value in it */
if (!reghasvalue(regm,value,preg))
{ regm_t save;
save = regcon.immed.mval;
c = cat(c,allocreg(&regm,preg,TYint)); // allocate register
regcon.immed.mval = save;
c = movregconst(c,*preg,value,flags); // store value into reg
}
return c;
}
/************************
* When we don't know whether a function symbol is defined or not
* within this module, we stuff it in this linked list of references
* to be fixed up later.
*/
struct fixlist
{ //symbol *Lsymbol; // symbol we don't know about
int Lseg; // where the fixup is going (CODE or DATA, never UDATA)
int Lflags; // CFxxxx
targ_size_t Loffset; // addr of reference to symbol
targ_size_t Lval; // value to add into location
#if TARGET_OSX
symbol *Lfuncsym; // function the symbol goes in
#endif
fixlist *Lnext; // next in threaded list
static AArray *start;
static int nodel; // don't delete from within searchfixlist
};
AArray *fixlist::start = NULL;
int fixlist::nodel = 0;
/* The AArray, being hashed on the pointer value of the symbol s, is in a different
* order from run to run. This plays havoc with trying to compare the .obj file output.
* When needing to do that, set FLARRAY to 1. This will replace the AArray with a
* simple (and very slow) linear array. Handy for tracking down compiler issues, though.
*/
#define FLARRAY 0
#if FLARRAY
struct Flarray
{
symbol *s;
fixlist *fl;
};
Flarray *flarray;
size_t flarray_dim;
size_t flarray_max;
#endif
/****************************
* Add to the fix list.
*/
void addtofixlist(symbol *s,targ_size_t soffset,int seg,targ_size_t val,int flags)
{ fixlist *ln;
static char zeros[8];
int numbytes;
//printf("addtofixlist(%p '%s')\n",s,s->Sident);
assert(flags);
ln = (fixlist *) mem_calloc(sizeof(fixlist));
//ln->Lsymbol = s;
ln->Loffset = soffset;
ln->Lseg = seg;
ln->Lflags = flags;
ln->Lval = val;
#if TARGET_OSX
ln->Lfuncsym = funcsym_p;
#endif
#if FLARRAY
fixlist **pv;
for (size_t i = 0; 1; i++)
{
if (i == flarray_dim)
{
if (flarray_dim == flarray_max)
{
flarray_max = flarray_max * 2 + 1000;
flarray = (Flarray *)mem_realloc(flarray, flarray_max * sizeof(flarray[0]));
}
flarray_dim += 1;
flarray[i].s = s;
flarray[i].fl = NULL;
pv = &flarray[i].fl;
break;
}
if (flarray[i].s == s)
{
pv = &flarray[i].fl;
break;
}
}
#else
if (!fixlist::start)
fixlist::start = new AArray(&ti_pvoid, sizeof(fixlist *));
fixlist **pv = (fixlist **)fixlist::start->get(&s);
#endif
ln->Lnext = *pv;
*pv = ln;
#if TARGET_SEGMENTED
switch (flags & (CFoff | CFseg))
{
case CFoff: numbytes = tysize[TYnptr]; break;
case CFseg: numbytes = 2; break;
case CFoff | CFseg: numbytes = tysize[TYfptr]; break;
default: assert(0);
}
#else
numbytes = tysize[TYnptr];
if (I64 && !(flags & CFoffset64))
numbytes = 4;
assert(!(flags & CFseg));
#endif
#ifdef DEBUG
assert(numbytes <= sizeof(zeros));
#endif
obj_bytes(seg,soffset,numbytes,zeros);
}
/****************************
* Given a function symbol we've just defined the offset for,
* search for it in the fixlist, and resolve any matches we find.
* Input:
* s function symbol just defined
*/
void searchfixlist(symbol *s)
{
//printf("searchfixlist(%s)\n",s->Sident);
if (fixlist::start)
{
#if FLARRAY
fixlist **lp = NULL;
size_t i;
for (i = 0; i < flarray_dim; i++)
{
if (flarray[i].s == s)
{ lp = &flarray[i].fl;
break;
}
}
#else
fixlist **lp = (fixlist **)fixlist::start->in(&s);
#endif
if (lp)
{ fixlist *p;
while ((p = *lp) != NULL)
{
//dbg_printf("Found reference at x%lx\n",p->Loffset);
// Determine if it is a self-relative fixup we can
// resolve directly.
if (s->Sseg == p->Lseg &&
(s->Sclass == SCstatic ||
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
(!(config.flags3 & CFG3pic) && s->Sclass == SCglobal)) &&
#else
s->Sclass == SCglobal) &&
#endif
s->Sxtrnnum == 0 && p->Lflags & CFselfrel)
{ targ_size_t ad;
//printf("Soffset = x%lx, Loffset = x%lx, Lval = x%lx\n",s->Soffset,p->Loffset,p->Lval);
ad = s->Soffset - p->Loffset - REGSIZE + p->Lval;
obj_bytes(p->Lseg,p->Loffset,REGSIZE,&ad);
}
else
{
#if TARGET_OSX
symbol *funcsymsave = funcsym_p;
funcsym_p = p->Lfuncsym;
reftoident(p->Lseg,p->Loffset,s,p->Lval,p->Lflags);
funcsym_p = funcsymsave;
#else
reftoident(p->Lseg,p->Loffset,s,p->Lval,p->Lflags);
#endif
}
*lp = p->Lnext;
mem_free(p); /* remove from list */
}
if (!fixlist::nodel)
{
#if FLARRAY
flarray[i].s = NULL;
if (i + 1 == flarray_dim)
flarray_dim -= 1;
#else
fixlist::start->del(&s);
#endif
}
}
}
}
/****************************
* End of module. Output remaining fixlist elements as references
* to external symbols.
*/
STATIC int outfixlist_dg(void *parameter, void *pkey, void *pvalue)
{
//printf("outfixlist_dg(pkey = %p, pvalue = %p)\n", pkey, pvalue);
symbol *s = *(symbol **)pkey;
fixlist **plnext = (fixlist **)pvalue;
while (*plnext)
{
fixlist *ln = *plnext;
symbol_debug(s);
//printf("outfixlist '%s' offset %04x\n",s->Sident,ln->Loffset);
#if TARGET_SEGMENTED
if (tybasic(s->ty()) == TYf16func)
{
obj_far16thunk(s); /* make it into a thunk */
searchfixlist(s);
}
else
#endif
{
if (s->Sxtrnnum == 0)
{ if (s->Sclass == SCstatic)
{
#if SCPP
if (s->Sdt)
{
outdata(s);
searchfixlist(s);
continue;
}
synerr(EM_no_static_def,prettyident(s)); // no definition found for static
#else // MARS
printf("Error: no definition for static %s\n",prettyident(s)); // no definition found for static
err_exit(); // BUG: do better
#endif
}
if (s->Sflags & SFLwasstatic)
{
// Put it in BSS
s->Sclass = SCstatic;
s->Sfl = FLunde;
dtnzeros(&s->Sdt,type_size(s->Stype));
outdata(s);
searchfixlist(s);
continue;
}
s->Sclass = SCextern; /* make it external */
objextern(s);
if (s->Sflags & SFLweak)
{
obj_wkext(s, NULL);
}
}
#if TARGET_OSX
symbol *funcsymsave = funcsym_p;
funcsym_p = ln->Lfuncsym;
reftoident(ln->Lseg,ln->Loffset,s,ln->Lval,ln->Lflags);
funcsym_p = funcsymsave;
#else
reftoident(ln->Lseg,ln->Loffset,s,ln->Lval,ln->Lflags);
#endif
*plnext = ln->Lnext;
#if TERMCODE
mem_free(ln);
#endif
}
}
s->Sxtrnnum = 0;
return 0;
}
void outfixlist()
{
//printf("outfixlist()\n");
#if FLARRAY
for (size_t i = 0; i < flarray_dim; i++)
{
fixlist::nodel++;
outfixlist_dg(NULL, &flarray[i].s, &flarray[i].fl);
fixlist::nodel--;
}
#else
if (fixlist::start)
{
fixlist::nodel++;
fixlist::start->apply(NULL, &outfixlist_dg);
fixlist::nodel--;
#if TERMCODE
delete fixlist::start;
#endif
fixlist::start = NULL;
}
#endif
}
#endif // !SPP

3680
backend/cgobj.c Normal file

File diff suppressed because it is too large Load Diff

1013
backend/cgreg.c Normal file

File diff suppressed because it is too large Load Diff

3206
backend/cgsched.c Normal file

File diff suppressed because it is too large Load Diff

780
backend/cgxmm.c Normal file
View File

@@ -0,0 +1,780 @@
// Copyright (C) 2011-2012 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "cc.h"
#include "oper.h"
#include "el.h"
#include "code.h"
#include "global.h"
#include "type.h"
#if SCPP
#include "exh.h"
#endif
#include "xmm.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
unsigned xmmoperator(tym_t tym, unsigned oper);
/*******************************************
* Move constant value into xmm register xreg.
*/
code *movxmmconst(unsigned xreg, unsigned sz, targ_size_t value, regm_t flags)
{
/* Generate:
* MOV reg,value
* MOV xreg,reg
* Not so efficient. We should at least do a PXOR for 0.
*/
assert(mask[xreg] & XMMREGS);
assert(sz == 4 || sz == 8);
code *c;
if (I32 && sz == 8)
{
unsigned r;
regm_t rm = ALLREGS;
c = allocreg(&rm,&r,TYint); // allocate scratch register
union { targ_size_t s; targ_long l[2]; } u;
u.l[1] = 0;
u.s = value;
targ_long *p = &u.l[0];
c = movregconst(c,r,p[0],0);
c = genfltreg(c,0x89,r,0); // MOV floatreg,r
c = movregconst(c,r,p[1],0);
c = genfltreg(c,0x89,r,4); // MOV floatreg+4,r
unsigned op = xmmload(TYdouble);
c = genfltreg(c,op,xreg - XMM0,0); // MOVSD XMMreg,floatreg
}
else
{
unsigned reg;
c = regwithvalue(CNIL,ALLREGS,value,&reg,(sz == 8) ? 64 : 0);
c = gen2(c,LODD,modregxrmx(3,xreg-XMM0,reg)); // MOVD xreg,reg
if (sz == 8)
code_orrex(c, REX_W);
}
return c;
}
/***********************************************
* Do simple orthogonal operators for XMM registers.
*/
code *orthxmm(elem *e, regm_t *pretregs)
{ elem *e1 = e->E1;
elem *e2 = e->E2;
regm_t retregs = *pretregs & XMMREGS;
if (!retregs)
retregs = XMMREGS;
code *c = codelem(e1,&retregs,FALSE); // eval left leaf
unsigned reg = findreg(retregs);
regm_t rretregs = XMMREGS & ~retregs;
code *cr = scodelem(e2, &rretregs, retregs, TRUE); // eval right leaf
unsigned op = xmmoperator(e1->Ety, e->Eoper);
unsigned rreg = findreg(rretregs);
code *cg;
if (OTrel(e->Eoper))
{
retregs = mPSW;
cg = NULL;
code *cc = gen2(CNIL,op,modregxrmx(3,rreg-XMM0,reg-XMM0));
return cat4(c,cr,cg,cc);
}
else
cg = getregs(retregs);
code *co = gen2(CNIL,op,modregxrmx(3,reg-XMM0,rreg-XMM0));
if (retregs != *pretregs)
co = cat(co,fixresult(e,retregs,pretregs));
return cat4(c,cr,cg,co);
}
/************************
* Generate code for an assignment using XMM registers.
*/
code *xmmeq(elem *e,regm_t *pretregs)
{
tym_t tymll;
unsigned reg;
int i;
code *cl,*cr,*c,cs;
elem *e11;
bool regvar; /* TRUE means evaluate into register variable */
regm_t varregm;
unsigned varreg;
targ_int postinc;
//printf("xmmeq(e = %p, *pretregs = %s)\n", e, regm_str(*pretregs));
elem *e1 = e->E1;
elem *e2 = e->E2;
int e2oper = e2->Eoper;
tym_t tyml = tybasic(e1->Ety); /* type of lvalue */
regm_t retregs = *pretregs;
if (!(retregs & XMMREGS))
retregs = XMMREGS; // pick any XMM reg
cs.Iop = xmmstore(tyml);
regvar = FALSE;
varregm = 0;
if (config.flags4 & CFG4optimized)
{
// Be careful of cases like (x = x+x+x). We cannot evaluate in
// x if x is in a register.
if (isregvar(e1,&varregm,&varreg) && // if lvalue is register variable
doinreg(e1->EV.sp.Vsym,e2) // and we can compute directly into it
)
{ regvar = TRUE;
retregs = varregm;
reg = varreg; /* evaluate directly in target register */
}
}
if (*pretregs & mPSW && !EOP(e1)) // if evaluating e1 couldn't change flags
{ // Be careful that this lines up with jmpopcode()
retregs |= mPSW;
*pretregs &= ~mPSW;
}
cr = scodelem(e2,&retregs,0,TRUE); // get rvalue
// Look for special case of (*p++ = ...), where p is a register variable
if (e1->Eoper == OPind &&
((e11 = e1->E1)->Eoper == OPpostinc || e11->Eoper == OPpostdec) &&
e11->E1->Eoper == OPvar &&
e11->E1->EV.sp.Vsym->Sfl == FLreg
)
{
postinc = e11->E2->EV.Vint;
if (e11->Eoper == OPpostdec)
postinc = -postinc;
cl = getlvalue(&cs,e11,RMstore | retregs);
freenode(e11->E2);
}
else
{ postinc = 0;
cl = getlvalue(&cs,e1,RMstore | retregs); // get lvalue (cl == CNIL if regvar)
}
c = getregs_imm(varregm);
reg = findreg(retregs & XMMREGS);
cs.Irm |= modregrm(0,(reg - XMM0) & 7,0);
if ((reg - XMM0) & 8)
cs.Irex |= REX_R;
// Do not generate mov from register onto itself
if (!(regvar && reg == XMM0 + ((cs.Irm & 7) | (cs.Irex & REX_B ? 8 : 0))))
c = gen(c,&cs); // MOV EA+offset,reg
if (e1->Ecount || // if lvalue is a CSE or
regvar) // rvalue can't be a CSE
{
c = cat(c,getregs_imm(retregs)); // necessary if both lvalue and
// rvalue are CSEs (since a reg
// can hold only one e at a time)
cssave(e1,retregs,EOP(e1)); // if lvalue is a CSE
}
c = cat4(cr,cl,c,fixresult(e,retregs,pretregs));
Lp:
if (postinc)
{
int reg = findreg(idxregm(&cs));
if (*pretregs & mPSW)
{ // Use LEA to avoid touching the flags
unsigned rm = cs.Irm & 7;
if (cs.Irex & REX_B)
rm |= 8;
c = genc1(c,0x8D,buildModregrm(2,reg,rm),FLconst,postinc);
if (tysize(e11->E1->Ety) == 8)
code_orrex(c, REX_W);
}
else if (I64)
{
c = genc2(c,0x81,modregrmx(3,0,reg),postinc);
if (tysize(e11->E1->Ety) == 8)
code_orrex(c, REX_W);
}
else
{
if (postinc == 1)
c = gen1(c,0x40 + reg); // INC reg
else if (postinc == -(targ_int)1)
c = gen1(c,0x48 + reg); // DEC reg
else
{
c = genc2(c,0x81,modregrm(3,0,reg),postinc);
}
}
}
freenode(e1);
return c;
}
/********************************
* Generate code for conversion using SSE2 instructions.
*
* OPs32_d
* OPs64_d (64-bit only)
* OPu32_d (64-bit only)
* OPd_f
* OPf_d
* OPd_s32
* OPd_s64 (64-bit only)
*
*/
code *xmmcnvt(elem *e,regm_t *pretregs)
{
code *c;
unsigned op=0, regs;
tym_t ty;
unsigned char rex = 0;
bool zx = false; // zero extend uint
/* There are no ops for integer <-> float/real conversions
* but there are instructions for them. In order to use these
* try to fuse chained conversions. Be careful not to loose
* precision for real to long.
*/
elem *e1 = e->E1;
switch (e->Eoper)
{
case OPd_f:
if (e1->Eoper == OPs32_d)
;
else if (I64 && e1->Eoper == OPs64_d)
rex = REX_W;
else if (I64 && e1->Eoper == OPu32_d)
{ rex = REX_W;
zx = true;
}
else
{ regs = XMMREGS;
op = CVTSD2SS;
ty = TYfloat;
break;
}
// directly use si2ss
regs = ALLREGS;
e1 = e1->E1;
op = CVTSI2SS;
ty = TYfloat;
break;
case OPs32_d: goto Litod;
case OPs64_d: rex = REX_W; goto Litod;
case OPu32_d: rex = REX_W; zx = true; goto Litod;
Litod:
regs = ALLREGS;
op = CVTSI2SD;
ty = TYdouble;
break;
case OPd_s32: ty = TYint; goto Ldtoi;
case OPd_s64: ty = TYlong; rex = REX_W; goto Ldtoi;
Ldtoi:
regs = XMMREGS;
switch (e1->Eoper)
{
case OPf_d:
e1 = e1->E1;
op = CVTTSS2SI;
break;
case OPld_d:
if (e->Eoper == OPd_s64)
return cnvt87(e,pretregs); // precision
/* FALL-THROUGH */
default:
op = CVTTSD2SI;
break;
}
break;
case OPf_d:
regs = XMMREGS;
op = CVTSS2SD;
ty = TYdouble;
break;
}
assert(op);
c = codelem(e1, &regs, FALSE);
unsigned reg = findreg(regs);
if (reg >= XMM0)
reg -= XMM0;
else if (zx)
{ assert(I64);
c = cat(c,getregs(regs));
c = genregs(c,0x89,reg,reg); // MOV reg,reg to zero upper 32-bit
code_orflag(c,CFvolatile);
}
unsigned retregs = *pretregs;
if (tyxmmreg(ty)) // target is XMM
{ if (!(*pretregs & XMMREGS))
retregs = XMMREGS;
}
else // source is XMM
{ assert(regs & XMMREGS);
if (!(retregs & ALLREGS))
retregs = ALLREGS;
}
unsigned rreg;
c = cat(c,allocreg(&retregs,&rreg,ty));
if (rreg >= XMM0)
rreg -= XMM0;
c = gen2(c, op, modregxrmx(3,rreg,reg));
assert(I64 || !rex);
if (rex)
code_orrex(c, rex);
if (*pretregs != retregs)
c = cat(c,fixresult(e,retregs,pretregs));
return c;
}
/********************************
* Generate code for op=
*/
code *xmmopass(elem *e,regm_t *pretregs)
{ elem *e1 = e->E1;
elem *e2 = e->E2;
tym_t ty1 = tybasic(e1->Ety);
unsigned sz1 = tysize[ty1];
regm_t rretregs = XMMREGS & ~*pretregs;
if (!rretregs)
rretregs = XMMREGS;
code *cr = codelem(e2,&rretregs,FALSE); // eval right leaf
unsigned rreg = findreg(rretregs);
code cs;
code *cl,*cg;
regm_t retregs;
unsigned reg;
bool regvar = FALSE;
if (config.flags4 & CFG4optimized)
{
// Be careful of cases like (x = x+x+x). We cannot evaluate in
// x if x is in a register.
unsigned varreg;
regm_t varregm;
if (isregvar(e1,&varregm,&varreg) && // if lvalue is register variable
doinreg(e1->EV.sp.Vsym,e2) // and we can compute directly into it
)
{ regvar = TRUE;
retregs = varregm;
reg = varreg; // evaluate directly in target register
cl = NULL;
cg = getregs(retregs); // destroy these regs
}
}
if (!regvar)
{
cl = getlvalue(&cs,e1,rretregs); // get EA
retregs = *pretregs & XMMREGS & ~rretregs;
if (!retregs)
retregs = XMMREGS & ~rretregs;
cg = allocreg(&retregs,&reg,ty1);
cs.Iop = xmmload(ty1); // MOVSD xmm,xmm_m64
code_newreg(&cs,reg - XMM0);
cg = gen(cg,&cs);
}
unsigned op = xmmoperator(e1->Ety, e->Eoper);
code *co = gen2(CNIL,op,modregxrmx(3,reg-XMM0,rreg-XMM0));
if (!regvar)
{
cs.Iop = xmmstore(ty1); // reverse operand order of MOVS[SD]
gen(co,&cs);
}
if (e1->Ecount || // if lvalue is a CSE or
regvar) // rvalue can't be a CSE
{
cl = cat(cl,getregs_imm(retregs)); // necessary if both lvalue and
// rvalue are CSEs (since a reg
// can hold only one e at a time)
cssave(e1,retregs,EOP(e1)); // if lvalue is a CSE
}
co = cat(co,fixresult(e,retregs,pretregs));
freenode(e1);
return cat4(cr,cl,cg,co);
}
/******************
* Negate operator
*/
code *xmmneg(elem *e,regm_t *pretregs)
{
//printf("xmmneg()\n");
//elem_print(e);
assert(*pretregs);
tym_t tyml = tybasic(e->E1->Ety);
int sz = tysize[tyml];
regm_t retregs = *pretregs & XMMREGS;
if (!retregs)
retregs = XMMREGS;
/* Generate:
* MOV reg,e1
* MOV rreg,signbit
* XOR reg,rreg
*/
code *cl = codelem(e->E1,&retregs,FALSE);
cl = cat(cl,getregs(retregs));
unsigned reg = findreg(retregs);
regm_t rretregs = XMMREGS & ~retregs;
unsigned rreg;
cl = cat(cl,allocreg(&rretregs,&rreg,tyml));
targ_size_t signbit = 0x80000000;
if (sz == 8)
signbit = 0x8000000000000000LL;
code *c = movxmmconst(rreg, sz, signbit, 0);
code *cg = getregs(retregs);
unsigned op = (sz == 8) ? XORPD : XORPS; // XORPD/S reg,rreg
code *co = gen2(CNIL,op,modregxrmx(3,reg-XMM0,rreg-XMM0));
co = cat(co,fixresult(e,retregs,pretregs));
return cat4(cl,c,cg,co);
}
/*****************************
* Get correct load operator based on type.
* It is important to use the right one even if the number of bits moved is the same,
* as there are performance consequences for using the wrong one.
*/
unsigned xmmload(tym_t tym)
{ unsigned op;
switch (tybasic(tym))
{
case TYfloat:
case TYifloat: op = LODSS; break; // MOVSS
case TYdouble:
case TYidouble: op = LODSD; break; // MOVSD
case TYfloat4: op = LODAPS; break; // MOVAPS
case TYdouble2: op = LODAPD; break; // MOVAPD
case TYschar16:
case TYuchar16:
case TYshort8:
case TYushort8:
case TYlong4:
case TYulong4:
case TYllong2:
case TYullong2: op = LODDQA; break; // MOVDQA
default:
printf("tym = x%x\n", tym);
assert(0);
}
return op;
}
/*****************************
* Get correct store operator based on type.
*/
unsigned xmmstore(tym_t tym)
{ unsigned op;
switch (tybasic(tym))
{
case TYfloat:
case TYifloat: op = STOSS; break; // MOVSS
case TYdouble:
case TYidouble:
case TYllong:
case TYullong:
case TYuint:
case TYlong:
case TYcfloat: op = STOSD; break; // MOVSD
case TYfloat4: op = STOAPS; break; // MOVAPS
case TYdouble2: op = STOAPD; break; // MOVAPD
case TYschar16:
case TYuchar16:
case TYshort8:
case TYushort8:
case TYlong4:
case TYulong4:
case TYllong2:
case TYullong2: op = STODQA; break; // MOVDQA
default:
printf("tym = x%x\n", tym);
assert(0);
}
return op;
}
/************************************
* Get correct XMM operator based on type and operator.
*/
unsigned xmmoperator(tym_t tym, unsigned oper)
{
tym = tybasic(tym);
unsigned op;
switch (oper)
{
case OPadd:
case OPaddass:
switch (tym)
{
case TYfloat:
case TYifloat: op = ADDSS; break;
case TYdouble:
case TYidouble: op = ADDSD; break;
// SIMD vector types
case TYfloat4: op = ADDPS; break;
case TYdouble2: op = ADDPD; break;
case TYschar16:
case TYuchar16: op = PADDB; break;
case TYshort8:
case TYushort8: op = PADDW; break;
case TYlong4:
case TYulong4: op = PADDD; break;
case TYllong2:
case TYullong2: op = PADDQ; break;
default: assert(0);
}
break;
case OPmin:
case OPminass:
switch (tym)
{
case TYfloat:
case TYifloat: op = SUBSS; break;
case TYdouble:
case TYidouble: op = SUBSD; break;
// SIMD vector types
case TYfloat4: op = SUBPS; break;
case TYdouble2: op = SUBPD; break;
case TYschar16:
case TYuchar16: op = PSUBB; break;
case TYshort8:
case TYushort8: op = PSUBW; break;
case TYlong4:
case TYulong4: op = PSUBD; break;
case TYllong2:
case TYullong2: op = PSUBQ; break;
default: assert(0);
}
break;
case OPmul:
case OPmulass:
switch (tym)
{
case TYfloat:
case TYifloat: op = MULSS; break;
case TYdouble:
case TYidouble: op = MULSD; break;
// SIMD vector types
case TYfloat4: op = MULPS; break;
case TYdouble2: op = MULPD; break;
case TYshort8:
case TYushort8: op = PMULLW; break;
default: assert(0);
}
break;
case OPdiv:
case OPdivass:
switch (tym)
{
case TYfloat:
case TYifloat: op = DIVSS; break;
case TYdouble:
case TYidouble: op = DIVSD; break;
// SIMD vector types
case TYfloat4: op = DIVPS; break;
case TYdouble2: op = DIVPD; break;
default: assert(0);
}
break;
case OPor:
case OPorass:
switch (tym)
{
// SIMD vector types
case TYschar16:
case TYuchar16:
case TYshort8:
case TYushort8:
case TYlong4:
case TYulong4:
case TYllong2:
case TYullong2: op = POR; break;
default: assert(0);
}
break;
case OPand:
case OPandass:
switch (tym)
{
// SIMD vector types
case TYschar16:
case TYuchar16:
case TYshort8:
case TYushort8:
case TYlong4:
case TYulong4:
case TYllong2:
case TYullong2: op = PAND; break;
default: assert(0);
}
break;
case OPxor:
case OPxorass:
switch (tym)
{
// SIMD vector types
case TYschar16:
case TYuchar16:
case TYshort8:
case TYushort8:
case TYlong4:
case TYulong4:
case TYllong2:
case TYullong2: op = PXOR; break;
default: assert(0);
}
break;
case OPlt:
case OPle:
case OPgt:
case OPge:
case OPne:
case OPeqeq:
case OPunord: /* !<>= */
case OPlg: /* <> */
case OPleg: /* <>= */
case OPule: /* !> */
case OPul: /* !>= */
case OPuge: /* !< */
case OPug: /* !<= */
case OPue: /* !<> */
case OPngt:
case OPnge:
case OPnlt:
case OPnle:
case OPord:
case OPnlg:
case OPnleg:
case OPnule:
case OPnul:
case OPnuge:
case OPnug:
case OPnue:
switch (tym)
{
case TYfloat:
case TYifloat: op = UCOMISS; break;
case TYdouble:
case TYidouble: op = UCOMISD; break;
default: assert(0);
}
break;
default:
assert(0);
}
return op;
}
code *cdvector(elem *e, regm_t *pretregs)
{
/* e should look like:
* vector
* |
* param
* / \
* param op2
* / \
* op op1
*/
if (!config.fpxmmregs)
{ printf("SIMD operations not supported on this platform\n");
exit(1);
}
elem *e1 = e->E1;
assert(e1->Eoper == OPparam);
elem *op2 = e1->E2;
e1 = e1->E1;
assert(e1->Eoper == OPparam);
elem *eop = e1->E1;
assert(eop->Eoper == OPconst);
elem *op1 = e1->E2;
tym_t ty1 = tybasic(op1->Ety);
unsigned sz1 = tysize[ty1];
assert(sz1 == 16); // float or double
regm_t retregs = *pretregs & XMMREGS;
if (!retregs)
retregs = XMMREGS;
code *c = codelem(op1,&retregs,FALSE); // eval left leaf
unsigned reg = findreg(retregs);
regm_t rretregs = XMMREGS & ~retregs;
code *cr = scodelem(op2, &rretregs, retregs, TRUE); // eval right leaf
unsigned rreg = findreg(rretregs);
code *cg = getregs(retregs);
unsigned op = el_tolong(eop);
code *co = gen2(CNIL,op,modregxrmx(3,reg-XMM0,rreg-XMM0));
co = cat(co,fixresult(e,retregs,pretregs));
return cat4(c,cr,cg,co);
}
#endif // !SPP

3990
backend/cod1.c Normal file

File diff suppressed because it is too large Load Diff

4997
backend/cod2.c Normal file

File diff suppressed because it is too large Load Diff

6458
backend/cod3.c Normal file

File diff suppressed because it is too large Load Diff

3438
backend/cod4.c Normal file

File diff suppressed because it is too large Load Diff

207
backend/cod5.c Normal file
View File

@@ -0,0 +1,207 @@
// Copyright (C) 1995-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "el.h"
#include "oper.h"
#include "code.h"
#include "global.h"
#include "type.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
STATIC void pe_add(block *b);
STATIC int need_prolog(block *b);
/********************************************************
* Determine which blocks get the function prolog and epilog
* attached to them.
*/
void cod5_prol_epi()
{
#if 1
cod5_noprol();
#else
tym_t tym;
tym_t tyf;
block *b;
block *bp;
list_t bl;
int nepis;
tyf = funcsym_p->ty();
tym = tybasic(tyf);
if (!(config.flags4 & CFG4optimized) ||
anyiasm ||
usedalloca ||
usednteh ||
tyf & (mTYnaked | mTYloadds) ||
tym == TYifunc ||
tym == TYmfunc || // can't yet handle ECX passed as parameter
tym == TYjfunc || // can't yet handle EAX passed as parameter
config.flags & (CFGalwaysframe | CFGtrace) ||
// config.fulltypes ||
(config.wflags & WFwindows && tyfarfunc(tym)) ||
need_prolog(startblock)
)
{ // First block gets the prolog, all return blocks
// get the epilog.
//printf("not even a candidate\n");
cod5_noprol();
return;
}
// Turn on BFLoutsideprolog for all blocks outside the ones needing the prolog.
for (b = startblock; b; b = b->Bnext)
b->Bflags &= ~BFLoutsideprolog; // start with them all off
pe_add(startblock);
// Look for only one block (bp) that will hold the prolog
bp = NULL;
nepis = 0;
for (b = startblock; b; b = b->Bnext)
{ int mark;
if (b->Bflags & BFLoutsideprolog)
continue;
// If all predecessors are marked
mark = 0;
assert(b->Bpred);
for (bl = b->Bpred; bl; bl = list_next(bl))
{
if (list_block(bl)->Bflags & BFLoutsideprolog)
{
if (mark == 2)
goto L1;
mark = 1;
}
else
{
if (mark == 1)
goto L1;
mark = 2;
}
}
if (mark == 1)
{
if (bp) // if already have one
goto L1;
bp = b;
}
// See if b is an epilog
mark = 0;
for (bl = b->Bsucc; bl; bl = list_next(bl))
{
if (list_block(bl)->Bflags & BFLoutsideprolog)
{
if (mark == 2)
goto L1;
mark = 1;
}
else
{
if (mark == 1)
goto L1;
mark = 2;
}
}
if (mark == 1 || b->BC == BCret || b->BC == BCretexp)
{ b->Bflags |= BFLepilog;
nepis++;
if (nepis > 1 && config.flags4 & CFG4space)
goto L1;
}
}
if (bp)
{ bp->Bflags |= BFLprolog;
//printf("=============== prolog opt\n");
}
#endif
}
/**********************************************
* No prolog/epilog optimization.
*/
void cod5_noprol()
{
block *b;
//printf("no prolog optimization\n");
startblock->Bflags |= BFLprolog;
for (b = startblock; b; b = b->Bnext)
{
b->Bflags &= ~BFLoutsideprolog;
switch (b->BC)
{ case BCret:
case BCretexp:
b->Bflags |= BFLepilog;
break;
default:
b->Bflags &= ~BFLepilog;
}
}
}
/*********************************************
* Add block b, and its successors, to those blocks outside those requiring
* the function prolog.
*/
STATIC void pe_add(block *b)
{ list_t bl;
if (b->Bflags & BFLoutsideprolog ||
need_prolog(b))
return;
b->Bflags |= BFLoutsideprolog;
for (bl = b->Bsucc; bl; bl = list_next(bl))
pe_add(list_block(bl));
}
/**********************************************
* Determine if block needs the function prolog to be set up.
*/
STATIC int need_prolog(block *b)
{
if (b->Bregcon.used & fregsaved)
goto Lneed;
// If block referenced a param in 16 bit code
if (!I32 && b->Bflags & BFLrefparam)
goto Lneed;
// If block referenced a stack local
if (b->Bflags & BFLreflocal)
goto Lneed;
return 0;
Lneed:
return 1;
}
#endif

136
backend/code.c Normal file
View File

@@ -0,0 +1,136 @@
// Copyright (C) 1987-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <time.h>
#include "cc.h"
#include "el.h"
#include "code.h"
#include "global.h"
static code *code_list;
/*****************
* Allocate code
*/
#if SCPP && __SC__ && __INTSIZE == 4 && TX86 && !_DEBUG_TRACE && !MEM_DEBUG
__declspec(naked) code *code_calloc()
{
if (sizeof(code) != 0x28)
util_assert("code",__LINE__);
__asm
{
mov EAX,code_list
test EAX,EAX
je L20
mov ECX,[EAX]
mov code_list,ECX
jmp L29
L20: push sizeof(code)
call mem_fmalloc
;add ESP,4
L29:
xor ECX,ECX
mov DWORD PTR [EAX],0
mov 4[EAX],ECX ;these pair
mov 8[EAX],ECX
mov 12[EAX],ECX
mov 16[EAX],ECX
mov 20[EAX],ECX
mov 24[EAX],ECX
mov 28[EAX],ECX
mov 32[EAX],ECX
mov 36[EAX],ECX
ret
}
}
#else
code *code_calloc()
{ code *c;
static code czero;
//printf("code %x\n", sizeof(code));
c = code_list;
if (c)
code_list = code_next(c);
else
c = (code *)mem_fmalloc(sizeof(*c));
*c = czero; // zero it out
//dbg_printf("code_calloc: %p\n",c);
return c;
}
#endif
/*****************
* Free code
*/
void code_free(code *cstart)
{ code **pc;
code *c;
for (pc = &cstart; (c = *pc) != NULL; pc = &code_next(c))
{
if (c->Iop == ASM)
{
mem_free(c->IEV1.as.bytes);
}
}
*pc = code_list;
code_list = cstart;
}
/*****************
* Terminate code
*/
void code_term()
{
#if TERMCODE
code *cn;
int count = 0;
while (code_list)
{ cn = code_next(code_list);
mem_ffree(code_list);
code_list = cn;
count++;
}
#ifdef DEBUG
printf("Max # of codes = %d\n",count);
#endif
#else
#ifdef DEBUG
int count = 0;
for (code *cn = code_list; cn; cn = code_next(cn))
count++;
printf("Max # of codes = %d\n",count);
#endif
#endif
}
#endif // !SPP

1049
backend/code.h Normal file

File diff suppressed because it is too large Load Diff

746
backend/cppman.c Normal file
View File

@@ -0,0 +1,746 @@
// Copyright (C) 1987-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/* C++ name mangling routines */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "cc.h"
#if !NEWMANGLE
#define NEW_UNMANGLER 1
#include "parser.h"
#include "token.h"
#include "global.h"
#include "oper.h"
#include "el.h"
#include "type.h"
#include "cpp.h"
#include "filespec.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
//char *cpp_name = NULL;
char cpp_name[2 * IDMAX + 1] = { 0 };
/* Names for special variables */
char cpp_name_new[] = "__nw";
char cpp_name_delete[] = "__dl";
char cpp_name_ct[] = "__ct";
char cpp_name_dt[] = "__dt";
char cpp_name_as[] = "__as";
char cpp_name_vc[] = "__vc";
char cpp_name_primdt[] = "__pd";
char cpp_name_scaldeldt[] = "__sd";
static symbol *ssymbol;
/****************************
*/
struct OPTABLE oparray[] =
{
{ TKnew, OPnew, cpp_name_new, "new" },
{ TKdelete, OPdelete, cpp_name_delete,"del" },
{ TKadd, OPadd, "__pl", "+" },
{ TKadd, OPuadd, "__pl", "+" },
{ TKmin, OPmin, "__mi", "-" },
{ TKmin, OPneg, "__mi", "-" },
{ TKstar, OPmul, "__ml", "*" },
{ TKstar, OPind, "__ml", "*" },
{ TKdiv, OPdiv, "__dv", "/" },
{ TKmod, OPmod, "__md", "%" },
{ TKxor, OPxor, "__er", "^" },
{ TKand, OPand, "__ad", "&" },
{ TKand, OPaddr, "__ad", "&" },
{ TKor, OPor, "__or", "|" },
{ TKcom, OPcom, "__co", "~" },
{ TKnot, OPnot, "__nt", "!" },
{ TKeq, OPeq, "__as", "=" },
{ TKeq, OPstreq, "__as", "=" },
{ TKlt, OPlt, "__lt", "<" },
{ TKgt, OPgt, "__gt", ">" },
{ TKunord, OPunord, "__uno", "!<>=" },
{ TKlg, OPlg, "__lg", "<>" },
{ TKleg, OPleg, "__leg", "<>=" },
{ TKule, OPule, "__ule", "!>" },
{ TKul, OPul, "__ul", "!>=" },
{ TKuge, OPuge, "__uge", "!<" },
{ TKug, OPug, "__ug", "!<=" },
{ TKue, OPue, "__ue", "!<>" },
{ TKaddass, OPaddass, "__apl", "+=" },
{ TKminass, OPminass, "__ami", "-=" },
{ TKmulass, OPmulass, "__amu", "*=" },
{ TKdivass, OPdivass, "__adv", "/=" },
{ TKmodass, OPmodass, "__amd", "%=" },
{ TKxorass, OPxorass, "__aer", "^=" },
{ TKandass, OPandass, "__aad", "&=" },
{ TKorass, OPorass, "__aor", "|=" },
{ TKshl, OPshl, "__ls", "<<" },
{ TKshr, OPshr, "__rs", ">>" },
{ TKshrass, OPshrass, "__ars", "<<=" },
{ TKshlass, OPshlass, "__als", ">>=" },
{ TKeqeq, OPeqeq, "__eq", "==" },
{ TKne, OPne, "__ne", "!=" },
{ TKle, OPle, "__le", "<=" },
{ TKge, OPge, "__ge", ">=" },
{ TKandand, OPandand, "__aa", "&&" },
{ TKoror, OPoror, "__oo", "||" },
{ TKplpl, OPpostinc, "__pp", "++" },
{ TKplpl, OPpreinc, "__pp", "++" },
{ TKmimi, OPpostdec, "__mm", "--" },
{ TKmimi, OPpredec, "__mm", "--" },
{ TKlpar, OPcall, "__cl", "()" },
{ TKlbra, OPbrack, "__vc", "[]" },
{ TKarrow, OParrow, "__rf", "->" },
{ TKcomma, OPcomma, "__cm", "," },
{ TKarrowstar, OParrowstar, "__rm", "->*" },
};
/***********************************
* Cat together two names into a static buffer.
* n1 can be the same as the static buffer.
*/
char *cpp_catname(char *n1,char *n2)
{
static char cpp_name[IDMAX + 1];
#ifdef DEBUG
assert(n1 && n2);
#endif
if (strlen(n1) + strlen(n2) >= sizeof(cpp_name))
{
#if SCPP
lexerr(EM_ident2big); // identifier is too long
#else
assert(0);
#endif
cpp_name[0] = 0;
}
else
strcat(strcpy(cpp_name,n1),n2);
return cpp_name;
}
/***********************************
* 'Combine' a class and a member name into one name.
*/
char *cpp_genname(char *cl_name,char *mem_name)
{
#if NEWMANGLE
return cpp_catname(alloca_strdup2(mem_name,cl_name),"@");
#else
char format[2 + 3 + 1];
sprintf(format,"__%d",strlen(cl_name));
return cpp_catname(cpp_catname(mem_name,format),cl_name);
#endif
}
/****************************************
* Convert from identifier to operator
*/
char *cpp_unmangleident(const char *p)
{ int i;
for (i = 0; i < arraysize(oparray); i++)
{ if (strcmp(p,oparray[i].string) == 0)
{
strcpy(cpp_name,"operator ");
strcat(cpp_name,oparray[i].pretty);
p = cpp_name;
break;
}
}
return (char *)p;
}
/****************************************
* Find index in oparray[] for operator.
* Returns:
* index or -1 if not found
*/
int cpp_opidx(int op)
{ int i;
for (i = 0; i < arraysize(oparray); i++)
if (oparray[i].oper == (char) op)
return i;
return -1;
}
/***************************************
* Find identifier string associated with operator.
* Returns:
* NULL if not found
*/
char *cpp_opident(int op)
{ int i;
i = cpp_opidx(op);
return (i == -1) ? NULL : oparray[i].string;
}
/********************************
* 'Mangle' a name for output.
* Returns:
* pointer to mangled name (a static buffer)
*/
char *cpp_mangle(symbol *s)
{ char *p;
symbol *sclass;
if (!CPP)
return s->Sident;
ssymbol = s;
symbol_debug(s);
//dbg_printf("cpp_mangle(%s)\n",s->Sident);
p = symbol_ident(s);
sclass = s->Sscope;
if (sclass)
{ symbol_debug(sclass);
p = cpp_genname(symbol_ident(sclass),p);
while (1)
{
char format[10 + 1];
char *cl_name;
sclass = sclass->Sscope;
if (!sclass)
break;
cl_name = symbol_ident(sclass);
sprintf(format,"%d",strlen(cl_name));
p = cpp_catname(cpp_catname(p,format),cl_name);
}
}
type_debug(s->Stype);
// Function symbols defined statically don't have Sfunc
if (tyfunc(s->Stype->Tty) &&
s->Sfunc && s->Sfunc->Fflags & Ftypesafe)
{ if (!s->Sscope)
p = cpp_catname(p,"__");
p = cpp_typetostring(s->Stype,p);
}
/*dbg_printf("cpp_mangle(%s)\n",p);*/
ssymbol = NULL;
return p;
}
/**********************************
* Convert from operator token to name.
* Returns:
* pointer to corresponding name
*/
#if SCPP
char *cpp_operator(int *poper,type **pt)
{
int i;
type *typ_spec;
*pt = NULL;
stoken(); /* skip over operator keyword */
for (i = 0; i < arraysize(oparray); i++)
{ if (oparray[i].tokn == tok.TKval)
goto L1;
}
/* Look for type conversion */
if (type_specifier(&typ_spec,NULL ARG_FALSE))
{ type *t;
t = ptr_operator(typ_spec); // parse ptr-operator
fixdeclar(t);
type_free(typ_spec);
*pt = t;
return cpp_typetostring(t,"__op");
}
cpperr(EM_not_overloadable); // that token cannot be overloaded
stoken();
return "_";
L1:
*poper = oparray[i].oper;
switch (*poper)
{ case OPcall:
if (stoken() != TKrpar)
synerr(EM_rpar); /* ')' expected */
break;
case OPbrack:
if (stoken() != TKrbra)
synerrEM_rbra); /* ']' expected */
break;
}
stoken();
return oparray[i].string;
}
#endif
/***********************************
* Generate and return a pointer to a string constructed from
* the type, appended to the prefix.
* Since these generated strings determine the uniqueness of names,
* they are also used to determine if two types are the same.
* Returns:
* pointer to static name[]
*/
char *cpp_typetostring(type *t,char *prefix)
{ int i;
param_t *p;
type *tstart;
bool dofuncret = FALSE; /* BUG: this should be passed in */
static int nest = 0;
symbol *s;
if (prefix)
{ strcpy(cpp_name, prefix);
i = strlen(prefix);
}
else
i = 0;
/*dbg_printf("cpp_typetostring:\n");
type_print(t);*/
tstart = t;
for (; t; t = t->Tnext, dofuncret = TRUE)
{ char c1,c2;
int nestclass;
type_debug(t);
if (i > IDMAX - 4) /* if not room for 4 more + 0 */
{ //cpperr(EM_type_complex); // type is too complex
assert(0);
i = 0;
}
if (t->Tty & mTYconst)
cpp_name[i++] = 'C';
if (t->Tty & mTYvolatile)
cpp_name[i++] = 'V';
c1 = 0;
nestclass = 0;
/* Function return types are ignored */
switch (tybasic(t->Tty))
{
case TYschar: c1 = 'S'; goto L2;
case TYuchar: c1 = 'U'; goto L2;
case TYchar: L2: c2 = 'c'; break;
case TYushort: c1 = 'U';
case TYshort: c2 = 's'; break;
case TYuint: c1 = 'U';
case TYint: c2 = 'i'; break;
#if LONGLONG && __INTSIZE == 4 // DJB
case TYullong: c1 = 'U';
case TYllong: c2 = 'x'; break;
#endif
case TYulong: c1 = 'U';
case TYlong: c2 = 'l'; break;
#if M_UNIX || M_XENIX
case TYnptr: // For Gnu gdb and ARM compatibility
#endif
case TYfptr: c2 = 'P'; break;
case TYvptr: c2 = 'h'; break;
case TYfloat: c2 = 'f'; break;
case TYldouble: c2 = 'r'; break;
case TYdouble: c2 = 'd'; break;
case TYvoid: c2 = 'v'; break;
#if TX86
case TYnref:
case TYfref:
#endif
case TYref: c2 = 'R'; break;
#if M_UNIX || M_XENIX
case TYmfunc:
case TYnfunc:
case TYnpfunc: // Near functions under Unix are coded as F
case TYnsysfunc: // see ARM page 124
#endif
case TYfpfunc: c2 = 'F'; goto L4;
#if TX86
case TYfsysfunc:
#endif
case TYffunc: c2 = 'D'; goto L4;
#if TX86
case TYsptr: c2 = 'b'; break;
#if !(M_UNIX || M_XENIX)
case TYnptr: c2 = 'p'; break;
#endif
case TYcptr: c2 = 'E'; break;
case TYf16ptr: c2 = 'g'; break;
case TYf16func: c2 = 'G'; goto L4;
case TYhptr: c2 = 'H'; break;
#if !(M_UNIX || M_XENIX)
case TYnpfunc: c2 = 'N'; goto L4;
case TYmfunc:
case TYnsysfunc:
case TYnfunc: c2 = 'B'; goto L4;
#endif
case TYfsfunc: c2 = 'I'; goto L4;
case TYnsfunc: c2 = 'j'; goto L4;
#else
case TYpsfunc: c2 = 'F'; goto L4;
case TYcomp: c2 = 'o'; break;
case TYmemptr: c2 = 'm'; break;
#endif
L4:
cpp_name[i++] = c2;
if (i > IDMAX - 2)
{ //cpperr(EM_type_complex);
assert(0);
i = 0;
}
/* Append the types of the parameters to the name */
{ int n;
int paramidx[10]; /* previous parameter indices */
n = 1; /* parameter number */
for (p = t->Tparamtypes; p; p = p->Pnext)
{ int len;
cpp_name[i] = 0;
nest++;
cpp_typetostring(p->Ptype,cpp_name);
nest--;
len = strlen(cpp_name);
if (n < arraysize(paramidx))
{ paramidx[n] = i;
if (len - i > 2) /* only if we get real savings */
{ int j;
/* 'common subexpression' with any previous */
/* matching type, if match, replace with */
/* 'T' parameter_number */
for (j = 1; j < n; j++)
if (memcmp(&cpp_name[paramidx[j]],&cpp_name[i],len - i) == 0)
{ sprintf(cpp_name + i,"T%d",j);
len = i + 2;
break;
}
}
}
if (len > IDMAX - 2)
{ //cpperr(EM_type_complex);
assert(0);
len = 0;
n = 0;
}
i = len;
n++;
}
}
if (variadic(t))
cpp_name[i++] = 'e';
else if (t->Tflags & TFfixed && !t->Tparamtypes)
cpp_name[i++] = 'v'; /* func(void) */
/* Determine if function return types should be considered */
if (dofuncret || nest)
{ cpp_name[i++] = '_';
continue;
}
else
goto L1; /* ignore what the function returns */
#if TX86
case TYmemptr:
cpp_name[i++] = 'm';
#endif
case TYstruct:
s = t->Ttag;
L6:
if (s->Sstruct->Sflags & STRnotagname)
{
s->Sstruct->Sflags &= ~STRnotagname;
#if SCPP
warerr(WM_notagname,ssymbol ? (char *)ssymbol->Sident : "Unknown" ); /* no tag name for struct */
#endif
}
goto L5;
case TYenum:
s = t->Ttag;
if (s->Senum->SEflags & SENnotagname)
{
s->Senum->SEflags &= ~SENnotagname;
#if SCPP
warerr(WM_notagname, ssymbol ? (char *)ssymbol->Sident : "Unknown" ); /* no tag name for struct */
#endif
}
L5:
{ int len;
char *p;
/* Append the tag to the name */
p = symbol_ident(s);
len = strlen(p);
if (i + len + nestclass > IDMAX - sizeof(len) * 3)
{ //cpperr(EM_type_complex); /* type is too complex */
assert(0);
goto L1;
}
sprintf(cpp_name + i,("X%d%s" + 1 - nestclass),len,p);
/* Handle nested classes */
s = s->Sscope;
if (s)
{ nestclass = 1;
i = strlen(cpp_name);
goto L6;
}
goto L3;
}
case TYarray:
if (i > IDMAX - 1 - sizeof(t->Tdim) * 3)
{ //cpperr(EM_type_complex); // type is too complex
assert(0);
goto L1;
}
sprintf(cpp_name + i,"A%d",t->Tdim);
L3: i = strlen(cpp_name);
continue;
default:
debug(type_print(t));
assert(0);
}
if (c1)
cpp_name[i++] = c1;
cpp_name[i++] = c2;
}
L1:
cpp_name[i] = 0; // terminate the string
return cpp_name;
}
/***********************************
* Create mangled name for template instantiation.
*/
#if SCPP
char *template_mangle(symbol *s,param_t *arglist)
{
/* mangling ::= "__PT" N template_name { type | expr }
N ::= number of characters in template_name
type ::= mangled type
expr ::= "V" value
value ::= integer | string | address | float | double | long_double | numeric 
integer ::= digit { digit }
string ::= "S" integer "_" { char }
address ::= "R" integer "_" { char }
float ::= "F" hex_digits
double ::= "D" hex_digits
long_double ::= "L" hex_digits
*/
char *n;
param_t *p;
ssymbol = s;
assert(s);
symbol_debug(s);
assert(s->Sclass == SCtemplate);
n = cpp_catname("__PT",unsstr(strlen((char *)s->Sident)));
n = cpp_catname(n,(char *)s->Sident);
for (p = arglist; p; p = p->Pnext)
{
if (p->Ptype)
{ /* Argument is a type */
n = cpp_typetostring(p->Ptype,n);
}
else
{ /* Argument is an expression */
elem *e = p->Pelem;
tym_t ty = tybasic(e->ET->Tty);
char *p;
char a[2];
int ni;
#if NEW_UNMANGLER
double d;
#endif
n = cpp_catname(n,"V");
/*n = cpp_typetostring(e->ET,n);*/
switch (e->Eoper)
{ case OPconst:
switch (ty)
{
#if !(NEW_UNMANGLER)
case TYfloat: ni = FLOATSIZE; a[0] = 'F'; goto L1;
case TYdouble: ni = DOUBLESIZE; a[0] = 'D'; goto L1;
case TYldouble: ni = LNGDBLSIZE; a[0] = 'L'; goto L1;
L1:
a[1] = 0;
n = cpp_catname(n,a);
p = (char *)&e->EV.Vdouble;
#elif !NEW_UNMANGLER
case TYfloat:
float f;
ni = FLOATSIZE;
a[0] = 'F';
f = e->EV.Vfloat;
p = (char *)&f;
goto L1;
case TYdouble:
double d;
ni = tysize[TYdouble];
a[0] = 'D';
d = e->EV.Vdouble;
p = (char *)&d;
goto L1;
case TYldouble:
ni = tysize[TYldouble];
a[0] = 'L';
if (config.flags & CFGldblisdbl)
p = (char *)&e->EV.Vdouble;
else
{
d = e->EV.Vldouble;
}
p = (char *)&d;
// ni = tysize[TYdouble];
ni = sizeof(long double); // just until new unmangler is in
L1:
a[1] = 0;
n = cpp_catname(n,a);
#endif
#if !NEW_UNMANGLER
while (ni--)
{ char c;
static char hex[17] = "0123456789ABCDEF";
static char buf[3];
c = *p++;
buf[0] = hex[c & 15];
buf[1] = hex[(c >> 4) & 15];
n = cpp_catname(n,buf);
}
break;
#else // NEW_UNMANGLER
case TYfloat: d = e->EV.Vfloat; goto L1;
case TYdouble: d = e->EV.Vdouble; goto L1;
case TYldouble: if (config.flags & CFGldblisdbl)
d = e->EV.Vdouble;
else
d = e->EV.Vldouble;
L1: char buf[32];
n = cpp_catname(n,"N");
ni = sprintf(buf, "%g", d);
p = buf-1;
while (ni--)
{ char c;
c = *++p;
if (c == '-')
*p = 'n';
else if (c == '+')
*p = 'p';
else if (c == '.')
*p = 'd';
}
p = buf;
goto L2;
#endif // NEW_UNMANGLER
default:
if (tyintegral(ty))
{ char buf[sizeof(long) * 3 + 1];
sprintf(buf,"%lu",el_tolong(e));
cpp_catname(n,buf);
break;
}
assert(0);
}
break;
case OPstring:
p = e->EV.ss.Vstring;
n = cpp_catname(n,"S");
goto L2;
case OPrelconst:
p = (char *)e->EV.sp.Vsym->Sident;
n = cpp_catname(n,"R");
L2:
n = cpp_catname(n,unsstr(strlen(p)));
n = cpp_catname(n,"_");
n = cpp_catname(n,p);
break;
default:
assert(errcnt);
break;
}
}
} /* for */
ssymbol = NULL;
return n;
}
#endif
/*********************************
* Mangle a vtbl or vbtbl name.
* Returns:
* pointer to generated symbol with mangled name
*/
#if SCPP
symbol *mangle_tbl(
int flag, // 0: vtbl, 1: vbtbl
type *t, // type for symbol
Classsym *stag, // class we're putting tbl in
Classsym *sbase) // base class (NULL if none)
{ const char *id;
symbol *s;
if (flag == 0)
id = config.flags3 & CFG3rtti ? "rttivtbl" : "vtbl";
else
id = "vbtbl";
if (sbase)
id = cpp_genname((char *)stag->Sident,cpp_genname((char *)sbase->Sident,id));
else
id = cpp_genname((char *)stag->Sident,id);
//
// This can happen for MI cases, the virtual table could already be defined
//
s = scope_search( id, SCTglobal | SCTnspace | SCTlocal );
if (s)
return(s);
s = scope_define(id,SCTglobal | SCTnspace | SCTlocal, SCunde);
s->Stype = t;
t->Tcount++;
#if XCOFF_OBJ || CFM68K || CFMV2
if (config.CFMOption && config.CFMxf) // cross fragment C++
s->Scfmflags = stag->Scfmflags; // Copy the flags from the stag
#endif
return s;
}
#endif
#endif

126
backend/cv4.h Normal file
View File

@@ -0,0 +1,126 @@
//_ cv4.h
// Codeview 4 stuff
// See "Microsoft Symbol and Type OMF" document
#define OEM 0x42 // Digital Mars OEM number (picked at random)
// Symbol Indices
#define S_COMPILE 1
#define S_REGISTER 2
#define S_CONST 3
#define S_UDT 4
#define S_SSEARCH 5
#define S_END 6
#define S_SKIP 7
#define S_CVRESERVE 8
#define S_OBJNAME 9
#define S_ENDARG 0x0A
#define S_COBOLUDT 0x0B
#define S_MANYREG 0x0C
#define S_RETURN 0x0D
#define S_ENTRYTHIS 0x0E
#define S_TDBNAME 0x0F
#define S_BPREL16 0x100
#define S_LDATA16 0x101
#define S_GDATA16 0x102
#define S_PUB16 0x103
#define S_LPROC16 0x104
#define S_GPROC16 0x105
#define S_THUNK16 0x106
#define S_BLOCK16 0x107
#define S_WITH16 0x108
#define S_LABEL16 0x109
#define S_CEXMODEL16 0x10A
#define S_VFTPATH16 0x10B
#define S_BPREL32 0x200
#define S_LDATA32 0x201
#define S_GDATA32 0x202
#define S_PUB32 0x203
#define S_LPROC32 0x204
#define S_GPROC32 0x205
#define S_THUNK32 0x206
#define S_BLOCK32 0x207
#define S_WITH32 0x208
#define S_LABEL32 0x209
#define S_CEXMODEL32 0x20A
#define S_VFTPATH32 0x20B
// Leaf Indices
#define LF_MODIFIER 1
#define LF_POINTER 2
#define LF_ARRAY 3
#define LF_CLASS 4
#define LF_STRUCTURE 5
#define LF_UNION 6
#define LF_ENUM 7
#define LF_PROCEDURE 8
#define LF_MFUNCTION 9
#define LF_VTSHAPE 0x0A
#define LF_COBOL0 0x0B
#define LF_COBOL1 0x0C
#define LF_BARRAY 0x0D
#define LF_LABEL 0x0E
#define LF_NULL 0x0F
#define LF_NOTTRAN 0x10
#define LF_DIMARRAY 0x11
#define LF_VFTPATH 0x12
#define LF_PRECOMP 0x13
#define LF_ENDPRECOMP 0x14
#define LF_OEM 0x15
#define LF_TYPESERVER 0x16
// D extensions (not used, causes linker to fail)
#define LF_DYN_ARRAY 0x17
#define LF_ASSOC_ARRAY 0x18
#define LF_DELEGATE 0x19
#define LF_SKIP 0x200
#define LF_ARGLIST 0x201
#define LF_DEFARG 0x202
#define LF_LIST 0x203
#define LF_FIELDLIST 0x204
#define LF_DERIVED 0x205
#define LF_BITFIELD 0x206
#define LF_METHODLIST 0x207
#define LF_DIMCONU 0x208
#define LF_DIMCONLU 0x209
#define LF_DIMVARU 0x20A
#define LF_DIMVARLU 0x20B
#define LF_REFSYM 0x20C
#define LF_BCLASS 0x400
#define LF_VBCLASS 0x401
#define LF_IVBCLASS 0x402
#define LF_ENUMERATE 0x403
#define LF_FRIENDFCN 0x404
#define LF_INDEX 0x405
#define LF_MEMBER 0x406
#define LF_STMEMBER 0x407
#define LF_METHOD 0x408
#define LF_NESTTYPE 0x409
#define LF_VFUNCTAB 0x40A
#define LF_FRIENDCLS 0x40B
#define LF_NUMERIC 0x8000
#define LF_CHAR 0x8000
#define LF_SHORT 0x8001
#define LF_USHORT 0x8002
#define LF_LONG 0x8003
#define LF_ULONG 0x8004
#define LF_REAL32 0x8005
#define LF_REAL64 0x8006
#define LF_REAL80 0x8007
#define LF_REAL128 0x8008
#define LF_QUADWORD 0x8009
#define LF_UQUADWORD 0x800A
#define LF_REAL48 0x800B
#define LF_COMPLEX32 0x800C
#define LF_COMPLEX64 0x800D
#define LF_COMPLEX80 0x800E
#define LF_COMPLEX128 0x800F
#define LF_VARSTRING 0x8010

415
backend/debug.c Normal file
View File

@@ -0,0 +1,415 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#ifdef DEBUG
#if !SPP
#include <stdio.h>
#include <time.h>
#include "cc.h"
#include "oper.h"
#include "type.h"
#include "el.h"
#include "token.h"
#include "global.h"
#include "vec.h"
#include "go.h"
#include "code.h"
#include "debtab.c"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
#define ferr(p) dbg_printf("%s",(p))
/*******************************
* Write out storage class.
*/
char *str_class(enum SC c)
{ static char sc[SCMAX][10] =
{
#define X(a,b) #a,
ENUMSCMAC
#undef X
};
static char buffer[9 + 3];
(void) assert(arraysize(sc) == SCMAX);
if ((unsigned) c < (unsigned) SCMAX)
sprintf(buffer,"SC%s",sc[(int) c]);
else
sprintf(buffer,"SC%u",(unsigned)c);
return buffer;
}
void WRclass(enum SC c)
{
dbg_printf("%11s ",str_class(c));
}
/***************************
* Write out oper numbers.
*/
void WROP(unsigned oper)
{
if (oper >= OPMAX)
{ dbg_printf("op = x%x, OPMAX = %d\n",oper,OPMAX);
assert(0);
}
ferr(debtab[oper]);
ferr(" ");
}
/*******************************
* Write TYxxxx
*/
void WRTYxx(tym_t t)
{
#if TX86
if (t & mTYnear)
dbg_printf("mTYnear|");
#if TARGET_SEGMENTED
if (t & mTYfar)
dbg_printf("mTYfar|");
if (t & mTYcs)
dbg_printf("mTYcs|");
#endif
#endif
if (t & mTYconst)
dbg_printf("mTYconst|");
if (t & mTYvolatile)
dbg_printf("mTYvolatile|");
#if !MARS && (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4)
if (t & mTYtransu)
dbg_printf("mTYtransu|");
#endif
t = tybasic(t);
if (t >= TYMAX)
{ dbg_printf("TY %lx\n",(long)t);
assert(0);
}
dbg_printf("TY%s ",tystring[tybasic(t)]);
}
void WRBC(unsigned bc)
{ static char bcs[][7] =
{"unde ","goto ","true ","ret ","retexp",
"exit ","asm ","switch","ifthen","jmptab",
"try ","catch ","jump ",
"_try ","_filte","_final","_ret ","_excep",
"jcatch",
"jplace",
};
assert(sizeof(bcs) / sizeof(bcs[0]) == BCMAX);
assert(bc < BCMAX);
dbg_printf("BC%s",bcs[bc]);
}
/************************
* Write arglst
*/
void WRarglst(list_t a)
{ int n = 1;
if (!a) dbg_printf("0 args\n");
while (a)
{ const char* c = (const char*)list_ptr(a);
dbg_printf("arg %d: '%s'\n", n, c ? c : "NULL");
a = a->next;
n++;
}
}
/***************************
* Write out equation elem.
*/
void WReqn(elem *e)
{ static int nest;
if (!e)
return;
if (OTunary(e->Eoper))
{
WROP(e->Eoper);
if (OTbinary(e->E1->Eoper))
{ nest++;
ferr("(");
WReqn(e->E1);
ferr(")");
nest--;
}
else
WReqn(e->E1);
}
else if (e->Eoper == OPcomma && !nest)
{ WReqn(e->E1);
dbg_printf(";\n\t");
WReqn(e->E2);
}
else if (OTbinary(e->Eoper))
{
if (OTbinary(e->E1->Eoper))
{ nest++;
ferr("(");
WReqn(e->E1);
ferr(")");
nest--;
}
else
WReqn(e->E1);
ferr(" ");
WROP(e->Eoper);
if (e->Eoper == OPstreq)
dbg_printf("%ld",(long)type_size(e->ET));
ferr(" ");
if (OTbinary(e->E2->Eoper))
{ nest++;
ferr("(");
WReqn(e->E2);
ferr(")");
nest--;
}
else
WReqn(e->E2);
}
else
{
switch (e->Eoper)
{ case OPconst:
switch (tybasic(e->Ety))
{
case TYfloat:
dbg_printf("%g <float> ",e->EV.Vfloat);
break;
case TYdouble:
dbg_printf("%g ",e->EV.Vdouble);
break;
case TYldouble:
dbg_printf("%Lg ",e->EV.Vldouble);
break;
case TYcent:
case TYucent:
dbg_printf("%lld+%lld ", e->EV.Vcent.msw, e->EV.Vcent.lsw);
break;
default:
dbg_printf("%lld ",el_tolong(e));
break;
}
break;
case OPrelconst:
ferr("#");
/* FALL-THROUGH */
case OPvar:
dbg_printf("%s",e->EV.sp.Vsym->Sident);
if (e->EV.sp.Vsym->Ssymnum != -1)
dbg_printf("(%d)",e->EV.sp.Vsym->Ssymnum);
if (e->Eoffset != 0)
{
if (sizeof(e->Eoffset) == 8)
dbg_printf(".x%llx", e->Eoffset);
else
dbg_printf(".%ld",(long)e->Eoffset);
}
break;
case OPasm:
case OPstring:
dbg_printf("\"%s\"",e->EV.ss.Vstring);
if (e->EV.ss.Voffset)
dbg_printf("+%ld",(long)e->EV.ss.Voffset);
break;
case OPmark:
case OPgot:
case OPframeptr:
case OPhalt:
WROP(e->Eoper);
break;
case OPstrthis:
break;
default:
WROP(e->Eoper);
assert(0);
}
}
}
void WRblocklist(list_t bl)
{
for (; bl; bl = list_next(bl))
{ register block *b = list_block(bl);
if (b && b->Bweight)
dbg_printf("B%d (%p) ",b->Bdfoidx,b);
else
dbg_printf("%p ",b);
}
ferr("\n");
}
void WRdefnod()
{ register int i;
for (i = 0; i < deftop; i++)
{ dbg_printf("defnod[%d] in B%d = (",defnod[i].DNblock->Bdfoidx,i);
WReqn(defnod[i].DNelem);
dbg_printf(");\n");
}
}
void WRFL(enum FL fl)
{ static char fls[FLMAX][7] =
{"unde ","const ","oper ","func ","data ",
"reg ",
"pseudo",
"auto ","para ","extrn ","tmp ",
"code ","block ","udata ","cs ","swit ",
"fltrg ","offst ","datsg ",
"ctor ","dtor ","regsav","asm ",
#if TX86
"ndp ",
#endif
#if TARGET_SEGMENTED
"farda ","csdat ",
#endif
"local ","tlsdat",
"bprel ","frameh","blocko","alloca",
"stack ","dsym ",
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
"got ","gotoff",
#endif
};
if ((unsigned)fl >= (unsigned)FLMAX)
dbg_printf("FL%d",fl);
else
dbg_printf("FL%s",fls[fl]);
}
/***********************
* Write out block.
*/
void WRblock(block *b)
{
if (OPTIMIZER)
{
if (b && b->Bweight)
dbg_printf("B%d: (%p), weight=%d",b->Bdfoidx,b,b->Bweight);
else
dbg_printf("block %p",b);
if (!b)
{ ferr("\n");
return;
}
dbg_printf(" flags=x%x weight=%d",b->Bflags,b->Bweight);
#if 0
dbg_printf("\tfile %p, line %d",b->Bfilptr,b->Blinnum);
#endif
dbg_printf(" ");
WRBC(b->BC);
dbg_printf(" Btry=%p Bindex=%d",b->Btry,b->Bindex);
#if SCPP
if (b->BC == BCtry)
dbg_printf(" catchvar = %p",b->catchvar);
#endif
dbg_printf("\n");
dbg_printf("\tBpred: "); WRblocklist(b->Bpred);
dbg_printf("\tBsucc: "); WRblocklist(b->Bsucc);
if (b->Belem)
{ if (debugf) /* if full output */
elem_print(b->Belem);
else
{ ferr("\t");
WReqn(b->Belem);
dbg_printf(";\n");
}
}
if (b->Bcode)
b->Bcode->print();
ferr("\n");
}
else
{
targ_llong *pu;
int ncases;
list_t bl;
assert(b);
dbg_printf("********* Basic Block %p ************\n",b);
if (b->Belem) elem_print(b->Belem);
dbg_printf("block: ");
WRBC(b->BC);
dbg_printf(" Btry=%p Bindex=%d",b->Btry,b->Bindex);
dbg_printf("\n");
dbg_printf("\tBpred:\n");
for (bl = b->Bpred; bl; bl = list_next(bl))
dbg_printf("\t%p\n",list_block(bl));
bl = b->Bsucc;
switch (b->BC)
{
case BCswitch:
pu = b->BS.Bswitch;
assert(pu);
ncases = *pu;
dbg_printf("\tncases = %d\n",ncases);
dbg_printf("\tdefault: %p\n",list_block(bl));
while (ncases--)
{ bl = list_next(bl);
dbg_printf("\tcase %lld: %p\n",*++pu,list_block(bl));
}
break;
case BCiftrue:
case BCgoto:
case BCasm:
#if SCPP
case BCtry:
case BCcatch:
#endif
case BCjcatch:
case BC_try:
case BC_filter:
case BC_finally:
case BC_ret:
case BC_except:
Lsucc:
dbg_printf("\tBsucc:\n");
for ( ; bl; bl = list_next(bl))
dbg_printf("\t%p\n",list_block(bl));
break;
case BCret:
case BCretexp:
case BCexit:
break;
default:
assert(0);
}
}
}
void WRfunc()
{
block *b;
dbg_printf("func: '%s'\n",funcsym_p->Sident);
for (b = startblock; b; b = b->Bnext)
WRblock(b);
}
#endif /* DEBUG */
#endif /* !SPP */

383
backend/dt.c Normal file
View File

@@ -0,0 +1,383 @@
// Copyright (C) 1984-1998 by Symantec
// Copyright (C) 2000-2010 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "cc.h"
#include "oper.h"
#include "global.h"
#include "el.h"
#include "type.h"
#include "dt.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
static dt_t *dt_freelist;
/**********************************************
* Allocate a data definition struct.
*/
dt_t *dt_calloc(char dtx)
{
dt_t *dt;
static dt_t dtzero;
if (dt_freelist)
{
dt = dt_freelist;
dt_freelist = dt->DTnext;
*dt = dtzero;
}
else
dt = (dt_t *) mem_fcalloc(sizeof(dt_t));
dt->dt = dtx;
return dt;
}
/**********************************************
* Free a data definition struct.
*/
void dt_free(dt_t *dt)
{ dt_t *dtn;
for (; dt; dt = dtn)
{
switch (dt->dt)
{
case DT_abytes:
case DT_nbytes:
mem_free(dt->DTpbytes);
break;
}
dtn = dt->DTnext;
dt->DTnext = dt_freelist;
dt_freelist = dt;
}
}
/*********************************
* Free free list.
*/
void dt_term()
{
#if TERMCODE
dt_t *dtn;
while (dt_freelist)
{ dtn = dt_freelist->DTnext;
mem_ffree(dt_freelist);
dt_freelist = dtn;
}
#endif
}
/**********************
* Construct a DT_azeros record, and return it.
* Increment dsout.
*/
dt_t **dtnzeros(dt_t **pdtend,targ_size_t size)
{ dt_t *dt;
//printf("dtnzeros(x%x)\n",size);
assert((long) size >= 0);
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
if (size)
{ dt = dt_calloc(DT_azeros);
dt->DTazeros = size;
*pdtend = dt;
pdtend = &dt->DTnext;
#if SCPP
dsout += size;
#endif
}
return pdtend;
}
/**********************
* Construct a DTsymsize record.
*/
void dtsymsize(symbol *s)
{
symbol_debug(s);
s->Sdt = dt_calloc(DT_symsize);
}
/**********************
* Construct a DTnbytes record, and return it.
*/
dt_t ** dtnbytes(dt_t **pdtend,targ_size_t size,const char *ptr)
{ dt_t *dt;
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
if (size)
{ if (size == 1)
{ dt = dt_calloc(DT_1byte);
dt->DTonebyte = *ptr;
}
else if (size <= 7)
{ dt = dt_calloc(DT_ibytes);
dt->DTn = size;
memcpy(dt->DTdata,ptr,size);
}
else
{
dt = dt_calloc(DT_nbytes);
dt->DTnbytes = size;
dt->DTpbytes = (char *) MEM_PH_MALLOC(size);
memcpy(dt->DTpbytes,ptr,size);
}
*pdtend = dt;
pdtend = &dt->DTnext;
}
return pdtend;
}
/**********************
* Construct a DTabytes record, and return it.
*/
dt_t **dtabytes(dt_t **pdtend,tym_t ty, targ_size_t offset, targ_size_t size, const char *ptr)
{ dt_t *dt;
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
dt = dt_calloc(DT_abytes);
dt->DTnbytes = size;
dt->DTpbytes = (char *) MEM_PH_MALLOC(size);
dt->Dty = ty;
dt->DTabytes = offset;
memcpy(dt->DTpbytes,ptr,size);
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
/**********************
* Construct a DTibytes record, and return it.
*/
dt_t ** dtdword(dt_t **pdtend, int value)
{ dt_t *dt;
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
dt = dt_calloc(DT_ibytes);
dt->DTn = 4;
union { char* cp; int* lp; } u;
u.cp = dt->DTdata;
*u.lp = value;
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
dt_t ** dtsize_t(dt_t **pdtend, targ_size_t value)
{ dt_t *dt;
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
dt = dt_calloc(DT_ibytes);
dt->DTn = NPTRSIZE;
union { char* cp; int* lp; } u;
u.cp = dt->DTdata;
*u.lp = value;
if (NPTRSIZE == 8)
u.lp[1] = value >> 32;
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
/**********************
* Concatenate two dt_t's.
*/
dt_t ** dtcat(dt_t **pdtend,dt_t *dt)
{
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
/**********************
* Construct a DTcoff record, and return it.
*/
dt_t ** dtcoff(dt_t **pdtend,targ_size_t offset)
{ dt_t *dt;
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
dt = dt_calloc(DT_coff);
#if TARGET_SEGMENTED
dt->Dty = TYcptr;
#else
dt->Dty = TYnptr;
#endif
dt->DToffset = offset;
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
/**********************
* Construct a DTxoff record, and return it.
*/
dt_t ** dtxoff(dt_t **pdtend,symbol *s,targ_size_t offset,tym_t ty)
{ dt_t *dt;
symbol_debug(s);
while (*pdtend)
pdtend = &((*pdtend)->DTnext);
dt = dt_calloc(DT_xoff);
dt->DTsym = s;
dt->DToffset = offset;
dt->Dty = ty;
*pdtend = dt;
pdtend = &dt->DTnext;
return pdtend;
}
/**************************
* 'Optimize' a list of dt_t's.
* (Try to collapse it into one DT_azeros object.)
*/
void dt_optimize(dt_t *dt)
{ dt_t *dtn;
if (dt)
{ for (; 1; dt = dtn)
{
dtn = dt->DTnext;
if (!dtn)
break;
switch (dt->dt)
{
case DT_azeros:
if (dtn->dt == DT_1byte && dtn->DTonebyte == 0)
{
dt->DTazeros += 1;
goto L1;
}
else if (dtn->dt == DT_azeros)
{
dt->DTazeros += dtn->DTazeros;
goto L1;
}
break;
case DT_1byte:
if (dt->DTonebyte == 0)
{
if (dtn->dt == DT_1byte && dtn->DTonebyte == 0)
{
dt->DTazeros = 2;
goto L1;
}
else if (dtn->dt == DT_azeros)
{
dt->DTazeros = 1 + dtn->DTazeros;
L1:
dt->dt = DT_azeros;
dt->DTnext = dtn->DTnext;
dtn->DTnext = NULL;
dt_free(dtn);
dtn = dt;
}
}
break;
}
}
}
}
/**************************
* Make a common block for s.
*/
void init_common(symbol *s)
{
//printf("init_common('%s')\n", s->Sident);
dtnzeros(&s->Sdt,type_size(s->Stype));
if (s->Sdt)
s->Sdt->dt = DT_common;
}
/**********************************
* Compute size of a dt
*/
unsigned dt_size(dt_t *dtstart)
{ dt_t *dt;
unsigned datasize;
datasize = 0;
for (dt = dtstart; dt; dt = dt->DTnext)
{
switch (dt->dt)
{ case DT_abytes:
datasize += size(dt->Dty);
break;
case DT_ibytes:
datasize += dt->DTn;
break;
case DT_nbytes:
datasize += dt->DTnbytes;
break;
case DT_symsize:
case DT_azeros:
datasize += dt->DTazeros;
break;
case DT_common:
break;
case DT_xoff:
case DT_coff:
datasize += size(dt->Dty);
break;
case DT_1byte:
datasize++;
break;
default:
#ifdef DEBUG
dbg_printf("dt = %p, dt = %d\n",dt,dt->dt);
#endif
assert(0);
}
}
return datasize;
}
#endif /* !SPP */

114
backend/dt.h Normal file
View File

@@ -0,0 +1,114 @@
// Copyright (C) 1984-1995 by Symantec
// Copyright (C) 2000-2010 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
//#pragma once
#ifndef DT_H
#define DT_H 1
/**********************************
* Data definitions
* DTibytes 1..7 bytes
* DT1byte one byte of data follows
* n
* DTabytes offset of bytes of data
* a { a data bytes }
* DTnbytes bytes of data
* a { a data bytes }
* a = offset
* DTazeros # of 0 bytes
* a
* DTsymsize same as DTazeros, but the type of the symbol gives
* the size
* DTcommon # of 0 bytes (in a common block)
* a
* DTxoff offset from symbol
* w a
* w = symbol number (pointer for CPP)
* a = offset
* DTcoff offset into code segment
* DTend mark end of list
*/
struct dt_t
{ dt_t *DTnext; // next in list
char dt; // type (DTxxxx)
unsigned char Dty; // pointer type
union
{
struct // DTibytes
{ char DTn_; // number of bytes
#define DTn _DU._DI.DTn_
char DTdata_[8]; // data
#define DTdata _DU._DI.DTdata_
}_DI;
char DTonebyte_; // DT1byte
#define DTonebyte _DU.DTonebyte_
targ_size_t DTazeros_; // DTazeros,DTcommon,DTsymsize
#define DTazeros _DU.DTazeros_
struct // DTabytes
{
char *DTpbytes_; // pointer to the bytes
#define DTpbytes _DU._DN.DTpbytes_
unsigned DTnbytes_; // # of bytes
#define DTnbytes _DU._DN.DTnbytes_
#if TX86
int DTseg_; // segment it went into
#define DTseg _DU._DN.DTseg_
#endif
targ_size_t DTabytes_; // offset of abytes for DTabytes
#define DTabytes _DU._DN.DTabytes_
}_DN;
struct // DTxoff
{
symbol *DTsym_; // symbol pointer
#define DTsym _DU._DS.DTsym_
targ_size_t DToffset_; // offset from symbol
#define DToffset _DU._DS.DToffset_
}_DS;
}_DU;
};
enum
{
DT_abytes,
DT_azeros, // 1
DT_xoff,
DT_1byte,
DT_nbytes,
DT_common,
DT_symsize,
DT_coff,
DT_ibytes, // 8
};
#if TX86
dt_t *dt_calloc(char dtx);
void dt_free(dt_t *);
void dt_term(void);
#endif
dt_t **dtnbytes(dt_t **,targ_size_t,const char *);
dt_t **dtabytes(dt_t **pdtend,tym_t ty, targ_size_t offset, targ_size_t size, const char *ptr);
dt_t **dtdword(dt_t **, int value);
dt_t **dtsize_t(dt_t **, targ_size_t value);
dt_t **dtnzeros(dt_t **pdtend,targ_size_t size);
dt_t **dtxoff(dt_t **pdtend,symbol *s,targ_size_t offset,tym_t ty);
dt_t **dtselfoff(dt_t **pdtend,targ_size_t offset,tym_t ty);
dt_t **dtcoff(dt_t **pdtend,targ_size_t offset);
dt_t ** dtcat(dt_t **pdtend,dt_t *dt);
void dt_optimize(dt_t *dt);
void dtsymsize(symbol *);
void init_common(symbol *);
unsigned dt_size(dt_t *dtstart);
#endif /* DT_H */

2531
backend/dwarf.c Normal file

File diff suppressed because it is too large Load Diff

18
backend/dwarf.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef DWARF_H
#define DWARF_H
/* ==================== Dwarf debug ======================= */
// #define USE_DWARF_D_EXTENSIONS
void dwarf_initfile(const char *filename);
void dwarf_termfile();
void dwarf_initmodule(const char *filename, const char *modulename);
void dwarf_termmodule();
void dwarf_func_start(Symbol *sfunc);
void dwarf_func_term(Symbol *sfunc);
unsigned dwarf_typidx(type *t);
unsigned dwarf_abbrev_code(unsigned char *data, size_t nbytes);
#endif

470
backend/dwarf2.h Normal file
View File

@@ -0,0 +1,470 @@
// dwarf2.h
// Reflects declarations from the Dwarf 3 spec, not the Digital Mars
// dwarf implementation
enum
{
DW_TAG_array_type = 0x01,
DW_TAG_class_type = 0x02,
DW_TAG_entry_point = 0x03,
DW_TAG_enumeration_type = 0x04,
DW_TAG_formal_parameter = 0x05,
DW_TAG_imported_declaration = 0x08,
DW_TAG_label = 0x0A,
DW_TAG_lexical_block = 0x0B,
DW_TAG_member = 0x0D,
DW_TAG_pointer_type = 0x0F,
DW_TAG_reference_type = 0x10,
DW_TAG_compile_unit = 0x11,
DW_TAG_string_type = 0x12,
DW_TAG_structure_type = 0x13,
DW_TAG_subroutine_type = 0x15,
DW_TAG_typedef = 0x16,
DW_TAG_union_type = 0x17,
DW_TAG_unspecified_parameters = 0x18,
DW_TAG_variant = 0x19,
DW_TAG_common_block = 0x1A,
DW_TAG_common_inclusion = 0x1B,
DW_TAG_inheritance = 0x1C,
DW_TAG_inlined_subroutine = 0x1D,
DW_TAG_module = 0x1E,
DW_TAG_ptr_to_member_type = 0x1F,
DW_TAG_set_type = 0x20,
DW_TAG_subrange_type = 0x21,
DW_TAG_with_stmt = 0x22,
DW_TAG_access_declaration = 0x23,
DW_TAG_base_type = 0x24,
DW_TAG_catch_block = 0x25,
DW_TAG_const_type = 0x26,
DW_TAG_constant = 0x27,
DW_TAG_enumerator = 0x28,
DW_TAG_file_type = 0x29,
DW_TAG_friend = 0x2A,
DW_TAG_namelist = 0x2B,
DW_TAG_namelist_item = 0x2C,
DW_TAG_packed_type = 0x2D,
DW_TAG_subprogram = 0x2E,
DW_TAG_template_type_param = 0x2F,
DW_TAG_template_value_param = 0x30,
DW_TAG_thrown_type = 0x31,
DW_TAG_try_block = 0x32,
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
DW_TAG_dwarf_procedure = 0x36,
DW_TAG_restrict_type = 0x37,
DW_TAG_interface_type = 0x38,
DW_TAG_namespace = 0x39,
DW_TAG_imported_module = 0x3A,
DW_TAG_unspecified_type = 0x3B,
DW_TAG_partial_unit = 0x3C,
DW_TAG_imported_unit = 0x3D,
DW_TAG_condition = 0x3F,
DW_TAG_shared_type = 0x40,
// D programming language extensions
#ifdef USE_DWARF_D_EXTENSIONS
DW_TAG_darray_type = 0x41,
DW_TAG_aarray_type = 0x42,
DW_TAG_delegate_type = 0x43,
#endif
DW_TAG_lo_user = 0x4080,
DW_TAG_hi_user = 0xFFFF,
};
enum
{
DW_CHILDREN_no = 0x00,
DW_CHILDREN_yes = 0x01,
};
enum
{
DW_AT_sibling = 0x01,
DW_AT_location = 0x02,
DW_AT_name = 0x03,
DW_AT_ordering = 0x09,
DW_AT_byte_size = 0x0B,
DW_AT_bit_offset = 0x0C,
DW_AT_bit_size = 0x0D,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_language = 0x13,
DW_AT_discr = 0x15,
DW_AT_discr_value = 0x16,
DW_AT_visibility = 0x17,
DW_AT_import = 0x18,
DW_AT_string_length = 0x19,
DW_AT_common_reference = 0x1A,
DW_AT_comp_dir = 0x1B,
DW_AT_const_value = 0x1C,
DW_AT_containing_type = 0x1D,
DW_AT_default_value = 0x1E,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
DW_AT_producer = 0x25,
DW_AT_prototyped = 0x27,
DW_AT_return_addr = 0x2A,
DW_AT_start_scope = 0x2C,
DW_AT_stride_size = 0x2E,
DW_AT_upper_bound = 0x2F,
DW_AT_abstract_origin = 0x31,
DW_AT_accessibility = 0x32,
DW_AT_address_class = 0x33,
DW_AT_artificial = 0x34,
DW_AT_base_types = 0x35,
DW_AT_calling_convention = 0x36,
DW_AT_count = 0x37,
DW_AT_data_member_location = 0x38,
DW_AT_decl_column = 0x39,
DW_AT_decl_file = 0x3A,
DW_AT_decl_line = 0x3B,
DW_AT_declaration = 0x3C,
DW_AT_discr_list = 0x3D,
DW_AT_encoding = 0x3E,
DW_AT_external = 0x3F,
DW_AT_frame_base = 0x40,
DW_AT_friend = 0x41,
DW_AT_identifier_case = 0x42,
DW_AT_macro_info = 0x43,
DW_AT_namelist_item = 0x44,
DW_AT_priority = 0x45,
DW_AT_segment = 0x46,
DW_AT_specification = 0x47,
DW_AT_static_link = 0x48,
DW_AT_type = 0x49,
DW_AT_use_location = 0x4A,
DW_AT_variable_parameter = 0x4B,
DW_AT_virtuality = 0x4C,
DW_AT_vtable_elem_location = 0x4D,
DW_AT_allocated = 0x4E,
DW_AT_associated = 0x4F,
DW_AT_data_location = 0x50,
DW_AT_byte_stride = 0x51,
DW_AT_entry_pc = 0x52,
DW_AT_use_UTF8 = 0x53,
DW_AT_extension = 0x54,
DW_AT_ranges = 0x55,
DW_AT_trampoline = 0x56,
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
DW_AT_description = 0x5A,
DW_AT_binary_scale = 0x5B,
DW_AT_decimal_scale = 0x5C,
DW_AT_small = 0x5D,
DW_AT_decimal_sign = 0x5E,
DW_AT_digit_count = 0x5F,
DW_AT_picture_string = 0x60,
DW_AT_mutable = 0x61,
DW_AT_threads_scaled = 0x62,
DW_AT_explicit = 0x63,
DW_AT_object_pointer = 0x64,
DW_AT_endianity = 0x65,
DW_AT_elemental = 0x66,
DW_AT_pure = 0x67,
DW_AT_recursive = 0x68,
DW_AT_lo_user = 0x2000,
DW_AT_MIPS_linkage_name = 0x2007,
DW_AT_GNU_vector = 0x2107,
DW_AT_hi_user = 0x3FFF,
};
enum
{
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0A,
DW_FORM_data1 = 0x0B,
DW_FORM_flag = 0x0C,
DW_FORM_sdata = 0x0D,
DW_FORM_strp = 0x0E,
DW_FORM_udata = 0x0F,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16,
};
enum
{
DW_OP_addr = 0x03,
DW_OP_deref = 0x06,
DW_OP_const1u = 0x08,
DW_OP_const1s = 0x09,
DW_OP_const2u = 0x0a,
DW_OP_const2s = 0x0b,
DW_OP_const4u = 0x0c,
DW_OP_const4s = 0x0d,
DW_OP_const8u = 0x0e,
DW_OP_const8s = 0x0f,
DW_OP_constu = 0x10,
DW_OP_consts = 0x11,
DW_OP_dup = 0x12,
DW_OP_drop = 0x13,
DW_OP_over = 0x14,
DW_OP_pick = 0x15,
DW_OP_swap = 0x16,
DW_OP_rot = 0x17,
DW_OP_xderef = 0x18,
DW_OP_abs = 0x19,
DW_OP_and = 0x1a,
DW_OP_div = 0x1b,
DW_OP_minus = 0x1c,
DW_OP_mod = 0x1d,
DW_OP_mul = 0x1e,
DW_OP_neg = 0x1f,
DW_OP_not = 0x20,
DW_OP_or = 0x21,
DW_OP_plus = 0x22,
DW_OP_plus_uconst = 0x23,
DW_OP_shl = 0x24,
DW_OP_shr = 0x25,
DW_OP_shra = 0x26,
DW_OP_xor = 0x27,
DW_OP_skip = 0x2f,
DW_OP_bra = 0x28,
DW_OP_eq = 0x29,
DW_OP_ge = 0x2a,
DW_OP_gt = 0x2b,
DW_OP_le = 0x2c,
DW_OP_lt = 0x2d,
DW_OP_ne = 0x2e,
DW_OP_lit0 = 0x30,
DW_OP_lit1 = 0x31,
DW_OP_lit31 = 0x4f,
DW_OP_reg0 = 0x50,
DW_OP_reg1 = 0x51,
DW_OP_reg31 = 0x6f,
DW_OP_breg0 = 0x70,
DW_OP_breg1 = 0x71,
DW_OP_breg31 = 0x8f,
DW_OP_regx = 0x90,
DW_OP_fbreg = 0x91,
DW_OP_bregx = 0x92,
DW_OP_piece = 0x93,
DW_OP_deref_size = 0x94,
DW_OP_xderef_size = 0x95,
DW_OP_nop = 0x96,
DW_OP_push_object_address = 0x97,
DW_OP_call2 = 0x98,
DW_OP_call4 = 0x99,
DW_OP_call_ref = 0x9a,
DW_OP_form_tls_address = 0x9b,
DW_OP_call_frame_cfa = 0x9c,
DW_OP_bit_piece = 0x9d,
DW_OP_lo_user = 0xe0,
DW_OP_hi_user = 0xff,
};
enum
{
DW_ATE_address = 0x01,
DW_ATE_boolean = 0x02,
DW_ATE_complex_float = 0x03,
DW_ATE_float = 0x04,
DW_ATE_signed = 0x05,
DW_ATE_signed_char = 0x06,
DW_ATE_unsigned = 0x07,
DW_ATE_unsigned_char = 0x08,
DW_ATE_imaginary_float = 0x09,
DW_ATE_packed_decimal = 0x0a,
DW_ATE_numeric_string = 0x0b,
DW_ATE_editted = 0x0c,
DW_ATE_signed_fixed = 0x0d,
DW_ATE_unsigned_fixed = 0x0e,
DW_ATE_decimal_float = 0x0f,
DW_ATE_lo_user = 0x80,
DW_ATE_hi_user = 0xff,
};
enum
{
DW_DS_unsigned = 0x01,
DW_DS_leading_overpunch = 0x02,
DW_DS_trailing_overpunch = 0x03,
DW_DS_leading_separate = 0x04,
DW_DS_trailing_separate = 0x05,
};
enum
{
DW_END_default = 0x00,
DW_END_big = 0x01,
DW_END_little = 0x02,
DW_END_lo_user = 0x40,
DW_END_hi_user = 0xff,
};
enum
{
DW_ACCESS_public = 0x01,
DW_ACCESS_protected = 0x02,
DW_ACCESS_private = 0x03,
};
enum
{
DW_VIS_local = 0x01,
DW_VIS_exported = 0x02,
DW_VIS_qualified = 0x03,
};
enum
{
DW_VIRTUALITY_none = 0x00,
DW_VIRTUALITY_virtual = 0x01,
DW_VIRTUALITY_pure_virtual = 0x02,
};
enum
{
DW_LANG_C89 = 0x0001,
DW_LANG_C = 0x0002,
DW_LANG_Ada83 = 0x0003,
DW_LANG_C_plus_plus = 0x0004,
DW_LANG_Cobol74 = 0x0005,
DW_LANG_Cobol85 = 0x0006,
DW_LANG_Fortran77 = 0x0007,
DW_LANG_Fortran90 = 0x0008,
DW_LANG_Pascal83 = 0x0009,
DW_LANG_Modula2 = 0x000a,
DW_LANG_Java = 0x000b,
DW_LANG_C99 = 0x000c,
DW_LANG_Ada95 = 0x000d,
DW_LANG_Fortran95 = 0x000e,
DW_LANG_PLI = 0x000f,
DW_LANG_ObjC = 0x0010,
DW_LANG_ObjC_plus_plus = 0x0011,
DW_LANG_UPC = 0x0012,
DW_LANG_D = 0x0013,
DW_LANG_lo_user = 0x8000,
DW_LANG_hi_user = 0xffff,
};
enum
{
DW_ID_case_sensitive = 0x00,
DW_ID_up_case = 0x01,
DW_ID_down_case = 0x02,
DW_ID_case_insensitive = 0x03,
};
enum
{
DW_CC_normal = 0x01,
DW_CC_program = 0x02,
DW_CC_nocall = 0x03,
DW_CC_lo_user = 0x40,
DW_CC_hi_user = 0xff,
};
enum
{
DW_INL_not_inlined = 0x00,
DW_INL_inlined = 0x01,
DW_INL_declared_not_inlined = 0x02,
DW_INL_declared_inlined = 0x03,
};
enum
{
DW_ORD_row_major = 0x00,
DW_ORD_col_major = 0x01,
};
enum
{
DW_DSC_label = 0x00,
DW_DSC_range = 0x01,
};
enum
{
DW_LNS_copy = 0x01,
DW_LNS_advance_pc = 0x02,
DW_LNS_advance_line = 0x03,
DW_LNS_set_file = 0x04,
DW_LNS_set_column = 0x05,
DW_LNS_negate_stmt = 0x06,
DW_LNS_set_basic_block = 0x07,
DW_LNS_const_add_pc = 0x08,
DW_LNS_fixed_advance_pc = 0x09,
DW_LNS_set_prologue_end = 0x0a,
DW_LNS_set_epilogue_begin = 0x0b,
DW_LNS_set_isa = 0x0c,
};
enum
{
DW_LNE_end_sequence = 0x01,
DW_LNE_set_address = 0x02,
DW_LNE_define_file = 0x03,
DW_LNE_lo_user = 0x80,
DW_LNE_hi_user = 0xff,
};
enum
{
DW_MACINFO_define = 0x01,
DW_MACINFO_undef = 0x02,
DW_MACINFO_start_file = 0x03,
DW_MACINFO_end_file = 0x04,
DW_MACINFO_vendor_ext = 0xff,
};
enum
{
DW_CFA_advance_loc = 0x40,
DW_CFA_offset = 0x80,
DW_CFA_restore = 0xc0,
DW_CFA_nop = 0x00,
DW_CFA_set_loc = 0x01,
DW_CFA_advance_loc1 = 0x02,
DW_CFA_advance_loc2 = 0x03,
DW_CFA_advance_loc4 = 0x04,
DW_CFA_offset_extended = 0x05,
DW_CFA_restore_extended = 0x06,
DW_CFA_undefined = 0x07,
DW_CFA_same_value = 0x08,
DW_CFA_register = 0x09,
DW_CFA_remember_state = 0x0a,
DW_CFA_restore_state = 0x0b,
DW_CFA_def_cfa = 0x0c,
DW_CFA_def_cfa_register = 0x0d,
DW_CFA_def_cfa_offset = 0x0e,
DW_CFA_def_cfa_expression = 0x0f,
DW_CFA_expression = 0x10,
DW_CFA_offset_extended_sf = 0x11,
DW_CFA_def_cfa_sf = 0x12,
DW_CFA_def_cfa_offset_sf = 0x13,
DW_CFA_val_offset = 0x14,
DW_CFA_val_offset_sf = 0x15,
DW_CFA_val_expression = 0x16,
DW_CFA_GNU_window_save = 0x2d,
DW_CFA_GNU_args_size = 0x2e,
DW_CFA_GNU_negative_offset_extended = 0x2f,
DW_CFA_lo_user = 0x1c,
DW_CFA_hi_user = 0x3f,
};

124
backend/ee.c Normal file
View File

@@ -0,0 +1,124 @@
// Copyright (C) 1995-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/*
* Code to handle debugger expression evaluation
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "token.h"
#include "global.h"
#include "type.h"
#include "oper.h"
#include "el.h"
#include "exh.h"
#if TX86
#include "cgcv.h"
#endif
#if SCPP
#include "parser.h"
#endif
#include "iasm.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
#if MARS
EEcontext eecontext;
#endif
//////////////////////////////////////
// Convert any symbols generated for the debugger expression to SCstack
// storage class.
void eecontext_convs(unsigned marksi)
{ unsigned u;
unsigned top;
symtab_t *ps;
// Change all generated SCtmp's and SCauto's to SCstack's
#if SCPP
ps = &globsym;
#else
ps = cstate.CSpsymtab;
#endif
top = ps->top;
//printf("eecontext_convs(%d,%d)\n",marksi,top);
for (u = marksi; u < top; u++)
{ symbol *s;
s = ps->tab[u];
switch (s->Sclass)
{
case SCauto:
case SCtmp:
case SCregister:
s->Sclass = SCstack;
s->Sfl = FLstack;
break;
}
}
}
////////////////////////////////////////
// Parse the debugger expression.
#if SCPP
void eecontext_parse()
{
if (eecontext.EEimminent)
{ type *t;
unsigned marksi;
symbol *s;
//printf("imminent\n");
marksi = globsym.top;
eecontext.EEin++;
s = symbol_genauto(tspvoid);
eecontext.EEelem = func_expr_dtor(TRUE);
t = eecontext.EEelem->ET;
if (tybasic(t->Tty) != TYvoid)
{ unsigned op;
elem *e;
e = el_unat(OPind,t,el_var(s));
op = tyaggregate(t->Tty) ? OPstreq : OPeq;
eecontext.EEelem = el_bint(op,t,e,eecontext.EEelem);
}
eecontext.EEin--;
eecontext.EEimminent = 0;
eecontext.EEfunc = funcsym_p;
eecontext_convs(marksi);
// Generate the typedef
if (eecontext.EEtypedef && config.fulltypes)
{ symbol *s;
s = symbol_name(eecontext.EEtypedef,SCtypedef,t);
cv_outsym(s);
symbol_free(s);
}
}
}
#endif
#endif

3326
backend/el.c Normal file

File diff suppressed because it is too large Load Diff

219
backend/el.h Normal file
View File

@@ -0,0 +1,219 @@
// Copyright (C) 1985-1995 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/* Routines to handle elems. */
#if __SC__
#pragma once
#endif
#ifndef EL_H
#define EL_H 1
/******************************************
* Elems:
* Elems are the basic tree element. They can be either
* terminal elems (leaves), unary elems (left subtree exists)
* or binary elems (left and right subtrees exist).
*/
struct elem
{
#ifdef DEBUG
unsigned short id;
#define IDelem 0x4C45 // 'EL'
#define elem_debug(e) assert((e)->id == IDelem)
#else
#define elem_debug(e)
#endif
unsigned char Eoper; // operator (OPxxxx)
unsigned char Ecount; // # of parents of this elem - 1,
// always 0 until CSE elimination is done
unsigned char Eflags;
#define EFLAGS_variadic 1 // variadic function call
union eve EV; // variants for each type of elem
union
{
// PARSER
struct
{
unsigned PEFflags_;
#define PEFflags _EU._EP.PEFflags_
#define PEFnotlvalue 1 // although elem may look like
// an lvalue, it isn't
#define PEFtemplate_id 0x10 // symbol is a template-id
#define PEFparentheses 0x20 // expression was within ()
#define PEFaddrmem 0x40 // address of member
#define PEFdependent 0x80 // value-dependent
#define PEFmember 0x100 // was a class member access
Symbol *Emember_; // if PEFmember, this is the member
#define Emember _EU._EP.Emember_
}_EP;
// OPTIMIZER
struct
{
tym_t Ety_; // data type (TYxxxx)
#define Ety _EU._EO.Ety_
unsigned Eexp_; // index into expnod[]
#define Eexp _EU._EO.Eexp_
// These flags are all temporary markers, used once and then
// thrown away.
unsigned char Nflags_; // NFLxxx
#define Nflags _EU._EO.Nflags_
#define NFLli 1 // loop invariant
#define NFLnogoal 2 // evaluate elem for side effects only
#define NFLassign 8 // unambiguous assignment elem
#define NFLaecp 0x10 // AE or CP or VBE expression
#define NFLdelcse 0x40 // this is not the generating CSE
#define NFLtouns 0x80 // relational operator was changed from signed to unsigned
#if MARS
unsigned char Ejty_; // original Jupiter/Mars type
#define Ejty _EU._EO.Ejty_
#endif
}_EO;
// CODGEN
struct
{
// Ety2: Must be in same position as Ety!
tym_t Ety2_; // data type (TYxxxx)
#define Ety2 _EU._EC.Ety2_
unsigned char Ecomsub_; // number of remaining references to
// this common subexp (used to determine
// first, intermediate, and last references
// to a CSE)
#define Ecomsub _EU._EC.Ecomsub_
}_EC;
}_EU;
struct TYPE *ET; // pointer to type of elem if TYstruct | TYarray
Srcpos Esrcpos; // source file position
};
#define typemask(e) ((!MARS && PARSER) ? (e)->ET->Tty : (e)->Ety )
#define typetym(e) ((e)->ET->Tty)
#define el_fl(e) ((enum FL)((e)->EV.sp.Vsym->Sfl))
#define Eoffset EV.sp.Voffset
#define Esymnum EV.sp.Vsymnum
#define list_elem(list) ((elem *) list_ptr(list))
#define list_setelem(list,ptr) list_ptr(list) = (elem *)(ptr)
#define cnst(e) ((e)->Eoper == OPconst) /* Determine if elem is a constant */
#define E1 EV.eop.Eleft /* left child */
#define E2 EV.eop.Eright /* right child */
#define Erd EV.sp.spu.Erd // reaching definition
#define el_int(a,b) el_long(a,b)
typedef elem *elem_p; /* try to reduce the symbol table size */
void el_init(void);
void el_reset(void);
void el_term(void);
elem_p el_calloc(void);
void el_free(elem_p);
elem_p el_combine(elem_p ,elem_p);
elem_p el_param(elem_p ,elem_p);
elem_p el_params(elem_p , ...);
elem *el_params(void **args, int length);
elem *el_combines(void **args, int length);
int el_nparams(elem *e);
elem_p el_pair(tym_t, elem_p, elem_p);
void el_copy(elem_p ,elem_p);
elem_p el_alloctmp(tym_t);
elem_p el_selecte1(elem_p);
elem_p el_selecte2(elem_p);
elem_p el_copytree(elem_p);
void el_replace_sym(elem *e,symbol *s1,symbol *s2);
elem_p el_scancommas(elem_p);
int el_countCommas(elem_p);
int el_sideeffect(elem_p);
int el_depends(elem *ea,elem *eb);
#if LONGLONG
targ_llong el_tolongt(elem_p);
targ_llong el_tolong(elem_p);
#else
targ_long el_tolongt(elem_p);
targ_long el_tolong(elem_p);
#endif
int el_allbits(elem_p,int);
int el_signx32(elem_p);
targ_ldouble el_toldouble(elem_p);
void el_toconst(elem_p);
elem_p el_same(elem_p *);
int el_match(elem_p ,elem_p);
int el_match2(elem_p ,elem_p);
int el_match3(elem_p ,elem_p);
int el_match4(elem_p ,elem_p);
int el_match5(elem_p ,elem_p);
int el_appears(elem *e,symbol *s);
Symbol *el_basesym(elem *e);
int el_anydef(elem *ed, elem *e);
elem_p el_bint(unsigned,type *,elem_p ,elem_p);
elem_p el_unat(unsigned,type *,elem_p);
elem_p el_bin(unsigned,tym_t,elem_p ,elem_p);
elem_p el_una(unsigned,tym_t,elem_p);
#if LONGLONG // DJB
elem_p el_longt(type *,targ_llong);
#else
elem_p el_longt(type *,targ_long);
#endif
symbol *el_alloc_localgot();
elem_p el_var(symbol *);
elem_p el_settype(elem_p ,type *);
elem_p el_typesize(type *);
elem_p el_ptr(symbol *);
void el_replace_sym(elem *e,symbol *s1,symbol *s2);
elem * el_ptr_offset(symbol *s,targ_size_t offset);
void el_replacesym(elem *,symbol *,symbol *);
elem_p el_nelems(type *);
#if LONGLONG
elem_p el_long(tym_t,targ_llong);
#else
elem_p el_long(tym_t,targ_long);
#endif
int ERTOL(elem_p);
int el_noreturn(elem_p);
elem *el_dctor(elem *e,void *decl);
elem *el_ddtor(elem *e,void *decl);
elem *el_ctor(elem *ector,elem *e,symbol *sdtor);
elem *el_dtor(elem *edtor,elem *e);
elem *el_zero(type *t);
elem_p el_const(tym_t,union eve *);
elem_p el_test(tym_t,union eve *);
elem_p * el_parent(elem_p ,elem_p *);
#ifdef DEBUG
void el_check(elem_p);
#else
#define el_check(e) ((void)0)
#endif
elem *el_convfloat(elem *);
elem *el_convstring(elem *);
elem *el_convert(elem *e);
int el_isdependent(elem *);
unsigned el_alignsize(elem *);
void elem_print(elem *);
void el_hydrate(elem **);
void el_dehydrate(elem **);
#endif

3111
backend/elfobj.c Normal file

File diff suppressed because it is too large Load Diff

2089
backend/evalu8.c Normal file

File diff suppressed because it is too large Load Diff

47
backend/exh.h Normal file
View File

@@ -0,0 +1,47 @@
// Copyright (C) 1993-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
//#pragma once
#ifndef EXCEPT_H
#define EXCEPT_H 1
struct Aobject
{
symbol *AOsym; // symbol for active object
targ_size_t AOoffset; // offset from that object
symbol *AOfunc; // cleanup function
};
/* except.c */
void except_init(void);
void except_term(void);
elem *except_obj_ctor(elem *e,symbol *s,targ_size_t offset,symbol *sdtor);
elem *except_obj_dtor(elem *e,symbol *s,targ_size_t offset);
elem *except_throw_expression(void);
type *except_declaration(symbol *cv);
void except_exception_spec(type *t);
void except_index_set(int index);
int except_index_get(void);
void except_pair_setoffset(void *p,targ_size_t offset);
void except_pair_append(void *p, int index);
void except_push(void *p,elem *e,block *b);
void except_pop(void *p,elem *e,block *b);
void except_mark();
void except_release();
symbol *except_gensym();
symbol *except_gentables();
void except_fillInEHTable(symbol *s);
void except_reset();
#endif

852
backend/gdag.c Normal file
View File

@@ -0,0 +1,852 @@
// Copyright (C) 1986-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if (SCPP || MARS) && !HTOD
#include <stdio.h>
#include <time.h>
#include "cc.h"
#include "global.h"
#include "el.h"
#include "go.h"
#include "ty.h"
#include "oper.h"
#include "vec.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
STATIC void aewalk(elem **pn , vec_t ae);
STATIC elem * delcse(elem **pe);
STATIC void removecses(elem **pe);
STATIC void boundscheck(elem *e, vec_t ae);
enum Aetype { AEcse, AEarraybounds };
static Aetype aetype;
/*************************************
* Determine if floating point should be cse'd.
*/
inline int cse_float(elem *e)
{
#if TX86
// Don't CSE floating stuff if generating
// inline 8087 code, the code generator
// can't handle it yet
return !(tyfloating(e->Ety) && config.inline8087 &&
e->Eoper != OPvar && e->Eoper != OPconst);
#else
return 1;
#endif
}
/************************************
* Build DAGs (basically find all the common subexpressions).
* Must be done after all other optimizations, because most
* of them depend on the trees being trees, not DAGs.
* The general strategy is:
* Compute available expressions (AEs)
* For each block
* stick together nodes that match, keeping AEs up to date
* For each block
* unstick unprofitable common subexpressions
* (this is generally target-dependent)
*/
void builddags()
{ register unsigned i;
register vec_t aevec;
cmes("builddags()\n");
assert(dfo);
flowae(); /* compute available expressions */
if (exptop <= 1) /* if no AEs */
return;
aetype = AEcse;
#ifdef DEBUG
for (i = 0; i < exptop; i++)
{
//dbg_printf("expnod[%d] = %p\n",i,expnod[i]);
if (expnod[i])
elem_debug(expnod[i]);
}
#endif
#if 0
dbg_printf("defkill "); vec_println(defkill,exptop);
dbg_printf("starkill "); vec_println(starkill,exptop);
dbg_printf("vptrkill "); vec_println(vptrkill,exptop);
#endif
#if 0
/* This is the 'correct' algorithm for CSEs. We can't use it */
/* till we fix the code generator. */
for (i = 0; i < dfotop; i++)
{ register block *b;
b = dfo[i];
if (b->Belem)
{
#if 0
dbg_printf("dfo[%d] = %p\n",i,b);
dbg_printf("b->Bin "); vec_println(b->Bin,exptop);
dbg_printf("b->Bout "); vec_println(b->Bout,exptop);
aewalk(&(b->Belem),b->Bin);
dbg_printf("b->Bin "); vec_println(b->Bin,exptop);
dbg_printf("b->Bout "); vec_println(b->Bout,exptop);
#else
aewalk(&(b->Belem),b->Bin);
#endif
/* Bin and Bout would be equal at this point */
/* except that we deleted some elems from */
/* expnod[] and so it's a subset of Bout */
/* assert(veceq(b->Bin,b->Bout)); */
}
}
#else
/* Do CSEs across extended basic blocks only. This is because */
/* the code generator can only track register contents */
/* properly across extended basic blocks. */
aevec = vec_calloc(exptop);
for (i = 0; i < dfotop; i++)
{ register block *b;
b = dfo[i];
/* if not first block and (there are more than one */
/* predecessor or the only predecessor is not the */
/* previous block), then zero out the available */
/* expressions. */
if ((i != 0 &&
(list_block(b->Bpred) != dfo[i - 1] ||
list_next(b->Bpred) != NULL))
|| b->BC == BCasm
|| b->BC == BC_finally
#if SCPP
|| b->BC == BCcatch
#endif
#if MARS
|| b->BC == BCjcatch
#endif
)
vec_clear(aevec);
if (b->Belem) /* if there is an expression */
aewalk(&(b->Belem),aevec);
}
vec_free(aevec);
#endif
// Need 2 passes to converge on solution
for (int j = 0; j < 2; j++)
for (i = 0; i < dfotop; i++)
{ register block *b;
b = dfo[i];
if (b->Belem)
{
#if 0
dbg_printf("b = 0x%x\n",b);
#endif
removecses(&(b->Belem));
}
}
}
/**********************************
*/
STATIC void aeclear(elem *n,vec_t ae)
{ int i;
i = n->Eexp;
assert(i);
if (n->Ecount == 0)
{
expnod[i] = 0;
vec_clearbit(i,ae);
if (EUNA(n))
aeclear(n->E1,ae);
else if (EBIN(n))
{ aeclear(n->E1,ae);
aeclear(n->E2,ae);
}
}
}
/****************************
* Walk tree, building DAG as we go.
* ae = vector of available expressions
*/
STATIC void aewalk(register elem **pn,register vec_t ae)
{ register vec_t aer;
register unsigned i,op;
register elem *n,*t;
n = *pn;
assert(n && ae);
//printf("visiting %d: (",n->Eexp); WReqn(*pn); dbg_printf(")\n");
//chkvecdim(exptop);
op = n->Eoper;
if (n->Eexp) // if an AE
{ // Try to find an equivalent AE, and point to it instead
assert(expnod[n->Eexp] == n);
if (aetype == AEcse)
{
foreach (i,exptop,ae)
{ elem *e = expnod[i];
// Attempt to replace n with e
if (e == NULL) // if elem no longer exists
vec_clearbit(i,ae); // it's not available
else if (n != e &&
el_match(n,e) &&
e->Ecount < 0xFF-1 && // must fit in unsigned char
cse_float(n)
)
{
*pn = e; // replace n with e
//dbg_printf("cse: %p (",n); WReqn(*pn); dbg_printf(")\n");
e->Ecount++;
#ifdef DEBUG
assert(e->Ecount != 0);
#endif
aeclear(n,ae);
el_free(n);
return;
}
}
}
}
switch (op)
{ case OPcolon:
case OPcolon2:
// ae = ae & ael & aer
// AEs gened by ael and aer are mutually exclusive
aer = vec_clone(ae);
aewalk(&(n->E1),ae);
aewalk(&(n->E2),aer);
vec_andass(ae,aer);
vec_free(aer);
break;
case OPandand:
case OPoror:
aewalk(&(n->E1),ae);
/* ae &= aer */
aer = vec_clone(ae);
aewalk(&(n->E2),aer);
if (!el_noreturn(n->E2))
vec_andass(ae,aer);
vec_free(aer);
break;
case OPnegass:
t = Elvalue(n);
if (t->Eoper == OPind)
aewalk(&(t->E1),ae);
break;
case OPctor:
case OPdtor:
case OPdctor:
break;
case OPasm:
vec_clear(ae); // kill everything
return;
default:
if (OTbinary(op))
{ if (ERTOL(n))
{
// Don't CSE constants that will turn into
// an INC or DEC anyway
if (n->E2->Eoper == OPconst &&
n->E2->EV.Vint == 1 &&
(op == OPaddass || op == OPminass ||
op == OPpostinc || op == OPpostdec)
)
;
else
aewalk(&(n->E2),ae);
}
if (OTassign(op))
{ t = Elvalue(n);
if (t->Eoper == OPind)
aewalk(&(t->E1),ae);
}
else
aewalk(&(n->E1),ae);
if (!ERTOL(n))
aewalk(&(n->E2),ae);
}
else if (OTunary(op))
{ assert(op != OPnegass);
aewalk(&(n->E1),ae);
}
}
if (OTdef(op))
{
assert(n->Eexp == 0); // should not be an AE
/* remove all AEs that could be affected by this def */
if (Eunambig(n)) // if unambiguous definition
{ symbol *s;
assert(t->Eoper == OPvar);
s = t->EV.sp.Vsym;
if (!(s->Sflags & SFLunambig))
vec_subass(ae,starkill);
foreach (i,exptop,ae) /* for each ae elem */
{ register elem *e = expnod[i];
if (!e) continue;
if (OTunary(e->Eoper))
{
if (vec_testbit(e->E1->Eexp,ae))
continue;
}
else if (OTbinary(e->Eoper))
{
if (vec_testbit(e->E1->Eexp,ae) &&
vec_testbit(e->E2->Eexp,ae))
continue;
}
else if (e->Eoper == OPvar)
{ if (e->EV.sp.Vsym != s)
continue;
}
else
continue;
vec_clearbit(i,ae);
}
}
else /* else ambiguous definition */
{
vec_subass(ae,defkill);
if (OTcalldef(op))
vec_subass(ae,vptrkill);
}
// GEN the lvalue of an assignment operator
if (OTassign(op) && !OTpost(op) && t->Eexp)
vec_setbit(t->Eexp,ae);
}
if (n->Eexp) // if an AE
{
#if TARGET_SEGMENTED
if (op == OPvp_fp || op == OPcvp_fp)
/* Invalidate all other OPvp_fps */
vec_subass(ae,vptrkill);
#endif
/*dbg_printf("available: ("); WReqn(n); dbg_printf(")\n");
elem_print(n);*/
vec_setbit(n->Eexp,ae); /* mark this elem as available */
}
}
/**************************
* Remove a CSE.
* Input:
* pe pointer to pointer to CSE
* Output:
* *pe new elem to replace the old
* Returns:
* *pe
*/
STATIC elem * delcse(elem **pe)
{ elem *e;
e = el_calloc();
el_copy(e,*pe);
#ifdef DEBUG
if (debugc)
{ dbg_printf("deleting unprofitable CSE (");
WReqn(e);
dbg_printf(")\n");
}
#endif
assert(e->Ecount != 0);
if (EOP(e))
{
if (e->E1->Ecount == 0xFF-1)
{ elem *ereplace;
ereplace = el_calloc();
el_copy(ereplace,e->E1);
e->E1 = ereplace;
ereplace->Ecount = 0;
}
else
{
e->E1->Ecount++;
#ifdef DEBUG
assert(e->E1->Ecount != 0);
#endif
}
if (EBIN(e))
{
if (e->E2->Ecount == 0xFF-1)
{ elem *ereplace;
ereplace = el_calloc();
el_copy(ereplace,e->E2);
e->E2 = ereplace;
ereplace->Ecount = 0;
}
else
{ e->E2->Ecount++;
#ifdef DEBUG
assert(e->E2->Ecount != 0);
#endif
}
}
}
--(*pe)->Ecount;
#ifdef DEBUG
assert((*pe)->Ecount != 0xFF);
#endif
(*pe)->Nflags |= NFLdelcse; // not generating node
e->Ecount = 0;
#if FLOATS_IN_CODE
if (FLT_CODESEG_CELEM(e))
flt_record_const(e);
#endif
*pe = e;
return *pe;
}
/******************************
* 'Unstick' CSEs that would be unprofitable to do. These are usually
* things like addressing modes, and are usually target-dependent.
*/
STATIC void removecses(elem **pe)
{ unsigned op;
elem *e;
L1: e = *pe;
assert(e);
elem_debug(e);
if (e->Nflags & NFLdelcse && e->Ecount)
{
delcse(pe);
goto L1;
}
op = e->Eoper;
if (OTunary(op))
{
if (op == OPind)
{ elem *e1;
e1 = e->E1;
if (e1->Eoper == OPadd &&
e1->Ecount // == 1
)
{
if (I32)
{
e1 = delcse(&e->E1);
if (e1->E1->Ecount) // == 1)
delcse(&e1->E1);
if (e1->E2->Ecount && e1->E2->Eoper != OPind)
delcse(&e1->E2);
}
// Look for *(var + const). The + and the const
// shouldn't be CSEs.
else if (e1->E2->Eoper == OPconst &&
(e1->E1->Eoper == OPvar || (e1->E1->Eoper == OPind && e1->E1->Ety & (mTYconst | mTYimmutable)))
)
{
e1 = delcse(&e->E1);
}
}
if (I32 && e1->Eoper == OPadd &&
e1->E1->Eoper == OPadd &&
e1->E1->E1->Ecount &&
e1->E1->E1->Eoper == OPshl &&
e1->E1->E1->E2->Eoper == OPconst &&
e1->E1->E1->E2->EV.Vuns <= 3
)
{
delcse(&e1->E1->E1);
}
if (I32 && e1->Eoper == OPadd &&
e1->E1->Eoper == OPadd &&
e1->E1->Ecount &&
e1->E1->E1->Eoper == OPshl &&
e1->E1->E1->E2->Eoper == OPconst &&
e1->E1->E1->E2->EV.Vuns <= 3
)
{
delcse(&e1->E1);
}
else if (I32 && e1->Eoper == OPadd &&
e1->E1->Ecount &&
e1->E1->Eoper == OPshl &&
e1->E1->E2->Eoper == OPconst &&
e1->E1->E2->EV.Vuns <= 3
)
{
delcse(&e1->E1);
}
// Remove *e1 where it's a double
if (e->Ecount && tyfloating(e->Ety))
e = delcse(pe);
}
// This CSE is too easy to regenerate
else if (op == OPu16_32 && !I32 && e->Ecount)
e = delcse(pe);
}
else if (OTbinary(op))
{
if (e->Ecount > 0 && OTrel(op) && e->Ecount < 4
#if TX86
/* Don't CSE floating stuff if generating */
/* inline 8087 code, the code generator */
/* can't handle it yet */
&& !(tyfloating(e->E1->Ety) && config.inline8087)
#endif
)
e = delcse(pe);
removecses(&(e->E2));
}
else /* leaf node */
{
return;
}
pe = &(e->E1);
goto L1;
}
/*****************************************
* Do optimizations based on if we know an expression is
* 0 or !=0, even though we don't know anything else.
*/
STATIC void abewalk(elem *n,vec_t ae,vec_t aeval);
STATIC void abeboolres(elem *n,vec_t abe,vec_t abeval);
STATIC void abefree(elem *e,vec_t abe);
STATIC void abeset(elem *n,vec_t abe,vec_t abeval,int flag);
void boolopt()
{ unsigned i;
vec_t aevec;
vec_t aevecval;
cmes("boolopt()\n");
if (!dfo)
compdfo();
flowae(); /* compute available expressions */
if (exptop <= 1) /* if no AEs */
return;
#if 0
for (i = 0; i < exptop; i++)
dbg_printf("expnod[%d] = 0x%x\n",i,expnod[i]);
dbg_printf("defkill "); vec_println(defkill,exptop);
dbg_printf("starkill "); vec_println(starkill,exptop);
dbg_printf("vptrkill "); vec_println(vptrkill,exptop);
#endif
/* Do CSEs across extended basic blocks only. This is because */
/* the code generator can only track register contents */
/* properly across extended basic blocks. */
aevec = vec_calloc(exptop);
aevecval = vec_calloc(exptop);
// Mark each expression that we know starts off with a non-zero value
for (i = 0; i < exptop; i++)
{ elem *e = expnod[i];
if (e)
{ elem_debug(e);
if (e->Eoper == OPvar && e->EV.sp.Vsym->Sflags & SFLtrue)
{ vec_setbit(i,aevec);
vec_setbit(i,aevecval);
}
}
}
for (i = 0; i < dfotop; i++)
{ register block *b;
b = dfo[i];
/* if not first block and (there are more than one */
/* predecessor or the only predecessor is not the */
/* previous block), then zero out the available */
/* expressions. */
if ((i != 0 &&
(list_block(b->Bpred) != dfo[i - 1] ||
list_next(b->Bpred) != NULL))
|| b->BC == BCasm
)
vec_clear(aevec);
if (b->Belem) /* if there is an expression */
abewalk(b->Belem,aevec,aevecval);
}
vec_free(aevec);
vec_free(aevecval);
}
/****************************
* Walk tree, replacing bool expressions that we know
* ae = vector of available boolean expressions
* aeval = parallel vector of values corresponding to whether bool
* value is 1 or 0
* n = elem tree to look at
*/
STATIC void abewalk(elem *n,vec_t ae,vec_t aeval)
{ vec_t aer,aerval;
unsigned i,op;
unsigned i1,i2;
elem *t;
assert(n && ae);
elem_debug(n);
/*dbg_printf("visiting: ("); WReqn(*pn); dbg_printf("), Eexp = %d\n",n->Eexp);*/
/*chkvecdim(exptop);*/
op = n->Eoper;
switch (op)
{ case OPcolon:
case OPcolon2:
/* ae = ae & ael & aer */
/* AEs gened by ael and aer are mutually exclusive */
aer = vec_clone(ae);
aerval = vec_clone(aeval);
abewalk(n->E1,ae,aeval);
goto L1;
case OPandand:
case OPoror:
abewalk(n->E1,ae,aeval);
abeboolres(n->E1,ae,aeval);
/* ae &= aer */
aer = vec_clone(ae);
aerval = vec_clone(aeval);
abeset(n->E1,aer,aerval,(op == OPandand));
L1:
abewalk(n->E2,aer,aerval);
if (!el_noreturn(n->E2))
{ vec_xorass(aerval,aeval);
vec_subass(aer,aerval);
vec_andass(ae,aer);
}
vec_free(aer);
vec_free(aerval);
break;
case OPbool:
case OPnot:
abewalk(n->E1,ae,aeval);
abeboolres(n->E1,ae,aeval);
break;
case OPnegass:
t = Elvalue(n);
if (t->Eoper == OPind)
abewalk(t->E1,ae,aeval);
break;
case OPasm:
vec_clear(ae); // kill everything
return;
default:
if (OTbinary(op))
{ if (ERTOL(n))
abewalk(n->E2,ae,aeval);
if (OTassign(op))
{ t = Elvalue(n);
if (t->Eoper == OPind)
abewalk(t->E1,ae,aeval);
}
else
abewalk(n->E1,ae,aeval);
if (!ERTOL(n))
abewalk(n->E2,ae,aeval);
}
else if (OTunary(op))
abewalk(n->E1,ae,aeval);
break;
}
if (OTdef(op))
{ assert(n->Eexp == 0); // should not be an AE
/* remove all AEs that could be affected by this def */
if (Eunambig(n)) /* if unambiguous definition */
{ symbol *s;
assert(t->Eoper == OPvar);
s = t->EV.sp.Vsym;
if (!(s->Sflags & SFLunambig))
vec_subass(ae,starkill);
foreach (i,exptop,ae) /* for each ae elem */
{ register elem *e = expnod[i];
if (!e) continue;
if (OTunary(e->Eoper))
{
if (vec_testbit(e->E1->Eexp,ae))
continue;
}
else if (OTbinary(e->Eoper))
{
if (vec_testbit(e->E1->Eexp,ae) &&
vec_testbit(e->E2->Eexp,ae))
continue;
}
else if (e->Eoper == OPvar)
{ if (e->EV.sp.Vsym != s)
continue;
}
else
continue;
vec_clearbit(i,ae);
}
}
else /* else ambiguous definition */
{
vec_subass(ae,defkill);
if (OTcalldef(op))
vec_subass(ae,vptrkill);
}
/* GEN the lvalue of an assignment operator */
#if 1
if (op == OPeq && (i1 = t->Eexp) != 0 && (i2 = n->E2->Eexp) != 0)
{
if (vec_testbit(i2,ae))
{
vec_setbit(i1,ae);
if (vec_testbit(i2,aeval))
vec_setbit(i1,aeval);
else
vec_clearbit(i1,aeval);
}
}
#else
if ((OTopeq(op) || op == OPeq || op == OPnegass) && n->E1->Eexp)
{ vec_setbit(t->Eexp,ae);
if (n->E1->Eoper == OPbit)
vec_setbit(n->E1->Eexp,ae);
}
#endif
}
else if (n->Eexp) /* if an AE */
{
#if TARGET_SEGMENTED
if (op == OPvp_fp || op == OPcvp_fp)
/* Invalidate all other OPvp_fps */
vec_subass(ae,vptrkill);
#endif
/*dbg_printf("available: ("); WReqn(n); dbg_printf(")\n");
elem_print(n);*/
// vec_setbit(n->Eexp,ae); /* mark this elem as available */
}
}
/************************************
* Elem e is to be evaluated for a boolean result.
* See if we already know its value.
*/
STATIC void abeboolres(elem *n,vec_t ae,vec_t aeval)
{ unsigned i;
elem_debug(n);
if (n->Eexp)
{ /* Try to find an equivalent AE, and point to it instead */
assert(expnod[n->Eexp] == n);
foreach (i,exptop,ae)
{ elem *e = expnod[i];
// Attempt to replace n with e
//dbg_printf("Looking at expnod[%d] = %p\n",i,e);
assert(e);
elem_debug(e);
if (n != e && el_match(n,e))
{
#ifdef DEBUG
if (debugc)
{ dbg_printf("Elem %p: ",n);
WReqn(n);
dbg_printf(" is replaced by %d\n",vec_testbit(i,aeval) != 0);
}
#endif
abefree(n,ae);
n->EV.Vlong = vec_testbit(i,aeval) != 0;
n->Eoper = OPconst;
n->Ety = TYint;
changes++;
break;
}
}
}
}
/****************************
* Remove e from available expressions, and its children.
*/
STATIC void abefree(elem *e,vec_t ae)
{
//dbg_printf("abefree %p: "); WReqn(e); dbg_printf("\n");
assert(e->Eexp);
vec_clearbit(e->Eexp,ae);
expnod[e->Eexp] = NULL;
if (EOP(e))
{ if (EBIN(e))
{ abefree(e->E2,ae);
el_free(e->E2);
e->E2 = NULL;
}
abefree(e->E1,ae);
el_free(e->E1);
e->E1 = NULL;
}
}
/************************************
* Elem e is to be evaluated for a boolean result.
* Set its result according to flag.
*/
STATIC void abeset(elem *e,vec_t ae,vec_t aeval,int flag)
{ unsigned i;
while (1)
{
i = e->Eexp;
if (i && expnod[i])
{
//dbg_printf("abeset for expnod[%d] = %p: ",i,e); WReqn(e); dbg_printf("\n");
vec_setbit(i,ae);
if (flag)
vec_setbit(i,aeval);
else
vec_clearbit(i,aeval);
}
switch (e->Eoper)
{ case OPnot:
flag ^= 1;
case OPbool:
case OPeq:
e = e->E1;
continue;
}
break;
}
}
#endif

1721
backend/gflow.c Normal file

File diff suppressed because it is too large Load Diff

589
backend/global.h Normal file
View File

@@ -0,0 +1,589 @@
// Copyright (C) 1984-1996 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
// Globals
//#pragma once
#ifndef GLOBAL_H
#define GLOBAL_H 1
#ifndef EL_H
#include "el.h"
#endif
#ifdef DEBUG
CEXTERN char debuga; /* cg - watch assignaddr() */
CEXTERN char debugb; /* watch block optimization */
CEXTERN char debugc; /* watch code generated */
CEXTERN char debugd; /* watch debug information generated */
CEXTERN char debuge; // dump eh info
CEXTERN char debugf; /* trees after dooptim */
CEXTERN char debugg; /* trees for code generator */
CEXTERN char debugo; // watch optimizer
CEXTERN char debugr; // watch register allocation
CEXTERN char debugs; /* watch common subexp eliminator */
CEXTERN char debugt; /* do test points */
CEXTERN char debugu;
CEXTERN char debugw; /* watch progress */
CEXTERN char debugx; /* suppress predefined CPP stuff */
CEXTERN char debugy; /* watch output to il buffer */
#endif /* DEBUG */
#define CR '\r' // Used because the MPW version of the compiler warps
#define LF '\n' // \n into \r and \r into \n. The translator version
// does not and this causes problems with the compilation
// with the translator
#define CR_STR "\r"
#define LF_STR "\n"
struct seg_data;
/************************
* Bit masks
*/
CEXTERN const unsigned mask[32];
CEXTERN const unsigned long maskl[32];
extern char *argv0;
CEXTERN char *finname,*foutname,*foutdir;
CEXTERN char OPTIMIZER,PARSER;
CEXTERN symtab_t globsym;
#if AUTONEST
CEXTERN int pushcount;
#endif
CEXTERN Config config; // precompiled part of configuration
CEXTERN Configv configv; // non-ph part of configuration
CEXTERN char sytab[];
CEXTERN volatile int controlc_saw; /* a control C was seen */
CEXTERN unsigned maxblks; /* array max for all block stuff */
CEXTERN unsigned numblks; /* number of basic blocks (if optimized) */
CEXTERN block *startblock; /* beginning block of function */
CEXTERN block **dfo; /* array of depth first order */
CEXTERN unsigned dfotop; /* # of items in dfo[] */
CEXTERN block **labelarr; /* dynamically allocated array, index is label #*/
CEXTERN unsigned labelmax; /* size of labelarr[] */
CEXTERN unsigned labeltop; /* # of used entries in labelarr[] */
CEXTERN block *curblock; /* current block being read in */
CEXTERN block *block_last;
CEXTERN int errcnt;
CEXTERN regm_t fregsaved;
#if SCPP
CEXTERN targ_size_t dsout; /* # of bytes actually output to data */
#endif
CEXTERN tym_t pointertype; /* default data pointer type */
// cg.c
extern symbol *localgot;
extern symbol *tls_get_addr_sym;
// iasm.c
Symbol *asm_define_label(const char *id);
// cpp.c
#if SCPP || MARS
char *cpp_mangle(Symbol *s);
#else
#define cpp_mangle(s) ((s)->Sident)
#endif
// ee.c
void eecontext_convs(unsigned marksi);
void eecontext_parse();
// exp2.c
#define REP_THRESHOLD (REGSIZE * (6+ (REGSIZE == 4)))
/* doesn't belong here, but func to OPxxx is in exp2 */
void exp2_setstrthis(elem *e,Symbol *s,targ_size_t offset,type *t);
symbol *exp2_qualified_lookup(Classsym *sclass, int flags, int *pflags);
elem *exp2_copytotemp(elem *e);
/* util.c */
#if __clang__
void util_exit(int) __attribute__((analyzer_noreturn));
void util_assert(char *, int) __attribute__((analyzer_noreturn));
#else
void util_exit(int);
void util_assert(char *, int);
#if __DMC__
#pragma ZTC noreturn(util_exit)
#pragma ZTC noreturn(util_assert)
#endif
#endif
void util_progress();
void util_set16(void);
void util_set32(void);
void util_set64(void);
int ispow2(targ_ullong);
#if TX86
#if __GNUC__
#define util_malloc(n,size) mem_malloc((n)*(size))
#define util_calloc(n,size) mem_calloc((n)*(size))
#define util_free mem_free
#define util_realloc(oldp,n,size) mem_realloc(oldp,(n)*(size))
#define parc_malloc mem_malloc
#define parc_calloc mem_calloc
#define parc_realloc mem_realloc
#define parc_strdup mem_strdup
#define parc_free mem_free
#else
void *util_malloc(unsigned n,unsigned size);
void *util_calloc(unsigned n,unsigned size);
void util_free(void *p);
void *util_realloc(void *oldp,unsigned n,unsigned size);
void *parc_malloc(size_t len);
void *parc_calloc(size_t len);
void *parc_realloc(void *oldp,size_t len);
char *parc_strdup(const char *s);
void parc_free(void *p);
#endif
#endif
void swap(int *,int *);
void crlf(FILE *);
char *unsstr(unsigned);
int isignore(int);
int isillegal(int);
#if !defined(__SC__) && !defined(_MSC_VER)
int ishex(int);
#endif
/* from cgcs.c */
extern void comsubs(void);
void cgcs_term();
/* errmsgs.c */
CEXTERN char *dlcmsgs(int);
extern void errmsgs_term();
/* from evalu8.c */
int boolres(elem *);
int iftrue(elem *);
int iffalse(elem *);
elem *poptelem(elem *);
elem *poptelem2(elem *);
elem *poptelem3(elem *);
elem *poptelem4(elem *);
elem *selecte1(elem *,type *);
//CEXTERN type *declar(type *,char *,int);
/* from err.c */
void err_message(const char *format,...);
void dll_printf(const char *format,...);
void cmderr(unsigned,...);
int synerr(unsigned,...);
void preerr(unsigned,...);
#if __clang__
void err_exit(void) __attribute__((analyzer_noreturn));
void err_nomem(void) __attribute__((analyzer_noreturn));
void err_fatal(unsigned,...) __attribute__((analyzer_noreturn));
#else
void err_exit(void);
void err_nomem(void);
void err_fatal(unsigned,...);
#if __DMC__
#pragma ZTC noreturn(err_exit)
#pragma ZTC noreturn(err_nomem)
#pragma ZTC noreturn(err_fatal)
#endif
#endif
int cpperr(unsigned,...);
#if TX86
int tx86err(unsigned,...);
extern int errmsgs_tx86idx;
#endif
void warerr(unsigned,...);
void err_warning_enable(unsigned warnum, int on);
CEXTERN void lexerr(unsigned,...);
int typerr(int,type *,type *,...);
void err_noctor(Classsym *stag,list_t arglist);
void err_nomatch(const char *, list_t);
void err_ambiguous(Symbol *,Symbol *);
void err_noinstance(Symbol *s1,Symbol *s2);
void err_redeclar(Symbol *s,type *t1,type *t2);
void err_override(Symbol *sfbase,Symbol *sfder);
void err_notamember(const char *id, Classsym *s, symbol *alternate = NULL);
/* exp.c */
elem *expression(void),*const_exp(void),*assign_exp(void);
elem *exp_simplecast(type *);
/* file.c */
char *file_getsource(const char *iname);
int file_isdir(const char *fname);
void file_progress(void);
void file_remove(char *fname);
int file_stat(const char *fname,struct stat *pbuf);
int file_exists(const char *fname);
long file_size(const char *fname);
void file_term(void);
#if __NT__ && _WINDLL
char *file_nettranslate(const char *filename,const char *mode);
#else
#define file_nettranslate(f,m) ((char *)(f))
#endif
char *file_unique();
/* from msc.c */
type *newpointer(type *),
*newpointer_share(type *),
*reftoptr(type *t),
*newref(type *),
*topointer(type *),
*type_ptr(elem *, type *);
int type_chksize(unsigned long);
tym_t tym_conv(type *);
type * type_arrayroot(type *);
void chklvalue(elem *);
int tolvalue(elem **);
void chkassign(elem *);
void chknosu(elem *);
void chkunass(elem *);
void chknoabstract(type *);
CEXTERN targ_llong msc_getnum(void);
CEXTERN targ_size_t alignmember(type *,targ_size_t,targ_size_t);
CEXTERN targ_size_t align(targ_size_t,targ_size_t);
/* nteh.c */
unsigned char *nteh_context_string();
void nteh_declarvars(Blockx *bx);
elem *nteh_setScopeTableIndex(Blockx *blx, int scope_index);
Symbol *nteh_contextsym();
unsigned nteh_contextsym_size();
Symbol *nteh_ecodesym();
code *nteh_unwind(regm_t retregs,unsigned index);
code *linux_unwind(regm_t retregs,unsigned index);
int nteh_offset_sindex();
int nteh_offset_sindex_seh();
int nteh_offset_info();
/* os.c */
void *globalrealloc(void *oldp,size_t nbytes);
void *vmem_baseaddr();
void vmem_reservesize(unsigned long *psize);
unsigned long vmem_physmem();
void *vmem_reserve(void *ptr,unsigned long size);
int vmem_commit(void *ptr, unsigned long size);
void vmem_decommit(void *ptr,unsigned long size);
void vmem_release(void *ptr,unsigned long size);
void *vmem_mapfile(const char *filename,void *ptr,unsigned long size,int flag);
void vmem_setfilesize(unsigned long size);
void vmem_unmapfile();
void os_loadlibrary(const char *dllname);
void os_freelibrary();
void *os_getprocaddress(const char *funcname);
void os_heapinit();
void os_heapterm();
void os_term();
unsigned long os_unique();
int os_file_exists(const char *name);
long os_file_size(int fd);
char *file_8dot3name(const char *filename);
int file_write(char *name, void *buffer, unsigned len);
int file_createdirs(char *name);
int os_critsecsize32();
int os_critsecsize64();
#ifdef PSEUDO_REGS
/* pseudo.c */
Symbol *pseudo_declar(char *);
CEXTERN unsigned char pseudoreg[];
CEXTERN regm_t pseudomask[];
#endif /* PSEUDO_REGS */
/* Symbol.c */
symbol **symtab_realloc(symbol **tab, size_t symmax);
symbol **symtab_malloc(size_t symmax);
symbol **symtab_calloc(size_t symmax);
void symtab_free(symbol **tab);
#if TERMCODE
void symbol_keep(Symbol *s);
#else
#define symbol_keep(s) ((void)(s))
#endif
void symbol_print(Symbol *s);
void symbol_term(void);
char *symbol_ident(symbol *s);
Symbol *symbol_calloc(const char *id);
Symbol *symbol_name(const char *name, int sclass, type *t);
Symbol *symbol_generate(int sclass, type *t);
Symbol *symbol_genauto(type *t);
Symbol *symbol_genauto(elem *e);
Symbol *symbol_genauto(tym_t ty);
void symbol_func(Symbol *);
Funcsym *symbol_funcalias(Funcsym *sf);
Symbol *defsy(const char *p, Symbol **parent);
void symbol_addtotree(Symbol **parent,Symbol *s);
//Symbol *lookupsym(const char *p);
Symbol *findsy(const char *p, Symbol *rover);
void createglobalsymtab(void);
void createlocalsymtab(void);
void deletesymtab(void);
void meminit_free(meminit_t *m);
baseclass_t *baseclass_find(baseclass_t *bm,Classsym *sbase);
baseclass_t *baseclass_find_nest(baseclass_t *bm,Classsym *sbase);
int baseclass_nitems(baseclass_t *b);
void symbol_free(Symbol *s);
SYMIDX symbol_add(Symbol *s);
void freesymtab(Symbol **stab, SYMIDX n1, SYMIDX n2);
Symbol * symbol_copy(Symbol *s);
Symbol * symbol_searchlist(symlist_t sl, const char *vident);
#if TX86
// cg87.c
void cg87_reset();
#endif
unsigned char loadconst(elem *e, int im);
/* From cgopt.c */
CEXTERN void opt(void);
/* cgobj.c */
void obj_init(Outbuffer *, const char *filename, const char *csegname);
void obj_initfile(const char *filename, const char *csegname, const char *modname);
size_t obj_mangle(Symbol *s,char *dest);
void obj_termfile(void);
void obj_term(void);
void obj_import(elem *e);
void objlinnum(Srcpos srcpos, targ_size_t offset);
void obj_dosseg(void);
void obj_startaddress(Symbol *);
void obj_includelib(const char *);
void obj_exestr(const char *p);
void obj_user(const char *p);
void obj_compiler();
void obj_wkext(Symbol *,Symbol *);
void obj_lzext(Symbol *,Symbol *);
void obj_alias(const char *n1,const char *n2);
void obj_theadr(const char *modname);
void objseggrp(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
void obj_staticctor(Symbol *s,int dtor,int seg);
void obj_staticdtor(Symbol *s);
void obj_funcptr(Symbol *s);
void obj_ehtables(Symbol *sfunc,targ_size_t size,Symbol *ehsym);
void obj_ehsections();
void obj_moduleinfo(Symbol *scc);
int obj_comdat(Symbol *);
int obj_comdatsize(Symbol *, targ_size_t symsize);
void obj_setcodeseg(int seg,targ_size_t offset);
int obj_codeseg(char *name,int suffix);
seg_data *obj_tlsseg();
seg_data *obj_tlsseg_bss();
int obj_fardata(char *name, targ_size_t size, targ_size_t *poffset);
void obj_browse(char *, unsigned);
void objend(void);
void obj_export(Symbol *s, unsigned argsize);
void objpubdef(int seg, Symbol *s, targ_size_t offset);
#if ELFOBJ
void objpubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize);
#elif MACHOBJ
#define objpubdefsize(seg, s, offset, symsize) objpubdef(seg, s, offset)
#endif
int objextdef(const char *);
int elf_data_start(Symbol *sdata, targ_size_t datasize, int seg);
int objextern(Symbol *);
int obj_comdef(Symbol *s, int flag, targ_size_t size, targ_size_t count);
void obj_lidata(int seg, targ_size_t offset, targ_size_t count);
void obj_write_zeros(seg_data *pseg, targ_size_t count);
void obj_write_byte(seg_data *pseg, unsigned byte);
void obj_write_bytes(seg_data *pseg, unsigned nbytes, void *p);
void obj_byte(int seg, targ_size_t offset, unsigned byte);
unsigned obj_bytes(int seg, targ_size_t offset, unsigned nbytes, void *p);
void objledata(int seg, targ_size_t offset, targ_size_t data, unsigned lcfd, unsigned idx1, unsigned idx2);
void obj_long(int seg, targ_size_t offset, unsigned long data, unsigned lcfd, unsigned idx1, unsigned idx2);
void reftodatseg(int seg, targ_size_t offset, targ_size_t val, unsigned targetdatum, int flags);
void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
void reftocodseg(int seg, targ_size_t offset, targ_size_t val);
int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags);
void obj_far16thunk(Symbol *s);
void obj_fltused();
// objrecor.c
void objfile_open(const char *);
void objfile_close(void *data, unsigned len);
void objfile_delete();
void objfile_term();
/* cod3.c */
void cod3_thunk(Symbol *sthunk,Symbol *sfunc,unsigned p,tym_t thisty,
targ_size_t d,int i,targ_size_t d2);
/* out.c */
void outfilename(char *name,int linnum);
void outcsegname(char *csegname);
void outthunk(Symbol *sthunk, Symbol *sfunc, unsigned p, tym_t thisty, targ_size_t d, int i, targ_size_t d2);
void outdata(Symbol *s);
void outcommon(Symbol *s, targ_size_t n);
void out_regcand(symtab_t *);
void writefunc(Symbol *sfunc);
void alignOffset(int seg,targ_size_t datasize);
void out_reset();
symbol *out_readonly_sym(tym_t ty, void *p, int len);
/* blockopt.c */
extern unsigned bc_goal[BCMAX];
block *block_calloc();
void block_init();
void block_term();
#if MARS
void block_next(Blockx *bctx,enum BC bc,block *bn);
block *block_goto(Blockx *bctx,enum BC bc,block *bn);
#else
void block_next(enum BC,block *);
#endif
void block_setlabel(unsigned lbl);
void block_goto();
void block_goto(block *);
void block_goto(block *bgoto, block *bnew);
void block_ptr(void);
void block_pred(void);
void block_clearvisit();
void block_visit(block *b);
void block_compbcount(void);
void blocklist_free(block **pb);
void block_optimizer_free(block *b);
void block_free(block *b);
void blocklist_hydrate(block **pb);
void blocklist_dehydrate(block **pb);
void block_appendexp(block *b, elem *e);
void block_initvar(Symbol *s);
void block_endfunc(int flag);
void brcombine(void);
void blockopt(int);
void compdfo(void);
#define block_initvar(s) (curblock->Binitvar = (s))
#ifdef DEBUG
/* debug.c */
CEXTERN const char *regstring[];
void WRclass(enum SC c);
void WRTYxx(tym_t t);
void WROP(unsigned oper);
void WRBC(unsigned bc);
void WRarglst(list_t a);
void WRblock(block *b);
void WRblocklist(list_t bl);
void WReqn(elem *e);
void WRfunc(void);
void WRdefnod(void);
void WRFL(enum FL);
char *sym_ident(SYMIDX si);
#endif
/* cgelem.c */
elem *doptelem(elem *,int);
void postoptelem(elem *);
unsigned swaprel(unsigned);
int elemisone(elem *);
/* msc.c */
targ_size_t size(tym_t);
Symbol *symboldata(targ_size_t offset,tym_t ty);
int dom(block *A , block *B);
unsigned revop(unsigned op);
unsigned invrel(unsigned op);
int binary(const char *p, const char __near * __near *tab, int high);
/* go.c */
void go_term(void);
int go_flag(char *cp);
void optfunc(void);
/* filename.c */
#if !MARS
extern Srcfiles srcfiles;
Sfile **filename_indirect(Sfile *sf);
Sfile *filename_search( const char *name );
Sfile *filename_add( const char *name );
void filename_hydrate( Srcfiles *fn );
void filename_dehydrate( Srcfiles *fn );
void filename_merge( Srcfiles *fn );
void filename_mergefl(Sfile *sf);
void filename_translate(Srcpos *);
void filename_free( void );
int filename_cmp(const char *f1,const char *f2);
void srcpos_hydrate(Srcpos *);
void srcpos_dehydrate(Srcpos *);
#endif
// tdb.c
unsigned long tdb_gettimestamp();
void tdb_write(void *buf,unsigned size,unsigned numindices);
unsigned long tdb_typidx(void *buf);
//unsigned long tdb_typidx(unsigned char *buf,unsigned length);
void tdb_term();
// rtlsym.c
void rtlsym_init();
void rtlsym_reset();
void rtlsym_term();
#if ELFOBJ || MACHOBJ
void elf_add_cdata();
symbol * elf_sym_cdata(tym_t, char *, int );
int elf_data_cdata(char *str,int len,int *pseg);
#if ELFOBJ
int elf_getsegment(const char *name, const char *suffix,
int type, int flags, int align);
void elf_addrel(int seg, targ_size_t offset, unsigned type,
unsigned symidx, targ_size_t val);
#endif
#if MACHOBJ
int mach_getsegment(const char *sectname, const char *segname,
int align, int flags, int flags2 = 0);
void mach_addrel(int seg, targ_size_t offset, symbol *targsym,
unsigned targseg, int rtype, int val = 0);
#endif
void elf_func_start(Symbol *sfunc);
void elf_func_term(Symbol *sfunc);
unsigned elf_addstr(Outbuffer *strtab, const char *);
void dwarf_CFA_set_loc(size_t location);
void dwarf_CFA_set_reg_offset(int reg, int offset);
void dwarf_CFA_offset(int reg, int offset);
void dwarf_CFA_args_size(size_t sz);
#endif
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
void elfobj_gotref(symbol *s);
symbol *elfobj_getGOTsym();
void elfobj_refGOTsym();
elem * exp_isconst();
elem *lnx_builtin_next_arg(elem *efunc,list_t arglist);
char *lnx_redirect_funcname(const char *);
void lnx_funcdecl(symbol *,enum SC,enum_SC,int);
int lnx_attributes(int hinttype,const void *hint, type **ptyp, tym_t *ptym,int *pattrtype);
#endif
#endif /* GLOBAL_H */

741
backend/glocal.c Normal file
View File

@@ -0,0 +1,741 @@
// Copyright (C) 1993-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !DEMO && !SPP
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if __sun&&__SVR4
#include <alloca.h>
#endif
#include "cc.h"
#include "global.h"
#include "el.h"
#include "go.h"
#include "type.h"
#include "oper.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
typedef struct loc_t
{
elem *e;
int flags;
# define LFvolatile 1 // contains volatile refs or defs
# define LFambigref 2 // references ambiguous data
# define LFambigdef 4 // defines ambiguous data
# define LFsymref 8 // reference to symbol s
# define LFsymdef 0x10 // definition of symbol s
# define LFunambigref 0x20 // references unambiguous data other than s
# define LFunambigdef 0x40 // defines unambiguous data other than s
#if TX86
# define LFinp 0x80 // input from I/O port
# define LFoutp 0x100 // output to I/O port
#endif
# define LFfloat 0x200 // sets float flags and/or depends on
// floating point settings
} loc_t;
static loc_t *loctab;
static unsigned locmax;
static unsigned loctop;
STATIC void local_exp(elem *e,int goal);
STATIC int local_chkrem(elem *e,elem *eu);
STATIC void local_ins(elem *e);
STATIC void local_rem(unsigned u);
STATIC int local_getflags(elem *e,symbol *s);
STATIC void local_remove(int flags);
STATIC void local_ambigref(void);
STATIC void local_ambigdef(void);
STATIC void local_symref(symbol *s);
STATIC void local_symdef(symbol *s);
///////////////////////////////
// This optimization attempts to replace sequences like:
// x = func();
// y = 3;
// z = x + 5;
// with:
// y = 3;
// z = (x = func()) + 5;
// In other words, we attempt to localize expressions by moving them
// as near as we can to where they are used. This should minimize
// temporary generation and register usage.
void localize()
{ block *b;
cmes("localize()\n");
// Table should not get any larger than the symbol table
locmax = globsym.symmax;
loctab = (loc_t *) alloca(locmax * sizeof(*loctab));
for (b = startblock; b; b = b->Bnext) /* for each block */
{
loctop = 0; // start over for each block
if (b->Belem &&
/* Overly broad way to account for the case:
* try
* { i++;
* foo(); // throws exception
* i++; // shouldn't combine previous i++ with this one
* }
*/
!b->Btry)
{
local_exp(b->Belem,0);
}
}
}
//////////////////////////////////////
// Input:
// goal !=0 if we want the result of the expression
//
STATIC void local_exp(elem *e,int goal)
{ symbol *s;
unsigned u;
elem *e1;
int op1;
Loop:
elem_debug(e);
int op = e->Eoper;
switch (op)
{ case OPcomma:
local_exp(e->E1,0);
e = e->E2;
goto Loop;
case OPandand:
case OPoror:
local_exp(e->E1,1);
loctop = 0; // we can do better than this, fix later
break;
case OPcolon:
case OPcolon2:
loctop = 0; // we can do better than this, fix later
break;
case OPinfo:
if (e->E1->Eoper == OPmark)
{ loctop = 0;
e = e->E2;
goto Loop;
}
goto case_bin;
case OPdtor:
case OPctor:
case OPdctor:
loctop = 0; // don't move expressions across ctor/dtor
break; // boundaries, it would goof up EH cleanup
case OPddtor:
loctop = 0; // don't move expressions across ctor/dtor
// boundaries, it would goof up EH cleanup
local_exp(e->E1,0);
loctop = 0;
break;
case OPeq:
case OPstreq:
e1 = e->E1;
local_exp(e->E2,1);
if (e1->Eoper == OPvar)
{ s = e1->EV.sp.Vsym;
if (s->Sflags & SFLunambig)
{ local_symdef(s);
if (!goal)
local_ins(e);
}
else
local_ambigdef();
}
else
{
assert(!OTleaf(e1->Eoper));
local_exp(e1->E1,1);
if (OTbinary(e1->Eoper))
local_exp(e1->E2,1);
local_ambigdef();
}
break;
case OPpostinc:
case OPpostdec:
case OPaddass:
case OPminass:
case OPmulass:
case OPdivass:
case OPmodass:
case OPashrass:
case OPshrass:
case OPshlass:
case OPandass:
case OPxorass:
case OPorass:
if (ERTOL(e))
{ local_exp(e->E2,1);
case OPnegass:
e1 = e->E1;
op1 = e1->Eoper;
if (op1 != OPvar)
{
local_exp(e1->E1,1);
if (OTbinary(op1))
local_exp(e1->E2,1);
}
else if (loctop && (op == OPaddass || op == OPxorass))
{ unsigned u;
s = e1->EV.sp.Vsym;
for (u = 0; u < loctop; u++)
{ elem *em;
em = loctab[u].e;
if (em->Eoper == op &&
em->E1->EV.sp.Vsym == s &&
tysize(em->Ety) == tysize(e1->Ety) &&
em->E1->EV.sp.Voffset == e1->EV.sp.Voffset &&
!el_sideeffect(em->E2)
)
{ // Change (x += a),(x += b) to
// (x + a),(x += a + b)
changes++;
e->E2 = el_bin(opeqtoop(op),e->E2->Ety,em->E2,e->E2);
em->Eoper = opeqtoop(op);
em->E2 = el_copytree(em->E2);
local_rem(u);
#ifdef DEBUG
if (debugc)
{ dbg_printf("Combined equation ");
WReqn(e);
dbg_printf(";\n");
e = doptelem(e,GOALvalue);
}
#endif
break;
}
}
}
}
else
{
e1 = e->E1;
op1 = e1->Eoper;
if (op1 != OPvar)
{
local_exp(e1->E1,1);
if (OTbinary(op1))
local_exp(e1->E2,1);
}
if (loctop)
{ if (op1 == OPvar &&
((s = e1->EV.sp.Vsym)->Sflags & SFLunambig))
local_symref(s);
else
local_ambigref();
}
local_exp(e->E2,1);
}
if (op1 == OPvar &&
((s = e1->EV.sp.Vsym)->Sflags & SFLunambig))
{ local_symref(s);
local_symdef(s);
if (op == OPaddass || op == OPxorass)
local_ins(e);
}
else if (loctop)
{
local_remove(LFambigdef | LFambigref);
}
break;
#if TX86
case OPstrlen:
#endif
case OPind:
local_exp(e->E1,1);
local_ambigref();
break;
case OPnewarray:
case OPmultinewarray:
local_exp(e->E1,1);
local_exp(e->E2,1);
goto Lrd;
case OPstrcmp:
case OPmemcmp:
case OPbt:
case OParray:
case OPfield:
local_exp(e->E1,1);
local_exp(e->E2,1);
local_ambigref();
break;
case OPstrcpy:
case OPmemcpy:
case OPstrcat:
case OPcall:
case OPcallns:
local_exp(e->E2,1);
case OPstrctor:
case OPucall:
case OPucallns:
local_exp(e->E1,1);
goto Lrd;
case OPbtc:
case OPbtr:
case OPbts:
local_exp(e->E1,1);
local_exp(e->E2,1);
goto Lrd;
case OPasm:
Lrd:
local_remove(LFfloat | LFambigref | LFambigdef);
break;
#if TX86
case OPmemset:
local_exp(e->E2,1);
if (e->E1->Eoper == OPvar)
{
/* Don't want to rearrange (p = get(); p memset 0;)
* as elemxxx() will rearrange it back.
*/
s = e->E1->EV.sp.Vsym;
if (s->Sflags & SFLunambig)
local_symref(s);
else
local_ambigref(); // ambiguous reference
}
else
local_exp(e->E1,1);
local_ambigdef();
break;
#endif
case OPvar:
s = e->EV.sp.Vsym;
if (loctop)
{ unsigned u;
// If potential candidate for replacement
if (s->Sflags & SFLunambig)
{
for (u = 0; u < loctop; u++)
{ elem *em;
em = loctab[u].e;
if (em->E1->EV.sp.Vsym == s &&
(em->Eoper == OPeq || em->Eoper == OPstreq))
{
if (tysize(em->Ety) == tysize(e->Ety) &&
em->E1->EV.sp.Voffset == e->EV.sp.Voffset &&
(tyfloating(em->Ety) != 0) == (tyfloating(e->Ety) != 0))
{
#ifdef DEBUG
if (debugc)
{ dbg_printf("Moved equation ");
WReqn(em);
dbg_printf(";\n");
}
#endif
changes++;
em->Ety = e->Ety;
el_copy(e,em);
em->E1 = em->E2 = NULL;
em->Eoper = OPconst;
}
local_rem(u);
break;
}
}
local_symref(s);
}
else
local_ambigref(); // ambiguous reference
}
break;
case OPremquo:
if (e->E1->Eoper != OPvar)
goto case_bin;
s = e->E1->EV.sp.Vsym;
if (loctop)
{
if (s->Sflags & SFLunambig)
local_symref(s);
else
local_ambigref(); // ambiguous reference
}
goal = 1;
e = e->E2;
goto Loop;
default:
if (OTcommut(e->Eoper))
{ // Since commutative operators may get their leaves
// swapped, we eliminate any that may be affected by that.
for (u = 0; u < loctop;)
{
int f1,f2,f;
elem *eu;
f = loctab[u].flags;
eu = loctab[u].e;
s = eu->E1->EV.sp.Vsym;
f1 = local_getflags(e->E1,s);
f2 = local_getflags(e->E2,s);
if (f1 & f2 & LFsymref || // if both reference or
(f1 | f2) & LFsymdef || // either define
f & LFambigref && (f1 | f2) & LFambigdef ||
f & LFambigdef && (f1 | f2) & (LFambigref | LFambigdef)
)
local_rem(u);
else if (f & LFunambigdef && local_chkrem(e,eu->E2))
local_rem(u);
else
u++;
}
}
if (EUNA(e))
{ goal = 1;
e = e->E1;
goto Loop;
}
case_bin:
if (EBIN(e))
{ local_exp(e->E1,1);
goal = 1;
e = e->E2;
goto Loop;
}
break;
} // end of switch (e->Eoper)
}
///////////////////////////////////
// Examine expression tree eu to see if it defines any variables
// that e refs or defs.
// Note that e is a binary operator.
// Returns:
// !=0 if it does
STATIC int local_chkrem(elem *e,elem *eu)
{ int f1,f2;
int op;
symbol *s;
int result = 0;
while (1)
{ elem_debug(eu);
op = eu->Eoper;
if (OTassign(op) && eu->E1->Eoper == OPvar)
{ s = eu->E1->EV.sp.Vsym;
f1 = local_getflags(e->E1,s);
f2 = local_getflags(e->E2,s);
if ((f1 | f2) & (LFsymref | LFsymdef)) // if either reference or define
{ result = 1;
break;
}
}
if (OTbinary(op))
{ if (local_chkrem(e,eu->E2))
{ result = 1;
break;
}
}
else if (!OTunary(op))
break; // leaf node
eu = eu->E1;
}
return result;
}
//////////////////////////////////////
// Add entry e to loctab[]
STATIC void local_ins(elem *e)
{
elem_debug(e);
if (e->E1->Eoper == OPvar)
{ symbol *s;
s = e->E1->EV.sp.Vsym;
symbol_debug(s);
if (s->Sflags & SFLunambig) // if can only be referenced directly
{ int flags;
flags = local_getflags(e->E2,NULL);
#if TX86
if (!(flags & (LFvolatile | LFinp | LFoutp)) &&
#else
if (!(flags & LFvolatile) &&
#endif
!(e->E1->Ety & mTYvolatile))
{
// Add e to the candidate array
//dbg_printf("local_ins('%s'), loctop = %d, locmax = %d\n",s->Sident,loctop,locmax);
assert(loctop < locmax);
loctab[loctop].e = e;
loctab[loctop].flags = flags;
loctop++;
}
}
}
}
//////////////////////////////////////
// Remove entry i from loctab[], and then compress the table.
//
STATIC void local_rem(unsigned u)
{
//dbg_printf("local_rem(%u)\n",u);
assert(u < loctop);
if (u + 1 != loctop)
{ assert(u < loctop);
loctab[u] = loctab[loctop - 1];
}
loctop--;
}
//////////////////////////////////////
// Analyze and gather LFxxxx flags about expression e and symbol s.
STATIC int local_getflags(elem *e,symbol *s)
{ int flags;
elem_debug(e);
if (s)
symbol_debug(s);
flags = 0;
while (1)
{
if (e->Ety & mTYvolatile)
flags |= LFvolatile;
switch (e->Eoper)
{
case OPeq:
case OPstreq:
if (e->E1->Eoper == OPvar)
{ symbol *s1;
s1 = e->E1->EV.sp.Vsym;
if (s1->Sflags & SFLunambig)
flags |= (s1 == s) ? LFsymdef : LFunambigdef;
else
flags |= LFambigdef;
}
else
flags |= LFambigdef;
goto L1;
case OPpostinc:
case OPpostdec:
case OPaddass:
case OPminass:
case OPmulass:
case OPdivass:
case OPmodass:
case OPashrass:
case OPshrass:
case OPshlass:
case OPandass:
case OPxorass:
case OPorass:
if (e->E1->Eoper == OPvar)
{ symbol *s1;
s1 = e->E1->EV.sp.Vsym;
if (s1->Sflags & SFLunambig)
flags |= (s1 == s) ? LFsymdef | LFsymref
: LFunambigdef | LFunambigref;
else
flags |= LFambigdef | LFambigref;
}
else
flags |= LFambigdef | LFambigref;
L1:
flags |= local_getflags(e->E2,s);
e = e->E1;
break;
case OPucall:
case OPucallns:
case OPcall:
case OPcallns:
case OPnewarray:
case OPmultinewarray:
#if TX86
case OPstrcat:
case OPstrcpy:
case OPmemcpy:
case OPbtc:
case OPbtr:
case OPbts:
#endif
case OPstrctor:
flags |= LFambigref | LFambigdef;
break;
#if TX86
case OPmemset:
flags |= LFambigdef;
break;
#endif
case OPvar:
if (e->EV.sp.Vsym == s)
flags |= LFsymref;
else if (!(e->EV.sp.Vsym->Sflags & SFLunambig))
flags |= LFambigref;
break;
case OPind:
case OParray:
case OPfield:
#if TX86
case OPstrlen:
case OPstrcmp:
case OPmemcmp:
case OPbt:
#endif
flags |= LFambigref;
break;
#if TX86
case OPinp:
flags |= LFinp;
break;
case OPoutp:
flags |= LFoutp;
break;
#endif
}
if (EUNA(e))
{
if (tyfloating(e->Ety))
flags |= LFfloat;
e = e->E1;
}
else if (EBIN(e))
{
if (tyfloating(e->Ety))
flags |= LFfloat;
flags |= local_getflags(e->E2,s);
e = e->E1;
}
else
break;
}
return flags;
}
//////////////////////////////////////
// Remove all entries with flags set.
//
STATIC void local_remove(int flags)
{ unsigned u;
for (u = 0; u < loctop;)
{
if (loctab[u].flags & flags)
local_rem(u);
else
u++;
}
}
//////////////////////////////////////
// Ambiguous reference. Remove all with ambiguous defs
//
STATIC void local_ambigref()
{ unsigned u;
for (u = 0; u < loctop;)
{
if (loctab[u].flags & LFambigdef)
local_rem(u);
else
u++;
}
}
//////////////////////////////////////
// Ambigous definition. Remove all with ambiguous refs.
//
STATIC void local_ambigdef()
{ unsigned u;
for (u = 0; u < loctop;)
{
if (loctab[u].flags & (LFambigref | LFambigdef))
local_rem(u);
else
u++;
}
}
//////////////////////////////////////
// Reference to symbol.
// Remove any that define that symbol.
STATIC void local_symref(symbol *s)
{ unsigned u;
symbol_debug(s);
for (u = 0; u < loctop;)
{
if (local_getflags(loctab[u].e,s) & LFsymdef)
local_rem(u);
else
u++;
}
}
//////////////////////////////////////
// Definition of symbol.
// Remove any that reference that symbol.
STATIC void local_symdef(symbol *s)
{ unsigned u;
symbol_debug(s);
for (u = 0; u < loctop;)
{
if (local_getflags(loctab[u].e,s) & (LFsymref | LFsymdef))
local_rem(u);
else
u++;
}
}
#endif

3628
backend/gloop.c Normal file

File diff suppressed because it is too large Load Diff

368
backend/go.c Normal file
View File

@@ -0,0 +1,368 @@
// Copyright (C) 1986-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "cc.h"
#include "global.h"
#include "oper.h"
#include "el.h"
#include "go.h"
#include "type.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
/****************************
* Terminate use of globals.
*/
void go_term()
{
vec_free(defkill);
vec_free(starkill);
vec_free(vptrkill);
util_free(expnod);
util_free(expblk);
util_free(defnod);
}
#if DEBUG
// to print progress message and current trees set to
// DEBUG_TREES to 1 and uncomment next 2 lines
#define DEBUG_TREES 0
#if DEBUG_TREES
void dbg_optprint(char *);
#else
// to print progress message, undo comment
#define dbg_optprint(c) // dbg_printf(c)
#endif
#else
#define dbg_optprint(c)
#endif
/**************************************
* Parse optimizer command line flag.
* Input:
* cp flag string
* Returns:
* 0 not recognized
* !=0 recognized
*/
int go_flag(char *cp)
{ unsigned i;
unsigned flag;
enum GL // indices of various flags in flagtab[]
{
GLO,GLall,GLcnp,GLcp,GLcse,GLda,GLdc,GLdv,GLli,GLliv,GLlocal,GLloop,
GLnone,GLo,GLreg,GLspace,GLspeed,GLtime,GLtree,GLvbe,GLMAX
};
static const char *flagtab[] =
{ "O","all","cnp","cp","cse","da","dc","dv","li","liv","local","loop",
"none","o","reg","space","speed","time","tree","vbe"
};
static mftype flagmftab[] =
{ 0,MFall,MFcnp,MFcp,MFcse,MFda,MFdc,MFdv,MFli,MFliv,MFlocal,MFloop,
0,0,MFreg,0,MFtime,MFtime,MFtree,MFvbe
};
i = GLMAX;
assert(i == arraysize(flagtab));
assert(i == arraysize(flagmftab));
//printf("go_flag('%s')\n", cp);
flag = binary(cp + 1,flagtab,GLMAX);
if (mfoptim == 0 && flag != -1)
mfoptim = MFall & ~MFvbe;
if (*cp == '-') /* a regular -whatever flag */
{ /* cp -> flag string */
switch (flag)
{
case GLall:
case GLcnp:
case GLcp:
case GLdc:
case GLda:
case GLdv:
case GLcse:
case GLli:
case GLliv:
case GLlocal:
case GLloop:
case GLreg:
case GLspeed:
case GLtime:
case GLtree:
case GLvbe:
mfoptim &= ~flagmftab[flag]; /* clear bits */
break;
case GLo:
case GLO:
case GLnone:
mfoptim |= MFall & ~MFvbe; // inverse of -all
break;
case GLspace:
mfoptim |= MFtime; /* inverse of -time */
break;
case -1: /* not in flagtab[] */
goto badflag;
default:
assert(0);
}
}
else if (*cp == '+') /* a regular +whatever flag */
{ /* cp -> flag string */
switch (flag)
{
case GLall:
case GLcnp:
case GLcp:
case GLdc:
case GLda:
case GLdv:
case GLcse:
case GLli:
case GLliv:
case GLlocal:
case GLloop:
case GLreg:
case GLspeed:
case GLtime:
case GLtree:
case GLvbe:
mfoptim |= flagmftab[flag]; /* set bits */
break;
case GLnone:
mfoptim &= ~MFall; /* inverse of +all */
break;
case GLspace:
mfoptim &= ~MFtime; /* inverse of +time */
break;
case -1: /* not in flagtab[] */
goto badflag;
default:
assert(0);
}
}
if (mfoptim)
{
mfoptim |= MFtree | MFdc; // always do at least this much
config.flags4 |= (mfoptim & MFtime) ? CFG4speed : CFG4space;
}
else
{
config.flags4 &= ~CFG4optimized;
}
return 1; // recognized
badflag:
return 0;
}
#if DEBUG_TREES
void dbg_optprint(char *title)
{
block *b;
for (b = startblock; b; b = b->Bnext)
if (b->Belem)
{
dbg_printf("%s\n",title);
elem_print(b->Belem);
}
}
#endif
/****************************
* Optimize function.
*/
void optfunc()
{
#if !HTOD
block *b;
int iter; // iteration count
clock_t starttime;
cmes ("optfunc()\n");
dbg_optprint("optfunc\n");
#ifdef DEBUG
if (debugb)
{
dbg_printf("................Before optimization.........\n");
WRfunc();
}
#endif
iter = 0;
if (localgot)
{ // Initialize with:
// localgot = OPgot;
elem *e = el_long(TYnptr, 0);
e->Eoper = OPgot;
e = el_bin(OPeq, TYnptr, el_var(localgot), e);
startblock->Belem = el_combine(e, startblock->Belem);
}
// Each pass through the loop can reduce only one level of comma expression.
// The infinite loop check needs to take this into account.
int iterationLimit = 0;
for (b = startblock; b; b = b->Bnext)
{
if (!b->Belem)
continue;
int d = el_countCommas(b->Belem);
if (d > iterationLimit)
iterationLimit = d;
}
// Some functions can take enormous amounts of time to optimize.
// We try to put a lid on it.
starttime = clock();
do
{
//printf("iter = %d\n", iter);
if (++iter > 200)
{ assert(iter < iterationLimit); // infinite loop check
break;
}
#if MARS
util_progress();
#else
file_progress();
#endif
//printf("optelem\n");
/* canonicalize the trees */
for (b = startblock; b; b = b->Bnext)
if (b->Belem)
{
#if DEBUG
if(debuge)
{
dbg_printf("before\n");
elem_print(b->Belem);
//el_check(b->Belem);
}
#endif
b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALagain);
#if DEBUG
if(0 && debugf)
{
dbg_printf("after\n");
elem_print(b->Belem);
}
#endif
}
//printf("blockopt\n");
if (mfoptim & MFdc)
blockopt(0); // do block optimization
out_regcand(&globsym); // recompute register candidates
changes = 0; /* no changes yet */
if (mfoptim & MFcnp)
constprop(); /* make relationals unsigned */
if (mfoptim & (MFli | MFliv))
loopopt(); /* remove loop invariants and */
/* induction vars */
/* do loop rotation */
else
for (b = startblock; b; b = b->Bnext)
b->Bweight = 1;
dbg_optprint("boolopt\n");
if (mfoptim & MFcnp)
boolopt(); // optimize boolean values
if (changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC)
continue;
if (mfoptim & MFcnp)
constprop(); /* constant propagation */
if (mfoptim & MFcp)
copyprop(); /* do copy propagation */
/* Floating point constants and string literals need to be
* replaced with loads from variables in read-only data.
* This can result in localgot getting needed.
*/
symbol *localgotsave = localgot;
for (b = startblock; b; b = b->Bnext)
{
if (b->Belem)
{
b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALstruct);
if (b->Belem)
b->Belem = el_convert(b->Belem);
}
}
if (localgot != localgotsave)
{ /* Looks like we did need localgot, initialize with:
* localgot = OPgot;
*/
elem *e = el_long(TYnptr, 0);
e->Eoper = OPgot;
e = el_bin(OPeq, TYnptr, el_var(localgot), e);
startblock->Belem = el_combine(e, startblock->Belem);
}
/* localize() is after localgot, otherwise we wind up with
* more than one OPgot in a function, which mucks up OSX
* code generation which assumes at most one (localgotoffset).
*/
if (mfoptim & MFlocal)
localize(); // improve expression locality
if (mfoptim & MFda)
rmdeadass(); /* remove dead assignments */
cmes2 ("changes = %d\n", changes);
if (!(changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC))
break;
} while (1);
cmes2("%d iterations\n",iter);
if (mfoptim & MFdc)
blockopt(1); // do block optimization
for (b = startblock; b; b = b->Bnext)
{
if (b->Belem)
postoptelem(b->Belem);
}
if (mfoptim & MFvbe)
verybusyexp(); /* very busy expressions */
if (mfoptim & MFcse)
builddags(); /* common subexpressions */
if (mfoptim & MFdv)
deadvar(); /* eliminate dead variables */
#ifdef DEBUG
if (debugb)
{
dbg_printf(".............After optimization...........\n");
WRfunc();
}
#endif
// Prepare for code generator
for (b = startblock; b; b = b->Bnext)
{
block_optimizer_free(b);
}
#endif
}
#endif // !SPP

98
backend/go.h Normal file
View File

@@ -0,0 +1,98 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if __SC__
#pragma once
#endif
#ifndef GO_H
#define GO_H 1
/***************************************
* Bit masks for various optimizations.
*/
typedef unsigned mftype; /* a type big enough for all the flags */
#define MFdc 1 // dead code
#define MFda 2 // dead assignments
#define MFdv 4 // dead variables
#define MFreg 8 // register variables
#define MFcse 0x10 // global common subexpressions
#define MFvbe 0x20 // very busy expressions
#define MFtime 0x40 // favor time (speed) over space
#define MFli 0x80 // loop invariants
#define MFliv 0x100 // loop induction variables
#define MFcp 0x200 // copy propagation
#define MFcnp 0x400 // constant propagation
#define MFloop 0x800 // loop till no more changes
#define MFtree 0x1000 // optelem (tree optimization)
#define MFlocal 0x2000 // localize expressions
#define MFall (~0) // do everything
/**********************************
* Definition elem vector, used for reaching definitions.
*/
typedef struct DN
{
elem *DNelem; // pointer to definition elem
block *DNblock; // pointer to block that the elem is in
} dn;
/* Global Variables */
extern unsigned optab[];
extern mftype mfoptim;
extern unsigned changes; /* # of optimizations performed */
extern struct DN *defnod; /* array of definition elems */
extern unsigned deftop; /* # of entries in defnod[] */
extern elem **expnod; /* array of expression elems */
extern unsigned exptop; /* top of expnod[] */
extern block **expblk; /* parallel array of block pointers */
extern vec_t defkill; /* vector of AEs killed by an ambiguous */
/* definition */
extern vec_t starkill; /* vector of AEs killed by a definition */
/* of something that somebody could be */
/* pointing to */
extern vec_t vptrkill; /* vector of AEs killed by an access */
/* gdag.c */
void builddags(void);
void boolopt(void);
void opt_arraybounds();
/* gflow.c */
void flowrd(),flowlv(),flowae(),flowvbe(),
flowcp(),flowae(),genkillae(),flowarraybounds();
int ae_field_affect(elem *lvalue,elem *e);
/* glocal.c */
void localize(void);
/* gloop.c */
int blockinit(void);
void compdom(void);
void loopopt(void);
void updaterd(elem *n,vec_t GEN,vec_t KILL);
/* gother.c */
void rd_arraybounds(void);
void rd_free();
void constprop(void);
void copyprop(void);
void rmdeadass(void);
void elimass(elem *);
void deadvar(void);
void verybusyexp(void);
list_t listrds(vec_t, elem *, vec_t);
#endif /* GO_H */

1781
backend/gother.c Normal file

File diff suppressed because it is too large Load Diff

771
backend/html.c Normal file
View File

@@ -0,0 +1,771 @@
// Copyright (c) 1999-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
/* HTML parser
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <errno.h>
#include <wchar.h>
#include "html.h"
#if MARS
#include <assert.h>
#include "root.h"
//#include "../mars/mars.h"
#else
#include "outbuf.h"
#include "msgs2.h"
extern void html_err(const char *, unsigned, unsigned, ...);
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
#endif
#if __GNUC__
int memicmp(const char *s1, const char *s2, int n);
#if 0
{
int result = 0;
for (int i = 0; i < n; i++)
{ char c1 = s1[i];
char c2 = s2[i];
result = c1 - c2;
if (result)
{
if ('A' <= c1 && c1 <= 'Z')
c1 += 'a' - 'A';
if ('A' <= c2 && c2 <= 'Z')
c2 += 'a' - 'A';
result = c1 - c2;
if (result)
break;
}
}
return result;
}
#endif
#endif
extern int HtmlNamedEntity(unsigned char *p, int length);
static int isLineSeparator(const unsigned char* p);
/**********************************
* Determine if beginning of tag identifier
* or a continuation of a tag identifier.
*/
inline int istagstart(int c)
{
return (isalpha(c) || c == '_');
}
inline int istag(int c)
{
return (isalnum(c) || c == '_');
}
/**********************************************
*/
Html::Html(const char *sourcename, unsigned char *base, unsigned length)
{
//printf("Html::Html()\n");
this->sourcename = sourcename;
this->base = base;
p = base;
end = base + length;
linnum = 1;
dbuf = NULL;
inCode = 0;
}
/**********************************************
* Print error & quit.
*/
void Html::error(const char *format, ...)
{
printf("%s(%d) : HTML Error: ", sourcename, linnum);
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
printf("\n");
fflush(stdout);
//#if MARS
// global.errors++;
//#else
exit(EXIT_FAILURE);
//#endif
}
/**********************************************
* Extract all the code from an HTML file,
* concatenate it all together, and store in buf.
*/
#if MARS
void Html::extractCode(OutBuffer *buf)
#else
void Html::extractCode(Outbuffer *buf)
#endif
{
//printf("Html::extractCode()\n");
dbuf = buf; // save for other routines
buf->reserve(end - p);
inCode = 0;
while (1)
{
//printf("p = %p, *p = x%x\n", p, *p);
switch (*p)
{
#if 0 // strings are not recognized outside of tags
case '"':
case '\'':
skipString();
continue;
#endif
case '<':
if (p[1] == '!' && isCommentStart())
{ // Comments start with <!--
scanComment();
}
else if(p[1] == '!' && isCDATAStart())
{
scanCDATA();
}
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
skipTag();
else if (istagstart(*skipWhite(p + 1)))
skipTag();
else
goto Ldefault;
continue;
case 0:
case 0x1a:
break; // end of file
case '&':
if (inCode)
{ // Translate character entity into ascii for D parser
int c;
c = charEntity();
#if MARS
buf->writeUTF8(c);
#else
buf->writeByte(c);
#endif
}
else
p++;
continue;
case '\r':
if (p[1] == '\n')
goto Ldefault;
case '\n':
linnum++;
// Always extract new lines, so that D lexer counts the
// lines right.
buf->writeByte(*p);
p++;
continue;
default:
Ldefault:
if (inCode)
buf->writeByte(*p);
p++;
continue;
}
break;
}
buf->writeByte(0); // ending sentinel
#if SCPP
//printf("Code is: '%s'\n", buf->toString() + 3);
#endif
#if MARS
//printf("D code is: '%s'\n", (char *)buf->data);
#endif
}
/***********************************************
* Scan to end of <> tag.
* Look for <code> and </code> tags to start/stop D processing.
* Input:
* p is on opening '<' of tag; it's already verified that
* it's a tag by lookahead
* Output:
* p is past closing '>' of tag
*/
void Html::skipTag()
{
enum TagState // what parsing state we're in
{
TStagstart, // start of tag name
TStag, // in a tag name
TSrest, // following tag name
};
enum TagState state = TStagstart;
int inot;
unsigned char *tagstart = NULL;
int taglen = 0;
p++;
inot = 0;
if (*p == '/')
{ inot = 1;
p++;
}
while (1)
{
switch (*p)
{
case '>': // found end of tag
p++;
break;
case '"':
case '\'':
state = TSrest;
skipString();
continue;
case '<':
if (p[1] == '!' && isCommentStart())
{ // Comments start with <!--
scanComment();
}
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
{ error("nested tag");
skipTag();
}
else if (istagstart(*skipWhite(p + 1)))
{ error("nested tag");
skipTag();
}
// Treat comments as if they were whitespace
state = TSrest;
continue;
case 0:
case 0x1a:
error("end of file before end of tag");
break; // end of file
case '\r':
if (p[1] == '\n')
goto Ldefault;
case '\n':
linnum++;
// Always extract new lines, so that code lexer counts the
// lines right.
dbuf->writeByte(*p);
state = TSrest; // end of tag
p++;
continue;
case ' ':
case '\t':
case '\f':
case '\v':
if (state == TStagstart)
{ p++;
continue;
}
default:
Ldefault:
switch (state)
{
case TStagstart: // start of tag name
assert(istagstart(*p));
state = TStag;
tagstart = p;
taglen = 0;
break;
case TStag:
if (istag(*p))
{ // Continuing tag name
taglen++;
}
else
{ // End of tag name
state = TSrest;
}
break;
case TSrest:
break;
}
p++;
continue;
}
break;
}
// See if we parsed a <code> or </code> tag
if (taglen && memicmp((char *) tagstart, (char *) "CODE", taglen) == 0
&& *(p - 2) != '/') // ignore "<code />" (XHTML)
{
if (inot)
{ inCode--;
if (inCode < 0)
inCode = 0; // ignore extra </code>'s
}
else
inCode++;
}
}
/***********************************************
* Scan to end of attribute string.
*/
void Html::skipString()
{
int tc = *p;
while (1)
{
p++;
switch (*p)
{
case '"':
case '\'':
if (*p == tc)
{ p++;
break;
}
continue;
case '\r':
if (p[1] == '\n')
goto Ldefault;
case '\n':
linnum++;
// Always extract new lines, so that D lexer counts the
// lines right.
dbuf->writeByte(*p);
continue;
case 0:
case 0x1a:
Leof:
error("end of file before closing %c of string", tc);
break;
default:
Ldefault:
continue;
}
break;
}
}
/*********************************
* If p points to any white space, skip it
* and return pointer just past it.
*/
unsigned char *Html::skipWhite(unsigned char *q)
{
for (; 1; q++)
{
switch (*q)
{
case ' ':
case '\t':
case '\f':
case '\v':
case '\r':
case '\n':
continue;
default:
break;
}
break;
}
return q;
}
/***************************************************
* Scan to end of comment.
* Comments are defined any of a number of ways.
* IE 5.0: <!-- followed by >
* "HTML The Definitive Guide": <!-- text with at least one space in it -->
* Netscape: <!-- --> comments nest
* w3c: whitespace can appear between -- and > of comment close
*/
void Html::scanComment()
{
// Most of the complexity is dealing with the case that
// an arbitrary amount of whitespace can appear between
// the -- and the > of a comment close.
int scangt = 0;
//printf("scanComment()\n");
if (*p == '\n')
{ linnum++;
// Always extract new lines, so that D lexer counts the
// lines right.
dbuf->writeByte(*p);
}
while (1)
{
//scangt = 1; // IE 5.0 compatibility
p++;
switch (*p)
{
case '-':
if (p[1] == '-')
{
if (p[2] == '>') // optimize for most common case
{
p += 3;
break;
}
p++;
scangt = 1;
}
else
scangt = 0;
continue;
case '>':
if (scangt)
{ // found -->
p++;
break;
}
continue;
case ' ':
case '\t':
case '\f':
case '\v':
// skip white space
continue;
case '\r':
if (p[1] == '\n')
goto Ldefault;
case '\n':
linnum++; // remember to count lines
// Always extract new lines, so that D lexer counts the
// lines right.
dbuf->writeByte(*p);
continue;
case 0:
case 0x1a:
error("end of file before closing --> of comment");
break;
default:
Ldefault:
scangt = 0; // it's not -->
continue;
}
break;
}
//printf("*p = '%c'\n", *p);
}
/********************************************
* Determine if we are at the start of a comment.
* Input:
* p is on the opening '<'
* Returns:
* 0 if not start of a comment
* 1 if start of a comment, p is adjusted to point past --
*/
int Html::isCommentStart()
#ifdef __DMC__
__out(result)
{
if (result == 0)
;
else if (result == 1)
{
assert(p[-2] == '-' && p[-1] == '-');
}
else
assert(0);
}
__body
#endif /* __DMC__ */
{ unsigned char *s;
if (p[0] == '<' && p[1] == '!')
{
for (s = p + 2; 1; s++)
{
switch (*s)
{
case ' ':
case '\t':
case '\r':
case '\f':
case '\v':
// skip white space, even though spec says no
// white space is allowed
continue;
case '-':
if (s[1] == '-')
{
p = s + 2;
return 1;
}
goto No;
default:
goto No;
}
}
}
No:
return 0;
}
int Html::isCDATAStart()
{
const char * CDATA_START_MARKER = "<![CDATA[";
size_t len = strlen(CDATA_START_MARKER);
if (strncmp((char*)p, CDATA_START_MARKER, len) == 0)
{
p += len;
return 1;
}
else
{
return 0;
}
}
void Html::scanCDATA()
{
while(*p && *p != 0x1A)
{
int lineSepLength = isLineSeparator(p);
if (lineSepLength>0)
{
/* Always extract new lines, so that D lexer counts the lines
* right.
*/
linnum++;
dbuf->writeByte('\n');
p += lineSepLength;
continue;
}
else if (p[0] == ']' && p[1] == ']' && p[2] == '>')
{
/* end of CDATA section */
p += 3;
return;
}
else if (inCode)
{
/* this CDATA section contains D code */
dbuf->writeByte(*p);
}
p++;
}
}
/********************************************
* Convert an HTML character entity into a character.
* Forms are:
* &name; named entity
* &#ddd; decimal
* &#xhhhh; hex
* Input:
* p is on the &
*/
int Html::charEntity()
{ int c = 0;
int v;
int hex;
unsigned char *pstart = p;
//printf("Html::charEntity('%c')\n", *p);
if (p[1] == '#')
{
p++;
if (p[1] == 'x' || p[1] == 'X')
{ p++;
hex = 1;
}
else
hex = 0;
if (p[1] == ';')
goto Linvalid;
while (1)
{
p++;
switch (*p)
{
case 0:
case 0x1a:
error("end of file before end of character entity");
goto Lignore;
case '\n':
case '\r':
case '<': // tag start
// Termination is assumed
break;
case ';':
// Termination is explicit
p++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
v = *p - '0';
goto Lvalue;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
if (!hex)
goto Linvalid;
v = (*p - 'a') + 10;
goto Lvalue;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
if (!hex)
goto Linvalid;
v = (*p - 'A') + 10;
goto Lvalue;
Lvalue:
if (hex)
c = (c << 4) + v;
else
c = (c * 10) + v;
if (c > 0x10FFFF)
{
error("character entity out of range");
goto Lignore;
}
continue;
default:
Linvalid:
error("invalid numeric character reference");
goto Lignore;
}
break;
}
}
else
{
// It's a named entity; gather all characters until ;
unsigned char *idstart = p + 1;
while (1)
{
p++;
switch (*p)
{
case 0:
case 0x1a:
error("end of file before end of character entity");
break;
case '\n':
case '\r':
case '<': // tag start
// Termination is assumed
c = HtmlNamedEntity(idstart, p - idstart);
if (c == -1)
goto Lignore;
break;
case ';':
// Termination is explicit
c = HtmlNamedEntity(idstart, p - idstart);
if (c == -1)
goto Lignore;
p++;
break;
default:
continue;
}
break;
}
}
// Kludge to convert non-breaking space to ascii space
if (c == 160)
c = ' ';
return c;
Lignore:
//printf("Lignore\n");
p = pstart + 1;
return '&';
}
/**
* identify DOS, Linux, Mac, Next and Unicode line endings
* 0 if this is no line separator
* >0 the length of the separator
* Note: input has to be UTF-8
*/
static int isLineSeparator(const unsigned char* p)
{
// Linux
if( p[0]=='\n')
return 1;
// Mac & Dos
if( p[0]=='\r')
return (p[1]=='\n') ? 2 : 1;
// Unicode (line || paragraph sep.)
if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9))
return 3;
// Next
if( p[0]==0xC2 && p[1]==0x85)
return 2;
return 0;
}

50
backend/html.h Normal file
View File

@@ -0,0 +1,50 @@
// Copyright (c) 1999-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#if MARS
struct OutBuffer;
#else
struct Outbuffer;
#endif
struct Html
{
const char *sourcename;
unsigned char *base; // pointer to start of buffer
unsigned char *end; // past end of buffer
unsigned char *p; // current character
unsigned linnum; // current line number
#if MARS
OutBuffer *dbuf; // code source buffer
#else
Outbuffer *dbuf; // code source buffer
#endif
int inCode; // !=0 if in code
Html(const char *sourcename, unsigned char *base, unsigned length);
void error(const char *format, ...);
#if MARS
void extractCode(OutBuffer *buf);
#else
void extractCode(Outbuffer *buf);
#endif
void skipTag();
void skipString();
unsigned char *skipWhite(unsigned char *q);
void scanComment();
int isCommentStart();
void scanCDATA();
int isCDATAStart();
int charEntity();
static int namedEntity(unsigned char *p, int length);
};

430
backend/iasm.h Normal file
View File

@@ -0,0 +1,430 @@
/*
* Copyright (c) 1992-1999 by Symantec
* Copyright (c) 1999-2011 by Digital Mars
* All Rights Reserved
* http://www.digitalmars.com
* Written by Mike Cote, John Micco and Walter Bright
*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#include <setjmp.h>
/////////////////////////////////////////////////
// Instruction flags (usFlags)
//
//
// This is for when the reg field of modregrm specifies which instruction it is
#define NUM_MASK 0x7
#define NUM_MASKR 0x8 // for REX extended registers
#define _0 (0x0 | _modrm) // insure that some _modrm bit is set
#define _1 0x1 // with _0
#define _2 0x2
#define _3 0x3
#define _4 0x4
#define _5 0x5
#define _6 0x6
#define _7 0x7
#define _modrm 0x10
#define _r _modrm
#define _cb _modrm
#define _cw _modrm
#define _cd _modrm
#define _cq _modrm
#define _cp _modrm
#define _ib 0
#define _iw 0
#define _id 0
#define _rb 0
#define _rw 0
#define _rd 0
#define _16_bit 0x20
#define _32_bit 0x40
#define _64_bit 0x10000
#define _i64_bit 0x20000 // opcode is invalid in 64bit mode
#define _I386 0x80 // opcode is only for 386 and later
#define _16_bit_addr 0x100
#define _32_bit_addr 0x200
#define _fwait 0x400 // Add an FWAIT prior to the instruction opcode
#define _nfwait 0x800 // Do not add an FWAIT prior to the instruction
#define MOD_MASK 0xF000 // Mod mask
#define _modsi 0x1000 // Instruction modifies SI
#define _moddx 0x2000 // Instruction modifies DX
#define _mod2 0x3000 // Instruction modifies second operand
#define _modax 0x4000 // Instruction modifies AX
#define _modnot1 0x5000 // Instruction does not modify first operand
#define _modaxdx 0x6000 // instruction modifies AX and DX
#define _moddi 0x7000 // Instruction modifies DI
#define _modsidi 0x8000 // Instruction modifies SI and DI
#define _modcx 0x9000 // Instruction modifies CX
#define _modes 0xa000 // Instruction modifies ES
#define _modall 0xb000 // Instruction modifies all register values
#define _modsiax 0xc000 // Instruction modifies AX and SI
#define _modsinot1 0xd000 // Instruction modifies SI and not first param
#define _modcxr11 0xe000 // Instruction modifies CX and R11
#define _modxmm0 0xf000 // Instruction modifies XMM0
// translates opcode into equivalent vex encoding
#define VEX_128_W0(op) (_VEX(op)|_VEX_NOO)
#define VEX_128_W1(op) (_VEX(op)|_VEX_NOO|_VEX_W)
#define VEX_128_WIG(op) VEX_128_W0(op)
#define VEX_256_W0(op) (_VEX(op)|_VEX_NOO|_VEX_L)
#define VEX_256_W1(op) (_VEX(op)|_VEX_NOO|_VEX_W|_VEX_L)
#define VEX_256_WIG(op) VEX_256_W0(op)
#define VEX_NDS_128_W0(op) (_VEX(op)|_VEX_NDS)
#define VEX_NDS_128_W1(op) (_VEX(op)|_VEX_NDS|_VEX_W)
#define VEX_NDS_128_WIG(op) VEX_NDS_128_W0(op)
#define VEX_NDS_256_W0(op) (_VEX(op)|_VEX_NDS|_VEX_L)
#define VEX_NDS_256_W1(op) (_VEX(op)|_VEX_NDS|_VEX_W|_VEX_L)
#define VEX_NDS_256_WIG(op) VEX_NDS_256_W0(op)
#define VEX_NDD_128_W0(op) (_VEX(op)|_VEX_NDD)
#define VEX_NDD_128_W1(op) (_VEX(op)|_VEX_NDD|_VEX_W)
#define VEX_NDD_128_WIG(op) VEX_NDD_128_W0(op)
#define VEX_NDD_256_W0(op) (_VEX(op)|_VEX_NDD|_VEX_L)
#define VEX_NDD_256_W1(op) (_VEX(op)|_VEX_NDD|_VEX_W|_VEX_L)
#define VEX_NDD_256_WIG(op) VEX_NDD_256_W0(op)
#define VEX_DDS_128_W0(op) (_VEX(op)|_VEX_DDS)
#define VEX_DDS_128_W1(op) (_VEX(op)|_VEX_DDS|_VEX_W)
#define VEX_DDS_128_WIG(op) VEX_DDS_128_W0(op)
#define VEX_DDS_256_W0(op) (_VEX(op)|_VEX_DDS|_VEX_L)
#define VEX_DDS_256_W1(op) (_VEX(op)|_VEX_DDS|_VEX_W|_VEX_L)
#define VEX_DDS_256_WIG(op) VEX_DDS_256_W0(op)
#define _VEX_W 0x8000
/* Don't encode LIG/LZ use 128 for these.
*/
#define _VEX_L 0x0400
/* Encode nds, ndd, dds in the vvvv field, it gets
* overwritten with the actual register later.
*/
#define VEX_NOO 0 // neither of nds, ndd, dds
#define VEX_NDS 1
#define VEX_NDD 2
#define VEX_DDS 3
#define _VEX_NOO ( VEX_NOO << 11)
#define _VEX_NDS ( VEX_NDS << 11)
#define _VEX_NDD ( VEX_NDD << 11)
#define _VEX_DDS ( VEX_DDS << 11)
#define _VEX(op) (0xC4 << 24 | _VEX_MM(op >> 8) | (op & 0xFF))
#define _VEX_MM(op) \
( \
((op) & 0x00FF) == 0x000F ? (0x1 << 16 | _VEX_PP((op) >> 8)) : \
((op) & 0xFFFF) == 0x0F38 ? (0x2 << 16 | _VEX_PP((op) >> 16)) : \
((op) & 0xFFFF) == 0x0F3A ? (0x3 << 16 | _VEX_PP((op) >> 16)) : \
_VEX_ASSERT0 \
)
#define _VEX_PP(op) \
( \
(op) == 0x00 ? 0x00 << 8 : \
(op) == 0x66 ? 0x01 << 8 : \
(op) == 0xF3 ? 0x02 << 8 : \
(op) == 0xF2 ? 0x03 << 8 : \
_VEX_ASSERT0 \
)
// avoid dynamic initialization of the asm tables
#if DEBUG
#define _VEX_ASSERT0 (assert(0))
#else
#define _VEX_ASSERT0 (0)
#endif
/////////////////////////////////////////////////
// Operand flags - usOp1, usOp2, usOp3
//
typedef unsigned opflag_t;
// Operand flags for normal opcodes
#define _r8 CONSTRUCT_FLAGS( _8, _reg, _normal, 0 )
#define _r16 CONSTRUCT_FLAGS(_16, _reg, _normal, 0 )
#define _r32 CONSTRUCT_FLAGS(_32, _reg, _normal, 0 )
#define _r64 CONSTRUCT_FLAGS(_64, _reg, _normal, 0 )
#define _m8 CONSTRUCT_FLAGS(_8, _m, _normal, 0 )
#define _m16 CONSTRUCT_FLAGS(_16, _m, _normal, 0 )
#define _m32 CONSTRUCT_FLAGS(_32, _m, _normal, 0 )
#define _m48 CONSTRUCT_FLAGS( _48, _m, _normal, 0 )
#define _m64 CONSTRUCT_FLAGS( _64, _m, _normal, 0 )
#define _m128 CONSTRUCT_FLAGS( _anysize, _m, _normal, 0 )
#define _m256 CONSTRUCT_FLAGS( _anysize, _m, _normal, 0 )
#define _rm8 CONSTRUCT_FLAGS(_8, _rm, _normal, 0 )
#define _rm16 CONSTRUCT_FLAGS(_16, _rm, _normal, 0 )
#define _rm32 CONSTRUCT_FLAGS(_32, _rm, _normal, 0)
#define _rm64 CONSTRUCT_FLAGS(_64, _rm, _normal, 0)
#define _r32m8 CONSTRUCT_FLAGS(_32|_8, _rm, _normal, 0)
#define _r32m16 CONSTRUCT_FLAGS(_32|_16, _rm, _normal, 0)
#define _regm8 CONSTRUCT_FLAGS(_64|_32|_8, _rm, _normal, 0)
#define _imm8 CONSTRUCT_FLAGS(_8, _imm, _normal, 0 )
#define _imm16 CONSTRUCT_FLAGS(_16, _imm, _normal, 0)
#define _imm32 CONSTRUCT_FLAGS(_32, _imm, _normal, 0)
#define _imm64 CONSTRUCT_FLAGS(_64, _imm, _normal, 0)
#define _rel8 CONSTRUCT_FLAGS(_8, _rel, _normal, 0)
#define _rel16 CONSTRUCT_FLAGS(_16, _rel, _normal, 0)
#define _rel32 CONSTRUCT_FLAGS(_32, _rel, _normal, 0)
#define _p1616 CONSTRUCT_FLAGS(_32, _p, _normal, 0)
#define _m1616 CONSTRUCT_FLAGS(_32, _mnoi, _normal, 0)
#define _p1632 CONSTRUCT_FLAGS(_48, _p, _normal, 0 )
#define _m1632 CONSTRUCT_FLAGS(_48, _mnoi, _normal, 0)
#define _special CONSTRUCT_FLAGS( 0, 0, _rspecial, 0 )
#define _seg CONSTRUCT_FLAGS( 0, 0, _rseg, 0 )
#define _a16 CONSTRUCT_FLAGS( 0, 0, _addr16, 0 )
#define _a32 CONSTRUCT_FLAGS( 0, 0, _addr32, 0 )
#define _f16 CONSTRUCT_FLAGS( 0, 0, _fn16, 0)
// Near function pointer
#define _f32 CONSTRUCT_FLAGS( 0, 0, _fn32, 0)
// Far function pointer
#define _lbl CONSTRUCT_FLAGS( 0, 0, _flbl, 0 )
// Label (in current function)
#define _mmm32 CONSTRUCT_FLAGS( 0, _m, 0, _32)
#define _mmm64 CONSTRUCT_FLAGS( _64, _m, 0, _f64)
#define _mmm128 CONSTRUCT_FLAGS( 0, _m, 0, _f128)
#define _xmm_m16 CONSTRUCT_FLAGS( _16, _m, _rspecial, ASM_GET_uRegmask(_xmm))
#define _xmm_m32 CONSTRUCT_FLAGS( _32, _m, _rspecial, ASM_GET_uRegmask(_xmm))
#define _xmm_m64 CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_xmm))
#define _xmm_m128 CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_xmm))
#define _ymm_m256 CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_ymm))
#define _moffs8 (_rel8)
#define _moffs16 (_rel16 )
#define _moffs32 (_rel32 )
////////////////////////////////////////////////////////////////////
// Operand flags for floating point opcodes are all just aliases for
// normal opcode variants and only asm_determine_operator_flags should
// need to care.
//
#define _fm80 CONSTRUCT_FLAGS( 0, _m, 0, _f80 )
#define _fm64 CONSTRUCT_FLAGS( 0, _m, 0, _f64 )
#define _fm128 CONSTRUCT_FLAGS( 0, _m, 0, _f128 )
#define _fanysize (_f64 | _f80 | _f112 )
#define _float_m CONSTRUCT_FLAGS( _anysize, _float, 0, _fanysize)
#define _st CONSTRUCT_FLAGS( 0, _float, 0, _rst ) // stack register 0
#define _m112 CONSTRUCT_FLAGS( 0, _m, 0, _f112 )
#define _m224 _m112
#define _m512 _m224
#define _sti CONSTRUCT_FLAGS( 0, _float, 0, _rsti )
////////////////// FLAGS /////////////////////////////////////
#if 1
// bit size 5 3 3 7
#define CONSTRUCT_FLAGS( uSizemask, aopty, amod, uRegmask ) \
( (uSizemask) | (aopty) << 5 | (amod) << 8 | (uRegmask) << 11)
#define ASM_GET_uSizemask(us) ((us) & 0x1F)
#define ASM_GET_aopty(us) ((ASM_OPERAND_TYPE)(((us) >> 5) & 7))
#define ASM_GET_amod(us) ((ASM_MODIFIERS)(((us) >> 8) & 7))
#define ASM_GET_uRegmask(us) (((us) >> 11) & 0x7F)
#else
#define CONSTRUCT_FLAGS( uSizemask, aopty, amod, uRegmask ) \
( (uSizemask) | (aopty) << 4 | (amod) << 7 | (uRegmask) << 10)
#define ASM_GET_uSizemask(us) ((us) & 0x0F)
#define ASM_GET_aopty(us) ((ASM_OPERAND_TYPE)(((us) & 0x70) >> 4))
#define ASM_GET_amod(us) ((ASM_MODIFIERS)(((us) & 0x380) >> 7))
#define ASM_GET_uRegmask(us) (((us) & 0xFC00) >> 10)
#endif
// For uSizemask (5 bits)
#define _8 0x1
#define _16 0x2
#define _32 0x4
#define _48 0x8
#define _64 0x10
#define _anysize (_8 | _16 | _32 | _48 | _64 )
// For aopty (3 bits)
enum ASM_OPERAND_TYPE {
_reg, // _r8, _r16, _r32
_m, // _m8, _m16, _m32, _m48
_imm, // _imm8, _imm16, _imm32, _imm64
_rel, // _rel8, _rel16, _rel32
_mnoi, // _m1616, _m1632
_p, // _p1616, _p1632
_rm, // _rm8, _rm16, _rm32
_float // Floating point operand, look at cRegmask for the
// actual size
};
// For amod (3 bits)
enum ASM_MODIFIERS {
_normal, // Normal register value
_rseg, // Segment registers
_rspecial, // Special registers
_addr16, // 16 bit address
_addr32, // 32 bit address
_fn16, // 16 bit function call
_fn32, // 32 bit function call
_flbl // Label
};
// For uRegmask (7 bits)
// uRegmask flags when aopty == _float
#define _rst 0x1
#define _rsti 0x2
#define _f64 0x4
#define _f80 0x8
#define _f112 0x10
#define _f128 0x20
// _seg register values (amod == _rseg)
//
#define _ds CONSTRUCT_FLAGS( 0, 0, _rseg, 0x01 )
#define _es CONSTRUCT_FLAGS( 0, 0, _rseg, 0x02 )
#define _ss CONSTRUCT_FLAGS( 0, 0, _rseg, 0x04 )
#define _fs CONSTRUCT_FLAGS( 0, 0, _rseg, 0x08 )
#define _gs CONSTRUCT_FLAGS( 0, 0, _rseg, 0x10 )
#define _cs CONSTRUCT_FLAGS( 0, 0, _rseg, 0x20 )
//
// _special register values
//
#define _crn CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x01 ) // CRn register (0,2,3)
#define _drn CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x02 ) // DRn register (0-3,6-7)
#define _trn CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x04 ) // TRn register (3-7)
#define _mm CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x08 ) // MMn register (0-7)
#define _xmm CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x10 ) // XMMn register (0-7)
#define _xmm0 CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x20 ) // XMM0 register
#define _ymm CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x40 ) // YMMn register (0-15)
//
// Default register values
//
#define _al CONSTRUCT_FLAGS( 0, 0, _normal, 0x01 ) // AL register
#define _ax CONSTRUCT_FLAGS( 0, 0, _normal, 0x02 ) // AX register
#define _eax CONSTRUCT_FLAGS( 0, 0, _normal, 0x04 ) // EAX register
#define _dx CONSTRUCT_FLAGS( 0, 0, _normal, 0x08 ) // DX register
#define _cl CONSTRUCT_FLAGS( 0, 0, _normal, 0x10 ) // CL register
#define _rax CONSTRUCT_FLAGS( 0, 0, _normal, 0x40 ) // RAX register
#define _rplus_r 0x20
#define _plus_r CONSTRUCT_FLAGS( 0, 0, 0, _rplus_r )
// Add the register to the opcode (no mod r/m)
//////////////////////////////////////////////////////////////////
#define ITprefix 0x10 // special prefix
#define ITjump 0x20 // jump instructions CALL, Jxx and LOOPxx
#define ITimmed 0x30 // value of an immediate operand controls
// code generation
#define ITopt 0x40 // not all operands are required
#define ITshift 0x50 // rotate and shift instructions
#define ITfloat 0x60 // floating point coprocessor instructions
#define ITdata 0x70 // DB, DW, DD, DQ, DT pseudo-ops
#define ITaddr 0x80 // DA (define addresss) pseudo-op
#define ITMASK 0xF0
#define ITSIZE 0x0F // mask for size
enum OP_DB
{
#if SCPP
// These are the number of bytes
OPdb = 1,
OPdw = 2,
OPdd = 4,
OPdq = 8,
OPdt = 10,
OPdf = 4,
OPde = 10,
OPds = 2,
OPdi = 4,
OPdl = 8,
#endif
#if MARS
// Integral types
OPdb,
OPds,
OPdi,
OPdl,
// Float types
OPdf,
OPdd,
OPde,
// Deprecated
OPdw = OPds,
OPdq = OPdl,
OPdt = OPde,
#endif
};
/* from iasm.c */
int asm_state(int iFlags);
void asm_process_fixup( block **ppblockLabels );
typedef struct _PTRNTAB4 {
unsigned usOpcode;
unsigned usFlags;
opflag_t usOp1;
opflag_t usOp2;
opflag_t usOp3;
opflag_t usOp4;
} PTRNTAB4, * PPTRNTAB4, ** PPPTRNTAB4;
typedef struct _PTRNTAB3 {
unsigned usOpcode;
unsigned usFlags;
opflag_t usOp1;
opflag_t usOp2;
opflag_t usOp3;
} PTRNTAB3, * PPTRNTAB3, ** PPPTRNTAB3;
typedef struct _PTRNTAB2 {
unsigned usOpcode;
unsigned usFlags;
opflag_t usOp1;
opflag_t usOp2;
} PTRNTAB2, * PPTRNTAB2, ** PPPTRNTAB2;
typedef struct _PTRNTAB1 {
unsigned usOpcode;
unsigned usFlags;
opflag_t usOp1;
} PTRNTAB1, * PPTRNTAB1, ** PPPTRNTAB1;
typedef struct _PTRNTAB0 {
unsigned usOpcode;
#define ASM_END 0xffff // special opcode meaning end of table
unsigned usFlags;
} PTRNTAB0, * PPTRNTAB0, ** PPPTRNTAB0;
typedef union _PTRNTAB {
PTRNTAB0 *pptb0;
PTRNTAB1 *pptb1;
PTRNTAB2 *pptb2;
PTRNTAB3 *pptb3;
PTRNTAB4 *pptb4;
} PTRNTAB, * PPTRNTAB, ** PPPTRNTAB;
typedef struct
{
unsigned char usNumops;
PTRNTAB ptb;
} OP;

323
backend/mach.h Normal file
View File

@@ -0,0 +1,323 @@
/* Mach-O object file format */
#if __APPLE__
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/stab.h>
#include <mach-o/reloc.h>
//#include <mach-o/x86_64/reloc.h>
#ifndef S_DTRACE_DOF
#define S_DTRACE_DOF 15
#endif
#else
#include <stdint.h>
typedef int cpu_type_t;
typedef int cpu_subtype_t;
typedef int vm_prot_t;
struct mach_header
{
uint32_t magic;
#define MH_MAGIC 0xfeedface
#define MH_CIGAM 0xcefaedfe
cpu_type_t cputype;
#define CPU_TYPE_I386 ((cpu_type_t)7)
#define CPU_TYPE_X86_64 ((cpu_type_t)7 | 0x1000000)
#define CPU_TYPE_POWERPC ((cpu_type_t)18)
#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | 0x1000000)
cpu_subtype_t cpusubtype;
#define CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t)0)
#define CPU_SUBTYPE_I386_ALL ((cpu_subtype_t)3)
uint32_t filetype;
#define MH_OBJECT 1
#define MH_EXECUTE 2
#define MH_BUNDLE 8
#define MH_DYLIB 6
#define MH_PRELOAD 5
#define MH_CORE 4
#define MH_DYLINKER 7
#define MH_DSYM 10
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
#define MH_NOUNDEFS 1
#define MH_INCRLINK 2
#define MH_DYLDLINK 4
#define MH_TWOLEVEL 0x80
#define MH_BINDATLOAD 8
#define MH_PREBOUND 0x10
#define MH_PREBINDABLE 0x800
#define MH_NOFIXPREBINDING 0x400
#define MH_ALLMODSBOUND 0x1000
#define MH_CANONICAL 0x4000
#define MH_SPLIT_SEGS 0x20
#define MH_FORCE_FLAT 0x100
#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000
#define MH_NOMULTIDEFS 0x200
};
struct mach_header_64
{
uint32_t magic;
#define MH_MAGIC_64 0xfeedfacf
#define MH_CIGAM_64 0xcffaedfe
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
uint32_t reserved;
};
struct load_command
{
uint32_t cmd;
#define LC_SEGMENT 1
#define LC_SYMTAB 2
#define LC_DYSYMTAB 11
#define LC_SEGMENT_64 0x19
uint32_t cmdsize;
};
struct uuid_command
{
uint32_t cmd;
uint32_t cmdsize;
uint8_t uuid[16];
};
struct segment_command
{
uint32_t cmd;
uint32_t cmdsize;
char segname[16];
uint32_t vmaddr;
uint32_t vmsize;
uint32_t fileoff;
uint32_t filesize;
vm_prot_t maxprot;
vm_prot_t initprot;
uint32_t nsects;
uint32_t flags;
#define SG_HIGHVM 1
#define SG_FVMLIB 2
#define SG_NORELOC 4
#define SG_PROTECTED_VERSION_1 8
};
struct segment_command_64
{
uint32_t cmd;
uint32_t cmdsize;
char segname[16];
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
vm_prot_t maxprot;
vm_prot_t initprot;
uint32_t nsects;
uint32_t flags;
};
struct section
{
char sectname[16];
char segname[16];
uint32_t addr;
uint32_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
#define SECTION_TYPE 0xFF
#define SECTION_ATTRIBUTES 0xFFFFFF00
#define S_REGULAR 0
#define S_ZEROFILL 1
#define S_CSTRING_LITERALS 2
#define S_4BYTE_LITERALS 3
#define S_8BYTE_LITERALS 4
#define S_LITERAL_POINTERS 5
#define S_NON_LAZY_SYMBOL_POINTERS 6
#define S_LAZY_SYMBOL_POINTERS 7
#define S_SYMBOL_STUBS 8
#define S_MOD_INIT_FUNC_POINTERS 9
#define S_MOD_TERM_FUNC_POINTERS 10
#define S_COALESCED 11
#define S_GB_ZEROFILL 12
#define S_INTERPOSING 13
#define S_16BYTE_LITERALS 14
#define S_DTRACE_DOF 15
#define SECTION_ATTRIBUTES_USR 0xFF000000
#define S_ATTR_PURE_INSTRUCTIONS 0x80000000
#define S_ATTR_NO_TOC 0x40000000
#define S_ATTR_STRIP_STATIC_SYMS 0x20000000
#define S_ATTR_NO_DEAD_STRIP 0x10000000
#define S_ATTR_LIVE_SUPPORT 0x8000000
#define S_ATTR_SELF_MODIFYING_CODE 0x4000000
#define S_ATTR_DEBUG 0x2000000
#define SECTION_ATTRIBUTES_SYS 0xFFFF00
#define S_ATTR_SOME_INSTRUCTIONS 0x000400
#define S_ATTR_EXT_RELOC 0x000200
#define S_ATTR_LOC_RELOC 0x000100
uint32_t reserved1;
uint32_t reserved2;
};
struct section_64
{
char sectname[16];
char segname[16];
uint64_t addr;
uint64_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
uint32_t reserved3;
};
struct twolevel_hints_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t offset;
uint32_t nhints;
};
struct twolevel_hint
{
uint32_t isub_image:8, itoc:24;
};
struct symtab_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t symoff;
uint32_t nsyms;
uint32_t stroff;
uint32_t strsize;
};
struct nlist
{
union
{
int32_t n_strx;
} n_un;
uint8_t n_type;
#define N_EXT 1
#define N_STAB 0xE0
#define N_PEXT 0x10
#define N_TYPE 0x0E
#define N_UNDF 0
#define N_ABS 2
#define N_INDR 10
#define N_PBUD 12
#define N_SECT 14
uint8_t n_sect;
int16_t n_desc;
uint32_t n_value;
};
struct nlist_64
{
union
{
uint32_t n_strx;
} n_un;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
};
struct dysymtab_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t ilocalsym;
uint32_t nlocalsym;
uint32_t iextdefsym;
uint32_t nextdefsym;
uint32_t iundefsym;
uint32_t nundefsym;
uint32_t tocoff;
uint32_t ntoc;
uint32_t modtaboff;
uint32_t nmodtab;
uint32_t extrefsymoff;
uint32_t nextrefsyms;
uint32_t indirectsymoff;
uint32_t nindirectsyms;
uint32_t extreloff;
uint32_t nextrel;
uint32_t locreloff;
uint32_t nlocrel;
};
struct relocation_info
{
int32_t r_address;
#define R_SCATTERED 0x80000000
uint32_t r_symbolnum:24,
r_pcrel:1,
r_length:2,
r_extern:1,
r_type:4;
// for i386
#define GENERIC_RELOC_VANILLA 0
#define GENERIC_RELOC_PAIR 1
#define GENERIC_RELOC_SECTDIFF 2
#define GENERIC_RELOC_PB_LA_PTR 3
#define GENERIC_RELOC_LOCAL_SECTDIFF 4
// for x86_64
#define X86_64_RELOC_UNSIGNED 0
#define X86_64_RELOC_SIGNED 1
#define X86_64_RELOC_BRANCH 2
#define X86_64_RELOC_GOT_LOAD 3
#define X86_64_RELOC_GOT 4
#define X86_64_RELOC_SUBTRACTOR 5
#define X86_64_RELOC_SIGNED_1 6
#define X86_64_RELOC_SIGNED_2 7
#define X86_64_RELOC_SIGNED_4 8
};
struct scattered_relocation_info
{
#if LITTLE_ENDIAN
uint32_t r_address:24,
r_type:4,
r_length:2,
r_pcrel:1,
r_scattered:1;
int32_t r_value;
#elif BIG_ENDIAN
uint32_t r_scattered:1,
r_pcrel:1,
r_length:2,
r_type:4,
r_address:24;
int32_t r_value;
#endif
};
#endif

2757
backend/machobj.c Normal file

File diff suppressed because it is too large Load Diff

277
backend/md5.c Normal file
View File

@@ -0,0 +1,277 @@
/*
**********************************************************************
** md5.c **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
/* -- include the following line if the md5.h header file is separate -- */
#include "md5.h"
/* forward declaration */
static void Transform (UINT4 *buf, UINT4 *in);
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G and H are basic MD5 functions: selection, majority, parity */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
void MD5Init (mdContext)
MD5_CTX *mdContext;
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}
void MD5Update (mdContext, inBuf, inLen)
MD5_CTX *mdContext;
unsigned char *inBuf;
unsigned int inLen;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
void MD5Final (mdContext)
MD5_CTX *mdContext;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
}
/* Basic MD5 step. Transform buf based on in.
*/
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */
FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */
FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */
FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */
FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */
FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */
FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */
FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */
FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */
FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */
FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */
FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */
FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */
FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */
FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */
FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */
GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */
GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */
GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */
GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */
GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */
GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */
GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */
GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */
GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */
GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */
GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */
GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */
GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */
GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */
GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */
HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */
HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */
HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */
HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */
HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */
HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */
HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */
HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */
HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */
HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */
HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */
HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */
HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */
HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */
HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */
II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */
II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */
II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */
II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */
II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */
II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */
II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */
II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */
II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */
II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */
II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */
II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */
II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */
II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */
II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*
**********************************************************************
** End of md5.c **
******************************* (cut) ********************************
*/

61
backend/md5.h Normal file
View File

@@ -0,0 +1,61 @@
/*
**********************************************************************
** md5.h -- Header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
/* typedef a 32 bit type */
typedef unsigned long int UINT4;
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5Init (MD5_CTX *mdContext);
void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned inLen);
void MD5Final (MD5_CTX *mdContext);
/*
**********************************************************************
** End of md5.h **
******************************* (cut) ********************************
*/

381
backend/melf.h Normal file
View File

@@ -0,0 +1,381 @@
/* ELF file format */
typedef unsigned short elf_u16_f32;
typedef unsigned int elf_u32_f32;
typedef int elf_s32_f32;
typedef unsigned int elf_add_f32;
typedef unsigned int elf_off_f32;
typedef unsigned char elf_u8_f32;
#define EI_NIDENT 16
typedef struct
{
// unsigned char EHident[EI_NIDENT]; /* Header identification info */
#define EI_MAG0 0 /* Identification byte offset 0*/
#define EI_MAG1 1 /* Identification byte offset 1*/
#define EI_MAG2 2 /* Identification byte offset 2*/
#define EI_MAG3 3 /* Identification byte offset 3*/
#define ELFMAG0 0x7f /* Magic number byte 0 */
#define ELFMAG1 'E' /* Magic number byte 1 */
#define ELFMAG2 'L' /* Magic number byte 2 */
#define ELFMAG3 'F' /* Magic number byte 3 */
#define EI_CLASS 4 /* File class byte offset 4 */
#define ELFCLASSNONE 0 // invalid
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define EI_DATA 5 /* Data encoding byte offset 5 */
#define ELFDATANONE 0 // invalid
#define ELFDATA2LSB 1 /* 2's comp,lsb low address */
#define ELFDATA2MSB 2 /* 2's comp,msb low address */
#define EI_VERSION 6 /* Header version byte offset 6 */
//#define EV_CURRENT 1 /* Current header format */
#define EI_OSABI 7 /* OS ABI byte offset 7 */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX */
#define ELFOSABI_NETBSD 2
#define ELFOSABI_LINUX 3
#define ELFOSABI_FREEBSD 9
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone/embedded */
#define EI_ABIVERSION 8 /* ABI version byte offset 8 */
#define EI_PAD 9 /* Byte to start of padding */
elf_u16_f32 e_type; /* Object file type */
#define ET_NONE 0 /* No specified file type */
#define ET_REL 1 /* Relocatable object file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Dynamic link object file */
#define ET_CORE 4 /* Core file */
#define ET_LOPROC 0xff00 /* Processor low index */
#define ET_HIPROC 0xffff /* Processor hi index */
elf_u16_f32 e_machine; /* Machine architecture */
#define EM_386 3 /* Intel 80386 */
#define EM_486 6 /* Intel 80486 */
#define EM_X86_64 62 // Advanced Micro Devices X86-64 processor
elf_u32_f32 e_version; /* File format version */
#define EV_NONE 0 // invalid version
#define EV_CURRENT 1 // Current file format
elf_add_f32 e_entry; /* Entry point virtual address */
elf_off_f32 e_phoff; /* Program header table(PHT)offset */
elf_off_f32 e_shoff; /* Section header table(SHT)offset */
elf_u32_f32 e_flags; /* Processor-specific flags */
elf_u16_f32 e_ehsize; /* Size of ELF header (bytes) */
#define EH_HEADER_SIZE 0x34
elf_u16_f32 e_phentsize; /* Size of PHT (bytes) */
#define EH_PHTENT_SIZE 0x20
elf_u16_f32 e_phnum; /* Number of PHT entries */
elf_u16_f32 e_shentsize; /* Size of SHT entry in bytes */
#define EH_SHTENT_SIZE 0x28
elf_u16_f32 e_shnum; /* Number of SHT entries */
elf_u16_f32 e_shstrndx; /* SHT index for string table */
} Elf32_Hdr;
/* Section header. */
typedef struct
{
elf_u32_f32 sh_name; /* String table offset for section name */
elf_u32_f32 sh_type; /* Section type */
#define SHT_NULL 0 /* SHT entry unused */
#define SHT_PROGDEF 1 /* Program defined data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocations with addends */
#define SHT_HASHTAB 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* String table for dynamic symbols */
#define SHT_NOTE 7 /* Notes */
#define SHT_RESDATA 8 /* Reserved data space */
#define SHT_NOBITS SHT_RESDATA
#define SHT_REL 9 /* Relocations no addends */
#define SHT_RESTYPE 10 /* Reserved section type*/
#define SHT_DYNTAB 11 /* Dynamic linker symbol table */
#define SHT_GROUP 17 /* Section group (COMDAT) */
elf_u32_f32 sh_flags; /* Section attribute flags */
#define SHF_WRITE (1 << 0) /* Writable during execution */
#define SHF_ALLOC (1 << 1) /* In memory during execution */
#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions*/
#define SHF_TLS (1 << 10) /* Thread local */
#define SHF_MASKPROC 0xf0000000 /* Mask for processor-specific */
elf_add_f32 sh_addr; /* Starting virtual memory address */
elf_off_f32 sh_offset; /* Offset to section in file */
elf_u32_f32 sh_size; /* Size of section */
elf_u32_f32 sh_link; /* Index to optional related section */
elf_u32_f32 sh_info; /* Optional extra section information */
elf_u32_f32 sh_addralign; /* Required section alignment */
elf_u32_f32 sh_entsize; /* Size of fixed size section entries */
} Elf32_Shdr;
// Special Section Header Table Indices
#define SHT_UNDEF 0 /* Undefined section */
#define SHT_ABS 0xfff1 /* Absolute value for symbol references */
#define SHT_COMMON 0xfff2 /* Symbol defined in common section */
#define SHT_RESVSTART 0xff00 /* Start of reserved indices */
#define SHT_PROCSTART 0xff00 /* Start of processor-specific */
#define SHT_PROCEND 0xff1f /* End of processor-specific */
#define SHT_RESVEND 0xffff /* End of reserved indices */
/* Symbol Table */
typedef struct
{
elf_u32_f32 st_name; /* string table index for symbol name */
elf_add_f32 st_value; /* Associated symbol value */
elf_u32_f32 st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
#define ELF_ST_BIND(s) ((s)>>4)
#define ELF_ST_TYPE(s) ((s)&0xf)
#define ELF_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* Weak symbol */
#define ST_NUM_BINDINGS 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_HIOS 12 /* End of OS-specific */
#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
#define STT_NOTYPE 0 /* Symbol type is unspecified */
#define STT_OBJECT 1 /* Symbol is a data object */
#define STT_FUNC 2 /* Symbol is a code object */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Symbol's name is file name */
#define STT_COMMON 5
#define STT_TLS 6
#define STT_NUM 5 /* Number of defined types. */
#define STT_LOOS 11 /* Start of OS-specific */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
#define STT_HIPROC 15 /* End of processor-specific */
unsigned char st_other; /* Currently not defined */
elf_u16_f32 st_shndx; /* SHT index for symbol definition */
} Elf32_Sym;
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef struct
{
elf_add_f32 r_offset; /* Address */
elf_u32_f32 r_info; /* Relocation type and symbol index */
#define ELF32_R_IDX(i) ((i) >> 8) /* Symbol idx */
#define ELF32_R_TYPE(i)((i) & 0xff) /* Type of relocation */
#define ELF32_R_INFO(i, t) (((i) << 8) + ((t) & 0xff))
#define RI_TYPE_NONE 0 /* No reloc */
#define RI_TYPE_SYM32 1 /* Symbol value 32 bit */
#define RI_TYPE_PC32 2 /* PC relative 32 bit */
#define RI_TYPE_GOT32 3 /* 32 bit GOT entry */
#define RI_TYPE_PLT32 4 /* 32 bit PLT address */
#define RI_TYPE_COPY 5 /* Copy symbol at runtime */
#define RI_TYPE_GLOBDAT 6 /* Create GOT entry */
#define RI_TYPE_JMPSLOT 7 /* Create PLT entry */
#define RI_TYPE_REL 8 /* Adjust by program base */
#define RI_TYPE_GOTOFF 9 /* 32 bit offset to GOT */
#define RI_TYPE_GOTPC 10 /* 32 bit PC relative offset to GOT */
#define RI_TYPE_TLS_TPOFF 14
#define RI_TYPE_TLS_IE 15
#define RI_TYPE_TLS_GOTIE 16
#define RI_TYPE_TLS_LE 17 /* negative offset relative to static TLS */
#define RI_TYPE_TLS_GD 18
#define RI_TYPE_TLS_LDM 19
#define RI_TYPE_TLS_GD_32 24
#define RI_TYPE_TLS_GD_PUSH 25
#define RI_TYPE_TLS_GD_CALL 26
#define RI_TYPE_TLS_GD_POP 27
#define RI_TYPE_TLS_LDM_32 28
#define RI_TYPE_TLS_LDM_PUSH 29
#define RI_TYPE_TLS_LDM_CALL 30
#define RI_TYPE_TLS_LDM_POP 31
#define RI_TYPE_TLS_LDO_32 32
#define RI_TYPE_TLS_IE_32 33
#define RI_TYPE_TLS_LE_32 34
#define RI_TYPE_TLS_DTPMOD32 35
#define RI_TYPE_TLS_DTPOFF32 36
#define RI_TYPE_TLS_TPOFF32 37
} Elf32_Rel;
/* stabs debug records */
typedef struct
{
elf_u32_f32 DBstring; /* string table index for the symbol */
elf_u8_f32 DBtype; /* type of the symbol */
#define DBT_UNDEF 0x00 /* undefined symbol */
#define DBT_EXT 0x01 /* exernal modifier */
#define DBT_ABS 0x02 /* absolute */
#define DBT_TEXT 0x04 /* code text */
#define DBT_DATA 0x06 /* data */
#define DBT_BSS 0x08 /* BSS */
#define DBT_INDR 0x0a /* indirect to another symbol */
#define DBT_COMM 0x12 /* common -visible after shr'd lib link */
#define DBT_SETA 0x14 /* Absolue set element */
#define DBT_SETT 0x16 /* code text segment set element */
#define DBT_SETD 0x18 /* data segment set element */
#define DBT_SETB 0x1a /* BSS segment set element */
#define DBT_SETV 0x1c /* Pointer to set vector */
#define DBT_WARNING 0x1e /* print warning during link */
#define DBT_FN 0x1f /* name of object file */
#define DBT_GSYM 0x20 /* global symbol */
#define DBT_FUN 0x24 /* function name */
#define DBT_STSYM 0x26 /* static data */
#define DBT_LCSYM 0x28 /* static bss */
#define DBT_MAIN 0x2a /* main routine */
#define DBT_RO 0x2c /* read only */
#define DBT_OPT 0x3c /* target option? */
#define DBT_REG 0x40 /* register variable */
#define DBT_TLINE 0x44 /* text line number */
#define DBT_DLINE 0x46 /* dat line number */
#define DBT_BLINE 0x48 /* bss line number */
#define DBT_STUN 0x62 /* structure or union */
#define DBT_SRCF 0x64 /* source file */
#define DBT_AUTO 0x80 /* stack variable */
#define DBT_TYPE 0x80 /* type definition */
#define DBT_INCS 0x84 /* include file start */
#define DBT_PARAM 0xa0 /* parameter */
#define DBT_INCE 0xa2 /* include file end */
elf_u8_f32 DBmisc; /* misc. info */
elf_u16_f32 DBdesc; /* description field */
elf_u32_f32 DBvalu; /* symbol value */
} elf_stab;
/* Program header. */
typedef struct
{
elf_u32_f32 PHtype; /* Program type */
#define PHT_NULL 0 /* SHT entry unused */
elf_off_f32 PHoff; /* Offset to segment in file */
elf_add_f32 PHvaddr; /* Starting virtual memory address */
elf_add_f32 PHpaddr; /* Starting absolute memory address */
elf_u32_f32 PHfilesz; /* Size of file image */
elf_u32_f32 PHmemsz; /* Size of memory image */
elf_u32_f32 PHflags; /* Program attribute flags */
elf_u32_f32 PHalign; /* Program loading alignment */
} elf_pht;
/* Legal values for sh_flags (section flags). */
/***************************** 64 bit Elf *****************************************/
typedef unsigned long long Elf64_Addr;
typedef unsigned long long Elf64_Off;
typedef unsigned long long Elf64_Xword;
typedef long long Elf64_Sxword;
typedef int Elf64_Sword;
typedef unsigned int Elf64_Word;
typedef unsigned short Elf64_Half;
typedef struct
{
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
typedef struct {
Elf64_Word sh_name;
Elf64_Word sh_type;
Elf64_Xword sh_flags;
Elf64_Addr sh_addr;
Elf64_Off sh_offset;
Elf64_Xword sh_size;
Elf64_Word sh_link;
Elf64_Word sh_info;
Elf64_Xword sh_addralign;
Elf64_Xword sh_entsize;
} Elf64_Shdr;
typedef struct {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
} Elf64_Phdr;
typedef struct {
Elf64_Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf64_Half st_shndx;
Elf64_Addr st_value;
Elf64_Xword st_size;
} Elf64_Sym;
typedef struct {
Elf64_Addr r_offset;
Elf64_Xword r_info;
#define ELF64_R_SYM(i) ((Elf64_Word)((i)>>32))
#define ELF64_R_TYPE(i) ((Elf64_Word)(i & 0xFFFFFFFF))
#define ELF64_R_INFO(s,t) ((((Elf64_Xword)(s))<<32)|(Elf64_Word)(t))
// X86-64 Relocation types
#define R_X86_64_NONE 0 // -- No relocation
#define R_X86_64_64 1 // 64 Direct 64 bit
#define R_X86_64_PC32 2 // 32 PC relative 32 bit signed
#define R_X86_64_GOT32 3 // 32 32 bit GOT entry
#define R_X86_64_PLT32 4 // 32 bit PLT address
#define R_X86_64_COPY 5 // -- Copy symbol at runtime
#define R_X86_64_GLOB_DAT 6 // 64 Create GOT entry
#define R_X86_64_JUMP_SLOT 7 // 64 Create PLT entry
#define R_X86_64_RELATIVE 8 // 64 Adjust by program base
#define R_X86_64_GOTPCREL 9 // 32 32 bit signed pc relative offset to GOT
#define R_X86_64_32 10 // 32 Direct 32 bit zero extended
#define R_X86_64_32S 11 // 32 Direct 32 bit sign extended
#define R_X86_64_16 12 // 16 Direct 16 bit zero extended
#define R_X86_64_PC16 13 // 16 16 bit sign extended pc relative
#define R_X86_64_8 14 // 8 Direct 8 bit sign extended
#define R_X86_64_PC8 15 // 8 8 bit sign extended pc relative
#define R_X86_64_DTPMOD64 16 // 64 ID of module containing symbol
#define R_X86_64_DTPOFF64 17 // 64 Offset in TLS block
#define R_X86_64_TPOFF64 18 // 64 Offset in initial TLS block
#define R_X86_64_TLSGD 19 // 32 PC relative offset to GD GOT block
#define R_X86_64_TLSLD 20 // 32 PC relative offset to LD GOT block
#define R_X86_64_DTPOFF32 21 // 32 Offset in TLS block
#define R_X86_64_GOTTPOFF 22 // 32 PC relative offset to IE GOT entry
#define R_X86_64_TPOFF32 23 // 32 Offset in initial TLS block
#define R_X86_64_PC64 24 // 64
#define R_X86_64_GOTOFF64 25 // 64
#define R_X86_64_GOTPC32 26 // 32
#define R_X86_64_GNU_VTINHERIT 250 // GNU C++ hack
#define R_X86_64_GNU_VTENTRY 251 // GNU C++ hack
} Elf64_Rel;
typedef struct {
Elf64_Addr r_offset;
Elf64_Xword r_info;
Elf64_Sxword r_addend;
} Elf64_Rela;

1707
backend/newman.c Normal file

File diff suppressed because it is too large Load Diff

915
backend/nteh.c Normal file
View File

@@ -0,0 +1,915 @@
// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
// Support for NT exception handling
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "el.h"
#include "code.h"
#include "oper.h"
#include "global.h"
#include "type.h"
#include "dt.h"
#if SCPP
#include "scope.h"
#endif
#include "exh.h"
#if !SPP && NTEXCEPTIONS
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
static symbol *s_table;
static symbol *s_context;
static char s_name_context_tag[] = "__nt_context";
static char s_name_context[] = "__context";
static char s_name_ecode[] = "__ecode";
static char text_nt[] =
"struct __nt_context {"
"int esp; int info; int prev; int handler; int stable; int sindex; int ebp;"
"};\n";
// member stable is not used for MARS or C++
int nteh_EBPoffset_sindex() { return -4; }
int nteh_EBPoffset_prev() { return -nteh_contextsym_size() + 8; }
int nteh_EBPoffset_info() { return -nteh_contextsym_size() + 4; }
int nteh_EBPoffset_esp() { return -nteh_contextsym_size() + 0; }
int nteh_offset_sindex() { return MARS ? 16 : 20; }
int nteh_offset_sindex_seh() { return 20; }
int nteh_offset_info() { return 4; }
/***********************************
*/
unsigned char *nteh_context_string()
{
if (config.flags2 & CFG2seh)
return (unsigned char *)text_nt;
else
return NULL;
}
/*******************************
* Get symbol for scope table for current function.
* Returns:
* symbol of table
*/
STATIC symbol *nteh_scopetable()
{ symbol *s;
type *t;
if (!s_table)
{
t = type_alloc(TYint);
s = symbol_generate(SCstatic,t);
s->Sseg = UNKNOWN;
symbol_keep(s);
s_table = s;
}
return s_table;
}
/*************************************
*/
void nteh_filltables()
{
#if MARS
symbol *s = s_table;
symbol_debug(s);
except_fillInEHTable(s);
#endif
}
/****************************
* Generate and output scope table.
* Not called for NTEH C++ exceptions
*/
void nteh_gentables()
{
symbol *s = s_table;
symbol_debug(s);
#if MARS
//except_fillInEHTable(s);
#else
/* NTEH table for C.
* The table consists of triples:
* parent index
* filter address
* handler address
*/
unsigned fsize = 4; // target size of function pointer
dt_t **pdt = &s->Sdt;
int sz = 0; // size so far
for (block *b = startblock; b; b = b->Bnext)
{
if (b->BC == BC_try)
{ dt_t *dt;
block *bhandler;
pdt = dtdword(pdt,b->Blast_index); // parent index
// If try-finally
if (list_nitems(b->Bsucc) == 2)
{
pdt = dtdword(pdt,0); // filter address
bhandler = list_block(list_next(b->Bsucc));
assert(bhandler->BC == BC_finally);
// To successor of BC_finally block
bhandler = list_block(bhandler->Bsucc);
}
else // try-except
{
bhandler = list_block(list_next(b->Bsucc));
assert(bhandler->BC == BC_filter);
pdt = dtcoff(pdt,bhandler->Boffset); // filter address
bhandler = list_block(list_next(list_next(b->Bsucc)));
assert(bhandler->BC == BC_except);
}
pdt = dtcoff(pdt,bhandler->Boffset); // handler address
sz += 4 + fsize * 2;
}
}
assert(sz != 0);
#endif
outdata(s); // output the scope table
#if MARS
nteh_framehandler(s);
#endif
s_table = NULL;
}
/**************************
* Declare frame variables.
*/
void nteh_declarvars(Blockx *bx)
{ symbol *s;
//printf("nteh_declarvars()\n");
#if MARS
if (!(bx->funcsym->Sfunc->Fflags3 & Fnteh)) // if haven't already done it
{ bx->funcsym->Sfunc->Fflags3 |= Fnteh;
s = symbol_name(s_name_context,SCbprel,tsint);
s->Soffset = -5 * 4; // -6 * 4 for C __try, __except, __finally
s->Sflags |= SFLfree | SFLnodebug;
type_setty(&s->Stype,mTYvolatile | TYint);
symbol_add(s);
bx->context = s;
}
#else
if (!(funcsym_p->Sfunc->Fflags3 & Fnteh)) // if haven't already done it
{ funcsym_p->Sfunc->Fflags3 |= Fnteh;
if (!s_context)
s_context = scope_search(s_name_context_tag,CPP ? SCTglobal : SCTglobaltag);
symbol_debug(s_context);
s = symbol_name(s_name_context,SCbprel,s_context->Stype);
s->Soffset = -6 * 4; // -5 * 4 for C++
s->Sflags |= SFLfree;
symbol_add(s);
type_setty(&s->Stype,mTYvolatile | TYstruct);
s = symbol_name(s_name_ecode,SCauto,type_alloc(mTYvolatile | TYint));
s->Sflags |= SFLfree;
symbol_add(s);
}
#endif
}
/**************************************
* Generate elem that sets the context index into the scope table.
*/
#if MARS
elem *nteh_setScopeTableIndex(Blockx *blx, int scope_index)
{
elem *e;
Symbol *s;
s = blx->context;
symbol_debug(s);
e = el_var(s);
e->EV.sp.Voffset = nteh_offset_sindex();
return el_bin(OPeq, TYint, e, el_long(TYint, scope_index));
}
#endif
/**********************************
* Return pointer to context symbol.
*/
symbol *nteh_contextsym()
{ SYMIDX si;
symbol *sp;
for (si = 0; 1; si++)
{ assert(si < globsym.top);
sp = globsym.tab[si];
symbol_debug(sp);
if (strcmp(sp->Sident,s_name_context) == 0)
return sp;
}
}
/**********************************
* Return size of context symbol on stack.
*/
unsigned nteh_contextsym_size()
{ int sz;
if (usednteh & NTEH_try)
{
#if MARS
sz = 5 * 4;
#elif SCPP
sz = 6 * 4;
#else
assert(0);
#endif
assert(usedalloca != 1);
}
else if (usednteh & NTEHcpp)
{ sz = 5 * 4; // C++ context record
assert(usedalloca != 1);
}
else if (usednteh & NTEHpassthru)
{ sz = 1 * 4;
}
else
sz = 0; // no context record
return sz;
}
/**********************************
* Return pointer to ecode symbol.
*/
symbol *nteh_ecodesym()
{ SYMIDX si;
symbol *sp;
for (si = 0; 1; si++)
{ assert(si < globsym.top);
sp = globsym.tab[si];
symbol_debug(sp);
if (strcmp(sp->Sident,s_name_ecode) == 0)
return sp;
}
}
/*********************************
* Mark EH variables as used so that they don't get optimized away.
*/
void nteh_usevars()
{
#if SCPP
// Turn off SFLdead and SFLunambig in Sflags
nteh_contextsym()->Sflags &= ~(SFLdead | SFLunambig);
nteh_contextsym()->Sflags |= SFLread;
nteh_ecodesym()->Sflags &= ~(SFLdead | SFLunambig);
nteh_ecodesym()->Sflags |= SFLread;
#else
// Turn off SFLdead and SFLunambig in Sflags
nteh_contextsym()->Sflags &= ~SFLdead;
nteh_contextsym()->Sflags |= SFLread;
#endif
}
/*********************************
* Generate NT exception handling function prolog.
*/
code *nteh_prolog()
{
code cs;
code *c1;
code *c;
if (usednteh & NTEHpassthru)
{
/* An sindex value of -2 is a magic value that tells the
* stack unwinder to skip this frame.
*/
assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64));
cs.Iop = 0x68;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL2 = FLconst;
cs.IEV2.Vint = -2;
return gen(CNIL,&cs); // PUSH -2
}
/* Generate instance of struct __nt_context on stack frame:
[ ] // previous ebp already there
push -1 // sindex
mov EDX,FS:__except_list
push offset FLAT:scope_table // stable (not for MARS or C++)
push offset FLAT:__except_handler3 // handler
push EDX // prev
mov FS:__except_list,ESP
sub ESP,8 // info, esp for __except support
*/
// useregs(mAX); // What is this for?
cs.Iop = 0x68;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL2 = FLconst;
cs.IEV2.Vint = -1;
c1 = gen(CNIL,&cs); // PUSH -1
if (usednteh & NTEHcpp || MARS)
{
// PUSH &framehandler
cs.IFL2 = FLframehandler;
#if MARS
nteh_scopetable();
#endif
}
else
{
// Do stable
cs.Iflags |= CFoff;
cs.IFL2 = FLextern;
cs.IEVsym2 = nteh_scopetable();
cs.IEVoffset2 = 0;
c1 = gen(c1,&cs); // PUSH &scope_table
cs.IFL2 = FLextern;
cs.IEVsym2 = rtlsym[RTLSYM_EXCEPT_HANDLER3];
makeitextern(rtlsym[RTLSYM_EXCEPT_HANDLER3]);
}
c = gen(NULL,&cs); // PUSH &__except_handler3
if (config.exe == EX_NT)
{
makeitextern(rtlsym[RTLSYM_EXCEPT_LIST]);
#if 0
cs.Iop = 0xFF;
cs.Irm = modregrm(0,6,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
gen(c,&cs); // PUSH FS:__except_list
#else
useregs(mDX);
cs.Iop = 0x8B;
cs.Irm = modregrm(0,DX,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
gen(c1,&cs); // MOV EDX,FS:__except_list
gen1(c,0x50 + DX); // PUSH EDX
#endif
cs.Iop = 0x89;
NEWREG(cs.Irm,SP);
gen(c,&cs); // MOV FS:__except_list,ESP
}
c = genc2(c,0x81,modregrm(3,5,SP),8); // SUB ESP,8
return cat(c1,c);
}
/*********************************
* Generate NT exception handling function epilog.
*/
code *nteh_epilog()
{
if (!(config.flags2 & CFG2seh))
return NULL;
/* Generate:
mov ECX,__context[EBP].prev
mov FS:__except_list,ECX
*/
code cs;
code *c;
unsigned reg;
#if MARS
reg = CX;
#else
reg = (tybasic(funcsym_p->Stype->Tnext->Tty) == TYvoid) ? AX : CX;
#endif
useregs(mask[reg]);
cs.Iop = 0x8B;
cs.Irm = modregrm(2,reg,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.prev
cs.IEV1.Vint = nteh_EBPoffset_prev();
c = gen(CNIL,&cs);
cs.Iop = 0x89;
cs.Irm = modregrm(0,reg,BPRM);
cs.Iflags |= CFfs;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
return gen(c,&cs);
}
/**************************
* Set/Reset ESP from context.
*/
code *nteh_setsp(int op)
{ code cs;
cs.Iop = op;
cs.Irm = modregrm(2,SP,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.esp
cs.IEV1.Vint = nteh_EBPoffset_esp();
return gen(CNIL,&cs); // MOV ESP,__context[EBP].esp
}
/****************************
* Put out prolog for BC_filter block.
*/
code *nteh_filter(block *b)
{ code *c;
code cs;
assert(b->BC == BC_filter);
c = CNIL;
if (b->Bflags & BFLehcode) // if referenced __ecode
{
/* Generate:
mov EAX,__context[EBP].info
mov EAX,[EAX]
mov EAX,[EAX]
mov __ecode[EBP],EAX
*/
c = getregs(mAX);
cs.Iop = 0x8B;
cs.Irm = modregrm(2,AX,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.info
cs.IEV1.Vint = nteh_EBPoffset_info();
c = gen(c,&cs); // MOV EAX,__context[EBP].info
cs.Irm = modregrm(0,AX,0);
gen(c,&cs); // MOV EAX,[EAX]
gen(c,&cs); // MOV EAX,[EAX]
cs.Iop = 0x89;
cs.Irm = modregrm(2,AX,BPRM);
cs.IFL1 = FLauto;
cs.IEVsym1 = nteh_ecodesym();
cs.IEVoffset1 = 0;
gen(c,&cs); // MOV __ecode[EBP],EAX
}
return c;
}
/*******************************
* Generate C++ or D frame handler.
*/
void nteh_framehandler(symbol *scopetable)
{ code *c;
// Generate:
// MOV EAX,&scope_table
// JMP __cpp_framehandler
if (scopetable)
{
symbol_debug(scopetable);
c = gencs(NULL,0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table
gencs(c,0xE9,0,FLfunc,rtlsym[RTLSYM_CPP_HANDLER]); // JMP __cpp_framehandler
pinholeopt(c,NULL);
codout(c);
code_free(c);
}
}
/*********************************
* Generate code to set scope index.
*/
code *nteh_gensindex(int sindex)
{ code *c;
if (!(config.flags2 & CFG2seh))
return NULL;
// Generate:
// MOV -4[EBP],sindex
c = genc(NULL,0xC7,modregrm(1,0,BP),FLconst,(targ_uns)nteh_EBPoffset_sindex(),FLconst,sindex); // 7 bytes long
c->Iflags |= CFvolatile;
#ifdef DEBUG
//assert(GENSINDEXSIZE == calccodsize(c));
#endif
return c;
}
/*********************************
* Generate code for setjmp().
*/
code *cdsetjmp(elem *e,regm_t *pretregs)
{ code cs;
code *c;
regm_t retregs;
unsigned stackpushsave;
unsigned flag;
c = NULL;
stackpushsave = stackpush;
#if SCPP
if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp))
{
/* If in C++ try block
If the frame that is calling setjmp has a try,catch block then
the call to setjmp3 is as follows:
__setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata);
__cpp_longjmp_unwind is a routine in the RTL. This is a
stdcall routine that will deal with unwinding for CPP Frames.
trylevel is the value that gets incremented at each catch,
constructor invocation.
funcdata is the same value that you put into EAX prior to
cppframehandler getting called.
*/
symbol *s;
s = except_gensym();
if (!s)
goto L1;
c = gencs(c,0x68,0,FLextern,s); // PUSH &scope_table
stackpush += 4;
genadjesp(c,4);
c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4);
// PUSH trylevel
stackpush += 4;
genadjesp(c,4);
cs.Iop = 0x68;
cs.Iflags = CFoff;
cs.Irex = 0;
cs.IFL2 = FLextern;
cs.IEVsym2 = rtlsym[RTLSYM_CPP_LONGJMP];
cs.IEVoffset2 = 0;
c = gen(c,&cs); // PUSH &_cpp_longjmp_unwind
stackpush += 4;
genadjesp(c,4);
flag = 3;
}
else
#endif
if (funcsym_p->Sfunc->Fflags3 & Fnteh)
{
/* If in NT SEH try block
If the frame that is calling setjmp has a try, except block
then the call to setjmp3 is as follows:
__setjmp3(environment,2,__seh_longjmp_unwind,trylevel);
__seth_longjmp_unwind is supplied by the RTL and is a stdcall
function. It is the name that MSOFT uses, we should
probably use the same one.
trylevel is the value that you increment at each try and
decrement at the close of the try. This corresponds to the
index field of the ehrec.
*/
int sindex_off;
sindex_off = 20; // offset of __context.sindex
cs.Iop = 0xFF;
cs.Irm = modregrm(2,6,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLbprel;
cs.IEVsym1 = nteh_contextsym();
cs.IEVoffset1 = sindex_off;
c = gen(c,&cs); // PUSH scope_index
stackpush += 4;
genadjesp(c,4);
cs.Iop = 0x68;
cs.Iflags = CFoff;
cs.Irex = 0;
cs.IFL2 = FLextern;
cs.IEVsym2 = rtlsym[RTLSYM_LONGJMP];
cs.IEVoffset2 = 0;
c = gen(c,&cs); // PUSH &_seh_longjmp_unwind
stackpush += 4;
genadjesp(c,4);
flag = 2;
}
else
{
/* If the frame calling setjmp has neither a try..except, nor a
try..catch, then call setjmp3 as follows:
_setjmp3(environment,0)
*/
L1:
flag = 0;
}
cs.Iop = 0x68;
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL2 = FLconst;
cs.IEV2.Vint = flag;
c = gen(c,&cs); // PUSH flag
stackpush += 4;
genadjesp(c,4);
c = cat(c,params(e->E1,REGSIZE));
c = cat(c,getregs(~rtlsym[RTLSYM_SETJMP3]->Sregsaved & (ALLREGS | mES)));
gencs(c,0xE8,0,FLfunc,rtlsym[RTLSYM_SETJMP3]); // CALL __setjmp3
c = genc2(c,0x81,modregrm(3,0,SP),stackpush - stackpushsave); // ADD ESP,8
genadjesp(c,-(stackpush - stackpushsave));
stackpush = stackpushsave;
retregs = regmask(e->Ety, TYnfunc);
return cat(c,fixresult(e,retregs,pretregs));
}
/****************************************
* Call _local_unwind(), which means call the __finally blocks until
* index is reached.
*/
code *nteh_unwind(regm_t retregs,unsigned index)
{ code *c;
code cs;
code *cs1;
code *cs2;
regm_t desregs;
int reg;
int local_unwind;
// Shouldn't this always be CX?
#if SCPP
reg = AX;
#else
reg = CX;
#endif
#if MARS
local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
cs.Iop = 0x8D;
cs.Irm = modregrm(2,reg,BPRM);
cs.Iflags = 0;
cs.Irex = 0;
cs.IFL1 = FLconst;
// EBP offset of __context.prev
cs.IEV1.Vint = nteh_EBPoffset_prev();
c = gen(c,&cs); // LEA ECX,contextsym
genc2(c,0x68,0,index); // PUSH index
gen1(c,0x50 + reg); // PUSH ECX
#if MARS
//gencs(c,0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table
gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),12); // ADD ESP,12
#else
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8
#endif
c = cat4(cs1,c,cs2,NULL);
return c;
}
/****************************************
* Call _local_unwind(), which means call the __finally blocks until
* index is reached.
*/
#if 0 // Replaced with inline calls to __finally blocks
code *linux_unwind(regm_t retregs,unsigned index)
{ code *c;
code *cs1;
code *cs2;
int i;
regm_t desregs;
int reg;
int local_unwind;
// Shouldn't this always be CX?
#if SCPP
reg = AX;
#else
reg = CX;
#endif
#if MARS
local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
c = genc2(c,0x68,0,index); // PUSH index
#if MARS
// gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),4); // ADD ESP,12
#else
gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2()
genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8
#endif
c = cat4(cs1,c,cs2,NULL);
return c;
}
#endif
/*************************************************
* Set monitor, hook monitor exception handler.
*/
#if MARS
code *nteh_monitor_prolog(Symbol *shandle)
{
/*
* PUSH handle
* PUSH offset _d_monitor_handler
* PUSH FS:__except_list
* MOV FS:__except_list,ESP
* CALL _d_monitor_prolog
*/
code *c1 = NULL;
code *c;
code cs;
Symbol *s;
regm_t desregs;
assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's
if (shandle->Sclass == SCfastpar)
{ assert(shandle->Spreg != DX);
c = gen1(NULL,0x50 + shandle->Spreg); // PUSH shandle
}
else
{
// PUSH shandle
#if 0
c = genc1(NULL,0xFF,modregrm(2,6,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize);
c->Isib = modregrm(0,4,SP);
#else
useregs(mCX);
c = genc1(NULL,0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize);
c->Isib = modregrm(0,4,SP);
gen1(c,0x50 + CX); // PUSH ECX
#endif
}
s = rtlsym[RTLSYM_MONITOR_HANDLER];
c = gencs(c,0x68,0,FLextern,s); // PUSH offset _d_monitor_handler
makeitextern(s);
#if 0
cs.Iop = 0xFF;
cs.Irm = modregrm(0,6,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
gen(c,&cs); // PUSH FS:__except_list
#else
useregs(mDX);
cs.Iop = 0x8B;
cs.Irm = modregrm(0,DX,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
c1 = gen(c1,&cs); // MOV EDX,FS:__except_list
gen1(c,0x50 + DX); // PUSH EDX
#endif
s = rtlsym[RTLSYM_MONITOR_PROLOG];
desregs = ~s->Sregsaved & ALLREGS;
c = cat(c,getregs(desregs));
c = gencs(c,0xE8,0,FLfunc,s); // CALL _d_monitor_prolog
cs.Iop = 0x89;
NEWREG(cs.Irm,SP);
gen(c,&cs); // MOV FS:__except_list,ESP
return cat(c1,c);
}
#endif
/*************************************************
* Release monitor, unhook monitor exception handler.
* Input:
* retregs registers to not destroy
*/
#if MARS
code *nteh_monitor_epilog(regm_t retregs)
{
/*
* CALL _d_monitor_epilog
* POP FS:__except_list
*/
code cs;
code *c;
code *cs1;
code *cs2;
code *cpop;
regm_t desregs;
Symbol *s;
assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's
s = rtlsym[RTLSYM_MONITOR_EPILOG];
//desregs = ~s->Sregsaved & ALLREGS;
desregs = 0;
gensaverestore(retregs & desregs,&cs1,&cs2);
c = getregs(desregs);
c = gencs(c,0xE8,0,FLfunc,s); // CALL __d_monitor_epilog
cs.Iop = 0x8F;
cs.Irm = modregrm(0,0,BPRM);
cs.Iflags = CFfs;
cs.Irex = 0;
cs.IFL1 = FLextern;
cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
cs.IEVoffset1 = 0;
cpop = gen(NULL,&cs); // POP FS:__except_list
c = cat4(cs1,c,cs2,cpop);
return c;
}
#endif
#endif

414
backend/oper.h Normal file
View File

@@ -0,0 +1,414 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if __SC__
#pragma once
#endif
#ifndef OPER_H
#define OPER_H 1
enum OPER
{
OPunde, /* place holder for undefined operator */
OPadd,
OPmin,
OPmul,
OPdiv,
OPmod,
OPshr, // unsigned right shift
OPshl,
OPand,
OPxor,
OPor,
OPashr, // signed right shift
OPnot,
OPbool, /* "booleanize" */
OPcom,
OPcond,
OPcomma,
OPoror,
OPandand,
OPbit, /* ref to bit field */
OPind, /* *E */
OPaddr, /* &E */
OPneg, /* unary - */
OPuadd, /* unary + */
#if TX86
OPvoid, // where casting to void is not a no-op
OPabs, /* absolute value */
OPsqrt, /* square root */
OPrndtol, // round to short, long, long long (inline 8087 only)
OPsin, // sine
OPcos, // cosine
OPrint, // round to int
OPscale, // ldexp
OPyl2x, // y * log2(x)
OPyl2xp1, // y * log2(x + 1)
OPstrlen, /* strlen() */
OPstrcpy, /* strcpy() */
OPstrcat, /* strcat() */
OPstrcmp, /* strcmp() */
OPmemcpy,
OPmemcmp,
OPmemset,
OPsetjmp, // setjmp()
#endif
OPremquo, // / and % in one operation
#if TX86
OPbsf, // bit scan forward
OPbsr, // bit scan reverse
OPbt, // bit test
OPbtc, // bit test and complement
OPbtr, // bit test and reset
OPbts, // bit test and set
OPbswap, // swap bytes
OProl, // rotate left
OPror, // rotate right
#endif
OPstreq, /* structure assignment */
OPnegass, // x = -x
OPpostinc, /* x++ */
OPpostdec, /* x-- */
OPeq,
OPaddass,
OPminass,
OPmulass,
OPdivass,
OPmodass,
OPshrass,
OPshlass,
OPandass,
OPxorass,
OPorass,
/* Convert from token to assignment operator */
#define asgtoktoop(tok) ((int) (tok) + ((int)OPeq - (int) TKeq))
OPashrass,
/* relational operators (in same order as corresponding tokens) */
#define RELOPMIN ((int)OPle)
OPle,
OPgt,
OPlt,
OPge,
OPeqeq,
OPne,
OPunord, /* !<>= */
OPlg, /* <> */
OPleg, /* <>= */
OPule, /* !> */
OPul, /* !>= */
OPuge, /* !< */
OPug, /* !<= */
OPue, /* !<> */
OPngt,
OPnge,
OPnlt,
OPnle,
OPord,
OPnlg,
OPnleg,
OPnule,
OPnul,
OPnuge,
OPnug,
OPnue,
#define rel_toktoop(tk) ((enum OPER)((int)tk - (int)TKle + (int)OPle))
/***************** End of relational operators ******************/
/* Convert from conversion operator to conversion index */
// parallel array invconvtab[] in cgelem.c)
#define CNVOPMIN (OPb_8)
#define CNVOPMAX (OPld_u64)
#define convidx(op) ((int)(op) - CNVOPMIN)
/* 8,16,32,64 integral type of unspecified sign
s,u signed/unsigned
f,d,ld float/double/long double
np,fp,vp,f16p near pointer/far pointer/handle pointer/far16 pointer
cvp const handle pointer
*/
OPb_8, // convert bit to byte
OPd_s32,
OPs32_d,
OPd_s16,
OPs16_d,
OPd_u16,
OPu16_d,
OPd_u32,
OPu32_d,
OPd_s64,
OPs64_d,
OPd_u64,
OPu64_d,
OPd_f,
OPf_d,
OPs16_32, // short to long
OPu16_32, // unsigned short to long
OP32_16, // long to short
OPu8_16, // unsigned char to short
OPs8_16, // signed char to short
OP16_8, // short to 8 bits
OPu32_64, // unsigned long to long long
OPs32_64, // long to long long
OP64_32, // long long to long
OPu64_128,
OPs64_128,
OP128_64,
#if TARGET_SEGMENTED
OPvp_fp,
OPcvp_fp, // const handle * => far *
OPoffset, // get offset of far pointer
OPnp_fp, // convert near pointer to far
OPnp_f16p, // from 0:32 to 16:16
OPf16p_np, // from 16:16 to 0:32
#endif
OPld_d,
OPd_ld,
OPld_u64,
/***************** End of conversion operators ******************/
OPc_r, // complex to real
OPc_i, // complex to imaginary
OPmsw, // top 32 bits of 64 bit word (32 bit code gen)
// top 16 bits of 32 bit word (16 bit code gen)
OPparam, /* function parameter separator */
OPcall, /* binary function call */
OPucall, /* unary function call */
OPcallns, // binary function call, no side effects
OPucallns, // unary function call, no side effects
OPsizeof, /* for forward-ref'd structs */
OPstrctor, /* call ctor on struct param */
OPstrthis, // 'this' pointer for OPstrctor
OPstrpar, /* structure func param */
OPconst, /* constant */
OPrelconst, /* constant that contains an address */
OPvar, /* variable */
OPreg, // register (used in inline asm operand expressions)
OPcolon, /* : as in ?: */
OPcolon2, // alternate version with different EH semantics
OPstring, /* address of string */
OPnullptr, // null pointer
OPasm, /* in-line assembly code */
OPinfo, // attach info (used to attach ctor/dtor
OPhalt, // insert HLT instruction
// info for exception handling)
OPctor,
OPdtor,
OPmark,
OPdctor, // D constructor
OPddtor, // D destructor
OPpair, // build register pair, E1 is lsb, E2 = msb
OPrpair, // build reversed register pair, E1 is msb, E2 = lsb
OPframeptr, // load pointer to base of frame
OPgot, // load pointer to global offset table
OPvector, // SIMD vector operations
// Jupiter operators
OParray, // access Jupiter array, left is handle, right is index
OParraylength, // evaluates array handle into array length
OPfield, // access Jupiter object field, left is handle, right is offset
OPnewarray, // allocate Jupiter array, left is dimension, right is type
OPmultinewarray, // allocate multidimensional Jupiter array
// left is dimensions, right is (numdims,type signature)
OPinstanceof, // left is class id, right is handle
OPfinalinstanceof, // left is class id, right is handle
OPcheckcast, // left is class id, right is handle
OPhstring, // handle to static string
OPnullcheck, // check if pointer is null
#if TX86
OPinp, /* input from I/O port */
OPoutp, /* output to I/O port */
#endif
/* C++ operators */
OPnew, // operator new
OPanew, // operator new[]
OPdelete, // operator delete
OPadelete, // operator delete[]
OPbrack, /* [] subscript */
OParrow, /* for -> overloading */
OParrowstar, /* for ->* overloading */
OPpreinc, /* ++x overloading */
OPpredec, /* --x overloading */
#ifdef TARGET_INLINEFUNC_OPS
TARGET_INLINEFUNC_OPS
#endif
OPMAX /* 1 past last operator */
};
typedef enum OPER OPER; /* needed for optabgen */
/************************************
* Determine things about relational operators.
*/
extern unsigned char rel_not[];
extern unsigned char rel_swap[];
extern unsigned char rel_integral[];
extern unsigned char rel_exception[];
extern unsigned char rel_unord[];
#define rel_not(op) rel_not[(int)(op) - RELOPMIN]
#define rel_swap(op) rel_swap[(int)(op) - RELOPMIN]
#define rel_integral(op) rel_integral[(int)(op) - RELOPMIN]
#define rel_exception(op) rel_exception[(int)(op) - RELOPMIN]
#define rel_unord(op) rel_unord[(int)(op) - RELOPMIN]
/**********************************
* Various types of operators:
* OTbinary binary
* OTunary unary
* OTleaf leaf
* OTcommut commutative (e1 op e2) == (e2 op e1)
* (assoc == !=)
* OTassoc associative (e1 op (e2 op e3)) == ((e1 op e2) op e3)
* (also commutative)
* OTassign assignment = op= i++ i-- i=-i str=
* OTpost post inc or post dec operator
* OTeop0e if (e op 0) => e
* OTeop00 if (e op 0) => 0
* OTeop1e if (e op 1) => e
* OTsideff there are side effects to the operator (assign call
* post ?: && ||)
* OTconv type conversion operator that could appear on lhs of
* assignment operator
* OTlogical logical operator (result is 0 or 1)
* OTwid high order bits of operation are irrelevant
* OTopeq an op= operator
* OTop an operator that has a corresponding op=
* OTcall function call
* OTrtol operators that evaluate right subtree first then left
* OTrel == != < <= > >= operators
* OTrel2 < <= > >= operators
* OTdef definition operator (assign call post asm)
* OTae potential common subexpression operator
* OTexp expression elem
* OTboolnop operation is a nop if boolean result is desired
*/
#if TX86
extern const unsigned char optab1[OPMAX],optab2[OPMAX],optab3[OPMAX];
extern const unsigned char opcost[OPMAX];
#else
extern unsigned char optab1[OPMAX],optab2[OPMAX];
#endif
/* optab1[] */ /* Use byte arrays to avoid index scaling */
#define _OTbinary 1
#define _OTunary 2
#define _OTcommut 4
#define _OTassoc 8
#define _OTsideff 0x10
#define _OTeop0e 0x20
#define _OTeop00 0x40
#define _OTeop1e 0x80
/* optab2[] */
#define _OTlogical 1
#define _OTwid 2
#define _OTcall 4
#define _OTrtol 8
#define _OTassign 0x10
#define _OTdef 0x20
#define _OTae 0x40
#define _OTexp 0x80
#if TX86
// optab3[]
#define _OTboolnop 1
#endif
#define OTbinary(op) (optab1[op]&_OTbinary)
#define OTunary(op) (optab1[op]&_OTunary)
#define OTleaf(op) (!(optab1[op]&(_OTunary|_OTbinary)))
#define OTcommut(op) (optab1[op]&_OTcommut)
#define OTassoc(op) (optab1[op]&_OTassoc)
#define OTassign(op) (optab2[op]&_OTassign)
#define OTpost(op) ((op) == OPpostinc || (op) == OPpostdec)
#define OTeop0e(op) (optab1[op]&_OTeop0e)
#define OTeop00(op) (optab1[op]&_OTeop00)
#define OTeop1e(op) (optab1[op]&_OTeop1e)
#define OTsideff(op) (optab1[op]&_OTsideff)
#define OTconv(op) ((op) >= CNVOPMIN && (op) <= CNVOPMAX)
#define OTlogical(op) (optab2[op]&_OTlogical)
#define OTwid(op) (optab2[op]&_OTwid)
#define OTopeq(op) ((op) >= OPaddass && (op) <= OPashrass)
#define OTop(op) ((op) >= OPadd && (op) <= OPor)
#define OTcall(op) (optab2[op]&_OTcall)
#define OTrtol(op) (optab2[op]&_OTrtol)
#define OTrel(op) ((op) >= OPle && (op) <= OPnue)
#define OTrel2(op) ((op) >= OPle && (op) <= OPge)
#define OTdef(op) (optab2[op]&_OTdef)
#define OTae(op) (optab2[op]&_OTae)
#define OTexp(op) (optab2[op]&_OTexp)
#if TX86
#define OTboolnop(op) (optab3[op]&_OTboolnop)
#define OTcalldef(op) (OTcall(op) || (op) == OPstrcpy || (op) == OPstrcat || (op) == OPmemcpy)
#else
#define OTcalldef(op) (OTcall(op))
#endif
/* Convert op= to op */
#define opeqtoop(opx) ((opx) - OPaddass + OPadd)
/* Convert op to op= */
#define optoopeq(opx) ((opx) - OPadd + OPaddass)
/***************************
* Determine properties of an elem.
* EBIN binary node?
* EUNA unary node?
* EOP operator node (unary or binary)?
* ERTOL right to left evaluation (left to right is default)
* Eunambig unambiguous definition elem?
*/
#define EBIN(e) (OTbinary((e)->Eoper))
#define EUNA(e) (OTunary((e)->Eoper))
/* ERTOL(e) is moved to el.c */
#if KEEPBITFIELDS
#define Elvalue(e) (((e)->E1->Eoper == OPbit) ? (e)->E1->E1 : (e)->E1)
#define Eunambig(e) (OTassign((e)->Eoper) && \
((e)->E1->Eoper == OPvar || \
((e)->E1->Eoper == OPbit && \
(e)->E1->E1->Eoper == OPvar)))
#else
#define Elvalue(e) ((e)->E1)
#define Eunambig(e) (OTassign((e)->Eoper) && \
(e)->E1->Eoper == OPvar)
#endif
#define EOP(e) (!OTleaf((e)->Eoper))
#endif /* OPER_H */

1131
backend/optabgen.c Normal file

File diff suppressed because it is too large Load Diff

953
backend/os.c Normal file
View File

@@ -0,0 +1,953 @@
// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/*
* Operating system specific routines.
* Placed here to avoid cluttering
* up code with OS .h files.
*/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#if DOS386
#include <dos.h>
#include <sys\stat.h>
#endif
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#define GetLastError() errno
#elif _WIN32
#include <dos.h>
#include <sys\stat.h>
#include <windows.h>
#endif
#if __DMC__ || __GNUC__
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
#else
#include <assert.h>
#endif
#if _WINDLL
extern void dll_printf(const char *format,...);
#define dbg_printf dll_printf
#else
#define dbg_printf printf
#endif
int file_createdirs(char *name);
/***********************************
* Called when there is an error returned by the operating system.
* This function does not return.
*/
void os_error(int line)
{
#if _WIN32
dbg_printf("System error: %ldL\n",GetLastError());
#endif
local_assert(line);
}
#if 1
#undef dbg_printf
#define dbg_printf (void)
#endif
#define os_error() os_error(__LINE__)
#pragma noreturn(os_error)
#if _WIN32
/*********************************
* Allocate a chunk of memory from the operating system.
* Bypass malloc and friends.
*/
static HANDLE hHeap;
void *globalrealloc(void *oldp,size_t newsize)
{
#if 0
void *p;
// Initialize heap
if (!hHeap)
{ hHeap = HeapCreate(0,0x10000,0);
if (!hHeap)
os_error();
}
newsize = (newsize + 3) & ~3L; // round up to dwords
if (newsize == 0)
{
if (oldp && HeapFree(hHeap,0,oldp) == FALSE)
os_error();
p = NULL;
}
else if (!oldp)
{
p = newsize ? HeapAlloc(hHeap,0,newsize) : NULL;
}
else
p = HeapReAlloc(hHeap,0,oldp,newsize);
#elif 1
MEMORY_BASIC_INFORMATION query;
void *p;
BOOL bSuccess;
if (!oldp)
p = VirtualAlloc (NULL, newsize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
else
{
VirtualQuery (oldp, &query, sizeof(query));
if (!newsize)
{
p = NULL;
goto L1;
}
else
{ newsize = (newsize + 0xFFFF) & ~0xFFFFL;
if (query.RegionSize >= newsize)
p = oldp;
else
{ p = VirtualAlloc(NULL,newsize,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
if (p)
memcpy(p,oldp,query.RegionSize);
L1:
bSuccess = VirtualFree(oldp,query.RegionSize,MEM_DECOMMIT);
if (bSuccess)
bSuccess = VirtualFree(oldp,0,MEM_RELEASE);
if (!bSuccess)
os_error();
}
}
}
#else
void *p;
if (!oldp)
p = (void *)GlobalAlloc (0, newsize);
else if (!newsize)
{ GlobalFree(oldp);
p = NULL;
}
else
p = (void *)GlobalReAlloc(oldp,newsize,0);
#endif
dbg_printf("globalrealloc(oldp = %p, size = x%x) = %p\n",oldp,newsize,p);
return p;
}
/*****************************************
* Functions to manage allocating a single virtual address space.
*/
void *vmem_reserve(void *ptr,unsigned long size)
{ void *p;
#if 1
p = VirtualAlloc(ptr,size,MEM_RESERVE,PAGE_READWRITE);
dbg_printf("vmem_reserve(ptr = %p, size = x%lx) = %p\n",ptr,size,p);
#else
dbg_printf("vmem_reserve(ptr = %p, size = x%lx) = %p\n",ptr,size,p);
p = VirtualAlloc(ptr,size,MEM_RESERVE,PAGE_READWRITE);
if (!p)
os_error();
#endif
return p;
}
/*****************************************
* Commit memory.
* Returns:
* 0 failure
* !=0 success
*/
int vmem_commit(void *ptr, unsigned long size)
{ int i;
dbg_printf("vmem_commit(ptr = %p,size = x%lx)\n",ptr,size);
i = (int) VirtualAlloc(ptr,size,MEM_COMMIT,PAGE_READWRITE);
if (i == 0)
dbg_printf("failed to commit\n");
return i;
}
void vmem_decommit(void *ptr,unsigned long size)
{
dbg_printf("vmem_decommit(ptr = %p, size = x%lx)\n",ptr,size);
if (ptr)
{ if (!VirtualFree(ptr, size, MEM_DECOMMIT))
os_error();
}
}
void vmem_release(void *ptr,unsigned long size)
{
dbg_printf("vmem_release(ptr = %p, size = x%lx)\n",ptr,size);
if (ptr)
{
if (!VirtualFree(ptr, 0, MEM_RELEASE))
os_error();
}
}
/********************************************
* Map file for read, copy on write, into virtual address space.
* Input:
* ptr address to map file to, if NULL then pick an address
* size length of the file
* flag 0 read / write
* 1 read / copy on write
* 2 read only
* Returns:
* NULL failure
* ptr pointer to start of mapped file
*/
static HANDLE hFile = INVALID_HANDLE_VALUE;
static HANDLE hFileMap = NULL;
static void *pview;
static void *preserve;
static size_t preserve_size;
void *vmem_mapfile(const char *filename,void *ptr,unsigned long size,int flag)
{
OSVERSIONINFO OsVerInfo;
OsVerInfo.dwOSVersionInfoSize = sizeof(OsVerInfo);
GetVersionEx(&OsVerInfo);
dbg_printf("vmem_mapfile(filename = '%s', ptr = %p, size = x%lx, flag = %d)\n",filename,ptr,size,flag);
hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto L1; // failure
dbg_printf(" file created\n");
// Windows 95 does not implement PAGE_WRITECOPY (unfortunately treating
// it just like PAGE_READWRITE).
if (flag == 1 && OsVerInfo.dwPlatformId == 1) // Windows 95, 98, ME
hFileMap = NULL;
else
hFileMap = CreateFileMapping(hFile,NULL,
(flag == 1) ? PAGE_WRITECOPY : PAGE_READWRITE,0,size,NULL);
if (hFileMap == NULL) // mapping failed
{
#if 1
// Win32s seems to always fail here.
DWORD nbytes;
dbg_printf(" mapping failed\n");
// If it was NT failing, assert.
assert(OsVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT);
// To work around, just read the file into memory.
assert(flag == 1);
preserve = vmem_reserve(ptr,size);
if (!preserve)
goto L2;
if (!vmem_commit(preserve,size))
{
vmem_release(preserve,size);
preserve = NULL;
goto L2;
}
preserve_size = size;
if (!ReadFile(hFile,preserve,size,&nbytes,NULL))
os_error();
assert(nbytes == size);
if (CloseHandle(hFile) != TRUE)
os_error();
hFile = INVALID_HANDLE_VALUE;
return preserve;
#else
// Instead of working around, we should find out why it failed.
os_error();
#endif
}
else
{
dbg_printf(" mapping created\n");
pview = MapViewOfFileEx(hFileMap,flag ? FILE_MAP_COPY : FILE_MAP_WRITE,
0,0,size,ptr);
if (pview == NULL) // mapping view failed
{ //os_error();
goto L3;
}
}
dbg_printf(" pview = %p\n",pview);
return pview;
Terminate:
if (UnmapViewOfFile(pview) == FALSE)
os_error();
pview = NULL;
L3:
if (CloseHandle(hFileMap) != TRUE)
os_error();
hFileMap = NULL;
L2:
if (CloseHandle(hFile) != TRUE)
os_error();
hFile = INVALID_HANDLE_VALUE;
L1:
return NULL; // failure
}
/*****************************
* Set size of mapped file.
*/
void vmem_setfilesize(unsigned long size)
{
if (hFile != INVALID_HANDLE_VALUE)
{ if (SetFilePointer(hFile,size,NULL,FILE_BEGIN) == 0xFFFFFFFF)
os_error();
if (SetEndOfFile(hFile) == FALSE)
os_error();
}
}
/*****************************
* Unmap previous file mapping.
*/
void vmem_unmapfile()
{
dbg_printf("vmem_unmapfile()\n");
vmem_decommit(preserve,preserve_size);
vmem_release(preserve,preserve_size);
preserve = NULL;
preserve_size = 0;
#if 0
if (pview)
{ int i;
i = UnmapViewOfFile(pview);
dbg_printf("i = x%x\n",i);
if (i == FALSE)
os_error();
}
#else
// Note that under Windows 95, UnmapViewOfFile() seems to return random
// values, not TRUE or FALSE.
if (pview && UnmapViewOfFile(pview) == FALSE)
os_error();
#endif
pview = NULL;
if (hFileMap != NULL && CloseHandle(hFileMap) != TRUE)
os_error();
hFileMap = NULL;
if (hFile != INVALID_HANDLE_VALUE && CloseHandle(hFile) != TRUE)
os_error();
hFile = INVALID_HANDLE_VALUE;
}
/****************************************
* Determine a base address that we can use for mapping files to.
*/
void *vmem_baseaddr()
{
OSVERSIONINFO OsVerInfo;
void *p;
OsVerInfo.dwOSVersionInfoSize = sizeof(OsVerInfo);
GetVersionEx(&OsVerInfo);
// These values for the address were determined by trial and error.
switch (OsVerInfo.dwPlatformId)
{
case VER_PLATFORM_WIN32s: // Win32s
// The fact that this is a different address than other
// WIN32 implementations causes us a lot of grief.
p = (void *) 0xC0000000;
break;
case 1: //VER_PLATFORM_WIN32_WINDOWS: // Windows 95
// I've found 0x90000000..0xB work. All others fail.
default: // unknown
p = (void *) 0x90000000;
break;
case VER_PLATFORM_WIN32_NT: // Windows NT
// Pick a value that is not coincident with the base address
// of any commonly used system DLLs.
p = (void *) 0x38000000;
break;
}
return p;
}
/********************************************
* Calculate the amount of memory to reserve, adjusting
* *psize downwards.
*/
void vmem_reservesize(unsigned long *psize)
{
MEMORYSTATUS ms;
OSVERSIONINFO OsVerInfo;
unsigned long size;
ms.dwLength = sizeof(ms);
GlobalMemoryStatus(&ms);
dbg_printf("dwMemoryLoad x%lx\n",ms.dwMemoryLoad);
dbg_printf("dwTotalPhys x%lx\n",ms.dwTotalPhys);
dbg_printf("dwAvailPhys x%lx\n",ms.dwAvailPhys);
dbg_printf("dwTotalPageFile x%lx\n",ms.dwTotalPageFile);
dbg_printf("dwAvailPageFile x%lx\n",ms.dwAvailPageFile);
dbg_printf("dwTotalVirtual x%lx\n",ms.dwTotalVirtual);
dbg_printf("dwAvailVirtual x%lx\n",ms.dwAvailVirtual);
OsVerInfo.dwOSVersionInfoSize = sizeof(OsVerInfo);
GetVersionEx(&OsVerInfo);
switch (OsVerInfo.dwPlatformId)
{
case VER_PLATFORM_WIN32s: // Win32s
case 1: //VER_PLATFORM_WIN32_WINDOWS: // Windows 95
default: // unknown
size = (ms.dwAvailPageFile < ms.dwAvailVirtual)
? ms.dwAvailPageFile
: ms.dwAvailVirtual;
size = (unsigned long long)size * 8 / 10;
size &= ~0xFFFFL;
if (size < *psize)
*psize = size;
break;
case VER_PLATFORM_WIN32_NT: // Windows NT
// NT can expand the paging file
break;
}
}
/********************************************
* Return amount of physical memory.
*/
unsigned long vmem_physmem()
{
MEMORYSTATUS ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatus(&ms);
return ms.dwTotalPhys;
}
//////////////////////////////////////////////////////////////
/***************************************************
* Load library.
*/
static HINSTANCE hdll;
void os_loadlibrary(const char *dllname)
{
hdll = LoadLibrary((LPCTSTR) dllname);
if (!hdll)
os_error();
}
/*************************************************
*/
void os_freelibrary()
{
if (hdll)
{
if (FreeLibrary(hdll) != TRUE)
os_error();
hdll = NULL;
}
}
/*************************************************
*/
void *os_getprocaddress(const char *funcname)
{ void *fp;
//printf("getprocaddress('%s')\n",funcname);
assert(hdll);
fp = (void *)GetProcAddress(hdll,(LPCSTR)funcname);
if (!fp)
os_error();
return fp;
}
//////////////////////////////////////////////////////////////
/*********************************
*/
void os_term()
{
if (hHeap)
{ if (HeapDestroy(hHeap) == FALSE)
{ hHeap = NULL;
os_error();
}
hHeap = NULL;
}
os_freelibrary();
}
/***************************************************
* Do our own storage allocator (being suspicious of the library one).
*/
#if 1
void os_heapinit() { }
void os_heapterm() { }
#else
static HANDLE hHeap;
void os_heapinit()
{
hHeap = HeapCreate(0,0x10000,0);
if (!hHeap)
os_error();
}
void os_heapterm()
{
if (hHeap)
{ if (HeapDestroy(hHeap) == FALSE)
os_error();
}
}
void * __cdecl calloc(size_t x,size_t y)
{ size_t size;
size = x * y;
return size ? HeapAlloc(hHeap,HEAP_ZERO_MEMORY,size) : NULL;
}
void __cdecl free(void *p)
{
if (p && HeapFree(hHeap,0,p) == FALSE)
os_error();
}
void * __cdecl malloc(size_t size)
{
return size ? HeapAlloc(hHeap,0,size) : NULL;
}
void * __cdecl realloc(void *p,size_t newsize)
{
if (newsize == 0)
free(p);
else if (!p)
p = malloc(newsize);
else
p = HeapReAlloc(hHeap,0,p,newsize);
return p;
}
#endif
//////////////////////////////////////////
// Return a value that will hopefully be unique every time
// we call it.
unsigned long os_unique()
{
unsigned long long x;
QueryPerformanceCounter((LARGE_INTEGER *)&x);
return x;
}
#elif DOS386
//////////////////////////////////////////
// Return a value that will hopefully be unique every time
// we call it.
unsigned long os_unique()
{
if (cputype() >= 5) // if cpuid instruction supported
{
__asm
{
mov EAX,1
cpuid
test EDX,0x20 // is rdtsc supported?
jz L1 // no
rdtsc
}
}
else
{
L1: time(NULL);
}
return _EAX;
}
#endif
/*******************************************
* Return !=0 if file exists.
* 0: file doesn't exist
* 1: normal file
* 2: directory
*/
int os_file_exists(const char *name)
{
#if _WIN32
DWORD dw;
int result;
dw = GetFileAttributes(name);
if (dw == -1L)
result = 0;
else if (dw & FILE_ATTRIBUTE_DIRECTORY)
result = 2;
else
result = 1;
return result;
#elif DOS386
struct FIND *find;
find = findfirst(name,FA_DIREC | FA_SYSTEM | FA_HIDDEN);
if (!find)
return 0;
return (find->attribute & FA_DIREC) ? 2 : 1;
#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
struct stat buf;
return stat(name,&buf) == 0; /* file exists if stat succeeded */
#else
return filesize(name) != -1L;
#endif
}
/**************************************
* Get file size of open file. Return -1L on error.
*/
#if _WIN32
extern "C" void * __cdecl _osfhnd[];
#endif
long os_file_size(int fd)
{
#if _WIN32
return GetFileSize(_osfhnd[fd],NULL);
#else
struct stat buf;
return (fstat(fd,&buf)) ? -1L : buf.st_size;
#endif
}
/**************************************************
* For 16 bit programs, we need the 16 bit filename.
* Returns:
* malloc'd string, NULL if none
*/
#if _WIN32
char *file_8dot3name(const char *filename)
{
HANDLE h;
WIN32_FIND_DATA fileinfo;
char *buf;
int i;
h = FindFirstFile(filename,&fileinfo);
if (h == INVALID_HANDLE_VALUE)
return NULL;
if (fileinfo.cAlternateFileName[0])
{
for (i = strlen(filename); i > 0; i--)
if (filename[i] == '\\' || filename[i] == ':')
{ i++;
break;
}
buf = (char *) malloc(i + 14);
if (buf)
{
memcpy(buf,filename,i);
strcpy(buf + i,fileinfo.cAlternateFileName);
}
}
else
buf = strdup(filename);
FindClose(h);
return buf;
}
#endif
/**********************************************
* Write a file.
* Returns:
* 0 success
*/
int file_write(char *name, void *buffer, unsigned len)
{
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
int fd;
ssize_t numwritten;
fd = open(name, O_CREAT | O_WRONLY | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (fd == -1)
goto err;
numwritten = ::write(fd, buffer, len);
if (len != numwritten)
goto err2;
if (close(fd) == -1)
goto err;
return 0;
err2:
close(fd);
err:
return 1;
#endif
#if _WIN32
HANDLE h;
DWORD numwritten;
h = CreateFile((LPTSTR)name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (h == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_PATH_NOT_FOUND)
{
if (!file_createdirs(name))
{
h = CreateFile((LPTSTR)name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (h != INVALID_HANDLE_VALUE)
goto Lok;
}
}
goto err;
}
Lok:
if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
goto err2;
if (len != numwritten)
goto err2;
if (!CloseHandle(h))
goto err;
return 0;
err2:
CloseHandle(h);
err:
return 1;
#endif
#if _MSDOS
return 1;
#endif
}
/********************************
* Create directories up to filename.
* Input:
* name path/filename
* Returns:
* 0 success
* !=0 failure
*/
int file_createdirs(char *name)
{
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
return 1;
#endif
#if _WIN32
int len = strlen(name);
char *path = (char *)alloca(len + 1);
char *p;
memcpy(path, name, len + 1);
for (p = path + len; ; p--)
{
if (p == path)
goto Lfail;
switch (*p)
{
case ':':
case '/':
case '\\':
*p = 0;
if (!CreateDirectory((LPTSTR)path, NULL))
{ // Failed
if (file_createdirs(path))
goto Lfail;
if (!CreateDirectory((LPTSTR)path, NULL))
goto Lfail;
}
return 0;
}
}
Lfail:
return 1;
#endif
#if _MSDOS
return 1;
#endif
}
/***********************************
* Return size of OS critical section.
* NOTE: can't use the sizeof() calls directly since cross compiling is
* supported and would end up using the host sizes rather than the target
* sizes.
*/
#if _WIN32
int os_critsecsize32()
{
return sizeof(CRITICAL_SECTION);
}
int os_critsecsize64()
{
assert(0);
return 0;
}
#endif
#if linux
int os_critsecsize32()
{
return 24; // sizeof(pthread_mutex_t) on 32 bit
}
int os_critsecsize64()
{
return 40; // sizeof(pthread_mutex_t) on 64 bit
}
#endif
#if __FreeBSD__
int os_critsecsize32()
{
return 4; // sizeof(pthread_mutex_t) on 32 bit
}
int os_critsecsize64()
{
return 8; // sizeof(pthread_mutex_t) on 64 bit
}
#endif
#if __OpenBSD__
int os_critsecsize32()
{
return 4; // sizeof(pthread_mutex_t) on 32 bit
}
int os_critsecsize64()
{
assert(0);
return 8; // sizeof(pthread_mutex_t) on 64 bit
}
#endif
#if __APPLE__
int os_critsecsize32()
{
#if __LP64__ // check for bit rot
assert(sizeof(pthread_mutex_t) == 64);
#else
assert(sizeof(pthread_mutex_t) == 44);
#endif
return 44;
}
int os_critsecsize64()
{
return 64;
}
#endif
#if __sun&&__SVR4
int os_critsecsize32()
{
return sizeof(pthread_mutex_t);
}
int os_critsecsize64()
{
assert(0);
return 0;
}
#endif
/* This is the magic program to get the size on Posix systems: */
#if 0
#include <stdio.h>
#include <pthread.h>
int main()
{
printf("%d\n", (int)sizeof(pthread_mutex_t));
return 0;
}
#endif

1534
backend/out.c Normal file

File diff suppressed because it is too large Load Diff

298
backend/outbuf.c Normal file
View File

@@ -0,0 +1,298 @@
// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
// Output buffer
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "cc.h"
#include "outbuf.h"
#include "mem.h"
#if DEBUG
static char __file__[] = __FILE__; // for tassert.h
#include "tassert.h"
#endif
Outbuffer::Outbuffer()
{
buf = NULL;
pend = NULL;
p = NULL;
len = 0;
inc = 0;
}
Outbuffer::Outbuffer(unsigned bufinc)
{
buf = NULL;
pend = NULL;
p = NULL;
len = 0;
inc = bufinc;
}
Outbuffer::~Outbuffer()
{
#if MEM_DEBUG
mem_free(buf);
#else
if (buf)
free(buf);
#endif
}
void Outbuffer::reset()
{
p = buf;
}
// Reserve nbytes in buffer
void Outbuffer::reserve(unsigned nbytes)
{
if (pend - p < nbytes)
{ unsigned oldlen = len;
unsigned used = p - buf;
if (inc > nbytes)
{
len = used + inc;
}
else
{
len = used + nbytes;
if (len < 2 * oldlen)
{ len = 2 * oldlen;
if (len < 8)
len = 8;
}
}
#if MEM_DEBUG
buf = (unsigned char *)mem_realloc(buf, len);
#else
if (buf)
buf = (unsigned char *) realloc(buf,len);
else
buf = (unsigned char *) malloc(len);
#endif
if (!buf)
{
fprintf(stderr, "Fatal Error: Out of memory");
exit(EXIT_FAILURE);
}
pend = buf + len;
p = buf + used;
}
}
// Position buffer for output at a specified location and size.
// If data will extend buffer size, reserve space
// If data will rewrite existing data
// position for write and return previous buffer size
//
// If data will append to buffer
// position for write and return new size
int Outbuffer::position(unsigned pos, unsigned nbytes)
{
int current_sz = size();
unsigned char *fend = buf+pos+nbytes; // future end of buffer
if (fend >= pend)
{
reserve (fend - pend);
}
setsize(pos);
return pos+nbytes > current_sz ? pos+nbytes : current_sz;
}
// Write an array to the buffer.
void Outbuffer::write(const void *b, int len)
{
if (pend - p < len)
reserve(len);
memcpy(p,b,len);
p += len;
}
// Write n zeros to the buffer.
void *Outbuffer::writezeros(unsigned len)
{
if (pend - p < len)
reserve(len);
void *pstart = memset(p,0,len);
p += len;
return pstart;
}
/**
* Writes an 8 bit byte.
*/
void Outbuffer::writeByte(int v)
{
if (pend == p)
reserve(1);
*p++ = v;
}
/**
* Writes a 32 bit int.
*/
void Outbuffer::write32(int v)
{
if (pend - p < 4)
reserve(4);
*(int *)p = v;
p += 4;
}
/**
* Writes a 64 bit long.
*/
#if __INTSIZE == 4
void Outbuffer::write64(long long v)
{
if (pend - p < 8)
reserve(8);
*(long long *)p = v;
p += 8;
}
#endif
/**
* Writes a 32 bit float.
*/
void Outbuffer::writeFloat(float v)
{
if (pend - p < sizeof(float))
reserve(sizeof(float));
*(float *)p = v;
p += sizeof(float);
}
/**
* Writes a 64 bit double.
*/
void Outbuffer::writeDouble(double v)
{
if (pend - p < sizeof(double))
reserve(sizeof(double));
*(double *)p = v;
p += sizeof(double);
}
/**
* Writes a String as a sequence of bytes.
*/
void Outbuffer::write(const char *s)
{
write(s,strlen(s));
}
/**
* Writes a String as a sequence of bytes.
*/
void Outbuffer::write(const unsigned char *s)
{
write(s,strlen((const char *)s));
}
/**
* Writes a NULL terminated String
*/
void Outbuffer::writeString(const char *s)
{
write(s,strlen(s)+1);
}
/**
* Inserts string at beginning of buffer.
*/
void Outbuffer::prependBytes(const char *s)
{
size_t len = strlen(s);
reserve(len);
memmove(buf + len,buf,p - buf);
memcpy(buf,s,len);
p += len;
}
/**
*/
void Outbuffer::bracket(char c1,char c2)
{
reserve(2);
memmove(buf + 1,buf,p - buf);
buf[0] = c1;
p[1] = c2;
p += 2;
}
/**
* Convert to a string.
*/
char *Outbuffer::toString()
{
if (pend == p)
reserve(1);
*p = 0; // terminate string
return (char *)buf;
}
/**
* Set current size of buffer.
*/
void Outbuffer::setsize(unsigned size)
{
p = buf + size;
}
void Outbuffer::writesLEB128(int value)
{
while (1)
{
unsigned char b = value & 0x7F;
value >>= 7; // arithmetic right shift
if (value == 0 && !(b & 0x40) ||
value == -1 && (b & 0x40))
{
writeByte(b);
break;
}
writeByte(b | 0x80);
}
}
void Outbuffer::writeuLEB128(unsigned value)
{
do
{ unsigned char b = value & 0x7F;
value >>= 7;
if (value)
b |= 0x80;
writeByte(b);
} while (value);
}

179
backend/outbuf.h Normal file
View File

@@ -0,0 +1,179 @@
// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
//#pragma once
#include <string.h>
// Output buffer
// (This used to be called OutBuffer, we renamed it to avoid name conflicts with Mars.)
struct Outbuffer
{
unsigned char *buf; // the buffer itself
unsigned char *pend; // pointer past the end of the buffer
unsigned char *p; // current position in buffer
unsigned len; // size of buffer
unsigned inc; // default increment size
Outbuffer();
Outbuffer(unsigned inc);
~Outbuffer();
void reset();
// Reserve nbytes in buffer
void reserve(unsigned nbytes);
// Write n zeros; return pointer to start of zeros
void *writezeros(unsigned n);
// Position buffer to accept the specified number of bytes at offset
int position(unsigned offset, unsigned nbytes);
// Write an array to the buffer, no reserve check
void writen(const void *b, int len)
{
memcpy(p,b,len);
p += len;
}
// Clear bytes, no reserve check
void clearn(int len)
{
int i;
for (i=0; i< len; i++)
*p++ = 0;
}
// Write an array to the buffer.
void write(const void *b, int len);
void write(Outbuffer *b) { write(b->buf,b->p - b->buf); }
/**
* Flushes the stream. This will write any buffered
* output bytes.
*/
void flush() { }
/**
* Writes an 8 bit byte, no reserve check.
*/
void writeByten(char v)
{
*p++ = v;
}
/**
* Writes an 8 bit byte.
*/
void writeByte(int v);
/**
* Writes a 16 bit little-end short, no reserve check.
*/
void writeWordn(int v)
{
#if _WIN32
*(unsigned short *)p = v;
#else
p[0] = v;
p[1] = v >> 8;
#endif
p += 2;
}
/**
* Writes a 16 bit little-end short.
*/
void writeWord(int v)
{
reserve(2);
writeWordn(v);
}
/**
* Writes a 16 bit big-end short.
*/
void writeShort(int v)
{
if (pend - p < 2)
reserve(2);
#if 0
p[0] = ((unsigned char *)&v)[1];
p[1] = v;
#else
unsigned char *q = p;
q[0] = v >> 8;
q[1] = v;
#endif
p += 2;
}
/**
* Writes a 16 bit char.
*/
void writeChar(int v)
{
writeShort(v);
}
/**
* Writes a 32 bit int.
*/
void write32(int v);
/**
* Writes a 64 bit long.
*/
#if __INTSIZE == 4
void write64(long long v);
#endif
/**
* Writes a 32 bit float.
*/
void writeFloat(float v);
/**
* Writes a 64 bit double.
*/
void writeDouble(double v);
void write(const char *s);
void write(const unsigned char *s);
void writeString(const char *s);
void prependBytes(const char *s);
void bracket(char c1,char c2);
/**
* Returns the number of bytes written.
*/
int size()
{
return p - buf;
}
char *toString();
void setsize(unsigned size);
void writesLEB128(int value);
void writeuLEB128(unsigned value);
};

5736
backend/ptrntab.c Normal file

File diff suppressed because it is too large Load Diff

125
backend/rtlsym.c Normal file
View File

@@ -0,0 +1,125 @@
// Copyright (C) 1996-1998 by Symantec
// Copyright (C) 2000-2010 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "cc.h"
#include "type.h"
#include "oper.h"
#include "global.h"
#include "code.h"
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
Symbol *rtlsym[RTLSYM_MAX];
#if MARS
// This varies depending on C ABI
#define FREGSAVED fregsaved
#else
#define FREGSAVED (mBP | mBX | mSI | mDI)
#endif
static Symbol rtlsym2[RTLSYM_MAX];
/******************************************
* Initialize rtl symbols.
*/
void rtlsym_init()
{
static int inited;
if (!inited)
{ inited++;
//printf("rtlsym_init(%s)\n", regm_str(FREGSAVED));
for (int i = 0; i < RTLSYM_MAX; i++)
{
rtlsym[i] = &rtlsym2[i];
#ifdef DEBUG
rtlsym[i]->id = IDsymbol;
#endif
rtlsym[i]->Stype = tsclib;
rtlsym[i]->Ssymnum = -1;
rtlsym[i]->Sclass = SCextern;
rtlsym[i]->Sfl = FLfunc;
#if ELFOBJ || MACHOBJ
rtlsym[i]->obj_si = (unsigned)-1;
rtlsym[i]->dwarf_off = (unsigned)-1;
#endif
rtlsym[i]->Sregsaved = FREGSAVED;
}
#if MARS
type *t = type_fake(TYnfunc);
t->Tmangle = mTYman_c;
t->Tcount++;
// Variadic function
type *tv = type_fake(TYnfunc);
tv->Tmangle = mTYman_c;
tv->Tcount++;
#endif
#if MACHOBJ
type *tw = type_fake(TYnpfunc);
tw->Tmangle = mTYman_sys;
tw->Tcount++;
#else
type *tw = NULL;
#endif
#undef SYMBOL_Z
#define SYMBOL_Z(e, fl, saved, n, flags, ty) \
if (ty) rtlsym[RTLSYM_##e]->Stype = (ty); \
if ((fl) != FLfunc) rtlsym[RTLSYM_##e]->Sfl = (fl); \
if (flags) rtlsym[RTLSYM_##e]->Sflags = (flags); \
if ((saved) != FREGSAVED) rtlsym[RTLSYM_##e]->Sregsaved = (saved); \
strcpy(rtlsym[RTLSYM_##e]->Sident, (n)); \
RTLSYMS
}
}
/*******************************
* Reset the symbols for the case when we are generating multiple
* .OBJ files from one compile.
*/
#if MARS
void rtlsym_reset()
{ int i;
clib_inited = 0;
for (i = 0; i < RTLSYM_MAX; i++)
{ rtlsym[i]->Sxtrnnum = 0;
rtlsym[i]->Stypidx = 0;
}
}
#endif
/*******************************
*/
void rtlsym_term()
{
}
#endif

155
backend/rtlsym.h Normal file
View File

@@ -0,0 +1,155 @@
// Copyright (C) 1994-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/*
ty
------------------------------------
0 tsclib TYnpfunc, C mangling
t TYnfunc, C mangling
tsjlib TYjfunc, C mangling
tsdlib TYjfunc, C mangling
*/
#if SCPP
#define SYMBOL_SCPP(e, fl, saved, n, flags, ty) SYMBOL_Z(e,fl,saved,n,flags,ty)
#else
#define SYMBOL_SCPP(e, fl, saved, n, flags, ty)
#endif
#if SCPP && TX86
#define SYMBOL_SCPP_TX86(e, fl, saved, n, flags, ty) SYMBOL_Z(e,fl,saved,n,flags,ty)
#else
#define SYMBOL_SCPP_TX86(e, fl, saved, n, flags, ty)
#endif
#if MARS
#define SYMBOL_MARS(e, fl, saved, n, flags, ty) SYMBOL_Z(e,fl,saved,n,flags,ty)
#else
#define SYMBOL_MARS(e, fl, saved, n, flags, ty)
#endif
#define RTLSYMS \
\
SYMBOL_MARS(THROW, FLfunc,(mES | mBP),"_d_throw@4", SFLexit, tw) \
SYMBOL_MARS(THROWC, FLfunc,(mES | mBP),"_d_throwc", SFLexit, t) \
SYMBOL_MARS(MONITOR_HANDLER, FLfunc,FREGSAVED,"_d_monitor_handler", 0, 0) \
SYMBOL_MARS(MONITOR_PROLOG, FLfunc,FREGSAVED,"_d_monitor_prolog",0,t) \
SYMBOL_MARS(MONITOR_EPILOG, FLfunc,FREGSAVED,"_d_monitor_epilog",0,t) \
SYMBOL_MARS(DCOVER, FLfunc,FREGSAVED,"_d_cover_register", 0, t) \
SYMBOL_MARS(DASSERT, FLfunc,FREGSAVED,"_d_assert", SFLexit, t) \
SYMBOL_MARS(DASSERTM, FLfunc,FREGSAVED,"_d_assertm", SFLexit, t) \
SYMBOL_MARS(DASSERT_MSG, FLfunc,FREGSAVED,"_d_assert_msg", SFLexit, t) \
SYMBOL_MARS(DUNITTEST, FLfunc,FREGSAVED,"_d_unittest", 0, t) \
SYMBOL_MARS(DUNITTESTM, FLfunc,FREGSAVED,"_d_unittestm", 0, t) \
SYMBOL_MARS(DUNITTEST_MSG, FLfunc,FREGSAVED,"_d_unittest_msg", 0, t) \
SYMBOL_MARS(DARRAY, FLfunc,FREGSAVED,"_d_array_bounds", SFLexit, t) \
SYMBOL_MARS(DINVARIANT, FLfunc,FREGSAVED,"D9invariant12_d_invariantFC6ObjectZv", 0, tsdlib) \
SYMBOL_MARS(_DINVARIANT, FLfunc,FREGSAVED,"_D9invariant12_d_invariantFC6ObjectZv", 0, tsdlib) \
SYMBOL_MARS(MEMCPY, FLfunc,FREGSAVED,"memcpy", 0, t) \
SYMBOL_MARS(MEMSET8, FLfunc,FREGSAVED,"memset", 0, t) \
SYMBOL_MARS(MEMSET16, FLfunc,FREGSAVED,"_memset16", 0, t) \
SYMBOL_MARS(MEMSET32, FLfunc,FREGSAVED,"_memset32", 0, t) \
SYMBOL_MARS(MEMSET64, FLfunc,FREGSAVED,"_memset64", 0, t) \
SYMBOL_MARS(MEMSET128, FLfunc,FREGSAVED,"_memset128",0, t) \
SYMBOL_MARS(MEMSET80, FLfunc,FREGSAVED,"_memset80", 0, t) \
SYMBOL_MARS(MEMSET160, FLfunc,FREGSAVED,"_memset160",0, t) \
SYMBOL_MARS(MEMSETFLOAT, FLfunc,FREGSAVED,"_memsetFloat", 0, t) \
SYMBOL_MARS(MEMSETDOUBLE, FLfunc,FREGSAVED,"_memsetDouble", 0, t) \
SYMBOL_MARS(MEMSETN, FLfunc,FREGSAVED,"_memsetn", 0, t) \
SYMBOL_MARS(MODULO, FLfunc,FREGSAVED,"_modulo", 0, t) \
SYMBOL_MARS(MONITORENTER, FLfunc,FREGSAVED,"_d_monitorenter",0, t) \
SYMBOL_MARS(MONITOREXIT, FLfunc,FREGSAVED,"_d_monitorexit",0, t) \
SYMBOL_MARS(CRITICALENTER, FLfunc,FREGSAVED,"_d_criticalenter",0, t) \
SYMBOL_MARS(CRITICALEXIT, FLfunc,FREGSAVED,"_d_criticalexit",0, t) \
SYMBOL_MARS(SWITCH_STRING, FLfunc,FREGSAVED,"_d_switch_string", 0, t) \
SYMBOL_MARS(SWITCH_USTRING,FLfunc,FREGSAVED,"_d_switch_ustring", 0, t) \
SYMBOL_MARS(SWITCH_DSTRING,FLfunc,FREGSAVED,"_d_switch_dstring", 0, t) \
SYMBOL_MARS(DSWITCHERR, FLfunc,FREGSAVED,"_d_switch_error", SFLexit, t) \
SYMBOL_MARS(DHIDDENFUNC, FLfunc,FREGSAVED,"_d_hidden_func", 0, t) \
SYMBOL_MARS(NEWCLASS, FLfunc,FREGSAVED,"_d_newclass", 0, t) \
SYMBOL_MARS(NEWARRAYT, FLfunc,FREGSAVED,"_d_newarrayT", 0, t) \
SYMBOL_MARS(NEWARRAYIT, FLfunc,FREGSAVED,"_d_newarrayiT", 0, t) \
SYMBOL_MARS(NEWARRAYMT, FLfunc,FREGSAVED,"_d_newarraymT", 0, tv) \
SYMBOL_MARS(NEWARRAYMIT, FLfunc,FREGSAVED,"_d_newarraymiT", 0, tv) \
SYMBOL_MARS(ARRAYLITERALT, FLfunc,FREGSAVED,"_d_arrayliteralT", 0, tv) \
SYMBOL_MARS(ARRAYLITERALTX, FLfunc,FREGSAVED,"_d_arrayliteralTX", 0, t) \
SYMBOL_MARS(ASSOCARRAYLITERALT, FLfunc,FREGSAVED,"_d_assocarrayliteralT", 0, tv) \
SYMBOL_MARS(ASSOCARRAYLITERALTX, FLfunc,FREGSAVED,"_d_assocarrayliteralTX", 0, t) \
SYMBOL_MARS(CALLFINALIZER, FLfunc,FREGSAVED,"_d_callfinalizer", 0, t) \
SYMBOL_MARS(CALLINTERFACEFINALIZER, FLfunc,FREGSAVED,"_d_callinterfacefinalizer", 0, t) \
SYMBOL_MARS(DELCLASS, FLfunc,FREGSAVED,"_d_delclass", 0, t) \
SYMBOL_MARS(DELINTERFACE, FLfunc,FREGSAVED,"_d_delinterface", 0, t) \
SYMBOL_MARS(ALLOCMEMORY, FLfunc,FREGSAVED,"_d_allocmemory", 0, t) \
SYMBOL_MARS(DELARRAY, FLfunc,FREGSAVED,"_d_delarray", 0, t) \
SYMBOL_MARS(DELARRAYT, FLfunc,FREGSAVED,"_d_delarray_t", 0, t) \
SYMBOL_MARS(DELMEMORY, FLfunc,FREGSAVED,"_d_delmemory", 0, t) \
SYMBOL_MARS(INTERFACE, FLfunc,FREGSAVED,"_d_interface_vtbl", 0, t) \
SYMBOL_MARS(DYNAMIC_CAST, FLfunc,FREGSAVED,"_d_dynamic_cast", 0, t) \
SYMBOL_MARS(INTERFACE_CAST,FLfunc,FREGSAVED,"_d_interface_cast", 0, t) \
SYMBOL_MARS(FATEXIT, FLfunc,FREGSAVED,"_fatexit", 0, t) \
SYMBOL_MARS(ARRAYCATT, FLfunc,FREGSAVED,"_d_arraycatT", 0, t) \
SYMBOL_MARS(ARRAYCATNT, FLfunc,FREGSAVED,"_d_arraycatnT", 0, tv) \
SYMBOL_MARS(ARRAYAPPENDT, FLfunc,FREGSAVED,"_d_arrayappendT", 0, t) \
SYMBOL_MARS(ARRAYAPPENDCT, FLfunc,FREGSAVED,"_d_arrayappendcT", 0, tv) \
SYMBOL_MARS(ARRAYAPPENDCTX, FLfunc,FREGSAVED,"_d_arrayappendcTX", 0, t) \
SYMBOL_MARS(ARRAYAPPENDCD, FLfunc,FREGSAVED,"_d_arrayappendcd", 0, t) \
SYMBOL_MARS(ARRAYAPPENDWD, FLfunc,FREGSAVED,"_d_arrayappendwd", 0, t) \
SYMBOL_MARS(ARRAYSETLENGTHT,FLfunc,FREGSAVED,"_d_arraysetlengthT", 0, t) \
SYMBOL_MARS(ARRAYSETLENGTHIT,FLfunc,FREGSAVED,"_d_arraysetlengthiT", 0, t) \
SYMBOL_MARS(ARRAYCOPY, FLfunc,FREGSAVED,"_d_arraycopy", 0, t) \
SYMBOL_MARS(ARRAYASSIGN, FLfunc,FREGSAVED,"_d_arrayassign", 0, t) \
SYMBOL_MARS(ARRAYCTOR, FLfunc,FREGSAVED,"_d_arrayctor", 0, t) \
SYMBOL_MARS(ARRAYSETASSIGN, FLfunc,FREGSAVED,"_d_arraysetassign", 0, t) \
SYMBOL_MARS(ARRAYSETCTOR, FLfunc,FREGSAVED,"_d_arraysetctor", 0, t) \
SYMBOL_MARS(ARRAYCAST, FLfunc,FREGSAVED,"_d_arraycast", 0, t) \
SYMBOL_MARS(ARRAYCAST_FROMBIT, FLfunc,FREGSAVED,"_d_arraycast_frombit", 0, t) \
SYMBOL_MARS(ARRAYEQ, FLfunc,FREGSAVED,"_adEq", 0, t) \
SYMBOL_MARS(ARRAYEQ2, FLfunc,FREGSAVED,"_adEq2", 0, t) \
SYMBOL_MARS(ARRAYEQBIT, FLfunc,FREGSAVED,"_adEqBit", 0, t) \
SYMBOL_MARS(ARRAYCMP, FLfunc,FREGSAVED,"_adCmp", 0, t) \
SYMBOL_MARS(ARRAYCMP2, FLfunc,FREGSAVED,"_adCmp2", 0, t) \
SYMBOL_MARS(ARRAYCMPCHAR, FLfunc,FREGSAVED,"_adCmpChar", 0, t) \
SYMBOL_MARS(ARRAYCMPBIT, FLfunc,FREGSAVED,"_adCmpBit", 0, t) \
SYMBOL_MARS(OBJ_EQ, FLfunc,FREGSAVED,"_d_obj_eq", 0, t) \
SYMBOL_MARS(OBJ_CMP, FLfunc,FREGSAVED,"_d_obj_cmp", 0, t) \
\
SYMBOL_Z(EXCEPT_HANDLER2, FLfunc,fregsaved,"_except_handler2", 0, 0) \
SYMBOL_Z(EXCEPT_HANDLER3, FLfunc,fregsaved,"_except_handler3", 0, 0) \
SYMBOL_SCPP(CPP_HANDLER, FLfunc,FREGSAVED,"_cpp_framehandler", 0, 0) \
SYMBOL_MARS(CPP_HANDLER, FLfunc,FREGSAVED,"_d_framehandler", 0, 0) \
SYMBOL_MARS(D_LOCAL_UNWIND2, FLfunc,FREGSAVED,"_d_local_unwind2", 0, 0) \
SYMBOL_SCPP(LOCAL_UNWIND2, FLfunc,FREGSAVED,"_local_unwind2", 0, 0) \
\
SYMBOL_Z(TLS_INDEX, FLextern,0,"_tls_index",0,tsint) \
SYMBOL_Z(TLS_ARRAY, FLextern,0,"_tls_array",0,tsint) \
SYMBOL_SCPP(AHSHIFT, FLfunc,0,"_AHSHIFT",0,tstrace) \
\
SYMBOL_SCPP_TX86(HDIFFN, FLfunc,mBX|mCX|mSI|mDI|mBP|mES,"_aNahdiff", 0, 0) \
SYMBOL_SCPP_TX86(HDIFFF, FLfunc,mBX|mCX|mSI|mDI|mBP|mES,"_aFahdiff", 0, 0) \
\
SYMBOL_Z(EXCEPT_LIST, FLextern,0,"_except_list",0,tsint) \
SYMBOL_Z(SETJMP3, FLfunc,FREGSAVED,"_setjmp3", 0, 0) \
SYMBOL_Z(LONGJMP, FLfunc,FREGSAVED,"_seh_longjmp_unwind@4", 0, 0) \
SYMBOL_Z(INTONLY, FLfunc,mSI|mDI,"_intonly", 0, 0) \
SYMBOL_Z(ALLOCA, FLfunc,fregsaved,"__alloca", 0, 0) \
SYMBOL_Z(CPP_LONGJMP, FLfunc,FREGSAVED,"_cpp_longjmp_unwind@4", 0, 0) \
SYMBOL_Z(PTRCHK, FLfunc,fregsaved,"_ptrchk", 0, 0) \
SYMBOL_Z(CHKSTK, FLfunc,fregsaved,"_chkstk", 0, 0) \
SYMBOL_Z(TRACE_PRO_N, FLfunc,ALLREGS|mBP|mES,"_trace_pro_n",0,tstrace) \
SYMBOL_Z(TRACE_PRO_F, FLfunc,ALLREGS|mBP|mES,"_trace_pro_f",0,tstrace) \
SYMBOL_Z(TRACE_EPI_N, FLfunc,ALLREGS|mBP|mES,"_trace_epi_n",0,tstrace) \
SYMBOL_Z(TRACE_EPI_F, FLfunc,ALLREGS|mBP|mES,"_trace_epi_f",0,tstrace) \

712
backend/strtold.c Normal file
View File

@@ -0,0 +1,712 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <float.h>
#include <string.h>
#include <math.h>
#if _WIN32
#include <fenv.h>
#include <fltpnt.h>
#endif
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
#include <errno.h>
#endif
#if _WIN32
// from \sc\src\include\setlocal.h
extern char * __cdecl __locale_decpoint;
void __pascal __set_errno (int an_errno);
#endif
#if _WIN32 || linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
#if 0
/* This is for compilers that don't support hex float literals,
* and also makes it clearer what constants we're trying to use.
*/
static long double negtab[] =
{1e-4096L,1e-2048L,1e-1024L,1e-512L,
1e-256L,1e-128L,1e-64L,1e-32L,1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L};
static long double postab[] =
{1e+4096L,1e+2048L,1e+1024L,1e+512L,
1e+256L,1e+128L,1e+64L,1e+32L,1e+16L,1e+8L,1e+4L,1e+2L,1e+1L};
#elif defined(__GNUC__) && __FreeBSD__ && __i386__
// GCC on FreeBSD/i386 incorrectly rounds long double constants to double precision. Workaround:
// Note that the [sizeof(long double)] takes care of whatever the 0 padding is for the
// target platform
static unsigned char _negtab_bytes[][sizeof(long double)] =
{ { 0xDE,0x9F,0xCE,0xD2,0xC8,0x04,0xDD,0xA6,0xD8,0x0A,0xBF,0xBF },
{ 0xE4,0x2D,0x36,0x34,0x4F,0x53,0xAE,0xCE,0x6B,0x25,0xBF,0xBF },
{ 0xBE,0xC0,0x57,0xDA,0xA5,0x82,0xA6,0xA2,0xB5,0x32,0xBF,0xBF },
{ 0x1C,0xD2,0x23,0xDB,0x32,0xEE,0x49,0x90,0x5A,0x39,0xBF,0xBF },
{ 0x3A,0x19,0x7A,0x63,0x25,0x43,0x31,0xC0,0xAC,0x3C,0xBF,0xBF },
{ 0xA1,0xE4,0xBC,0x64,0x7C,0x46,0xD0,0xDD,0x55,0x3E,0xBF,0xBF },
{ 0xA5,0xE9,0x39,0xA5,0x27,0xEA,0x7F,0xA8,0x2A,0x3F,0xBF,0xBF },
{ 0xBA,0x94,0x39,0x45,0xAD,0x1E,0xB1,0xCF,0x94,0x3F,0xBF,0xBF },
{ 0x5B,0xE1,0x4D,0xC4,0xBE,0x94,0x95,0xE6,0xC9,0x3F,0xBF,0xBF },
{ 0xFD,0xCE,0x61,0x84,0x11,0x77,0xCC,0xAB,0xE4,0x3F,0xBF,0xBF },
{ 0x2C,0x65,0x19,0xE2,0x58,0x17,0xB7,0xD1,0xF1,0x3F,0xBF,0xBF },
{ 0x0A,0xD7,0xA3,0x70,0x3D,0x0A,0xD7,0xA3,0xF8,0x3F,0xBF,0xBF },
{ 0xCD,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFB,0x3F,0xBF,0xBF },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x3F,0xBF,0xBF } };
static unsigned char _postab_bytes[][sizeof(long double)] =
{ { 0x9B,0x97,0x20,0x8A,0x02,0x52,0x60,0xC4,0x25,0x75,0x18,0x28 },
{ 0xE5,0x5D,0x3D,0xC5,0x5D,0x3B,0x8B,0x9E,0x92,0x5A,0x18,0x28 },
{ 0x17,0x0C,0x75,0x81,0x86,0x75,0x76,0xC9,0x48,0x4D,0x18,0x28 },
{ 0xC7,0x91,0x0E,0xA6,0xAE,0xA0,0x19,0xE3,0xA3,0x46,0x18,0x28 },
{ 0x8E,0xDE,0xF9,0x9D,0xFB,0xEB,0x7E,0xAA,0x51,0x43,0x18,0x28 },
{ 0xE0,0x8C,0xE9,0x80,0xC9,0x47,0xBA,0x93,0xA8,0x41,0x18,0x28 },
{ 0xD5,0xA6,0xCF,0xFF,0x49,0x1F,0x78,0xC2,0xD3,0x40,0x18,0x28 },
{ 0x9E,0xB5,0x70,0x2B,0xA8,0xAD,0xC5,0x9D,0x69,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x04,0xBF,0xC9,0x1B,0x8E,0x34,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x00,0x00,0x20,0xBC,0xBE,0x19,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9C,0x0C,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x05,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x02,0x40,0x18,0x28 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x3F,0x18,0x28 } };
static long double *negtab = (long double *) _negtab_bytes;
static long double *postab = (long double *) _postab_bytes;
#else
// Use exact values, computed separately, to bootstrap.
// The digits here past 17 are just for amusement value, they
// only contribute to the 'sticky' bit.
static long double negtab[] =
{
1 / 0x62.30290145104bcd64a60a9fc025254932bb0fd922271133eeae7be4a2f9151ffff868e970c234d8f51c5563f48bd2b496d868b27518ae42404964046f87cc1d213d5d0b54f74eb9281bb6c6e435fcb457200c03a5bca35f7792959da22e8d623b3e7b21e2b6100fab123cd8a1a75409f23956d4b941c759f83557de068edd2d00bcdd9d4a52ec8721ac7867f9e974996fb03d7ecd2fdc6349af06940d48741a6c2ed4684e5ab8d9c7bd7991dc03b4f63b8afd6b25ff66e42caeee333b7000a51987ec7038aec29e6ee8cac982a4ba47440496fcbe00d313d584e857fd214495bbdf373f41fd86fe49b70a5c7d2b17e0b2544f10cd4d8bfa89d0d73df29d0176cca7c234f4e6d2767113fd01c8c1a08a138c4ef80456c02d9a0ff4f1d4e3e51cb9255858325ed8d2399faddd9e9985a2df904ff6bf5c4f2ef0650ebc692c5508c2cbd6667097aced8e437b3d7fe03b2b6341a4c954108b89bc108f19ade5b533458e0dd75a53400d03119534074e89541bae9641fdd6266a3fdcbf778900fc509ba674343dd6769f3b72b882e7282566fbc6cc3f8d6b0dd9bc96119b31a96ddeff35e836b5d298f9994b8c90918e7b9a73491260806f233b7c94ab6feba2ebd6c1d9960e2d73a130d84c4a74fde9ce4724ed5bf546a03f40a8fb126ab1c32da38338eb3acc1a67778cfbe8b12acf1b23504dcd6cd995aca6a8b492ed8aa19adb95484971870239f4cea6e9cfda20c33857b32c450c3fecb534b71bd1a45b060904788f6e50fe78d6823613c8509ee3352c90ca19cfe90afb779eea37c8ab8db59a0a80627ce41d3cc425971d582dfe6d97ee63302b8e13e25feeaf19e63d326a7eb6d1c7bf2608c4cf1cc939c1307641d9b2c39497a8fcd8e0cd9e8d7c3172826ac9df13cb3d04e8d2fca26a9ff7d8b57e27ecf57bbb9373f46fee7aab86deb3f078787e2ab608b89572dac789bf627ede440b3f251f2b2322ab312bb95893d4b850be10e02d2408206e7bb8272181327ec8fa2e8a37a2d4390caea134c53c0adf9462ea75ecf9b5d0ed4d542dc19e1faf7a872e74f984d83e2dd8d92580152f18390a2b295138753d1fa8fd5d59c89f1b095edc162e2690f3cd8f62ff42923bbd87d1cde840b464a0e137d5e9a4eb8f8cde35c88baf63b71292baf1deeca19beb77fb8af6176ca776743074fa7021b97a1e0a68173c20ee69e79dadf7eb83cadbdfea5242a8329761ffe062053ccb5b92ac50b9c175a697b2b5341743c994a4503b9af26b398c6fed037d19eef4090ee8ae0725b1655fec303297cd0c2bd9cc1110c4e9968738b909454eb2a0dcfe388f15b8c898d3967a1b6dc3a5b4811a4f04f3618ac0280f4d3295a842bcfd82373a3f8ec72af2acd5071a8309cb2130504dd97d9556a1ebcad7947e0d0e30c7ae41eb659fb878f061814f6cea9c441c2d473bfe167b1a1c304e7613b22454ab9c41ff0b0905bc13176168dde6d488052f8cf8169c84cb4bf982870097012c23481161959127142e0e80cab3e6d7af6a25743dbeabcd0f237f1a016b67b2c2dfae78e341be10d6bfdf759b8ba1e81d1f4cce7c4823da7e1e7c34c0591cc245155e93b86ae5be806c0ed3f0da6146e599574efb29b172506be82913b1bb5154e05154ef084117f89a1e908efe7ae7d4724e8d2a67c001p+13600L,
1 / 0x9.e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba19648b21c11eb962b1b61b93cf2ee5ca6f7e928e61d08e2d694222771e50f30278c9836230af908b40a753b7d77cd8c6be7151aab4efac5dcd83e49d6907855eeb028af623f6f7024d2c36fa9ce9d04a487fa1fb992be221ef1bd0ad5f775677ce0de08402ad3fa140eac7d56c7c9dee0bedd8a6c038f9245b2e87c348ad803ecca8f0070f8dbb57a6a445f278b3d5cf42915e818415c7f3ef82df84658ccf45cfad379433f3389a4408f43c513ef5a83fb8886fbf56d9d4bd5f860792e55ecee70beb1810d76ce39de9ec24bcf99d01953761abd9d7389c0a244de3c195355d84eeebeee6f46eadb56c6815b785ce6b7b125ac8edb0708fd8f6cae5f5715f7915b33eb417bf03c19d7917c7ba1fc6b9681428c85744695f0e866d7efc9ac375d77c1a42f40660460944545ff87a7dc62d752f7a66a57b1ab730f203c1aa9f44484d80e2e5fc5a04779c56b8a9e110c7bcbea4ca7982da4663cfe491d0dbd21feab49869733554c36685e5510c4a656654419bd438e48ff35d6c7d6ab91bac974fb1264b4f111821fa2bca416afe609c313b41e449952fbed5a151440967abbb3a8281ed6a8f16f9210c17f94e3892ee98074ff01e3cb64f32dbb6643a7a8289c8c6c54de34c101349713b44938209ce1f3861ce0fb7fedcc235552eb57a7842d71c7fd8f66912e4ad2f869c29279498719342c12866ed6f1c850dabc98342c9e51b78db2ea50d142fd8277732ed56d55a5e5a191368b8abbb6067584ee87e354ec2e472149e28dcfb27d4d3fe30968651333e001p+6800L,
1 / 0x3.25d9d61a05d4305d9434f4a3c62d433949ae6209d4926c3f5bd2db49ef47187094c1a6970ca7e6bd2a73c5534936a8de061e8d4649f4f3235e005b80411640114a88bc491b9fc4ed520190fba035faaba6c356e38a31b5653f445975836cb0b6c975a351a28e4262ce3ce3a0b8df68368ae26a7b7e976a3310fc8f1f9031eb0f669a20288280bda5a580d98089dc1a47fe6b7595fb101a3616b6f4654b31fb6bfdf56deeecb1b896bc8fc51a16bf3fdeb3d814b505ba34c4118ad822a51abe1de3045b7a748e1042c462be695a9f9f2a07a7e89431922bbb9fc96359861c5cd134f451218b65dc60d7233e55c7231d2b9c9fce837d1e43f61f7de16cfb896634ee0ed1440ecc2cd8194c7d1e1a140ac53515c51a88991c4e871ec29f866e7c215bf55b2b722919f001p+3400L,
1 / 0x1c.633415d4c1d238d98cab8a978a0b1f138cb07303a269974845a71d46b099bc817343afac69be5b0e9449775c1366732a93abade4b2908ee0f95f635e85a91924c3fc0695e7fc7153329c57aebfa3edac96e14f5dbc51fb2eb21a2f221e25cfea703ed321aa1da1bf28f8733b4475b579c88976c194e6574746c40513c31e1ad9b83a8a975d96976f8f9546dc77f27267fc6cf801p+1696L,
1 / 0x5.53f75fdcefcef46eeddc80dcc7f755bc28f265f9ef17cc5573c063ff540e3c42d35a1d153624adc666b026b2716ed595d80fcf4a6e706bde50c612152f87d8d99f72bed3875b982e7c01p+848L,
1 / 0x2.4ee91f2603a6337f19bccdb0dac404dc08d3cff5ec2374e42f0f1538fd03df99092e953e01p+424L,
1 / 0x18.4f03e93ff9f4daa797ed6e38ed64bf6a1f01p+208L,
1 / 0x4.ee2d6d415b85acef81p+104L,
1 / 0x23.86f26fc1p+48L,
1 / 0x5.f5e1p+24L,
1 / 0x27.10p+8L,
1 / 0x64.p+0L,
1 / 0xa.p+0L,
};
static long double postab[] =
{
0x62.30290145104bcd64a60a9fc025254932bb0fd922271133eeae7be4a2f9151ffff868e970c234d8f51c5563f48bd2b496d868b27518ae42404964046f87cc1d213d5d0b54f74eb9281bb6c6e435fcb457200c03a5bca35f7792959da22e8d623b3e7b21e2b6100fab123cd8a1a75409f23956d4b941c759f83557de068edd2d00bcdd9d4a52ec8721ac7867f9e974996fb03d7ecd2fdc6349af06940d48741a6c2ed4684e5ab8d9c7bd7991dc03b4f63b8afd6b25ff66e42caeee333b7000a51987ec7038aec29e6ee8cac982a4ba47440496fcbe00d313d584e857fd214495bbdf373f41fd86fe49b70a5c7d2b17e0b2544f10cd4d8bfa89d0d73df29d0176cca7c234f4e6d2767113fd01c8c1a08a138c4ef80456c02d9a0ff4f1d4e3e51cb9255858325ed8d2399faddd9e9985a2df904ff6bf5c4f2ef0650ebc692c5508c2cbd6667097aced8e437b3d7fe03b2b6341a4c954108b89bc108f19ade5b533458e0dd75a53400d03119534074e89541bae9641fdd6266a3fdcbf778900fc509ba674343dd6769f3b72b882e7282566fbc6cc3f8d6b0dd9bc96119b31a96ddeff35e836b5d298f9994b8c90918e7b9a73491260806f233b7c94ab6feba2ebd6c1d9960e2d73a130d84c4a74fde9ce4724ed5bf546a03f40a8fb126ab1c32da38338eb3acc1a67778cfbe8b12acf1b23504dcd6cd995aca6a8b492ed8aa19adb95484971870239f4cea6e9cfda20c33857b32c450c3fecb534b71bd1a45b060904788f6e50fe78d6823613c8509ee3352c90ca19cfe90afb779eea37c8ab8db59a0a80627ce41d3cc425971d582dfe6d97ee63302b8e13e25feeaf19e63d326a7eb6d1c7bf2608c4cf1cc939c1307641d9b2c39497a8fcd8e0cd9e8d7c3172826ac9df13cb3d04e8d2fca26a9ff7d8b57e27ecf57bbb9373f46fee7aab86deb3f078787e2ab608b89572dac789bf627ede440b3f251f2b2322ab312bb95893d4b850be10e02d2408206e7bb8272181327ec8fa2e8a37a2d4390caea134c53c0adf9462ea75ecf9b5d0ed4d542dc19e1faf7a872e74f984d83e2dd8d92580152f18390a2b295138753d1fa8fd5d59c89f1b095edc162e2690f3cd8f62ff42923bbd87d1cde840b464a0e137d5e9a4eb8f8cde35c88baf63b71292baf1deeca19beb77fb8af6176ca776743074fa7021b97a1e0a68173c20ee69e79dadf7eb83cadbdfea5242a8329761ffe062053ccb5b92ac50b9c175a697b2b5341743c994a4503b9af26b398c6fed037d19eef4090ee8ae0725b1655fec303297cd0c2bd9cc1110c4e9968738b909454eb2a0dcfe388f15b8c898d3967a1b6dc3a5b4811a4f04f3618ac0280f4d3295a842bcfd82373a3f8ec72af2acd5071a8309cb2130504dd97d9556a1ebcad7947e0d0e30c7ae41eb659fb878f061814f6cea9c441c2d473bfe167b1a1c304e7613b22454ab9c41ff0b0905bc13176168dde6d488052f8cf8169c84cb4bf982870097012c23481161959127142e0e80cab3e6d7af6a25743dbeabcd0f237f1a016b67b2c2dfae78e341be10d6bfdf759b8ba1e81d1f4cce7c4823da7e1e7c34c0591cc245155e93b86ae5be806c0ed3f0da6146e599574efb29b172506be82913b1bb5154e05154ef084117f89a1e908efe7ae7d4724e8d2a67c001p+13600L,
0x9.e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba19648b21c11eb962b1b61b93cf2ee5ca6f7e928e61d08e2d694222771e50f30278c9836230af908b40a753b7d77cd8c6be7151aab4efac5dcd83e49d6907855eeb028af623f6f7024d2c36fa9ce9d04a487fa1fb992be221ef1bd0ad5f775677ce0de08402ad3fa140eac7d56c7c9dee0bedd8a6c038f9245b2e87c348ad803ecca8f0070f8dbb57a6a445f278b3d5cf42915e818415c7f3ef82df84658ccf45cfad379433f3389a4408f43c513ef5a83fb8886fbf56d9d4bd5f860792e55ecee70beb1810d76ce39de9ec24bcf99d01953761abd9d7389c0a244de3c195355d84eeebeee6f46eadb56c6815b785ce6b7b125ac8edb0708fd8f6cae5f5715f7915b33eb417bf03c19d7917c7ba1fc6b9681428c85744695f0e866d7efc9ac375d77c1a42f40660460944545ff87a7dc62d752f7a66a57b1ab730f203c1aa9f44484d80e2e5fc5a04779c56b8a9e110c7bcbea4ca7982da4663cfe491d0dbd21feab49869733554c36685e5510c4a656654419bd438e48ff35d6c7d6ab91bac974fb1264b4f111821fa2bca416afe609c313b41e449952fbed5a151440967abbb3a8281ed6a8f16f9210c17f94e3892ee98074ff01e3cb64f32dbb6643a7a8289c8c6c54de34c101349713b44938209ce1f3861ce0fb7fedcc235552eb57a7842d71c7fd8f66912e4ad2f869c29279498719342c12866ed6f1c850dabc98342c9e51b78db2ea50d142fd8277732ed56d55a5e5a191368b8abbb6067584ee87e354ec2e472149e28dcfb27d4d3fe30968651333e001p+6800L,
0x3.25d9d61a05d4305d9434f4a3c62d433949ae6209d4926c3f5bd2db49ef47187094c1a6970ca7e6bd2a73c5534936a8de061e8d4649f4f3235e005b80411640114a88bc491b9fc4ed520190fba035faaba6c356e38a31b5653f445975836cb0b6c975a351a28e4262ce3ce3a0b8df68368ae26a7b7e976a3310fc8f1f9031eb0f669a20288280bda5a580d98089dc1a47fe6b7595fb101a3616b6f4654b31fb6bfdf56deeecb1b896bc8fc51a16bf3fdeb3d814b505ba34c4118ad822a51abe1de3045b7a748e1042c462be695a9f9f2a07a7e89431922bbb9fc96359861c5cd134f451218b65dc60d7233e55c7231d2b9c9fce837d1e43f61f7de16cfb896634ee0ed1440ecc2cd8194c7d1e1a140ac53515c51a88991c4e871ec29f866e7c215bf55b2b722919f001p+3400L,
0x1c.633415d4c1d238d98cab8a978a0b1f138cb07303a269974845a71d46b099bc817343afac69be5b0e9449775c1366732a93abade4b2908ee0f95f635e85a91924c3fc0695e7fc7153329c57aebfa3edac96e14f5dbc51fb2eb21a2f221e25cfea703ed321aa1da1bf28f8733b4475b579c88976c194e6574746c40513c31e1ad9b83a8a975d96976f8f9546dc77f27267fc6cf801p+1696L,
0x5.53f75fdcefcef46eeddc80dcc7f755bc28f265f9ef17cc5573c063ff540e3c42d35a1d153624adc666b026b2716ed595d80fcf4a6e706bde50c612152f87d8d99f72bed3875b982e7c01p+848L,
0x2.4ee91f2603a6337f19bccdb0dac404dc08d3cff5ec2374e42f0f1538fd03df99092e953e01p+424L,
0x18.4f03e93ff9f4daa797ed6e38ed64bf6a1f01p+208L,
0x4.ee2d6d415b85acef81p+104L,
0x23.86f26fc1p+48L,
0x5.f5e1p+24L,
0x27.10p+8L,
0x64.p+0L,
0xa.p+0L,
};
#endif
/*************************
* Convert string to double.
* Terminates on first unrecognized character.
*/
long double strtold(const char *p,char **endp)
{
long double ldval;
int exp;
long long msdec,lsdec;
unsigned long msscale;
char dot,sign;
int pow;
int ndigits;
const char *pinit = p;
static char infinity[] = "infinity";
static char nans[] = "nans";
unsigned int old_cw;
unsigned int old_status;
#if _WIN32
fenv_t flagp;
fegetenv(&flagp); /* Store all exceptions, and current status word */
if (_8087)
{
// disable exceptions from occurring, set max precision, and round to nearest
#if __DMC__
__asm
{
fstcw word ptr old_cw
mov EAX,old_cw
mov ECX,EAX
and EAX,0xf0c0
or EAX,033fh
mov old_cw,EAX
fldcw word ptr old_cw
mov old_cw,ECX
}
#else
old_cw = _control87(_MCW_EM | _PC_64 | _RC_NEAR,
_MCW_EM | _MCW_PC | _MCW_RC);
#endif
}
#endif
while (isspace(*p))
p++;
sign = 0; /* indicating + */
switch (*p)
{ case '-':
sign++;
/* FALL-THROUGH */
case '+':
p++;
}
ldval = 0.0;
dot = 0; /* if decimal point has been seen */
exp = 0;
msdec = lsdec = 0;
msscale = 1;
ndigits = 0;
#if __DMC__
switch (*p)
{ case 'i':
case 'I':
if (memicmp(p,infinity,8) == 0)
{ p += 8;
goto L4;
}
if (memicmp(p,infinity,3) == 0) /* is it "inf"? */
{ p += 3;
L4:
ldval = HUGE_VAL;
goto L3;
}
break;
case 'n':
case 'N':
if (memicmp(p,nans,4) == 0) /* "nans"? */
{ p += 4;
ldval = NANS;
goto L5;
}
if (memicmp(p,nans,3) == 0) /* "nan"? */
{ p += 3;
ldval = NAN;
L5:
if (*p == '(') /* if (n-char-sequence) */
goto Lerr; /* invalid input */
goto L3;
}
}
#endif
if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
{ int guard = 0;
int anydigits = 0;
p += 2;
while (1)
{ int i = *p;
while (isxdigit(i))
{
anydigits = 1;
i = isalpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0';
if (ndigits < 16)
{
msdec = msdec * 16 + i;
if (msdec)
ndigits++;
}
else if (ndigits == 16)
{
while (msdec >= 0)
{
exp--;
msdec <<= 1;
i <<= 1;
if (i & 0x10)
msdec |= 1;
}
guard = i << 4;
ndigits++;
exp += 4;
}
else
{
guard |= i;
exp += 4;
}
exp -= dot;
i = *++p;
}
#ifdef _WIN32
if (i == *__locale_decpoint && !dot)
#else
if (i == '.' && !dot)
#endif
{ p++;
dot = 4;
}
else
break;
}
// Round up if (guard && (sticky || odd))
if (guard & 0x80 && (guard & 0x7F || msdec & 1))
{
msdec++;
if (msdec == 0) // overflow
{ msdec = 0x8000000000000000LL;
exp++;
}
}
if (anydigits == 0) // if error (no digits seen)
goto Lerr;
if (*p == 'p' || *p == 'P')
{
char sexp;
int e;
sexp = 0;
switch (*++p)
{ case '-': sexp++;
case '+': p++;
}
ndigits = 0;
e = 0;
while (isdigit(*p))
{
if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow
{
e = e * 10 + *p - '0';
}
p++;
ndigits = 1;
}
exp += (sexp) ? -e : e;
if (!ndigits) // if no digits in exponent
goto Lerr;
if (msdec)
{
#if __DMC__
// The 8087 has no instruction to load an
// unsigned long long
if (msdec < 0)
{
*(long long *)&ldval = msdec;
((unsigned short *)&ldval)[4] = 0x3FFF + 63;
}
else
{ // But does for a signed one
__asm
{
fild qword ptr msdec
fstp tbyte ptr ldval
}
}
#else
int e2 = 0x3FFF + 63;
// left justify mantissa
while (msdec >= 0)
{ msdec <<= 1;
e2--;
}
// Stuff mantissa directly into long double
*(long long *)&ldval = msdec;
((unsigned short *)&ldval)[4] = e2;
#endif
#if 0
if (0)
{ int i;
printf("msdec = x%llx, ldval = %Lg\n", msdec, ldval);
for (i = 0; i < 5; i++)
printf("%04x ",((unsigned short *)&ldval)[i]);
printf("\n");
printf("%llx\n",ldval);
}
#endif
// Exponent is power of 2, not power of 10
#if _WIN32 && __DMC__
__asm
{
fild dword ptr exp
fld tbyte ptr ldval
fscale // ST(0) = ST(0) * (2**ST(1))
fstp ST(1)
fstp tbyte ptr ldval
}
#else
ldval = ldexpl(ldval,exp);
#endif
}
goto L6;
}
else
goto Lerr; // exponent is required
}
else
{
while (1)
{ int i = *p;
while (isdigit(i))
{
ndigits = 1; /* must have at least 1 digit */
if (msdec < (0x7FFFFFFFFFFFLL-10)/10)
msdec = msdec * 10 + (i - '0');
else if (msscale < (0xFFFFFFFF-10)/10)
{ lsdec = lsdec * 10 + (i - '0');
msscale *= 10;
}
else
{
exp++;
}
exp -= dot;
i = *++p;
}
#if _WIN32
if (i == *__locale_decpoint && !dot)
#else
if (i == '.' && !dot)
#endif
{ p++;
dot++;
}
else
break;
}
if (!ndigits) // if error (no digits seen)
goto Lerr; // return 0.0
}
if (*p == 'e' || *p == 'E')
{
char sexp;
int e;
sexp = 0;
switch (*++p)
{ case '-': sexp++;
case '+': p++;
}
ndigits = 0;
e = 0;
while (isdigit(*p))
{
if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow
{
e = e * 10 + *p - '0';
}
p++;
ndigits = 1;
}
exp += (sexp) ? -e : e;
if (!ndigits) // if no digits in exponent
goto Lerr; // return 0.0
}
#if _WIN32
__asm
{
fild qword ptr msdec
mov EAX,msscale
cmp EAX,1
je La1
fild long ptr msscale
fmul
fild qword ptr lsdec
fadd
La1:
fstp tbyte ptr ldval
}
#else
ldval = msdec;
if (msscale != 1) /* if stuff was accumulated in lsdec */
ldval = ldval * msscale + lsdec;
#endif
if (ldval)
{ unsigned u;
u = 0;
pow = 4096;
#if _WIN32
//printf("msdec = x%x, lsdec = x%x, msscale = x%x\n",msdec,lsdec,msscale);
//printf("dval = %g, x%llx, exp = %d\n",dval,dval,exp);
__asm fld tbyte ptr ldval
#endif
while (exp > 0)
{
while (exp >= pow)
{
#if _WIN32
__asm
{
mov EAX,u
imul EAX,10
fld tbyte ptr postab[EAX]
fmul
}
#else
ldval *= postab[u];
#endif
exp -= pow;
}
pow >>= 1;
u++;
}
#if _WIN32
__asm fstp tbyte ptr ldval
#endif
while (exp < 0)
{ while (exp <= -pow)
{
#if _WIN32
__asm
{
mov EAX,u
imul EAX,10
fld tbyte ptr ldval
fld tbyte ptr negtab[EAX]
fmul
fstp tbyte ptr ldval
}
#else
ldval *= negtab[u];
#endif
if (ldval == 0)
#if _WIN32
__set_errno (ERANGE);
#else
errno = ERANGE;
#endif
exp += pow;
}
pow >>= 1;
u++;
}
#if 0
if (0)
{ int i;
for (i = 0; i < 5; i++)
printf("%04x ",ldval.value[i]);
printf("\n");
printf("%llx\n",dval);
}
#endif
}
L6: // if overflow occurred
if (ldval == HUGE_VAL)
#if _WIN32
__set_errno (ERANGE); // range error
#else
errno = ERANGE;
#endif
L1:
if (endp)
{
*endp = (char *) p;
}
L3:
#if _WIN32
fesetenv(&flagp); // reset floating point environment
if (_8087)
{
__asm
{
xor EAX,EAX
fstsw AX
fclex
fldcw word ptr old_cw
}
}
#endif
return (sign) ? -ldval : ldval;
Lerr:
p = pinit;
goto L1;
}
#else
long double strtold(const char *p,char **endp)
{
return strtod(p, endp);
}
#endif
/************************* Test ************************************/
#if 0
#include <stdio.h>
#include <float.h>
#include <errno.h>
extern "C" long double strtold(const char *p,char **endp);
struct longdouble
{
unsigned short value[5];
};
void main()
{
long double ld;
struct longdouble x;
int i;
errno = 0;
// ld = strtold("0x1.FFFFFFFFFFFFFFFEp16383", NULL);
ld = strtold("0x1.FFFFFFFFFFFFFFFEp-16382", NULL);
x = *(struct longdouble *)&ld;
for (i = 4; i >= 0; i--)
{
printf("%04x ", x.value[i]);
}
printf("\t%d\n", errno);
ld = strtold("1.0e5", NULL);
x = *(struct longdouble *)&ld;
for (i = 4; i >= 0; i--)
{
printf("%04x ", x.value[i]);
}
printf("\n");
}
#endif
/************************* Bigint ************************************/
#if 0
/* This program computes powers of 10 exactly.
* Used to generate postab[].
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NDIGITS 4096
void times10(unsigned *a)
{
int i;
for (i = 0; i < NDIGITS; i++)
{
a[i] *= 10;
if (i)
{
a[i] += a[i - 1] >> 8;
a[i - 1] &= 0xFF;
}
}
}
void print(unsigned *a)
{
int i;
int p;
int j;
for (i = NDIGITS; i; )
{
--i;
if (a[i])
break;
}
printf("0x%x.", a[i]);
p = i * 8;
i--;
for (j = 0; j < i; j++)
if (a[j])
break;
for (; i >= j; i--)
{
printf("%02x", a[i]);
}
printf("p+%d", p);
}
void main()
{
unsigned a[NDIGITS];
int i;
int j;
static long double tab[] =
{
0x62.30290145104bcd64a60a9fc025254932bb0fd922271133eeae7be4a2f9151ffff868e970c234d8f51c5563f48bd2b496d868b27518ae42404964046f87cc1d213d5d0b54f74eb9281bb6c6e435fcb457200c03a5bca35f7792959da22e8d623b3e7b21e2b6100fab123cd8a1a75409f23956d4b941c759f83557de068edd2d00bcdd9d4a52ec8721ac7867f9e974996fb03d7ecd2fdc6349af06940d48741a6c2ed4684e5ab8d9c7bd7991dc03b4f63b8afd6b25ff66e42caeee333b7000a51987ec7038aec29e6ee8cac982a4ba47440496fcbe00d313d584e857fd214495bbdf373f41fd86fe49b70a5c7d2b17e0b2544f10cd4d8bfa89d0d73df29d0176cca7c234f4e6d2767113fd01c8c1a08a138c4ef80456c02d9a0ff4f1d4e3e51cb9255858325ed8d2399faddd9e9985a2df904ff6bf5c4f2ef0650ebc692c5508c2cbd6667097aced8e437b3d7fe03b2b6341a4c954108b89bc108f19ade5b533458e0dd75a53400d03119534074e89541bae9641fdd6266a3fdcbf778900fc509ba674343dd6769f3b72b882e7282566fbc6cc3f8d6b0dd9bc96119b31a96ddeff35e836b5d298f9994b8c90918e7b9a73491260806f233b7c94ab6feba2ebd6c1d9960e2d73a130d84c4a74fde9ce4724ed5bf546a03f40a8fb126ab1c32da38338eb3acc1a67778cfbe8b12acf1b23504dcd6cd995aca6a8b492ed8aa19adb95484971870239f4cea6e9cfda20c33857b32c450c3fecb534b71bd1a45b060904788f6e50fe78d6823613c8509ee3352c90ca19cfe90afb779eea37c8ab8db59a0a80627ce41d3cc425971d582dfe6d97ee63302b8e13e25feeaf19e63d326a7eb6d1c7bf2608c4cf1cc939c1307641d9b2c39497a8fcd8e0cd9e8d7c3172826ac9df13cb3d04e8d2fca26a9ff7d8b57e27ecf57bbb9373f46fee7aab86deb3f078787e2ab608b89572dac789bf627ede440b3f251f2b2322ab312bb95893d4b850be10e02d2408206e7bb8272181327ec8fa2e8a37a2d4390caea134c53c0adf9462ea75ecf9b5d0ed4d542dc19e1faf7a872e74f984d83e2dd8d92580152f18390a2b295138753d1fa8fd5d59c89f1b095edc162e2690f3cd8f62ff42923bbd87d1cde840b464a0e137d5e9a4eb8f8cde35c88baf63b71292baf1deeca19beb77fb8af6176ca776743074fa7021b97a1e0a68173c20ee69e79dadf7eb83cadbdfea5242a8329761ffe062053ccb5b92ac50b9c175a697b2b5341743c994a4503b9af26b398c6fed037d19eef4090ee8ae0725b1655fec303297cd0c2bd9cc1110c4e9968738b909454eb2a0dcfe388f15b8c898d3967a1b6dc3a5b4811a4f04f3618ac0280f4d3295a842bcfd82373a3f8ec72af2acd5071a8309cb2130504dd97d9556a1ebcad7947e0d0e30c7ae41eb659fb878f061814f6cea9c441c2d473bfe167b1a1c304e7613b22454ab9c41ff0b0905bc13176168dde6d488052f8cf8169c84cb4bf982870097012c23481161959127142e0e80cab3e6d7af6a25743dbeabcd0f237f1a016b67b2c2dfae78e341be10d6bfdf759b8ba1e81d1f4cce7c4823da7e1e7c34c0591cc245155e93b86ae5be806c0ed3f0da6146e599574efb29b172506be82913b1bb5154e05154ef084117f89a1e908efe7ae7d4724e8d2a67c001p+13600L,
0x9.e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba19648b21c11eb962b1b61b93cf2ee5ca6f7e928e61d08e2d694222771e50f30278c9836230af908b40a753b7d77cd8c6be7151aab4efac5dcd83e49d6907855eeb028af623f6f7024d2c36fa9ce9d04a487fa1fb992be221ef1bd0ad5f775677ce0de08402ad3fa140eac7d56c7c9dee0bedd8a6c038f9245b2e87c348ad803ecca8f0070f8dbb57a6a445f278b3d5cf42915e818415c7f3ef82df84658ccf45cfad379433f3389a4408f43c513ef5a83fb8886fbf56d9d4bd5f860792e55ecee70beb1810d76ce39de9ec24bcf99d01953761abd9d7389c0a244de3c195355d84eeebeee6f46eadb56c6815b785ce6b7b125ac8edb0708fd8f6cae5f5715f7915b33eb417bf03c19d7917c7ba1fc6b9681428c85744695f0e866d7efc9ac375d77c1a42f40660460944545ff87a7dc62d752f7a66a57b1ab730f203c1aa9f44484d80e2e5fc5a04779c56b8a9e110c7bcbea4ca7982da4663cfe491d0dbd21feab49869733554c36685e5510c4a656654419bd438e48ff35d6c7d6ab91bac974fb1264b4f111821fa2bca416afe609c313b41e449952fbed5a151440967abbb3a8281ed6a8f16f9210c17f94e3892ee98074ff01e3cb64f32dbb6643a7a8289c8c6c54de34c101349713b44938209ce1f3861ce0fb7fedcc235552eb57a7842d71c7fd8f66912e4ad2f869c29279498719342c12866ed6f1c850dabc98342c9e51b78db2ea50d142fd8277732ed56d55a5e5a191368b8abbb6067584ee87e354ec2e472149e28dcfb27d4d3fe30968651333e001p+6800L,
0x3.25d9d61a05d4305d9434f4a3c62d433949ae6209d4926c3f5bd2db49ef47187094c1a6970ca7e6bd2a73c5534936a8de061e8d4649f4f3235e005b80411640114a88bc491b9fc4ed520190fba035faaba6c356e38a31b5653f445975836cb0b6c975a351a28e4262ce3ce3a0b8df68368ae26a7b7e976a3310fc8f1f9031eb0f669a20288280bda5a580d98089dc1a47fe6b7595fb101a3616b6f4654b31fb6bfdf56deeecb1b896bc8fc51a16bf3fdeb3d814b505ba34c4118ad822a51abe1de3045b7a748e1042c462be695a9f9f2a07a7e89431922bbb9fc96359861c5cd134f451218b65dc60d7233e55c7231d2b9c9fce837d1e43f61f7de16cfb896634ee0ed1440ecc2cd8194c7d1e1a140ac53515c51a88991c4e871ec29f866e7c215bf55b2b722919f001p+3400L,
0x1c.633415d4c1d238d98cab8a978a0b1f138cb07303a269974845a71d46b099bc817343afac69be5b0e9449775c1366732a93abade4b2908ee0f95f635e85a91924c3fc0695e7fc7153329c57aebfa3edac96e14f5dbc51fb2eb21a2f221e25cfea703ed321aa1da1bf28f8733b4475b579c88976c194e6574746c40513c31e1ad9b83a8a975d96976f8f9546dc77f27267fc6cf801p+1696L,
0x5.53f75fdcefcef46eeddc80dcc7f755bc28f265f9ef17cc5573c063ff540e3c42d35a1d153624adc666b026b2716ed595d80fcf4a6e706bde50c612152f87d8d99f72bed3875b982e7c01p+848L,
0x2.4ee91f2603a6337f19bccdb0dac404dc08d3cff5ec2374e42f0f1538fd03df99092e953e01p+424L,
0x18.4f03e93ff9f4daa797ed6e38ed64bf6a1f01p+208L,
0x4.ee2d6d415b85acef81p+104L,
0x23.86f26fc1p+48L,
0x5.f5e1p+24L,
0x27.10p+8L,
0x64.p+0L,
0xa.p+0L,
};
for (j = 1; j <= 4096; j *= 2)
{
printf("%4d: ", j);
memset(a, 0, sizeof(a));
a[0] = 1;
for (i = 0; i < j; i++)
times10(a);
print(a);
printf("L,\n");
}
for (i = 0; i < 13; i++)
{
printf("tab[%d] = %Lg\n", i, tab[i]);
}
}
#endif

2307
backend/symbol.c Normal file

File diff suppressed because it is too large Load Diff

54
backend/tassert.h Normal file
View File

@@ -0,0 +1,54 @@
// Copyright (C) 1989-1998 by Symantec
// Copyright (C) 2000-2011 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
//#pragma once
#ifndef TASSERT_H
#define TASSERT_H 1
/*****************************
* Define a local assert function.
*/
#undef assert
#define assert(e) ((e) || (local_assert(__LINE__), 0))
#if __clang__
void util_assert ( char * , int ) __attribute__((analyzer_noreturn));
static void local_assert(int line)
{
util_assert(__file__,line);
__builtin_unreachable();
}
#else
#if _MSC_VER
__declspec(noreturn)
#endif
void util_assert ( char * , int );
static void local_assert(int line)
{
util_assert(__file__,line);
}
#if __DMC__
#pragma noreturn(util_assert)
#pragma noreturn(local_assert)
#endif
#endif
#endif /* TASSERT_H */

61
backend/ti_achar.c Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2006-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#include <string.h>
#include <stdlib.h>
#include "tinfo.h"
// char*
TypeInfo_Achar ti_achar;
const char* TypeInfo_Achar::toString()
{
return "char*";
}
hash_t TypeInfo_Achar::getHash(void *p)
{ char* s;
hash_t hash = 0;
for (s = *(char**)p; *s; s++)
{
hash = hash * 11 + *s;
}
return hash;
}
int TypeInfo_Achar::equals(void *p1, void *p2)
{
char* s1 = *(char**)p1;
char* s2 = *(char**)p2;
return strcmp(s1, s2) == 0;
}
int TypeInfo_Achar::compare(void *p1, void *p2)
{
char* s1 = *(char**)p1;
char* s2 = *(char**)p2;
return strcmp(s1, s2);
}
size_t TypeInfo_Achar::tsize()
{
return sizeof(char*);
}
void TypeInfo_Achar::swap(void *p1, void *p2)
{
}

54
backend/ti_pvoid.c Normal file
View File

@@ -0,0 +1,54 @@
// Copyright (c) 2011-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#include <stdlib.h>
#include "tinfo.h"
// void*
TypeInfo_Pvoid ti_pvoid;
const char* TypeInfo_Pvoid::toString()
{
return "void*";
}
hash_t TypeInfo_Pvoid::getHash(void *p)
{ void* s = *(void **)p;
return (hash_t)s;
}
int TypeInfo_Pvoid::equals(void *p1, void *p2)
{
void* s1 = *(void**)p1;
void* s2 = *(void**)p2;
return s1 == s2;
}
int TypeInfo_Pvoid::compare(void *p1, void *p2)
{
void* s1 = *(void**)p1;
void* s2 = *(void**)p2;
return (s1 < s2) ? -1 : ((s1 == s2) ? 0 : 1);
}
size_t TypeInfo_Pvoid::tsize()
{
return sizeof(void*);
}
void TypeInfo_Pvoid::swap(void *p1, void *p2)
{
}

52
backend/tinfo.h Normal file
View File

@@ -0,0 +1,52 @@
// Copyright (c) 2000-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gpl.txt.
// See the included readme.txt for details.
#ifndef TYPEINFO_H
#define TYPEINFO_H
#include <stdlib.h>
typedef size_t hash_t;
struct TypeInfo
{
virtual const char* toString() = 0;
virtual hash_t getHash(void *p) = 0;
virtual int equals(void *p1, void *p2) = 0;
virtual int compare(void *p1, void *p2) = 0;
virtual size_t tsize() = 0;
virtual void swap(void *p1, void *p2) = 0;
};
struct TypeInfo_Achar : TypeInfo
{
const char* toString();
hash_t getHash(void *p);
int equals(void *p1, void *p2);
int compare(void *p1, void *p2);
size_t tsize();
void swap(void *p1, void *p2);
};
extern TypeInfo_Achar ti_achar;
struct TypeInfo_Pvoid : TypeInfo
{
const char* toString();
hash_t getHash(void *p);
int equals(void *p1, void *p2);
int compare(void *p1, void *p2);
size_t tsize();
void swap(void *p1, void *p2);
};
extern TypeInfo_Pvoid ti_pvoid;
#endif

458
backend/token.h Normal file
View File

@@ -0,0 +1,458 @@
// Copyright (C) 1984-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/**********************************
* Symbol tokens:
*
* TKstar * TKdot . TKeq =
* TKand & TKlbra [ TKaddass +=
* TKmin - TKrbra ] TKminass -=
* TKnot ! TKarrow -> TKmulass *=
* TKcom ~ TKdiv / TKdivass /=
* TKplpl ++ TKmod % TKmodass %=
* TKlpar ( TKxor ^ TKshrass >>=
* TKrpar ) TKor | TKshlass <<=
* TKques ? TKoror || TKandass &=
* TKcolon : TKandand && TKxorass ^=
* TKcomma , TKshl << TKorass |=
* TKmimi -- TKshr >> TKsemi ;
* TKlcur { TKrcur } TKlt <
* TKle <= TKgt > TKge >=
* TKeqeq == TKne != TKadd +
* TKellipsis ... TKcolcol :: TKdollar $
*
* Other tokens:
*
* TKstring string
* TKfilespec <filespec>
*/
//#pragma once
#ifndef TOKEN_H
#define TOKEN_H 1
#if !defined(TOKENS_ONLY) || TOKENS_ONLY
// Keyword tokens. Needn't be ascii sorted
typedef unsigned char enum_TK;
enum TK {
TKauto,
TKbreak,
TKcase,
TKchar,
TKconst,
TKcontinue,
TKdefault,
TKdo,
TKdouble,
TKelse,
TKenum,
TKextern,
TKfloat,
TKfor,
TKgoto,
TKif,
TKint,
TKlong,
TKregister,
TKreturn,
TKshort,
TKsigned,
TKsizeof,
TKstatic,
TKstruct,
TKswitch,
TKtypedef,
TKunion,
TKunsigned,
TKvoid,
TKvolatile,
TKwhile,
// ANSI C99
TK_Complex,
TK_Imaginary,
TKrestrict,
//#if CPP
TKbool,
TKcatch,
TKclass,
TKconst_cast,
TKdelete,
TKdynamic_cast,
TKexplicit,
TKfalse,
TKfriend,
TKinline,
TKmutable,
TKnamespace,
TKnew,
TKoperator,
TKoverload,
TKprivate,
TKprotected,
TKpublic,
TKreinterpret_cast,
TKstatic_cast,
TKtemplate,
TKthis,
TKthrow,
TKtrue,
TKtry,
TKtypeid,
TKtypename,
TKusing,
TKvirtual,
TKwchar_t,
TK_typeinfo,
TK_typemask,
//#endif
#if CPP0X
TKalignof,
TKchar16_t,
TKchar32_t,
TKconstexpr,
TKdecltype,
TKnoexcept,
TKnullptr,
TKstatic_assert,
TKthread_local,
#endif
TKasm,
TK_inf,
TK_nan,
TK_nans,
TK_i, // imaginary constant i
TK_with,
TK_istype,
TK_cdecl,
TK_fortran,
TK_pascal,
TK_debug,
TK_in,
TK_out,
TK_body,
TK_invariant,
#if TX86
TK_Seg16,
TK_System,
TK__emit__,
TK_far,
TK_huge,
TK_near,
TK_asm,
TK_based,
TK_cs,
TK_declspec,
TK_except,
TK_export,
TK_far16,
TK_fastcall,
TK_finally,
TK_handle,
TK_java,
TK_int64,
TK_interrupt,
TK_leave,
TK_loadds,
TK_real80,
TK_saveregs,
TK_segname,
TK_ss,
TK_stdcall,
TK_syscall,
TK_try,
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
TK_attribute,
TK_extension,
TK_format,
TK_restrict,
TK_bltin_const,
#endif
#else
TKcomp,
TKextended,
TK_handle,
TK_machdl,
TK_pasobj,
//#if CPP
TK__class,
TKinherited,
//#endif
#endif
TK_unaligned,
TKsymbol, // special internal token
#define KWMAX (TK_unaligned + 1) // number of keywords
TKcolcol, // ::
TKarrowstar, // ->*
TKdotstar, // .*
TKstar,TKand,TKmin,TKnot,TKcom,TKplpl,TKlpar,TKrpar,TKques,TKcolon,TKcomma,
TKmimi,TKlcur,TKdot,TKlbra,TKrbra,TKarrow,TKdiv,TKmod,TKxor,TKor,TKoror,
TKandand,TKshl,TKshr,TKrcur,TKeq,TKaddass,TKminass,TKmulass,TKdivass,
TKmodass,TKshrass,TKshlass,TKandass,TKxorass,TKorass,TKsemi,
TKadd,TKellipsis,
#if !TX86 || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
TKdollar,
#endif
/* The following relational tokens must be in the same order as the
corresponding operators.
*/
/* == != */
TKle,TKgt,TKlt,TKge,TKeqeq,TKne,
/* !<>= <> <>= !> !>= !< !<= !<> */
TKunord,TKlg,TKleg,TKule,TKul,TKuge,TKug,TKue,
TKstring,
TKfilespec, /* <filespec> */
TKpragma,
TKnum, /* integral number */
TKreal_f,
TKreal_d,
TKreal_da,
TKreal_ld,
TKident, /* identifier */
TKeol, /* end of line */
TKeof, /* end of file */
TKnone, /* no token */
TKMAX /* number of tokens */
};
#endif
#if !defined(TOKENS_ONLY) || !TOKENS_ONLY
struct token_t
{
enum_TK TKval; // what the token is
unsigned char TKflags; // Token flags
#define TKFfree 1 // free the token after it's scanned
#define TKFinherited 2 // keyword INHERITED prior to token
#define TKFpasstr 4 // pascal string
unsigned char TKty; // TYxxxx for TKstring and TKnum
union _TKutok
{
// Scheme for short IDs avoids malloc/frees
struct _ident // TKident
{ char *ident; // pointer to identifier
char idtext[4]; // if short identifier
} _idx;
struct _uts /* TKstring and TKfilespec */
{
char *string;/* for strings (not null terminated) */
int lenstr; /* length of string */
} uts;
symbol *sym; // TKsymbol
int pragma; // TKpragma: PRxxxx, pragma number
// -1 if unrecognized pragma
targ_long Vlong; /* integer when TKnum */
#if LONGLONG
targ_llong Vllong;
#else
#define Vllong Vlong
#endif
targ_float Vfloat;
targ_double Vdouble;
targ_ldouble Vldouble;
} TKutok;
Srcpos TKsrcpos; // line number from where it was taken
token_t *TKnext; // to create a list of tokens
#ifdef DEBUG
unsigned short id;
#define IDtoken 0xA745
#define token_debug(e) assert((e)->id == IDtoken)
#else
#define token_debug(e)
#endif
void setSymbol(symbol *s);
void print();
};
#define TKstr TKutok.uts.string
#define TKlenstr TKutok.uts.lenstr
#define TKid TKutok._idx.ident
#define TKsym TKutok.sym
// Use this for fast scans
#define _IDS 1 // start of identifier
#define _ID 2 // identifier
#define _TOK 4 // single character token
#define _EOL 8 // end of line
#define _MUL 0x10 // start of multibyte character sequence
#define _BCS 0x20 // in basic-source-character-set
#define _MTK 0x40 // could be multi-character token
#define _ZFF 0x80 // 0 or 0xFF (must be sign bit)
#define istok(x) (_chartype[(x) + 1] & _TOK)
#define iseol(x) (_chartype[(x) + 1] & _EOL)
#define isidstart(x) (_chartype[(x) + 1] & _IDS)
#define isidchar(x) (_chartype[(x) + 1] & (_IDS | _ID))
#define ismulti(x) (_chartype[(x) + 1] & _MUL)
#define isbcs(x) (_chartype[(x) + 1] & _BCS)
/* from token.c */
extern int igncomment;
extern char *tok_arg;
extern unsigned argmax;
extern token_t tok;
extern int ininclude;
CEXTERN char tok_ident[]; // identifier
extern unsigned char _chartype[];
extern token_t *toklist;
void token_setdbcs(int);
void token_setlocale(const char *);
token_t *token_copy(void);
void token_free(token_t *tl);
void token_hydrate(token_t **ptl);
void token_dehydrate(token_t **ptl);
token_t *token_funcbody(int bFlag);
token_t *token_defarg(void);
void token_funcbody_print(token_t *t);
void token_setlist(token_t *t);
void token_poplist(void);
void token_unget(void);
void token_markfree(token_t *t);
void token_setident(char *);
void token_semi(void);
Srcpos token_linnum(void);
enum_TK token_peek();
enum_TK rtoken(int);
#if SPP
#define stoken() rtoken(1)
#else
enum_TK stokenx(void);
inline enum_TK stoken() { return toklist ? stokenx() : rtoken(1); }
#endif
void token_init(void);
void removext(void);
void __near comment(void);
void __near cppcomment(void);
char *combinestrings(targ_size_t *plen);
char *combinestrings(targ_size_t *plen, tym_t *pty);
void __near inident(void);
void inidentX(char *p);
unsigned comphash(const char *p);
int insertSpace(unsigned char xclast, unsigned char xcnext);
void panic(enum_TK ptok);
void chktok(enum_TK toknum , unsigned errnum);
void chktok(enum_TK toknum , unsigned errnum, const char *str);
void opttok(enum_TK toknum);
bool iswhite(int c);
void token_term(void);
#define ptoken() rtoken(1)
#define token() rtoken(0)
#if !MARS
/* from pragma.c */
//enum_TK ptoken(void);
void pragma_process();
int __near pragma_search(char *id);
macro_t * __near macfind(void);
void __near listident(void);
void pragma_term(void);
macro_t *defmac(const char *name , const char *text);
int pragma_defined(void);
#endif
#if SPP && TX86
#define token_linnum() getlinnum()
#endif
// listing control
// Listings can be produce via -l and SCpre
// -l expand all characters not if'd out including
// comments
// SCpre list only characters to be compiled
// i.e. exclude comments and # preprocess lines
#if SPP
#define SCPRE_LISTING_ON() expflag--; assert(expflag >= 0)
#define SCPRE_LISTING_OFF() assert(expflag >= 0); expflag++
#define EXPANDED_LISTING_ON() expflag--; assert(expflag >= 0)
#define EXPANDED_LISTING_OFF() assert(expflag >= 0); expflag++
#else
#define SCPRE_LISTING_OFF()
#define SCPRE_LISTING_ON()
#define EXPANDED_LISTING_ON() expflag--; assert(expflag >= 0)
#define EXPANDED_LISTING_OFF() assert(expflag >= 0); expflag++
#endif
#define EXPANDING_LISTING() (expflag == 0)
#define NOT_EXPANDING_LISTING() (expflag)
#endif
/***********************************************
* This is the token lookahead API, which enables us to
* look an arbitrary number of tokens ahead and then
* be able to 'unget' all of them.
*/
struct Token_lookahead
{
int inited; // 1 if initialized
token_t *toks; // list of tokens
token_t **pend; // pointer to end of that list
void init()
{
toks = NULL;
pend = &toks;
inited = 1;
}
enum_TK lookahead()
{
#ifdef DEBUG
//assert(inited == 1);
#endif
*pend = token_copy();
(*pend)->TKflags |= TKFfree;
pend = &(*pend)->TKnext;
return stoken();
}
void term()
{
#ifdef DEBUG
//assert(inited == 1);
#endif
inited--;
if (toks)
{
token_unget();
token_setlist(toks);
stoken();
}
}
void discard()
{
inited--;
token_free(toks);
}
};
#endif /* TOKEN_H */

377
backend/ty.h Normal file
View File

@@ -0,0 +1,377 @@
// Copyright (C) 1983-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if __SC__
#pragma once
#endif
#ifndef TY_H
#define TY_H 1
//#define TYjhandle TYnptr // use for Jupiter handle
/*****************************************
* Data types.
* (consists of basic type + modifier bits)
*/
// Basic types.
// casttab[][] in exp2.c depends on the order of this
// typromo[] in cpp.c depends on the order too
enum TYM
{
TYbool = 0,
TYchar = 1,
TYschar = 2, // signed char
TYuchar = 3, // unsigned char
TYchar8 = 4,
TYchar16 = 5,
TYshort = 6,
TYwchar_t = 7,
TYushort = 8, // unsigned short
TYenum = 9, // enumeration value
TYint = 0xA,
TYuint = 0xB, // unsigned
TYlong = 0xC,
TYulong = 0xD, // unsigned long
TYdchar = 0xE, // 32 bit Unicode char
TYllong = 0xF, // 64 bit long
TYullong = 0x10, // 64 bit unsigned long
TYfloat = 0x11, // 32 bit real
TYdouble = 0x12, // 64 bit real
// long double is mapped to either of the following at runtime:
TYdouble_alias = 0x13, // 64 bit real (but distinct for overload purposes)
TYldouble = 0x14, // 80 bit real
// Add imaginary and complex types for D and C99
TYifloat = 0x15,
TYidouble = 0x16,
TYildouble = 0x17,
TYcfloat = 0x18,
TYcdouble = 0x19,
TYcldouble = 0x1A,
TYjhandle = 0x1B, // Jupiter handle type, equals TYnptr except
// that the debug type is different so the
// debugger can distinguish them
TYnullptr = 0x1C,
TYnptr = 0x1D, // data segment relative pointer
TYref = 0x24, // reference to another type
TYvoid = 0x25,
TYstruct = 0x26, // watch tyaggregate()
TYarray = 0x27, // watch tyaggregate()
TYnfunc = 0x28, // near C func
TYnpfunc = 0x2A, // near Cpp func
TYnsfunc = 0x2C, // near stdcall func
TYifunc = 0x2E, // interrupt func
TYptr = 0x33, // generic pointer type
TYmfunc = 0x37, // NT C++ member func
TYjfunc = 0x38, // LINKd D function
TYhfunc = 0x39, // C function with hidden parameter
TYnref = 0x3A, // near reference
TYcent = 0x3C, // 128 bit signed integer
TYucent = 0x3D, // 128 bit unsigned integer
#if TARGET_SEGMENTED
TYsptr = 0x1E, // stack segment relative pointer
TYcptr = 0x1F, // code segment relative pointer
TYf16ptr = 0x20, // special OS/2 far16 pointer
TYfptr = 0x21, // far pointer (has segment and offset)
TYhptr = 0x22, // huge pointer (has segment and offset)
TYvptr = 0x23, // __handle pointer (has segment and offset)
TYffunc = 0x29, // far C func
TYfpfunc = 0x2B, // far Cpp func
TYfsfunc = 0x2D, // far stdcall func
TYf16func = 0x34, // _far16 _pascal function
TYnsysfunc = 0x35, // near __syscall func
TYfsysfunc = 0x36, // far __syscall func
TYfref = 0x3B, // far reference
#endif
#if !MARS
TYmemptr = 0x2F, // pointer to member
TYident = 0x30, // type-argument
TYtemplate = 0x31, // unexpanded class template
TYvtshape = 0x32, // virtual function table
#endif
// SIMD vector types // D type
TYfloat4 = 0x3E, // float[4]
TYdouble2 = 0x3F, // double[2]
TYschar16 = 0x40, // byte[16]
TYuchar16 = 0x41, // ubyte[16]
TYshort8 = 0x42, // short[8]
TYushort8 = 0x43, // ushort[8]
TYlong4 = 0x44, // int[4]
TYulong4 = 0x45, // uint[4]
TYllong2 = 0x46, // long[2]
TYullong2 = 0x47, // ulong[2]
#if MARS
#define TYaarray TYnptr
#define TYdelegate (I64 ? TYcent : TYllong)
#define TYdarray (I64 ? TYucent : TYullong)
#endif
TYMAX = 0x48,
};
#define mTYbasic 0xFF /* bit mask for basic types */
#define tybasic(ty) ((ty) & mTYbasic)
#if TX86
// These change depending on memory model
extern int TYptrdiff, TYsize, TYsize_t;
/* Linkage type */
#define mTYnear 0x0800
#if TARGET_SEGMENTED
#define mTYfar 0x1000
#define mTYcs 0x2000 // in code segment
#endif
#define mTYthread 0x4000
#define mTYLINK 0x7800 // all linkage bits
#define mTYloadds 0x08000
#define mTYexport 0x10000
#define mTYweak 0x00000
#define mTYimport 0x20000
#define mTYnaked 0x40000
#define mTYMOD 0x78000 // all modifier bits
#else
#define TYTARG 0x11
#include "TGty.h" /* Target types */
#endif
/* Modifiers to basic types */
#ifdef JHANDLE
#define mTYarrayhandle 0x200
#else
#define mTYarrayhandle 0x0
#endif
#define mTYconst 0x100
#define mTYvolatile 0x200
#define mTYrestrict 0 // BUG: add for C99
#define mTYmutable 0 // need to add support
#define mTYunaligned 0 // non-zero for PowerPC
#define mTYimmutable 0x00080000 // immutable data
#define mTYshared 0x00100000 // shared data
#define mTYnothrow 0x00200000 // nothrow function
#if !MARS
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
#define mTYnoret 0x01000000 // function has no return
#define mTYtransu 0x01000000 // transparent union
#else
#define mTYfar16 0x01000000
#endif
#define mTYstdcall 0x02000000
#define mTYfastcall 0x04000000
#define mTYinterrupt 0x08000000
#define mTYcdecl 0x10000000
#define mTYpascal 0x20000000
#define mTYsyscall 0x40000000
#define mTYjava 0x80000000
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
#define mTYTFF 0xFE000000
#else
#define mTYTFF 0xFF000000
#endif
#endif
/* Flags in tytab[] array */
extern unsigned tytab[];
#define TYFLptr 1
#define TYFLreal 2
#define TYFLintegral 4
#define TYFLcomplex 8
#define TYFLimaginary 0x10
#define TYFLuns 0x20
#define TYFLmptr 0x40
#define TYFLfv 0x80 /* TYfptr || TYvptr */
#if TX86
#define TYFLfarfunc 0x100
#define TYFLpascal 0x200 // callee cleans up stack
#define TYFLrevparam 0x400 // function parameters are reversed
#define TYFLxmmreg 0x10000 // can be put in XMM register
#else
#define TYFLcallstkc 0x100 // callee cleans up stack
#define TYFLrevparam 0x200 // function parameters are reversed
#endif
#define TYFLnullptr 0x800
#define TYFLshort 0x1000
#define TYFLaggregate 0x2000
#define TYFLfunc 0x4000
#define TYFLref 0x8000
/* Groupings of types */
#define tyintegral(ty) (tytab[(ty) & 0xFF] & TYFLintegral)
#define tyarithmetic(ty) (tytab[(ty) & 0xFF] & (TYFLintegral | TYFLreal | TYFLimaginary | TYFLcomplex))
#define tyaggregate(ty) (tytab[(ty) & 0xFF] & TYFLaggregate)
#define tyscalar(ty) (tytab[(ty) & 0xFF] & (TYFLintegral | TYFLreal | TYFLimaginary | TYFLcomplex | TYFLptr | TYFLmptr | TYFLnullptr))
#define tyfloating(ty) (tytab[(ty) & 0xFF] & (TYFLreal | TYFLimaginary | TYFLcomplex))
#define tyimaginary(ty) (tytab[(ty) & 0xFF] & TYFLimaginary)
#define tycomplex(ty) (tytab[(ty) & 0xFF] & TYFLcomplex)
#define tyreal(ty) (tytab[(ty) & 0xFF] & TYFLreal)
// Fits into 64 bit register
#define ty64reg(ty) (tytab[(ty) & 0xFF] & (TYFLintegral | TYFLptr) && tysize(ty) <= NPTRSIZE)
// Can go in XMM floating point register
#define tyxmmreg(ty) (tytab[(ty) & 0xFF] & TYFLxmmreg)
// Is a vector type
#define tyvector(ty) (tybasic(ty) >= TYfloat4 && tybasic(ty) <= TYullong2)
#ifndef tyshort
/* Types that are chars or shorts */
#define tyshort(ty) (tytab[(ty) & 0xFF] & TYFLshort)
#endif
/* Detect TYlong or TYulong */
#ifndef tylong
#define tylong(ty) (tybasic(ty) == TYlong || tybasic(ty) == TYulong)
#endif
/* Use to detect a pointer type */
#ifndef typtr
#define typtr(ty) (tytab[(ty) & 0xFF] & TYFLptr)
#endif
/* Use to detect a reference type */
#ifndef tyref
#define tyref(ty) (tytab[(ty) & 0xFF] & TYFLref)
#endif
/* Use to detect a pointer type or a member pointer */
#ifndef tymptr
#define tymptr(ty) (tytab[(ty) & 0xFF] & (TYFLptr | TYFLmptr))
#endif
// Use to detect a nullptr type or a member pointer
#ifndef tynullptr
#define tynullptr(ty) (tytab[(ty) & 0xFF] & TYFLnullptr)
#endif
/* Detect TYfptr or TYvptr */
#ifndef tyfv
#define tyfv(ty) (tytab[(ty) & 0xFF] & TYFLfv)
#endif
/* Array to give the size in bytes of a type, -1 means error */
extern signed char tysize[];
extern signed char tyalignsize[];
// Give size of type
#define tysize(ty) tysize[(ty) & 0xFF]
#define tyalignsize(ty) tyalignsize[(ty) & 0xFF]
/* All data types that fit in exactly 8 bits */
#ifndef tybyte
#define tybyte(ty) (tysize(ty) == 1)
#endif
/* Types that fit into a single machine register */
#ifndef tyreg
#define tyreg(ty) (tysize(ty) <= REGSIZE)
#endif
/* Detect function type */
#ifndef tyfunc
#define tyfunc(ty) (tytab[(ty) & 0xFF] & TYFLfunc)
#endif
/* Detect function type where parameters are pushed left to right */
#ifndef tyrevfunc
#define tyrevfunc(ty) (tytab[(ty) & 0xFF] & TYFLrevparam)
#endif
/* Detect unsigned types */
#ifndef tyuns
#define tyuns(ty) (tytab[(ty) & 0xFF] & (TYFLuns | TYFLptr))
#endif
/* Target dependent info */
#if TX86
#define TYoffset TYuint /* offset to an address */
/* Detect cpp function type (callee cleans up stack) */
#define typfunc(ty) (tytab[(ty) & 0xFF] & TYFLpascal)
#else
/* Detect cpp function type (callee cleans up stack) */
#ifndef typfunc
#define typfunc(ty) (tytab[(ty) & 0xFF] & TYFLcallstkc)
#endif
#endif
/* Array to convert a type to its unsigned equivalent */
extern const tym_t tytouns[];
#ifndef touns
#define touns(ty) (tytouns[(ty) & 0xFF])
#endif
/* Determine if TYffunc or TYfpfunc (a far function) */
#ifndef tyfarfunc
#define tyfarfunc(ty) (tytab[(ty) & 0xFF] & TYFLfarfunc)
#endif
// Determine if parameter can go in register for TYjfunc
#ifndef tyjparam
#define tyjparam(ty) (tysize(ty) <= NPTRSIZE && !tyfloating(ty) && tybasic(ty) != TYstruct && tybasic(ty) != TYarray)
#endif
/* Determine relaxed type */
#ifndef tyrelax
#define tyrelax(ty) (_tyrelax[tybasic(ty)])
#endif
/* Array to give the 'relaxed' type for relaxed type checking */
extern unsigned char _tyrelax[];
#define type_relax (config.flags3 & CFG3relax) // !=0 if relaxed type checking
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
#define type_semirelax (config.flags3 & CFG3semirelax) // !=0 if semi-relaxed type checking
#else
#define type_semirelax type_relax
#endif
/* Determine functionally equivalent type */
extern unsigned char tyequiv[];
/* Give an ascii string for a type */
extern const char *tystring[];
#if TX86
/* Debugger value for type */
extern unsigned char dttab[];
extern unsigned short dttab4[];
#endif
#endif /* TY_H */

1480
backend/type.c Normal file

File diff suppressed because it is too large Load Diff

209
backend/type.h Normal file
View File

@@ -0,0 +1,209 @@
// Copyright (C) 1985-1994 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
#if __SC__
#pragma once
#endif
#ifndef __TYPE_H
#define __TYPE_H
#include <limits.h>
typedef unsigned char mangle_t;
#define mTYman_c 1 // C mangling
#define mTYman_cpp 2 // C++ mangling
#define mTYman_pas 3 // Pascal mangling
#define mTYman_for 4 // FORTRAN mangling
#define mTYman_sys 5 // _syscall mangling
#define mTYman_std 6 // _stdcall mangling
#define mTYman_d 7 // D mangling
/*********************************
* Data type.
*/
#define list_type(tl) ((struct TYPE *) list_ptr(tl))
struct TYPE
{
#ifdef DEBUG
unsigned short id;
#define IDtype 0x1234
#define type_debug(t) assert((t)->id == IDtype)
#else
#define type_debug(t)
#endif
tym_t Tty; /* mask (TYxxx) */
unsigned short Tflags; // TFxxxxx
mangle_t Tmangle; // name mangling
// Return name mangling of type
#define type_mangle(t) ((t)->Tmangle)
unsigned Tcount; // # pointing to this type
struct TYPE *Tnext; // next in list
// TYenum: gives base type
union
{
targ_size_t Tdim; // TYarray: # of elements in array
struct elem *Tel; // TFvla: gives dimension (NULL if '*')
struct PARAM *Tparamtypes; // TYfunc, TYtemplate: types of function parameters
struct Classsym *Ttag; // TYstruct,TYmemptr: tag symbol
// TYenum,TYvtshape: tag symbol
char *Tident; // TYident: identifier
#if SCPP
struct TYPE *Talternate; // typtr: type of parameter before converting
#endif
#if MARS
struct TYPE *Tkey; // typtr: key type for associative arrays
#endif
};
list_t Texcspec; // tyfunc(): list of types of exception specification
#if 0
unsigned short Tstabidx; // Index into stab types
#endif
#if SOURCE_4TYPES
Srcpos Tsrcpos; /* position of type definition */
#endif
#if HTOD
Symbol *Ttypedef; // if this type came from a typedef, this is
// the typedef symbol
#endif
};
typedef struct TYPETEMP
{ struct TYPE Ttype;
/* Tsym should really be part of a derived class, as we only
allocate room for it if TYtemplate
*/
Symbol *Tsym; // primary class template symbol
} typetemp_t;
/* Values for Tflags: */
#define TFprototype 1 /* if this function is prototyped */
#define TFfixed 2 /* if prototype has a fixed # of parameters */
#define TFforward 8 // TYstruct: if forward reference of tag name
#define TFsizeunknown 0x10 // TYstruct,TYarray: if size of type is unknown
// TYmptr: the Stag is TYident type
#define TFfuncret 0x20 // C++,tyfunc(): overload based on function return value
#define TFfuncparam 0x20 // TYarray: top level function parameter
#define TFstatic 0x40 // TYarray: static dimension
#define TFvla 0x80 // TYarray: variable length array
#define TFemptyexc 0x100 // tyfunc(): empty exception specification
// C
#define TFgenerated 4 // if we generated the prototype ourselves
// CPP
#define TFdependent 4 // template dependent type
#if DEHYDRATE
#define TFhydrated 0x20 // type data already hydrated
#endif
/* Return !=0 if function type has a variable number of arguments */
#define variadic(t) (((t)->Tflags & (TFprototype | TFfixed)) == TFprototype)
/* Data */
typedef type *typep_t;
extern typep_t tstypes[TYMAX];
extern typep_t tsptr2types[TYMAX];
#define tsbool tstypes[TYbool]
#define tschar tstypes[TYchar]
#define tsschar tstypes[TYschar]
#define tsuchar tstypes[TYuchar]
#define tschar16 tstypes[TYchar16]
#define tsshort tstypes[TYshort]
#define tsushort tstypes[TYushort]
#define tswchar_t tstypes[TYwchar_t]
#define tsint tstypes[TYint]
#define tsuns tstypes[TYuint]
#define tslong tstypes[TYlong]
#define tsulong tstypes[TYulong]
#define tsdchar tstypes[TYdchar]
#define tsllong tstypes[TYllong]
#define tsullong tstypes[TYullong]
#define tsfloat tstypes[TYfloat]
#define tsdouble tstypes[TYdouble]
#define tsreal64 tstypes[TYdouble_alias]
#define tsldouble tstypes[TYldouble]
#define tsvoid tstypes[TYvoid]
#define tsifloat tstypes[TYifloat]
#define tsidouble tstypes[TYidouble]
#define tsildouble tstypes[TYildouble]
#define tscfloat tstypes[TYcfloat]
#define tscdouble tstypes[TYcdouble]
#define tscldouble tstypes[TYcldouble]
#define tsnullptr tstypes[TYnullptr]
extern typep_t tslogical;
extern typep_t chartype;
extern typep_t tsclib;
extern typep_t tsdlib;
extern typep_t tspvoid,tspcvoid;
extern typep_t tsptrdiff, tssize;
extern typep_t tstrace;
#define tserr tsint /* error type */
// Return !=0 if type is a struct, class or union
#define type_struct(t) (tybasic((t)->Tty) == TYstruct)
/* Functions */
void type_print(type *t);
void type_free(type *);
void type_init(void);
void type_term(void);
type *type_copy(type *);
elem *type_vla_fix(type **pt);
type *type_setdim(type **,targ_size_t);
type *type_setdependent(type *t);
int type_isdependent(type *t);
type *type_copy(type *);
void type_hydrate(type **);
void type_dehydrate(type **);
targ_size_t type_size(type *);
unsigned type_alignsize(type *);
targ_size_t type_paramsize(type *t);
type *type_alloc(tym_t);
type *type_alloc_template(symbol *s);
type *type_allocn(tym_t,type *tn);
type *type_allocmemptr(Classsym *stag,type *tn);
type *type_fake(tym_t);
type *type_setty(type **,long);
type *type_settype(type **pt, type *t);
type *type_setmangle(type **pt,mangle_t mangle);
type *type_setcv(type **pt,tym_t cv);
int type_embed(type *t,type *u);
int type_isvla(type *t);
int type_jparam(type *t);
param_t *param_calloc(void);
param_t *param_append_type(param_t **,type *);
void param_free_l(param_t *);
void param_free(param_t **);
symbol *param_search(const char *name, param_t **pp);
void param_hydrate(param_t **);
void param_dehydrate(param_t **);
int typematch(type *t1, type *t2, int relax);
#endif

235
backend/var.c Normal file
View File

@@ -0,0 +1,235 @@
// Copyright (C) 1985-1998 by Symantec
// Copyright (C) 2000-2010 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
* This source file is made available for personal use
* only. The license is in /dmd/src/dmd/backendlicense.txt
* or /dm/src/dmd/backendlicense.txt
* For any other uses, please contact Digital Mars.
*/
/* Global variables for PARSER */
#include <stdio.h>
#include <time.h>
#include "cc.h"
#include "global.h"
#include "oper.h"
#include "type.h"
#include "go.h"
#include "ty.h"
#include "optab.c"
#include "tytab.c"
#if __SC__ && _MSDOS
#if __INTSIZE == 4
unsigned __cdecl _stack = 100000; // set default stack size
#else
unsigned __cdecl _stack = 60000; // set default stack size
#endif
#endif
/* Global flags:
*/
char PARSER; // indicate we're in the parser
char OPTIMIZER; // indicate we're in the optimizer
int structalign; /* alignment for members of structures */
char dbcs; // current double byte character set
int TYptrdiff = TYint;
int TYsize = TYuint;
int TYsize_t = TYuint;
#ifdef DEBUG
char debuga,debugb,debugc,debugd,debuge,debugf,debugr,debugs,debugt,debugu,debugw,debugx,debugy;
#endif
#if !MARS
linkage_t linkage;
int linkage_spec = 0; /* using the default */
/* Function types */
/* LINK_MAXDIM = C,C++,Pascal,FORTRAN,syscall,stdcall,Jupiter */
#if MEMMODELS == 1
tym_t functypetab[LINK_MAXDIM] =
{
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
TYnfunc,
TYnpfunc,
TYnpfunc,
TYnfunc,
#endif
};
#else
tym_t functypetab[LINK_MAXDIM][MEMMODELS] =
{
TYnfunc, TYffunc, TYnfunc, TYffunc, TYffunc,
#if VBTABLES
TYnfunc, TYffunc, TYnfunc, TYffunc, TYffunc,
#else
TYnpfunc, TYfpfunc, TYnpfunc, TYfpfunc, TYfpfunc,
#endif
TYnpfunc, TYfpfunc, TYnpfunc, TYfpfunc, TYfpfunc,
TYnpfunc, TYfpfunc, TYnpfunc, TYfpfunc, TYfpfunc,
TYnfunc, TYffunc, TYnfunc, TYffunc, TYffunc,
TYnsfunc, TYfsfunc, TYnsfunc, TYfsfunc, TYfsfunc,
TYjfunc, TYfpfunc, TYnpfunc, TYfpfunc, TYfpfunc,
};
#endif
/* Function mangling */
/* LINK_MAXDIM = C,C++,Pascal,FORTRAN,syscall,stdcall */
mangle_t funcmangletab[LINK_MAXDIM] =
{
mTYman_c,
mTYman_cpp,
mTYman_pas,
mTYman_for,
mTYman_sys,
mTYman_std,
mTYman_d,
};
/* Name mangling for global variables */
mangle_t varmangletab[LINK_MAXDIM] =
{
mTYman_c,
#if NEWMANGLE
mTYman_cpp,
#else
mTYman_c,
#endif
mTYman_pas,mTYman_for,mTYman_sys,mTYman_std,mTYman_d
};
#endif
targ_size_t dsout = 0; /* # of bytes actually output to data */
/* segment, used to pad for alignment */
/* File variables: */
char *argv0; // argv[0] (program name)
FILE *fdep = NULL; // dependency file stream pointer
FILE *flst = NULL; // list file stream pointer
FILE *fin = NULL; // input file
#if SPP
FILE *fout;
#endif
#if HTOD
char *fdmodulename = NULL;
FILE *fdmodule = NULL;
#endif
char *foutdir = NULL, // directory to place output files in
*finname = NULL,
*foutname = NULL,
*fsymname = NULL,
*fphreadname = NULL,
*ftdbname = NULL,
*fdepname = NULL,
*flstname = NULL; /* the filename strings */
list_t pathlist; /* include paths */
list_t headers; /* pre-include files */
/* Data from lexical analyzer: */
unsigned idhash = 0; // hash value of identifier
int xc = ' '; // character last read
/* Data for pragma processor:
*/
int colnumber = 0; /* current column number */
/* Other variables: */
int level = 0; /* declaration level */
/* 0: top level */
/* 1: function parameter declarations */
/* 2: function local declarations */
/* 3+: compound statement decls */
param_t *paramlst = NULL; /* function parameter list */
tym_t pointertype = TYnptr; /* default data pointer type */
/************************
* Bit masks
*/
const unsigned mask[32] =
{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,0x8000,
0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000,0x800000,
0x1000000,0x2000000,0x4000000,0x8000000,
0x10000000,0x20000000,0x40000000,0x80000000};
#if 0
const unsigned long maskl[32] =
{1,2,4,8,0x10,0x20,0x40,0x80,
0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000,0x8000,
0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000,0x800000,
0x1000000,0x2000000,0x4000000,0x8000000,
0x10000000,0x20000000,0x40000000,0x80000000};
#endif
/* From util.c */
/*****************************
* SCxxxx types.
*/
#if !SPP
char sytab[SCMAX] =
{
#define X(a,b) b,
ENUMSCMAC
#undef X
};
#endif /* !SPP */
volatile int controlc_saw; /* a control C was seen */
symtab_t globsym; /* global symbol table */
Pstate pstate; // parser state
Cstate cstate; // compiler state
/* From go.c */
mftype mfoptim = 0; // mask of optimizations to perform
unsigned changes; // # of optimizations performed
struct DN *defnod = NULL; // array of definition elems
elem **expnod = NULL; /* array of expression elems */
block **expblk = NULL; /* parallel array of block pointers */
unsigned
maxblks = 0, /* array max for all block stuff */
/* dfoblks <= numblks <= maxblks */
numcse, /* number of common subexpressions */
deftop = 0, /* # of entries in defnod[] */
exptop = 0; /* top of expnod[] */
vec_t defkill = NULL, /* vector of AEs killed by an ambiguous */
/* definition */
starkill = NULL, /* vector of AEs killed by a definition */
/* of something that somebody could be */
/* pointing to */
vptrkill = NULL; /* vector of AEs killed by an access */
/* to a vptr */
/* From debug.c */
#if DEBUG
const char *regstring[32] = {"AX","CX","DX","BX","SP","BP","SI","DI",
"R8","R9","R10","R11","R12","R13","R14","R15",
"XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7",
"ES","PSW","STACK","ST0","ST01","NOREG","RMload","RMstore"};
#endif
/* From nwc.c */
type *chartype; /* default 'char' type */

314
backend/xmm.h Normal file
View File

@@ -0,0 +1,314 @@
// XMM opcodes
enum
{
ADDSS = 0xF30F58,
ADDSD = 0xF20F58,
ADDPS = 0x000F58,
ADDPD = 0x660F58,
PADDB = 0x660FFC,
PADDW = 0x660FFD,
PADDD = 0x660FFE,
PADDQ = 0x660FD4,
SUBSS = 0xF30F5C,
SUBSD = 0xF20F5C,
SUBPS = 0x000F5C,
SUBPD = 0x660F5C,
PSUBB = 0x660FF8,
PSUBW = 0x660FF9,
PSUBD = 0x660FFA,
PSUBQ = 0x660FFB,
MULSS = 0xF30F59,
MULSD = 0xF20F59,
MULPS = 0x000F59,
MULPD = 0x660F59,
PMULLW = 0x660FD5,
DIVSS = 0xF30F5E,
DIVSD = 0xF20F5E,
DIVPS = 0x000F5E,
DIVPD = 0x660F5E,
PAND = 0x660FDB,
POR = 0x660FEB,
UCOMISS = 0x000F2E,
UCOMISD = 0x660F2E,
XORPS = 0x000F57,
XORPD = 0x660F57,
// Use STO and LOD instead of MOV to distinguish the direction
STOSS = 0xF30F11, // MOVSS
STOSD = 0xF20F11,
STOAPS = 0x000F29,
STOAPD = 0x660F29,
STODQA = 0x660F7F,
STOD = 0x660F7E,
STOQ = 0x660FD6,
LODSS = 0xF30F10, // MOVSS
LODSD = 0xF20F10,
LODAPS = 0x000F28,
LODAPD = 0x660F28,
LODDQA = 0x660F6F,
LODD = 0x660F6E,
LODQ = 0xF30F7E,
LODDQU = 0xF30F6F,
STODQU = 0xF30F7F,
MOVDQ2Q = 0xF20FD6,
MOVHLPS = 0x0F12,
LODHPD = 0x660F16,
STOHPD = 0x660F17,
LODHPS = 0x0F16,
STOHPS = 0x0F17,
MOVLHPS = 0x0F16,
LODLPD = 0x660F12,
STOLPD = 0x660F13,
LODLPS = 0x0F12,
STOLPS = 0x0F13,
MOVMSKPD = 0x660F50,
MOVMSKPS = 0x0F50,
MOVNTDQ = 0x660FE7,
MOVNTI = 0x0FC3,
MOVNTPD = 0x660F2B,
MOVNTPS = 0x0F2B,
MOVNTQ = 0x0FE7,
MOVQ2DQ = 0xF30FD6,
LODUPD = 0x660F10,
STOUPD = 0x660F11,
LODUPS = 0x0F10,
STOUPS = 0x0F11,
PACKSSDW = 0x660F6B,
PACKSSWB = 0x660F63,
PACKUSWB = 0x660F67,
PADDSB = 0x660FEC,
PADDSW = 0x660FED,
PADDUSB = 0x660FDC,
PADDUSW = 0x660FDD,
PANDN = 0x660FDF,
PCMPEQB = 0x660F74,
PCMPEQD = 0x660F76,
PCMPEQW = 0x660F75,
PCMPGTB = 0x660F64,
PCMPGTD = 0x660F66,
PCMPGTW = 0x660F65,
PMADDWD = 0x660FF5,
PSLLW = 0x660FF1,
PSLLD = 0x660FF2,
PSLLQ = 0x660FF3,
PSRAW = 0x660FE1,
PSRAD = 0x660FE2,
PSRLW = 0x660FD1,
PSRLD = 0x660FD2,
PSRLQ = 0x660FD3,
PSUBSB = 0x660FE8,
PSUBSW = 0x660FE9,
PSUBUSB = 0x660FD8,
PSUBUSW = 0x660FD9,
PUNPCKHBW = 0x660F68,
PUNPCKHDQ = 0x660F6A,
PUNPCKHWD = 0x660F69,
PUNPCKLBW = 0x660F60,
PUNPCKLDQ = 0x660F62,
PUNPCKLWD = 0x660F61,
PXOR = 0x660FEF,
ANDPD = 0x660F54,
ANDPS = 0x0F54,
ANDNPD = 0x660F55,
ANDNPS = 0x0F55,
CMPPS = 0x0FC2,
CMPPD = 0x660FC2,
CMPSD = 0xF20FC2,
CMPSS = 0xF30FC2,
COMISD = 0x660F2F,
COMISS = 0x0F2F,
CVTDQ2PD = 0xF30FE6,
CVTDQ2PS = 0x0F5B,
CVTPD2DQ = 0xF20FE6,
CVTPD2PI = 0x660F2D,
CVTPD2PS = 0x660F5A,
CVTPI2PD = 0x660F2A,
CVTPI2PS = 0x0F2A,
CVTPS2DQ = 0x660F5B,
CVTPS2PD = 0x0F5A,
CVTPS2PI = 0x0F2D,
CVTSD2SI = 0xF20F2D,
CVTSD2SS = 0xF20F5A,
CVTSI2SD = 0xF20F2A,
CVTSI2SS = 0xF30F2A,
CVTSS2SD = 0xF30F5A,
CVTSS2SI = 0xF30F2D,
CVTTPD2PI = 0x660F2C,
CVTTPD2DQ = 0x660FE6,
CVTTPS2DQ = 0xF30F5B,
CVTTPS2PI = 0x0F2C,
CVTTSD2SI = 0xF20F2C,
CVTTSS2SI = 0xF30F2C,
MASKMOVDQU = 0x660FF7,
MASKMOVQ = 0x0FF7,
MAXPD = 0x660F5F,
MAXPS = 0x0F5F,
MAXSD = 0xF20F5F,
MAXSS = 0xF30F5F,
MINPD = 0x660F5D,
MINPS = 0x0F5D,
MINSD = 0xF20F5D,
MINSS = 0xF30F5D,
ORPD = 0x660F56,
ORPS = 0x0F56,
PAVGB = 0x660FE0,
PAVGW = 0x660FE3,
PMAXSW = 0x660FEE,
PINSRW = 0x660FC4,
PMAXUB = 0x660FDE,
PMINSW = 0x660FEA,
PMINUB = 0x660FDA,
PMOVMSKB = 0x660FD7,
PMULHUW = 0x660FE4,
PMULHW = 0x660FE5,
PMULUDQ = 0x660FF4,
PSADBW = 0x660FF6,
PUNPCKHQDQ = 0x660F6D,
PUNPCKLQDQ = 0x660F6C,
RCPPS = 0x0F53,
RCPSS = 0xF30F53,
RSQRTPS = 0x0F52,
RSQRTSS = 0xF30F52,
SQRTPD = 0x660F51,
SHUFPD = 0x660FC6,
SHUFPS = 0x0FC6,
SQRTPS = 0x0F51,
SQRTSD = 0xF20F51,
SQRTSS = 0xF30F51,
UNPCKHPD = 0x660F15,
UNPCKHPS = 0x0F15,
UNPCKLPD = 0x660F14,
UNPCKLPS = 0x0F14,
PSHUFD = 0x660F70,
PSHUFHW = 0xF30F70,
PSHUFLW = 0xF20F70,
PSHUFW = 0x0F70,
PSLLDQ = 0x660F73,
PSRLDQ = 0x660F73,
PREFETCH = 0x0F18,
// SSE3 Pentium 4 (Prescott)
ADDSUBPD = 0x660FD0,
ADDSUBPS = 0xF20FD0,
HADDPD = 0x660F7C,
HADDPS = 0xF20F7C,
HSUBPD = 0x660F7D,
HSUBPS = 0xF20F7D,
MOVDDUP = 0xF20F12,
MOVSHDUP = 0xF30F16,
MOVSLDUP = 0xF30F12,
LDDQU = 0xF20FF0,
MONITOR = 0x0F01C8,
MWAIT = 0x0F01C9,
// SSSE3
PALIGNR = 0x660F3A0F,
PHADDD = 0x660F3802,
PHADDW = 0x660F3801,
PHADDSW = 0x660F3803,
PABSB = 0x660F381C,
PABSD = 0x660F381E,
PABSW = 0x660F381D,
PSIGNB = 0x660F3808,
PSIGND = 0x660F380A,
PSIGNW = 0x660F3809,
PSHUFB = 0x660F3800,
PMADDUBSW = 0x660F3804,
PMULHRSW = 0x660F380B,
PHSUBD = 0x660F3806,
PHSUBW = 0x660F3805,
PHSUBSW = 0x660F3807,
// SSE4.1
BLENDPD = 0x660F3A0D,
BLENDPS = 0x660F3A0C,
BLENDVPD = 0x660F3815,
BLENDVPS = 0x660F3814,
DPPD = 0x660F3A41,
DPPS = 0x660F3A40,
EXTRACTPS = 0x660F3A17,
INSERTPS = 0x660F3A21,
MPSADBW = 0x660F3A42,
PBLENDVB = 0x660F3810,
PBLENDW = 0x660F3A0E,
PEXTRD = 0x660F3A16,
PEXTRQ = 0x660F3A16,
PINSRB = 0x660F3A20,
PINSRD = 0x660F3A22,
PINSRQ = 0x660F3A22,
MOVNTDQA = 0x660F382A,
PACKUSDW = 0x660F382B,
PCMPEQQ = 0x660F3829,
PEXTRB = 0x660F3A14,
PHMINPOSUW = 0x660F3841,
PMAXSB = 0x660F383C,
PMAXSD = 0x660F383D,
PMAXUD = 0x660F383F,
PMAXUW = 0x660F383E,
PMINSB = 0x660F3838,
PMINSD = 0x660F3839,
PMINUD = 0x660F383B,
PMINUW = 0x660F383A,
PMOVSXBW = 0x660F3820,
PMOVSXBD = 0x660F3821,
PMOVSXBQ = 0x660F3822,
PMOVSXWD = 0x660F3823,
PMOVSXWQ = 0x660F3824,
PMOVSXDQ = 0x660F3825,
PMOVZXBW = 0x660F3830,
PMOVZXBD = 0x660F3831,
PMOVZXBQ = 0x660F3832,
PMOVZXWD = 0x660F3833,
PMOVZXWQ = 0x660F3834,
PMOVZXDQ = 0x660F3835,
PMULDQ = 0x660F3828,
PMULLD = 0x660F3840,
PTEST = 0x660F3817,
ROUNDPD = 0x660F3A09,
ROUNDPS = 0x660F3A08,
ROUNDSD = 0x660F3A0B,
ROUNDSS = 0x660F3A0A,
// SSE4.2
PCMPESTRI = 0x660F3A61,
PCMPESTRM = 0x660F3A60,
PCMPISTRI = 0x660F3A63,
PCMPISTRM = 0x660F3A62,
PCMPGTQ = 0x660F3837,
// CRC32
// SSE4a (AMD only)
// EXTRQ,INSERTQ,MOVNTSD,MOVNTSS
// POPCNT and LZCNT (have their own CPUID bits)
POPCNT = 0xF30FB8,
// LZCNT
// AVX
XGETBV = 0x0F01D0,
XSETBV = 0x0F01D1,
// AES
AESENC = 0x660F38DC,
AESENCLAST = 0x660F38DD,
AESDEC = 0x660F38DE,
AESDECLAST = 0x660F38DF,
AESIMC = 0x660F38DB,
AESKEYGENASSIST = 0x660F3ADF,
};

42
backendlicense.txt Normal file
View File

@@ -0,0 +1,42 @@
The Software is not generally available software. It has not undergone
testing and may contain errors. The Software was not designed to operate
after December 31, 1999. It may be incomplete and it may not function
properly. No support or maintenance is provided with this Software. Do
not install or distribute the Software if
you are not accustomed to using or distributing experimental software.
Do not use this software for life critical applications, or applications
that could cause significant harm or property damage.
Digital Mars licenses the Software to you on an "AS IS" basis, without
warranty of any kind. DIGITAL MARS AND SYMANTEC HEREBY EXPRESSLY DISCLAIM
ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY,
NONINFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. You are solely
responsible for determining the appropriateness of using this Software and
assume all risks associated with the use of this Software, including but not
limited to the risks of program errors, damage
to or loss of data, programs or equipment, unavailability or interruption of
operations and third party claims. You agree to defend, indemnify and hold
Digital Mars and Symantec, its subsidiaries, affiliates, directors, officers,
employees and agents harmless from all claims or demands made against them
(and any related losses, damages, expenses
and costs) arising out of your use of the Software. DIGITAL MARS AND SYMANTEC
WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, INCIDENTAL, OR
INDIRECT DAMAGES OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES (INCLUDING
LOST PROFITS OR SAVINGS), EVEN IF DIGITAL MARS OR SYMANTEC HAS BEEN ADVISED
OF THE POSSIBILITY OF SUCH DAMAGES.
Digital Mars and Symantec will not be liable for the loss of, or damage to,
your records or data, the records or
data of any third party, or any damages claimed by you based on a third party
claim.
If you send any messages to Digital Mars, on either the Digital Mars
newsgroups, the Digital Mars mailing list, or via email, you agree not
to make any claims of intellectual
property rights over the contents of those messages.
The Software is copyrighted and comes with a single user license,
and may not be redistributed. If you wish to obtain a redistribution license,
please contact Digital Mars.

234
builtin.c Normal file
View File

@@ -0,0 +1,234 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include <math.h>
#if __FreeBSD__
extern "C"
{
long double sinl(long double);
long double cosl(long double);
long double tanl(long double);
long double sqrtl(long double);
}
#endif
#include "mars.h"
#include "declaration.h"
#include "attrib.h"
#include "expression.h"
#include "scope.h"
#include "mtype.h"
#include "aggregate.h"
#include "identifier.h"
#include "id.h"
#include "module.h"
#if DMDV2
/**********************************
* Determine if function is a builtin one that we can
* evaluate at compile time.
*/
enum BUILTIN FuncDeclaration::isBuiltin()
{
static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real)
static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real)
static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint)
static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint)
static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong)
static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint)
static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real)
static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real)
//printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin);
if (builtin == BUILTINunknown)
{
builtin = BUILTINnot;
if (parent && parent->isModule())
{
// If it's in the std.math package
if (parent->ident == Id::math &&
parent->parent && (parent->parent->ident == Id::std || parent->parent->ident == Id::core) &&
!parent->parent->parent)
{
//printf("deco = %s\n", type->deco);
if (strcmp(type->deco, FeZe) == 0 || strcmp(type->deco, FeZe2) == 0)
{
if (ident == Id::sin)
builtin = BUILTINsin;
else if (ident == Id::cos)
builtin = BUILTINcos;
else if (ident == Id::tan)
builtin = BUILTINtan;
else if (ident == Id::_sqrt)
builtin = BUILTINsqrt;
else if (ident == Id::fabs)
builtin = BUILTINfabs;
else if (ident == Id::expm1)
builtin = BUILTINexpm1;
else if (ident == Id::exp2)
builtin = BUILTINexp2;
//printf("builtin = %d\n", builtin);
}
// if float or double versions
else if (strcmp(type->deco, "FNaNbNfdZd") == 0 ||
strcmp(type->deco, "FNaNbNffZf") == 0)
{
if (ident == Id::_sqrt)
builtin = BUILTINsqrt;
}
else if (strcmp(type->deco, FrealrealZreal) == 0)
{
if (ident == Id::atan2)
builtin = BUILTINatan2;
else if (ident == Id::yl2x)
builtin = BUILTINyl2x;
else if (ident == Id::yl2xp1)
builtin = BUILTINyl2xp1;
}
else if (strcmp(type->deco, FrealZlong) == 0 && ident == Id::rndtol)
builtin = BUILTINrndtol;
}
if (parent->ident == Id::bitop &&
parent->parent && parent->parent->ident == Id::core &&
!parent->parent->parent)
{
//printf("deco = %s\n", type->deco);
if (strcmp(type->deco, FuintZint) == 0 || strcmp(type->deco, FulongZint) == 0)
{
if (ident == Id::bsf)
builtin = BUILTINbsf;
else if (ident == Id::bsr)
builtin = BUILTINbsr;
}
else if (strcmp(type->deco, FuintZuint) == 0)
{
if (ident == Id::bswap)
builtin = BUILTINbswap;
}
}
}
}
return builtin;
}
int eval_bsf(uinteger_t n)
{
n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest
int k = 0;
while( n )
{ ++k;
n >>=1;
}
return k;
}
int eval_bsr(uinteger_t n)
{ int k= 0;
while(n>>=1)
{
++k;
}
return k;
}
uinteger_t eval_bswap(Expression *arg0)
{ uinteger_t n = arg0->toInteger();
#define BYTEMASK 0x00FF00FF00FF00FFLL
#define SHORTMASK 0x0000FFFF0000FFFFLL
#define INTMASK 0x0000FFFF0000FFFFLL
// swap adjacent ubytes
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
// swap adjacent ushorts
n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16);
TY ty = arg0->type->toBasetype()->ty;
// If 64 bits, we need to swap high and low uints
if (ty == Tint64 || ty == Tuns64)
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
return n;
}
/**************************************
* Evaluate builtin function.
* Return result; NULL if cannot evaluate it.
*/
Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments)
{
assert(arguments && arguments->dim);
Expression *arg0 = arguments->tdata()[0];
Expression *e = NULL;
switch (builtin)
{
case BUILTINsin:
if (arg0->op == TOKfloat64)
e = new RealExp(0, sinl(arg0->toReal()), arg0->type);
break;
case BUILTINcos:
if (arg0->op == TOKfloat64)
e = new RealExp(0, cosl(arg0->toReal()), arg0->type);
break;
case BUILTINtan:
if (arg0->op == TOKfloat64)
e = new RealExp(0, tanl(arg0->toReal()), arg0->type);
break;
case BUILTINsqrt:
if (arg0->op == TOKfloat64)
e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type);
break;
case BUILTINfabs:
if (arg0->op == TOKfloat64)
e = new RealExp(0, fabsl(arg0->toReal()), arg0->type);
break;
// These math intrinsics are not yet implemented
case BUILTINatan2:
break;
case BUILTINrndtol:
break;
case BUILTINexpm1:
break;
case BUILTINexp2:
break;
case BUILTINyl2x:
break;
case BUILTINyl2xp1:
break;
case BUILTINbsf:
if (arg0->op == TOKint64)
{ if (arg0->toInteger()==0)
error(loc, "bsf(0) is undefined");
else
e = new IntegerExp(loc, eval_bsf(arg0->toInteger()), Type::tint32);
}
break;
case BUILTINbsr:
if (arg0->op == TOKint64)
{ if (arg0->toInteger()==0)
error(loc, "bsr(0) is undefined");
else
e = new IntegerExp(loc, eval_bsr(arg0->toInteger()), Type::tint32);
}
break;
case BUILTINbswap:
if (arg0->op == TOKint64)
e = new IntegerExp(loc, eval_bswap(arg0), arg0->type);
break;
}
return e;
}
#endif

189
canthrow.c Normal file
View File

@@ -0,0 +1,189 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "mars.h"
#include "init.h"
#include "expression.h"
#include "template.h"
#include "statement.h"
#include "mtype.h"
#include "utf.h"
#include "declaration.h"
#include "aggregate.h"
#include "scope.h"
#include "attrib.h"
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow);
int lambdaCanThrow(Expression *e, void *param);
/********************************************
* Convert from expression to delegate that returns the expression,
* i.e. convert:
* expr
* to:
* t delegate() { return expr; }
*/
struct CanThrow
{
bool can;
bool mustnot;
};
int Expression::canThrow(bool mustNotThrow)
{
CanThrow ct;
ct.can = FALSE;
ct.mustnot = mustNotThrow;
apply(&lambdaCanThrow, &ct);
return ct.can;
}
int lambdaCanThrow(Expression *e, void *param)
{
CanThrow *pct = (CanThrow *)param;
switch (e->op)
{
case TOKdeclaration:
{ DeclarationExp *de = (DeclarationExp *)e;
pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot);
break;
}
case TOKcall:
{ CallExp *ce = (CallExp *)e;
if (global.errors && !ce->e1->type)
break; // error recovery
/* If calling a function or delegate that is typed as nothrow,
* then this expression cannot throw.
* Note that pure functions can throw.
*/
Type *t = ce->e1->type->toBasetype();
if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
;
else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
;
else
{
if (pct->mustnot)
e->error("%s is not nothrow", ce->e1->toChars());
pct->can = TRUE;
}
break;
}
case TOKnew:
{ NewExp *ne = (NewExp *)e;
if (ne->member)
{
// See if constructor call can throw
Type *t = ne->member->type->toBasetype();
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
{
if (pct->mustnot)
e->error("constructor %s is not nothrow", ne->member->toChars());
pct->can = TRUE;
}
}
// regard storage allocation failures as not recoverable
break;
}
case TOKnewanonclass:
assert(0); // should have been lowered by semantic()
break;
default:
break;
}
return pct->can; // stop walking if we determine this expression can throw
}
/**************************************
* Does symbol, when initialized, throw?
* Mirrors logic in Dsymbol_toElem().
*/
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow)
{
AttribDeclaration *ad;
VarDeclaration *vd;
TemplateMixin *tm;
TupleDeclaration *td;
//printf("Dsymbol_toElem() %s\n", s->toChars());
ad = s->isAttribDeclaration();
if (ad)
{
Dsymbols *decl = ad->include(NULL, NULL);
if (decl && decl->dim)
{
for (size_t i = 0; i < decl->dim; i++)
{
s = decl->tdata()[i];
if (Dsymbol_canThrow(s, mustNotThrow))
return 1;
}
}
}
else if ((vd = s->isVarDeclaration()) != NULL)
{
s = s->toAlias();
if (s != vd)
return Dsymbol_canThrow(s, mustNotThrow);
if (vd->storage_class & STCmanifest)
;
else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
;
else
{
if (vd->init)
{ ExpInitializer *ie = vd->init->isExpInitializer();
if (ie && ie->exp->canThrow(mustNotThrow))
return 1;
}
if (vd->edtor && !vd->noscope)
return vd->edtor->canThrow(mustNotThrow);
}
}
else if ((tm = s->isTemplateMixin()) != NULL)
{
//printf("%s\n", tm->toChars());
if (tm->members)
{
for (size_t i = 0; i < tm->members->dim; i++)
{
Dsymbol *sm = tm->members->tdata()[i];
if (Dsymbol_canThrow(sm, mustNotThrow))
return 1;
}
}
}
else if ((td = s->isTupleDeclaration()) != NULL)
{
for (size_t i = 0; i < td->objects->dim; i++)
{ Object *o = td->objects->tdata()[i];
if (o->dyncast() == DYNCAST_EXPRESSION)
{ Expression *eo = (Expression *)o;
if (eo->op == TOKdsymbol)
{ DsymbolExp *se = (DsymbolExp *)eo;
if (Dsymbol_canThrow(se->s, mustNotThrow))
return 1;
}
}
}
}
return 0;
}

2574
cast.c Normal file

File diff suppressed because it is too large Load Diff

1648
class.c Normal file

File diff suppressed because it is too large Load Diff

694
clone.c Normal file
View File

@@ -0,0 +1,694 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "root.h"
#include "aggregate.h"
#include "scope.h"
#include "mtype.h"
#include "declaration.h"
#include "module.h"
#include "id.h"
#include "expression.h"
#include "statement.h"
#include "init.h"
#include "template.h"
/*******************************************
* We need an opAssign for the struct if
* it has a destructor or a postblit.
* We need to generate one if a user-specified one does not exist.
*/
int StructDeclaration::needOpAssign()
{
#define X 0
if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
if (hasIdentityAssign)
goto Ldontneed;
if (dtor || postblit)
goto Lneed;
/* If any of the fields need an opAssign, then we
* need it too.
*/
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
tv = tv->nextOf()->toBasetype();
}
if (tv->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->needOpAssign())
goto Lneed;
}
}
Ldontneed:
if (X) printf("\tdontneed\n");
return 0;
Lneed:
if (X) printf("\tneed\n");
return 1;
#undef X
}
/******************************************
* Build opAssign for struct.
* S* opAssign(S s) { ... }
*
* Note that s will be constructed onto the stack, probably copy-constructed.
* Then, the body is:
* S tmp = *this; // bit copy
* *this = s; // bit copy
* tmp.dtor();
* Instead of running the destructor on s, run it on tmp instead.
*/
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
if (!needOpAssign())
return NULL;
//printf("StructDeclaration::buildOpAssign() %s\n", toChars());
FuncDeclaration *fop = NULL;
Parameters *fparams = new Parameters;
fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
#if STRUCTTHISREF
((TypeFunction *)ftype)->isref = 1;
#endif
fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype);
Expression *e = NULL;
if (postblit)
{ /* Swap:
* tmp = *this; *this = s; tmp.dtor();
*/
//printf("\tswap copy\n");
Identifier *idtmp = Lexer::uniqueId("__tmp");
VarDeclaration *tmp;
AssignExp *ec = NULL;
if (dtor)
{
tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
tmp->noscope = 1;
tmp->storage_class |= STCctfe;
e = new DeclarationExp(0, tmp);
ec = new AssignExp(0,
new VarExp(0, tmp),
#if STRUCTTHISREF
new ThisExp(0)
#else
new PtrExp(0, new ThisExp(0))
#endif
);
ec->op = TOKblit;
e = Expression::combine(e, ec);
}
ec = new AssignExp(0,
#if STRUCTTHISREF
new ThisExp(0),
#else
new PtrExp(0, new ThisExp(0)),
#endif
new IdentifierExp(0, Id::p));
ec->op = TOKblit;
e = Expression::combine(e, ec);
if (dtor)
{
/* Instead of running the destructor on s, run it
* on tmp. This avoids needing to copy tmp back in to s.
*/
Expression *ec2 = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
ec2 = new CallExp(0, ec2);
e = Expression::combine(e, ec2);
}
}
else
{ /* Do memberwise copy
*/
//printf("\tmemberwise copy\n");
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
// this.v = s.v;
AssignExp *ec = new AssignExp(0,
new DotVarExp(0, new ThisExp(0), v, 0),
new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
ec->op = TOKblit;
e = Expression::combine(e, ec);
}
}
Statement *s1 = new ExpStatement(0, e);
/* Add:
* return this;
*/
e = new ThisExp(0);
Statement *s2 = new ReturnStatement(0, e);
fop->fbody = new CompoundStatement(0, s1, s2);
members->push(fop);
fop->addMember(sc, this, 1);
sc = sc->push();
sc->stc = 0;
sc->linkage = LINKd;
fop->semantic(sc);
sc->pop();
//printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
return fop;
}
/*******************************************
* We need an opEquals for the struct if
* any fields has an opEquals.
* Generate one if a user-specified one does not exist.
*/
int StructDeclaration::needOpEquals()
{
#define X 0
if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
if (hasIdentityEquals)
goto Lneed;
/* If any of the fields has an opEquals, then we
* need it too.
*/
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
tv = tv->nextOf()->toBasetype();
}
if (tv->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->needOpEquals())
goto Lneed;
}
}
if (X) printf("\tdontneed\n");
return 0;
Lneed:
if (X) printf("\tneed\n");
return 1;
#undef X
}
/******************************************
* Build opEquals for struct.
* const bool opEquals(const S s) { ... }
*/
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
{
Dsymbol *eq = search_function(this, Id::eq);
if (eq)
{
for (size_t i = 0; i <= 1; i++)
{
Expression *e =
i == 0 ? new NullExp(loc, type->constOf()) // dummy rvalue
: type->constOf()->defaultInit(); // dummy lvalue
Expressions *arguments = new Expressions();
arguments->push(e);
// check identity opEquals exists
FuncDeclaration *fd = eq->isFuncDeclaration();
if (fd)
{ fd = fd->overloadResolve(loc, e, arguments, 1);
if (fd && !(fd->storage_class & STCdisable))
return fd;
}
TemplateDeclaration *td = eq->isTemplateDeclaration();
if (td)
{ fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1);
if (fd && !(fd->storage_class & STCdisable))
return fd;
}
}
return NULL;
}
if (!needOpEquals())
return NULL;
//printf("StructDeclaration::buildOpEquals() %s\n", toChars());
Parameters *parameters = new Parameters;
parameters->push(new Parameter(STCin, type, Id::p, NULL));
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
tf->mod = MODconst;
tf = (TypeFunction *)tf->semantic(loc, sc);
FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);
Expression *e = NULL;
/* Do memberwise compare
*/
//printf("\tmemberwise compare\n");
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
if (v->storage_class & STCref)
assert(0); // what should we do with this?
// this.v == s.v;
EqualExp *ec = new EqualExp(TOKequal, loc,
new DotVarExp(loc, new ThisExp(loc), v, 0),
new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
if (e)
e = new AndAndExp(loc, e, ec);
else
e = ec;
}
if (!e)
e = new IntegerExp(loc, 1, Type::tbool);
fop->fbody = new ReturnStatement(loc, e);
members->push(fop);
fop->addMember(sc, this, 1);
sc = sc->push();
sc->stc = 0;
sc->linkage = LINKd;
fop->semantic(sc);
sc->pop();
//printf("-StructDeclaration::buildOpEquals() %s\n", toChars());
return fop;
}
/******************************************
* Build __xopEquals for TypeInfo_Struct
* bool __xopEquals(in void* p, in void* q) { ... }
*/
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc)
{
if (!search_function(this, Id::eq))
return NULL;
/* static bool__xopEquals(in void* p, in void* q) {
* return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) );
* }
*/
Parameters *parameters = new Parameters;
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL));
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL));
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
tf = (TypeFunction *)tf->semantic(loc, sc);
Identifier *id = Lexer::idPool("__xopEquals");
FuncDeclaration *fop = new FuncDeclaration(loc, 0, id, STCstatic, tf);
Expression *e = new CallExp(0,
new DotIdExp(0,
new PtrExp(0, new CastExp(0,
new IdentifierExp(0, Id::p), type->pointerTo()->constOf())),
Id::eq),
new PtrExp(0, new CastExp(0,
new IdentifierExp(0, Id::q), type->pointerTo()->constOf())));
fop->fbody = new ReturnStatement(loc, e);
size_t index = members->dim;
members->push(fop);
sc = sc->push();
sc->stc = 0;
sc->linkage = LINKd;
unsigned errors = global.startGagging();
fop->semantic(sc);
if (errors == global.gaggedErrors)
{ fop->semantic2(sc);
if (errors == global.gaggedErrors)
{ fop->semantic3(sc);
if (errors == global.gaggedErrors)
fop->addMember(sc, this, 1);
}
}
if (global.endGagging(errors)) // if errors happened
{
members->remove(index);
if (!xerreq)
{
Expression *e = new IdentifierExp(loc, Id::empty);
e = new DotIdExp(loc, e, Id::object);
e = new DotIdExp(loc, e, Lexer::idPool("_xopEquals"));
e = e->semantic(sc);
Dsymbol *s = getDsymbol(e);
FuncDeclaration *fd = s->isFuncDeclaration();
xerreq = fd;
}
fop = xerreq;
}
sc->pop();
return fop;
}
/*******************************************
* Build copy constructor for struct.
* Copy constructors are compiler generated only, and are only
* callable from the compiler. They are not user accessible.
* A copy constructor is:
* void cpctpr(ref const S s) const
* {
* (*cast(S*)&this) = *cast(S*)s;
* (*cast(S*)&this).postBlit();
* }
* This is done so:
* - postBlit() never sees uninitialized data
* - memcpy can be much more efficient than memberwise copy
* - no fields are overlooked
*/
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
{
//printf("StructDeclaration::buildCpCtor() %s\n", toChars());
FuncDeclaration *fcp = NULL;
/* Copy constructor is only necessary if there is a postblit function,
* otherwise the code generator will just do a bit copy.
*/
if (postblit)
{
//printf("generating cpctor\n");
StorageClass stc = postblit->storage_class &
(STCdisable | STCsafe | STCtrusted | STCsystem | STCpure | STCnothrow);
if (stc & (STCsafe | STCtrusted))
stc = stc & ~STCsafe | STCtrusted;
Parameters *fparams = new Parameters;
fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd, stc);
ftype->mod = MODconst;
fcp = new FuncDeclaration(loc, 0, Id::cpctor, stc, ftype);
if (!(fcp->storage_class & STCdisable))
{
// Build *this = p;
Expression *e = new ThisExp(0);
#if !STRUCTTHISREF
e = new PtrExp(0, e);
#endif
AssignExp *ea = new AssignExp(0,
new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())),
new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo()))
);
ea->op = TOKblit;
Statement *s = new ExpStatement(0, ea);
// Build postBlit();
e = new ThisExp(0);
#if !STRUCTTHISREF
e = new PtrExp(0, e);
#endif
e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo()));
e = new DotVarExp(0, e, postblit, 0);
e = new CallExp(0, e);
s = new CompoundStatement(0, s, new ExpStatement(0, e));
fcp->fbody = s;
}
else
fcp->fbody = new ExpStatement(0, (Expression *)NULL);
members->push(fcp);
sc = sc->push();
sc->stc = 0;
sc->linkage = LINKd;
fcp->semantic(sc);
sc->pop();
}
return fcp;
}
/*****************************************
* Create inclusive postblit for struct by aggregating
* all the postblits in postblits[] with the postblits for
* all the members.
* Note the close similarity with AggregateDeclaration::buildDtor(),
* and the ordering changes (runs forward instead of backwards).
*/
#if DMDV2
FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
{
//printf("StructDeclaration::buildPostBlit() %s\n", toChars());
Expression *e = NULL;
StorageClass stc = 0;
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
dim *= ((TypeSArray *)tv)->dim->toInteger();
tv = tv->nextOf()->toBasetype();
}
if (tv->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->postblit)
{
stc |= sd->postblit->storage_class & STCdisable;
if (stc & STCdisable)
{
e = NULL;
break;
}
// this.v
Expression *ex = new ThisExp(0);
ex = new DotVarExp(0, ex, v, 0);
if (dim == 0)
{ // this.v.postblit()
ex = new DotVarExp(0, ex, sd->postblit, 0);
ex = new CallExp(0, ex);
}
else
{
// Typeinfo.postblit(cast(void*)&this.v);
Expression *ea = new AddrExp(0, ex);
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
Expression *et = v->type->getTypeInfo(sc);
et = new DotIdExp(0, et, Id::postblit);
ex = new CallExp(0, et, ea);
}
e = Expression::combine(e, ex); // combine in forward order
}
}
}
/* Build our own "postblit" which executes e
*/
if (e || (stc & STCdisable))
{ //printf("Building __fieldPostBlit()\n");
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit"));
dd->storage_class |= stc;
dd->fbody = new ExpStatement(0, e);
postblits.shift(dd);
members->push(dd);
dd->semantic(sc);
}
switch (postblits.dim)
{
case 0:
return NULL;
case 1:
return postblits.tdata()[0];
default:
e = NULL;
for (size_t i = 0; i < postblits.dim; i++)
{ FuncDeclaration *fd = postblits.tdata()[i];
stc |= fd->storage_class & STCdisable;
if (stc & STCdisable)
{
e = NULL;
break;
}
Expression *ex = new ThisExp(0);
ex = new DotVarExp(0, ex, fd, 0);
ex = new CallExp(0, ex);
e = Expression::combine(e, ex);
}
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__aggrPostBlit"));
dd->storage_class |= stc;
dd->fbody = new ExpStatement(0, e);
members->push(dd);
dd->semantic(sc);
return dd;
}
}
#endif
/*****************************************
* Create inclusive destructor for struct/class by aggregating
* all the destructors in dtors[] with the destructors for
* all the members.
* Note the close similarity with StructDeclaration::buildPostBlit(),
* and the ordering changes (runs backward instead of forwards).
*/
FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
{
//printf("AggregateDeclaration::buildDtor() %s\n", toChars());
Expression *e = NULL;
#if DMDV2
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
if (v->storage_class & STCref)
continue;
Type *tv = v->type->toBasetype();
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
while (tv->ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)tv;
dim *= ((TypeSArray *)tv)->dim->toInteger();
tv = tv->nextOf()->toBasetype();
}
if (tv->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->dtor)
{ Expression *ex;
// this.v
ex = new ThisExp(0);
ex = new DotVarExp(0, ex, v, 0);
if (dim == 0)
{ // this.v.dtor()
ex = new DotVarExp(0, ex, sd->dtor, 0);
ex = new CallExp(0, ex);
}
else
{
// Typeinfo.destroy(cast(void*)&this.v);
Expression *ea = new AddrExp(0, ex);
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
Expression *et = v->type->getTypeInfo(sc);
et = new DotIdExp(0, et, Id::destroy);
ex = new CallExp(0, et, ea);
}
e = Expression::combine(ex, e); // combine in reverse order
}
}
}
/* Build our own "destructor" which executes e
*/
if (e)
{ //printf("Building __fieldDtor()\n");
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor"));
dd->fbody = new ExpStatement(0, e);
dtors.shift(dd);
members->push(dd);
dd->semantic(sc);
}
#endif
switch (dtors.dim)
{
case 0:
return NULL;
case 1:
return dtors.tdata()[0];
default:
e = NULL;
for (size_t i = 0; i < dtors.dim; i++)
{ FuncDeclaration *fd = dtors.tdata()[i];
Expression *ex = new ThisExp(0);
ex = new DotVarExp(0, ex, fd, 0);
ex = new CallExp(0, ex);
e = Expression::combine(ex, e);
}
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor"));
dd->fbody = new ExpStatement(0, e);
members->push(dd);
dd->semantic(sc);
return dd;
}
}

74
complex_t.h Normal file
View File

@@ -0,0 +1,74 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2006 by Digital Mars
// All Rights Reserved
// written by Walter Bright and Burton Radons
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#ifndef DMD_COMPLEX_T_H
#define DMD_COMPLEX_T_H
/* Roll our own complex type for compilers that don't support complex
*/
struct complex_t
{
long double re;
long double im;
complex_t() { this->re = 0; this->im = 0; }
complex_t(long double re) { this->re = re; this->im = 0; }
complex_t(long double re, long double im) { this->re = re; this->im = im; }
complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
complex_t operator / (complex_t y)
{
long double abs_y_re = y.re < 0 ? -y.re : y.re;
long double abs_y_im = y.im < 0 ? -y.im : y.im;
long double r, den;
if (abs_y_re < abs_y_im)
{
r = y.re / y.im;
den = y.im + r * y.re;
return complex_t((re * r + im) / den,
(im * r - re) / den);
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
return complex_t((re + r * im) / den,
(im - r * re) / den);
}
}
operator bool () { return re || im; }
int operator == (complex_t y) { return re == y.re && im == y.im; }
int operator != (complex_t y) { return re != y.re || im != y.im; }
};
inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
inline long double creall(complex_t x)
{
return x.re;
}
inline long double cimagl(complex_t x)
{
return x.im;
}
#endif

399
cond.c Normal file
View File

@@ -0,0 +1,399 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "id.h"
#include "init.h"
#include "declaration.h"
#include "identifier.h"
#include "expression.h"
#include "cond.h"
#include "module.h"
#include "template.h"
#include "lexer.h"
#include "mtype.h"
#include "scope.h"
int findCondition(Strings *ids, Identifier *ident)
{
if (ids)
{
for (size_t i = 0; i < ids->dim; i++)
{
const char *id = ids->tdata()[i];
if (strcmp(id, ident->toChars()) == 0)
return TRUE;
}
}
return FALSE;
}
/* ============================================================ */
Condition::Condition(Loc loc)
{
this->loc = loc;
inc = 0;
}
/* ============================================================ */
DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
: Condition(0)
{
this->mod = mod;
this->level = level;
this->ident = ident;
}
Condition *DVCondition::syntaxCopy()
{
return this; // don't need to copy
}
/* ============================================================ */
void DebugCondition::setGlobalLevel(unsigned level)
{
global.params.debuglevel = level;
}
void DebugCondition::addGlobalIdent(const char *ident)
{
if (!global.params.debugids)
global.params.debugids = new Strings();
global.params.debugids->push((char *)ident);
}
DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
: DVCondition(mod, level, ident)
{
}
int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
{
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
if (inc == 0)
{
inc = 2;
if (ident)
{
if (findCondition(mod->debugids, ident))
inc = 1;
else if (findCondition(global.params.debugids, ident))
inc = 1;
else
{ if (!mod->debugidsNot)
mod->debugidsNot = new Strings();
mod->debugidsNot->push(ident->toChars());
}
}
else if (level <= global.params.debuglevel || level <= mod->debuglevel)
inc = 1;
}
return (inc == 1);
}
void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (ident)
buf->printf("debug (%s)", ident->toChars());
else
buf->printf("debug (%u)", level);
}
/* ============================================================ */
void VersionCondition::setGlobalLevel(unsigned level)
{
global.params.versionlevel = level;
}
void VersionCondition::checkPredefined(Loc loc, const char *ident)
{
static const char* reserved[] =
{
"DigitalMars", "X86", "X86_64",
"Windows", "Win32", "Win64",
"linux",
#if DMDV2
/* Although Posix is predefined by D1, disallowing its
* redefinition breaks makefiles and older builds.
*/
"Posix",
"D_NET",
#endif
"OSX", "FreeBSD",
"OpenBSD",
"Solaris",
"LittleEndian", "BigEndian",
"all",
"none",
};
for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
{
if (strcmp(ident, reserved[i]) == 0)
goto Lerror;
}
if (ident[0] == 'D' && ident[1] == '_')
goto Lerror;
return;
Lerror:
error(loc, "version identifier '%s' is reserved and cannot be set", ident);
}
void VersionCondition::addGlobalIdent(const char *ident)
{
checkPredefined(0, ident);
addPredefinedGlobalIdent(ident);
}
void VersionCondition::addPredefinedGlobalIdent(const char *ident)
{
if (!global.params.versionids)
global.params.versionids = new Strings();
global.params.versionids->push((char *)ident);
}
VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
: DVCondition(mod, level, ident)
{
}
int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
{
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
//if (ident) printf("\tident = '%s'\n", ident->toChars());
if (inc == 0)
{
inc = 2;
if (ident)
{
if (findCondition(mod->versionids, ident))
inc = 1;
else if (findCondition(global.params.versionids, ident))
inc = 1;
else
{
if (!mod->versionidsNot)
mod->versionidsNot = new Strings();
mod->versionidsNot->push(ident->toChars());
}
}
else if (level <= global.params.versionlevel || level <= mod->versionlevel)
inc = 1;
}
return (inc == 1);
}
void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (ident)
buf->printf("version (%s)", ident->toChars());
else
buf->printf("version (%u)", level);
}
/**************************** StaticIfCondition *******************************/
StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
: Condition(loc)
{
this->exp = exp;
}
Condition *StaticIfCondition::syntaxCopy()
{
return new StaticIfCondition(loc, exp->syntaxCopy());
}
int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
{
#if 0
printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
if (s)
{
printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
}
#endif
if (inc == 0)
{
if (!sc)
{
error(loc, "static if conditional cannot be at global scope");
inc = 2;
return 0;
}
sc = sc->push(sc->scopesym);
sc->sd = s; // s gets any addMember()
sc->flags |= SCOPEstaticif;
Expression *e = exp->semantic(sc);
sc->pop();
e = e->optimize(WANTvalue | WANTinterpret);
if (e->isBool(TRUE))
inc = 1;
else if (e->isBool(FALSE))
inc = 2;
else
{
e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
inc = 2;
}
}
return (inc == 1);
}
void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("static if(");
exp->toCBuffer(buf, hgs);
buf->writeByte(')');
}
/**************************** IftypeCondition *******************************/
IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
: Condition(loc)
{
this->targ = targ;
this->id = id;
this->tok = tok;
this->tspec = tspec;
}
Condition *IftypeCondition::syntaxCopy()
{
return new IftypeCondition(loc,
targ->syntaxCopy(),
id,
tok,
tspec ? tspec->syntaxCopy() : NULL);
}
int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
{
//printf("IftypeCondition::include()\n");
if (inc == 0)
{
if (!sc)
{
error(loc, "iftype conditional cannot be at global scope");
inc = 2;
return 0;
}
Type *t = targ->trySemantic(loc, sc);
if (t)
targ = t;
else
inc = 2; // condition is false
if (!t)
{
}
else if (id && tspec)
{
/* Evaluate to TRUE if targ matches tspec.
* If TRUE, declare id as an alias for the specialized type.
*/
MATCH m;
TemplateTypeParameter tp(loc, id, NULL, NULL);
TemplateParameters parameters;
parameters.setDim(1);
parameters.tdata()[0] = &tp;
Objects dedtypes;
dedtypes.setDim(1);
m = targ->deduceType(sc, tspec, &parameters, &dedtypes);
if (m == MATCHnomatch ||
(m != MATCHexact && tok == TOKequal))
inc = 2;
else
{
inc = 1;
Type *tded = (Type *)dedtypes.tdata()[0];
if (!tded)
tded = targ;
Dsymbol *s = new AliasDeclaration(loc, id, tded);
s->semantic(sc);
sc->insert(s);
if (sd)
s->addMember(sc, sd, 1);
}
}
else if (id)
{
/* Declare id as an alias for type targ. Evaluate to TRUE
*/
Dsymbol *s = new AliasDeclaration(loc, id, targ);
s->semantic(sc);
sc->insert(s);
if (sd)
s->addMember(sc, sd, 1);
inc = 1;
}
else if (tspec)
{
/* Evaluate to TRUE if targ matches tspec
*/
tspec = tspec->semantic(loc, sc);
//printf("targ = %s\n", targ->toChars());
//printf("tspec = %s\n", tspec->toChars());
if (tok == TOKcolon)
{ if (targ->implicitConvTo(tspec))
inc = 1;
else
inc = 2;
}
else /* == */
{ if (targ->equals(tspec))
inc = 1;
else
inc = 2;
}
}
else
inc = 1;
//printf("inc = %d\n", inc);
}
return (inc == 1);
}
void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("iftype(");
targ->toCBuffer(buf, id, hgs);
if (tspec)
{
if (tok == TOKcolon)
buf->writestring(" : ");
else
buf->writestring(" == ");
tspec->toCBuffer(buf, NULL, hgs);
}
buf->writeByte(')');
}

Some files were not shown because too many files have changed in this diff Show More