270 changes: 270 additions & 0 deletions src/root/stringtable.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.root.stringtable;

import core.stdc.stdint, core.stdc.string;
import ddmd.root.rmem;

enum POOL_BITS = 12;
enum POOL_SIZE = (1U << POOL_BITS);

// TODO: Merge with root.String
// MurmurHash2 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
// https://sites.google.com/site/murmurhash/
extern (C++) static uint32_t calcHash(const(char)* key, size_t len)
{
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
const(uint32_t) m = 0x5bd1e995;
const(int) r = 24;
// Initialize the hash to a 'random' value
uint32_t h = cast(uint32_t)len;
// Mix 4 bytes at a time into the hash
const(uint8_t)* data = cast(const(uint8_t)*)key;
while (len >= 4)
{
uint32_t k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Handle the last few bytes of the input array
switch (len & 3)
{
case 3:
h ^= data[2] << 16;
case 2:
h ^= data[1] << 8;
case 1:
h ^= data[0];
h *= m;
default:
break;
}
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}

extern (C++) static size_t nextpow2(size_t val)
{
size_t res = 1;
while (res < val)
res <<= 1;
return res;
}

extern (C++) __gshared const(double) loadFactor = 0.8;

struct StringEntry
{
uint32_t hash;
uint32_t vptr;
}

// StringValue is a variable-length structure. It has neither proper c'tors nor a
// factory method because the only thing which should be creating these is StringTable.
struct StringValue
{
void* ptrvalue;
size_t length;

extern (C++) char* lstring()
{
return cast(char*)(&this + 1);
}

extern (C++) const(size_t) len()
{
return length;
}

extern (C++) const(const(char)*) toDchars()
{
return cast(const(char)*)(&this + 1);
}
}

struct StringTable
{
private:
StringEntry* table;
size_t tabledim;
uint8_t** pools;
size_t npools;
size_t nfill;
size_t count;

public:
extern (C++) void _init(size_t size = 0)
{
size = nextpow2(cast(size_t)(size / loadFactor));
if (size < 32)
size = 32;
table = cast(StringEntry*)mem.xcalloc(size, (table[0]).sizeof);
tabledim = size;
pools = null;
npools = nfill = 0;
count = 0;
}

extern (C++) void reset(size_t size = 0)
{
for (size_t i = 0; i < npools; ++i)
mem.xfree(pools[i]);
mem.xfree(table);
mem.xfree(pools);
table = null;
pools = null;
_init(size);
}

extern (C++) ~this()
{
for (size_t i = 0; i < npools; ++i)
mem.xfree(pools[i]);
mem.xfree(table);
mem.xfree(pools);
table = null;
pools = null;
}

extern (C++) StringValue* lookup(const(char)* s, size_t length)
{
const(hash_t) hash = calcHash(s, length);
const(size_t) i = findSlot(hash, s, length);
// printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
return getValue(table[i].vptr);
}

extern (C++) StringValue* insert(const(char)* s, size_t length)
{
const(hash_t) hash = calcHash(s, length);
size_t i = findSlot(hash, s, length);
if (table[i].vptr)
return null; // already in table
if (++count > tabledim * loadFactor)
{
grow();
i = findSlot(hash, s, length);
}
table[i].hash = hash;
table[i].vptr = allocValue(s, length);
// printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
return getValue(table[i].vptr);
}

extern (C++) StringValue* update(const(char)* s, size_t length)
{
const(hash_t) hash = calcHash(s, length);
size_t i = findSlot(hash, s, length);
if (!table[i].vptr)
{
if (++count > tabledim * loadFactor)
{
grow();
i = findSlot(hash, s, length);
}
table[i].hash = hash;
table[i].vptr = allocValue(s, length);
}
// printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
return getValue(table[i].vptr);
}

/********************************
* Walk the contents of the string table,
* calling fp for each entry.
* Params:
* fp = function to call. Returns !=0 to stop
* Returns:
* last return value of fp call
*/
extern (C++) int apply(int function(StringValue*) fp)
{
for (size_t i = 0; i < tabledim; ++i)
{
StringEntry* se = &table[i];
if (!se.vptr)
continue;
StringValue* sv = getValue(se.vptr);
int result = (*fp)(sv);
if (result)
return result;
}
return 0;
}

private:
extern (C++) uint32_t allocValue(const(char)* s, size_t length)
{
const(size_t) nbytes = StringValue.sizeof + length + 1;
if (!npools || nfill + nbytes > POOL_SIZE)
{
pools = cast(uint8_t**)mem.xrealloc(pools, ++npools * (pools[0]).sizeof);
pools[npools - 1] = cast(uint8_t*)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
nfill = 0;
}
StringValue* sv = cast(StringValue*)&pools[npools - 1][nfill];
sv.ptrvalue = null;
sv.length = length;
.memcpy(sv.lstring(), s, length);
sv.lstring()[length] = 0;
const(uint32_t) vptr = cast(uint32_t)(npools << POOL_BITS | nfill);
nfill += nbytes + (-nbytes & 7); // align to 8 bytes
return vptr;
}

extern (C++) StringValue* getValue(uint32_t vptr)
{
if (!vptr)
return null;
const(size_t) idx = (vptr >> POOL_BITS) - 1;
const(size_t) off = vptr & POOL_SIZE - 1;
return cast(StringValue*)&pools[idx][off];
}

extern (C++) size_t findSlot(hash_t hash, const(char)* s, size_t length)
{
// quadratic probing using triangular numbers
// http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
for (size_t i = hash & (tabledim - 1), j = 1;; ++j)
{
StringValue* sv;
if (!table[i].vptr || table[i].hash == hash && (sv = getValue(table[i].vptr)).length == length && .memcmp(s, sv.lstring(), length) == 0)
return i;
i = (i + j) & (tabledim - 1);
}
}

extern (C++) void grow()
{
const(size_t) odim = tabledim;
StringEntry* otab = table;
tabledim *= 2;
table = cast(StringEntry*)mem.xcalloc(tabledim, (table[0]).sizeof);
for (size_t i = 0; i < odim; ++i)
{
StringEntry* se = &otab[i];
if (!se.vptr)
continue;
StringValue* sv = getValue(se.vptr);
table[findSlot(se.hash, sv.lstring(), sv.length)] = *se;
}
mem.xfree(otab);
}
}
157 changes: 0 additions & 157 deletions src/sapply.c

This file was deleted.

175 changes: 175 additions & 0 deletions src/sapply.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.sapply;

import ddmd.statement, ddmd.visitor;

/**************************************
* A Statement tree walker that will visit each Statement s in the tree,
* in depth-first evaluation order, and call fp(s,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.
*/
extern (C++) final class PostorderStatementVisitor : StoppableVisitor
{
alias visit = super.visit;
public:
StoppableVisitor v;

extern (D) this(StoppableVisitor v)
{
this.v = v;
}

bool doCond(Statement s)
{
if (!stop && s)
s.accept(this);
return stop;
}

bool applyTo(Statement s)
{
s.accept(v);
stop = v.stop;
return true;
}

void visit(Statement s)
{
applyTo(s);
}

void visit(PeelStatement s)
{
doCond(s.s) || applyTo(s);
}

void visit(CompoundStatement s)
{
for (size_t i = 0; i < s.statements.dim; i++)
if (doCond((*s.statements)[i]))
return;
applyTo(s);
}

void visit(UnrolledLoopStatement s)
{
for (size_t i = 0; i < s.statements.dim; i++)
if (doCond((*s.statements)[i]))
return;
applyTo(s);
}

void visit(ScopeStatement s)
{
doCond(s.statement) || applyTo(s);
}

void visit(WhileStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(DoStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(ForStatement s)
{
doCond(s._init) || doCond(s._body) || applyTo(s);
}

void visit(ForeachStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(ForeachRangeStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(IfStatement s)
{
doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
}

void visit(PragmaStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(SwitchStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(CaseStatement s)
{
doCond(s.statement) || applyTo(s);
}

void visit(DefaultStatement s)
{
doCond(s.statement) || applyTo(s);
}

void visit(SynchronizedStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(WithStatement s)
{
doCond(s._body) || applyTo(s);
}

void visit(TryCatchStatement s)
{
if (doCond(s._body))
return;
for (size_t i = 0; i < s.catches.dim; i++)
if (doCond((*s.catches)[i].handler))
return;
applyTo(s);
}

void visit(TryFinallyStatement s)
{
doCond(s._body) || doCond(s.finalbody) || applyTo(s);
}

void visit(OnScopeStatement s)
{
doCond(s.statement) || applyTo(s);
}

void visit(DebugStatement s)
{
doCond(s.statement) || applyTo(s);
}

void visit(LabelStatement s)
{
doCond(s.statement) || applyTo(s);
}
}

extern (C++) bool walkPostorder(Statement s, StoppableVisitor v)
{
scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
s.accept(pv);
return v.stop;
}
581 changes: 0 additions & 581 deletions src/scope.c

This file was deleted.

383 changes: 0 additions & 383 deletions src/sideeffect.c

This file was deleted.

342 changes: 342 additions & 0 deletions src/sideeffect.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.sideeffect;

import ddmd.apply, ddmd.declaration, ddmd.expression, ddmd.func, ddmd.globals, ddmd.mtype, ddmd.tokens, ddmd.visitor;

/**************************************************
* Front-end expression rewriting should create temporary variables for
* non trivial sub-expressions in order to:
* 1. save evaluation order
* 2. prevent sharing of sub-expression in AST
*/
extern (C++) bool isTrivialExp(Expression e)
{
extern (C++) final class IsTrivialExp : StoppableVisitor
{
alias visit = super.visit;
public:
extern (D) this()
{
}

void visit(Expression e)
{
/* Bugzilla 11201: CallExp is always non trivial expression,
* especially for inlining.
*/
if (e.op == TOKcall)
{
stop = true;
return;
}
// stop walking if we determine this expression has side effects
stop = lambdaHasSideEffect(e);
}
}

scope IsTrivialExp v = new IsTrivialExp();
return walkPostorder(e, v) == false;
}

/********************************************
* Determine if Expression has any side effects.
*/
extern (C++) bool hasSideEffect(Expression e)
{
extern (C++) final class LambdaHasSideEffect : StoppableVisitor
{
alias visit = super.visit;
public:
extern (D) this()
{
}

void visit(Expression e)
{
// stop walking if we determine this expression has side effects
stop = lambdaHasSideEffect(e);
}
}

scope LambdaHasSideEffect v = new LambdaHasSideEffect();
return walkPostorder(e, v);
}

/********************************************
* Determine if the call of f, or function type or delegate type t1, has any side effects.
* Returns:
* 0 has any side effects
* 1 nothrow + constant purity
* 2 nothrow + strong purity
*/
extern (C++) int callSideEffectLevel(FuncDeclaration f)
{
/* Bugzilla 12760: ctor call always has side effects.
*/
if (f.isCtorDeclaration())
return 0;
assert(f.type.ty == Tfunction);
TypeFunction tf = cast(TypeFunction)f.type;
if (tf.isnothrow)
{
PURE purity = f.isPure();
if (purity == PUREstrong)
return 2;
if (purity == PUREconst)
return 1;
}
return 0;
}

extern (C++) int callSideEffectLevel(Type t)
{
t = t.toBasetype();
TypeFunction tf;
if (t.ty == Tdelegate)
tf = cast(TypeFunction)(cast(TypeDelegate)t).next;
else
{
assert(t.ty == Tfunction);
tf = cast(TypeFunction)t;
}
tf.purityLevel();
PURE purity = tf.purity;
if (t.ty == Tdelegate && purity > PUREweak)
{
if (tf.isMutable())
purity = PUREweak;
else if (!tf.isImmutable())
purity = PUREconst;
}
if (tf.isnothrow)
{
if (purity == PUREstrong)
return 2;
if (purity == PUREconst)
return 1;
}
return 0;
}

extern (C++) bool lambdaHasSideEffect(Expression e)
{
switch (e.op)
{
// Sort the cases by most frequently used first
case TOKassign:
case TOKplusplus:
case TOKminusminus:
case TOKdeclaration:
case TOKconstruct:
case TOKblit:
case TOKaddass:
case TOKminass:
case TOKcatass:
case TOKmulass:
case TOKdivass:
case TOKmodass:
case TOKshlass:
case TOKshrass:
case TOKushrass:
case TOKandass:
case TOKorass:
case TOKxorass:
case TOKpowass:
case TOKin:
case TOKremove:
case TOKassert:
case TOKhalt:
case TOKdelete:
case TOKnew:
case TOKnewanonclass:
return true;
case TOKcall:
{
CallExp ce = cast(CallExp)e;
/* Calling a function or delegate that is pure nothrow
* has no side effects.
*/
if (ce.e1.type)
{
Type t = ce.e1.type.toBasetype();
if (t.ty == Tdelegate)
t = (cast(TypeDelegate)t).next;
if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0)
{
}
else
return true;
}
break;
}
case TOKcast:
{
CastExp ce = cast(CastExp)e;
/* if:
* cast(classtype)func() // because it may throw
*/
if (ce.to.ty == Tclass && ce.e1.op == TOKcall && ce.e1.type.ty == Tclass)
return true;
break;
}
default:
break;
}
return false;
}

/***********************************
* The result of this expression will be discarded.
* Complain if the operation has no side effects (and hence is meaningless).
*/
extern (C++) void discardValue(Expression e)
{
if (lambdaHasSideEffect(e)) // check side-effect shallowly
return;
switch (e.op)
{
case TOKcast:
{
CastExp ce = cast(CastExp)e;
if (ce.to.equals(Type.tvoid))
{
/*
* Don't complain about an expression with no effect if it was cast to void
*/
return;
}
break;
// complain
}
case TOKerror:
return;
case TOKvar:
{
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
if (v && (v.storage_class & STCtemp))
{
// Bugzilla 5810: Don't complain about an internal generated variable.
return;
}
break;
}
case TOKcall:
/* Issue 3882: */
if (global.params.warnings && !global.gag)
{
CallExp ce = cast(CallExp)e;
if (e.type.ty == Tvoid)
{
/* Don't complain about calling void-returning functions with no side-effect,
* because purity and nothrow are inferred, and because some of the
* runtime library depends on it. Needs more investigation.
*
* One possible solution is to restrict this message to only be called in hierarchies that
* never call assert (and or not called from inside unittest blocks)
*/
}
else if (ce.e1.type)
{
Type t = ce.e1.type.toBasetype();
if (t.ty == Tdelegate)
t = (cast(TypeDelegate)t).next;
if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0)
{
const(char)* s;
if (ce.f)
s = ce.f.toPrettyChars();
else if (ce.e1.op == TOKstar)
{
// print 'fp' if ce->e1 is (*fp)
s = (cast(PtrExp)ce.e1).e1.toChars();
}
else
s = ce.e1.toChars();
e.warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional", s, e.type.toChars());
}
}
}
return;
case TOKimport:
e.error("%s has no effect", e.toChars());
return;
case TOKandand:
{
AndAndExp aae = cast(AndAndExp)e;
discardValue(aae.e2);
return;
}
case TOKoror:
{
OrOrExp ooe = cast(OrOrExp)e;
discardValue(ooe.e2);
return;
}
case TOKquestion:
{
CondExp ce = cast(CondExp)e;
/* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
* redundant expression to make those types common. For example:
*
* struct S { this(int n); int v; alias v this; }
* S[int] aa;
* aa[1] = 0;
*
* The last assignment statement will be rewitten to:
*
* 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
*
* The last DotVarExp is necessary to take assigned value.
*
* int value = (aa[1] = 0); // value = aa[1].value
*
* To avoid false error, discardValue() should be called only when
* the both tops of e1 and e2 have actually no side effects.
*/
if (!lambdaHasSideEffect(ce.e1) && !lambdaHasSideEffect(ce.e2))
{
discardValue(ce.e1);
discardValue(ce.e2);
}
return;
}
case TOKcomma:
{
CommaExp ce = cast(CommaExp)e;
/* Check for compiler-generated code of the form auto __tmp, e, __tmp;
* In such cases, only check e for side effect (it's OK for __tmp to have
* no side effect).
* See Bugzilla 4231 for discussion
*/
CommaExp firstComma = ce;
while (firstComma.e1.op == TOKcomma)
firstComma = cast(CommaExp)firstComma.e1;
if (firstComma.e1.op == TOKdeclaration && ce.e2.op == TOKvar && (cast(DeclarationExp)firstComma.e1).declaration == (cast(VarExp)ce.e2).var)
{
return;
}
// Don't check e1 until we cast(void) the a,b code generation
//discardValue(ce->e1);
discardValue(ce.e2);
return;
}
case TOKtuple:
/* Pass without complaint if any of the tuple elements have side effects.
* Ideally any tuple elements with no side effects should raise an error,
* this needs more investigation as to what is the right thing to do.
*/
if (!hasSideEffect(e))
break;
return;
default:
break;
}
e.error("%s has no effect in expression (%s)", Token.toChars(e.op), e.toChars());
}
5,356 changes: 0 additions & 5,356 deletions src/statement.c

This file was deleted.

5,708 changes: 5,708 additions & 0 deletions src/statement.d

Large diffs are not rendered by default.

121 changes: 0 additions & 121 deletions src/staticassert.c

This file was deleted.

117 changes: 117 additions & 0 deletions src/staticassert.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.staticassert;

import ddmd.dscope, ddmd.dsymbol, ddmd.errors, ddmd.expression, ddmd.globals, ddmd.globals, ddmd.hdrgen, ddmd.id, ddmd.identifier, ddmd.mtype, ddmd.root.outbuffer, ddmd.visitor;

extern (C++) final class StaticAssert : Dsymbol
{
public:
Expression exp;
Expression msg;

/********************************* AttribDeclaration ****************************/
extern (D) this(Loc loc, Expression exp, Expression msg)
{
super(Id.empty);
this.loc = loc;
this.exp = exp;
this.msg = msg;
}

Dsymbol syntaxCopy(Dsymbol s)
{
assert(!s);
return new StaticAssert(loc, exp.syntaxCopy(), msg ? msg.syntaxCopy() : null);
}

void addMember(Scope* sc, ScopeDsymbol sds)
{
// we didn't add anything
}

void semantic(Scope* sc)
{
}

void semantic2(Scope* sc)
{
//printf("StaticAssert::semantic2() %s\n", toChars());
auto sds = new ScopeDsymbol();
sc = sc.push(sds);
sc.tinst = null;
sc.minst = null;
sc.flags |= SCOPEcondition;
sc = sc.startCTFE();
Expression e = exp.semantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
sc = sc.pop();
// Simplify expression, to make error messages nicer if CTFE fails
e = e.optimize(WANTvalue);
if (!e.type.isBoolean())
{
if (e.type.toBasetype() != Type.terror)
exp.error("expression %s of type %s does not have a boolean value", exp.toChars(), e.type.toChars());
return;
}
uint olderrs = global.errors;
e = e.ctfeInterpret();
if (global.errors != olderrs)
{
errorSupplemental(loc, "while evaluating: static assert(%s)", exp.toChars());
}
else if (e.isBool(false))
{
if (msg)
{
sc = sc.startCTFE();
msg = msg.semantic(sc);
msg = resolveProperties(sc, msg);
sc = sc.endCTFE();
msg = msg.ctfeInterpret();
if (StringExp se = msg.toStringExp())
{
// same with pragma(msg)
se = se.toUTF8(sc);
error("\"%.*s\"", cast(int)se.len, cast(char*)se.string);
}
else
error("%s", msg.toChars());
}
else
error("(%s) is false", exp.toChars());
if (sc.tinst)
sc.tinst.printInstantiationTrace();
if (!global.gag)
fatal();
}
else if (!e.isBool(true))
{
error("(%s) is not evaluatable at compile time", exp.toChars());
}
}

bool oneMember(Dsymbol* ps, Identifier ident)
{
//printf("StaticAssert::oneMember())\n");
*ps = null;
return true;
}

const(char)* kind()
{
return "static assert";
}

void accept(Visitor v)
{
v.visit(this);
}
}
1,379 changes: 0 additions & 1,379 deletions src/struct.c

This file was deleted.

407 changes: 0 additions & 407 deletions src/target.c

This file was deleted.

366 changes: 366 additions & 0 deletions src/target.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.target;

import core.stdc.string;
import ddmd.dmodule, ddmd.expression, ddmd.globals, ddmd.identifier, ddmd.mtype, ddmd.root.longdouble, ddmd.root.outbuffer;

struct Target
{
extern (C++) static __gshared int ptrsize;
extern (C++) static __gshared int realsize; // size a real consumes in memory
extern (C++) static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize
extern (C++) static __gshared int realalignsize; // alignment for reals
extern (C++) static __gshared bool reverseCppOverloads; // with dmc, overloaded functions are grouped and in reverse order
extern (C++) static __gshared int c_longsize; // size of a C 'long' or 'unsigned long' type
extern (C++) static __gshared int c_long_doublesize; // size of a C 'long double'
extern (C++) static __gshared int classinfosize; // size of 'ClassInfo'

extern (C++) static void _init()
{
// These have default values for 32 bit code, they get
// adjusted for 64 bit code.
ptrsize = 4;
classinfosize = 0x4C; // 76
if (global.params.isLP64)
{
ptrsize = 8;
classinfosize = 0x98; // 152
}
if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
{
realsize = 12;
realpad = 2;
realalignsize = 4;
c_longsize = 4;
}
else if (global.params.isOSX)
{
realsize = 16;
realpad = 6;
realalignsize = 16;
c_longsize = 4;
}
else if (global.params.isWindows)
{
realsize = 10;
realpad = 0;
realalignsize = 2;
reverseCppOverloads = !global.params.is64bit;
c_longsize = 4;
}
else
assert(0);
if (global.params.is64bit)
{
if (global.params.isLinux || global.params.isFreeBSD || global.params.isSolaris)
{
realsize = 16;
realpad = 6;
realalignsize = 16;
c_longsize = 8;
}
else if (global.params.isOSX)
{
c_longsize = 8;
}
}
c_long_doublesize = realsize;
if (global.params.is64bit && global.params.isWindows)
c_long_doublesize = 8;
}

/******************************
* Return memory alignment size of type.
*/
extern (C++) static uint alignsize(Type type)
{
assert(type.isTypeBasic());
switch (type.ty)
{
case Tfloat80:
case Timaginary80:
case Tcomplex80:
return Target.realalignsize;
case Tcomplex32:
if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
return 4;
break;
case Tint64:
case Tuns64:
case Tfloat64:
case Timaginary64:
case Tcomplex64:
if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
return global.params.is64bit ? 8 : 4;
break;
default:
break;
}
return cast(uint)type.size(Loc());
}

/******************************
* Return field alignment size of type.
*/
extern (C++) static uint fieldalign(Type type)
{
return type.alignsize();
}

/***********************************
* 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.
*/
extern (C++) static uint critsecsize()
{
if (global.params.isWindows)
{
// sizeof(CRITICAL_SECTION) for Windows.
return global.params.isLP64 ? 40 : 24;
}
else if (global.params.isLinux)
{
// sizeof(pthread_mutex_t) for Linux.
if (global.params.is64bit)
return global.params.isLP64 ? 40 : 32;
else
return global.params.isLP64 ? 40 : 24;
}
else if (global.params.isFreeBSD)
{
// sizeof(pthread_mutex_t) for FreeBSD.
return global.params.isLP64 ? 8 : 4;
}
else if (global.params.isOpenBSD)
{
// sizeof(pthread_mutex_t) for OpenBSD.
return global.params.isLP64 ? 8 : 4;
}
else if (global.params.isOSX)
{
// sizeof(pthread_mutex_t) for OSX.
return global.params.isLP64 ? 64 : 44;
}
else if (global.params.isSolaris)
{
// sizeof(pthread_mutex_t) for Solaris.
return 24;
}
assert(0);
return 0;
}

/***********************************
* Returns a Type for the va_list type of the target.
* NOTE: For Posix/x86_64 this returns the type which will really
* be used for passing an argument of type va_list.
*/
extern (C++) static Type va_listType()
{
if (global.params.isWindows)
{
return Type.tchar.pointerTo();
}
else if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris || global.params.isOSX)
{
if (global.params.is64bit)
{
return (new TypeIdentifier(Loc(), Identifier.idPool("__va_list_tag"))).pointerTo();
}
else
{
return Type.tchar.pointerTo();
}
}
else
{
assert(0);
return null;
}
}

/*
* Return true if the given type is supported for this target
*/
extern (C++) static int checkVectorType(int sz, Type type)
{
if (!global.params.is64bit && !global.params.isOSX)
return 1; // not supported
if (sz != 16 && sz != 32)
return 2; // wrong size
switch (type.ty)
{
case Tvoid:
case Tint8:
case Tuns8:
case Tint16:
case Tuns16:
case Tint32:
case Tuns32:
case Tfloat32:
case Tint64:
case Tuns64:
case Tfloat64:
break;
default:
return 3; // wrong base type
}
return 0;
}

/******************************
* Encode the given expression, which is assumed to be an rvalue literal
* as another type for use in CTFE.
* This corresponds roughly to the idiom *(Type *)&e.
*/
extern (C++) static Expression paintAsType(Expression e, Type type)
{
// We support up to 512-bit values.
ubyte[64] buffer;
memset(buffer.ptr, 0, buffer.sizeof);
assert(e.type.size() == type.size());
// Write the expression into the buffer.
switch (e.type.ty)
{
case Tint32:
case Tuns32:
case Tint64:
case Tuns64:
encodeInteger(e, buffer.ptr);
break;
case Tfloat32:
case Tfloat64:
encodeReal(e, buffer.ptr);
break;
default:
assert(0);
}
// Interpret the buffer as a new type.
switch (type.ty)
{
case Tint32:
case Tuns32:
case Tint64:
case Tuns64:
return decodeInteger(e.loc, type, buffer.ptr);
case Tfloat32:
case Tfloat64:
return decodeReal(e.loc, type, buffer.ptr);
default:
assert(0);
}
return null; // avoid warning
}

/******************************
* For the given module, perform any post parsing analysis.
* Certain compiler backends (ie: GDC) have special placeholder
* modules whose source are empty, but code gets injected
* immediately after loading.
*/
extern (C++) static void loadModule(Module m)
{
}

/******************************
* For the given symbol written to the OutBuffer, apply any
* target-specific prefixes based on the given linkage.
*/
extern (C++) static void prefixName(OutBuffer* buf, LINK linkage)
{
switch (linkage)
{
case LINKcpp:
if (global.params.isOSX)
buf.prependbyte('_');
break;
default:
break;
}
}
}

/******************************
* Private helpers for Target::paintAsType.
*/
// Write the integer value of 'e' into a unsigned byte buffer.
extern (C++) static void encodeInteger(Expression e, ubyte* buffer)
{
dinteger_t value = e.toInteger();
int size = cast(int)e.type.size();
for (int p = 0; p < size; p++)
{
int offset = p; // Would be (size - 1) - p; on BigEndian
buffer[offset] = ((value >> (p * 8)) & 0xFF);
}
}

// Write the bytes encoded in 'buffer' into an integer and returns
// the value as a new IntegerExp.
extern (C++) static Expression decodeInteger(Loc loc, Type type, ubyte* buffer)
{
dinteger_t value = 0;
int size = cast(int)type.size();
for (int p = 0; p < size; p++)
{
int offset = p; // Would be (size - 1) - p; on BigEndian
value |= (cast(dinteger_t)buffer[offset] << (p * 8));
}
return new IntegerExp(loc, value, type);
}

// Write the real value of 'e' into a unsigned byte buffer.
extern (C++) static void encodeReal(Expression e, ubyte* buffer)
{
switch (e.type.ty)
{
case Tfloat32:
{
float* p = cast(float*)buffer;
*p = cast(float)e.toReal();
break;
}
case Tfloat64:
{
double* p = cast(double*)buffer;
*p = cast(double)e.toReal();
break;
}
default:
assert(0);
}
}

// Write the bytes encoded in 'buffer' into a longdouble and returns
// the value as a new RealExp.
extern (C++) static Expression decodeReal(Loc loc, Type type, ubyte* buffer)
{
real value;
switch (type.ty)
{
case Tfloat32:
{
float* p = cast(float*)buffer;
value = ldouble(*p);
break;
}
case Tfloat64:
{
double* p = cast(double*)buffer;
value = ldouble(*p);
break;
}
default:
assert(0);
}
return new RealExp(loc, value, type);
}
8,517 changes: 0 additions & 8,517 deletions src/template.c

This file was deleted.

478 changes: 0 additions & 478 deletions src/tokens.c

This file was deleted.

988 changes: 988 additions & 0 deletions src/tokens.d

Large diffs are not rendered by default.

1,256 changes: 0 additions & 1,256 deletions src/traits.c

This file was deleted.

1,310 changes: 1,310 additions & 0 deletions src/traits.d

Large diffs are not rendered by default.

27 changes: 0 additions & 27 deletions src/unittests.c

This file was deleted.

305 changes: 0 additions & 305 deletions src/utf.c

This file was deleted.

774 changes: 774 additions & 0 deletions src/utf.d

Large diffs are not rendered by default.

197 changes: 0 additions & 197 deletions src/version.c

This file was deleted.

1,367 changes: 1,367 additions & 0 deletions src/visitor.d

Large diffs are not rendered by default.