mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-04-17 09:19:03 +02:00
Squashed 'dmd2/' content from commit 10017d5
git-subtree-dir: dmd2 git-subtree-split: 10017d50eaaff4ecdc37a0153b6c37ea0b004c81
This commit is contained in:
412
access.c
Normal file
412
access.c
Normal 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
320
aggregate.h
Normal 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
79
aliasthis.c
Normal 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
41
aliasthis.h
Normal 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
165
apply.c
Normal 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
193
argtypes.c
Normal 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
648
arrayop.c
Normal 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
77
arraytypes.h
Normal 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
117
artistic.txt
Normal 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
|
||||
189
attrib.h
Normal file
189
attrib.h
Normal 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
498
backend/aa.c
Normal 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
109
backend/aa.h
Normal 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
80
backend/backend.txt
Normal 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
292
backend/bcomplex.c
Normal 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
36
backend/bcomplex.h
Normal 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
2204
backend/blockopt.c
Normal file
File diff suppressed because it is too large
Load Diff
1557
backend/cc.h
Normal file
1557
backend/cc.h
Normal file
File diff suppressed because it is too large
Load Diff
1104
backend/cdef.h
Normal file
1104
backend/cdef.h
Normal file
File diff suppressed because it is too large
Load Diff
85
backend/cdeflnx.h
Normal file
85
backend/cdeflnx.h
Normal 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
61
backend/cg.c
Normal 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
3638
backend/cg87.c
Normal file
File diff suppressed because it is too large
Load Diff
2527
backend/cgcod.c
Normal file
2527
backend/cgcod.c
Normal file
File diff suppressed because it is too large
Load Diff
683
backend/cgcs.c
Normal file
683
backend/cgcs.c
Normal 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
2705
backend/cgcv.c
Normal file
File diff suppressed because it is too large
Load Diff
76
backend/cgcv.h
Normal file
76
backend/cgcv.h
Normal 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
4522
backend/cgelem.c
Normal file
File diff suppressed because it is too large
Load Diff
781
backend/cgen.c
Normal file
781
backend/cgen.c
Normal 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,®) &&
|
||||
!(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 = ®
|
||||
|
||||
/* 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(®m,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
3680
backend/cgobj.c
Normal file
File diff suppressed because it is too large
Load Diff
1013
backend/cgreg.c
Normal file
1013
backend/cgreg.c
Normal file
File diff suppressed because it is too large
Load Diff
3206
backend/cgsched.c
Normal file
3206
backend/cgsched.c
Normal file
File diff suppressed because it is too large
Load Diff
780
backend/cgxmm.c
Normal file
780
backend/cgxmm.c
Normal 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,®,(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, ®s, 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,®,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
3990
backend/cod1.c
Normal file
File diff suppressed because it is too large
Load Diff
4997
backend/cod2.c
Normal file
4997
backend/cod2.c
Normal file
File diff suppressed because it is too large
Load Diff
6458
backend/cod3.c
Normal file
6458
backend/cod3.c
Normal file
File diff suppressed because it is too large
Load Diff
3438
backend/cod4.c
Normal file
3438
backend/cod4.c
Normal file
File diff suppressed because it is too large
Load Diff
207
backend/cod5.c
Normal file
207
backend/cod5.c
Normal 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
136
backend/code.c
Normal 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
1049
backend/code.h
Normal file
File diff suppressed because it is too large
Load Diff
746
backend/cppman.c
Normal file
746
backend/cppman.c
Normal 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
126
backend/cv4.h
Normal 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
415
backend/debug.c
Normal 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
383
backend/dt.c
Normal 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
114
backend/dt.h
Normal 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
2531
backend/dwarf.c
Normal file
File diff suppressed because it is too large
Load Diff
18
backend/dwarf.h
Normal file
18
backend/dwarf.h
Normal 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
470
backend/dwarf2.h
Normal 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
124
backend/ee.c
Normal 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
3326
backend/el.c
Normal file
File diff suppressed because it is too large
Load Diff
219
backend/el.h
Normal file
219
backend/el.h
Normal 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
3111
backend/elfobj.c
Normal file
File diff suppressed because it is too large
Load Diff
2089
backend/evalu8.c
Normal file
2089
backend/evalu8.c
Normal file
File diff suppressed because it is too large
Load Diff
47
backend/exh.h
Normal file
47
backend/exh.h
Normal 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
852
backend/gdag.c
Normal 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
1721
backend/gflow.c
Normal file
File diff suppressed because it is too large
Load Diff
589
backend/global.h
Normal file
589
backend/global.h
Normal 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
741
backend/glocal.c
Normal 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
3628
backend/gloop.c
Normal file
File diff suppressed because it is too large
Load Diff
368
backend/go.c
Normal file
368
backend/go.c
Normal 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
98
backend/go.h
Normal 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
1781
backend/gother.c
Normal file
File diff suppressed because it is too large
Load Diff
771
backend/html.c
Normal file
771
backend/html.c
Normal 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
50
backend/html.h
Normal 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
430
backend/iasm.h
Normal 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
323
backend/mach.h
Normal 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
2757
backend/machobj.c
Normal file
File diff suppressed because it is too large
Load Diff
277
backend/md5.c
Normal file
277
backend/md5.c
Normal 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
61
backend/md5.h
Normal 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
381
backend/melf.h
Normal 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
1707
backend/newman.c
Normal file
File diff suppressed because it is too large
Load Diff
915
backend/nteh.c
Normal file
915
backend/nteh.c
Normal 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
414
backend/oper.h
Normal 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
1131
backend/optabgen.c
Normal file
File diff suppressed because it is too large
Load Diff
953
backend/os.c
Normal file
953
backend/os.c
Normal 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
1534
backend/out.c
Normal file
File diff suppressed because it is too large
Load Diff
298
backend/outbuf.c
Normal file
298
backend/outbuf.c
Normal 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
179
backend/outbuf.h
Normal 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
5736
backend/ptrntab.c
Normal file
File diff suppressed because it is too large
Load Diff
125
backend/rtlsym.c
Normal file
125
backend/rtlsym.c
Normal 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
155
backend/rtlsym.h
Normal 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
712
backend/strtold.c
Normal 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
2307
backend/symbol.c
Normal file
File diff suppressed because it is too large
Load Diff
54
backend/tassert.h
Normal file
54
backend/tassert.h
Normal 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
61
backend/ti_achar.c
Normal 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
54
backend/ti_pvoid.c
Normal 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
52
backend/tinfo.h
Normal 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
458
backend/token.h
Normal 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
377
backend/ty.h
Normal 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
1480
backend/type.c
Normal file
File diff suppressed because it is too large
Load Diff
209
backend/type.h
Normal file
209
backend/type.h
Normal 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
235
backend/var.c
Normal 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
314
backend/xmm.h
Normal 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
42
backendlicense.txt
Normal 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
234
builtin.c
Normal 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
189
canthrow.c
Normal 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;
|
||||
}
|
||||
694
clone.c
Normal file
694
clone.c
Normal 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
74
complex_t.h
Normal 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
399
cond.c
Normal 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, ¶meters, &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
Reference in New Issue
Block a user