From 6da7517c44af8856554a436c95f1f8406c436038 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 6 Apr 2017 23:48:56 +0200 Subject: [PATCH] LDC diff as of c2678f6f --- src/aggregate.d | 11 ++ src/arrayop.d | 5 + src/attrib.d | 54 ++++++- src/attrib.h | 14 +- src/builtin.d | 366 ++++++++++++++++++++++++++++++++++++++++++ src/complex_t.h | 4 +- src/cond.d | 2 + src/constfold.d | 16 ++ src/cppmangle.d | 27 +++- src/declaration.h | 32 ++++ src/dmodule.d | 71 ++++++++ src/doc.d | 4 + src/dscope.d | 12 ++ src/dstruct.d | 6 +- src/dsymbol.d | 32 ++++ src/dsymbol.h | 17 ++ src/dtemplate.d | 39 ++++- src/expression.d | 56 ++++++- src/expression.h | 30 +++- src/func.d | 286 ++++++++++++++++++++++++++++++--- src/globals.d | 72 +++++++++ src/globals.h | 75 ++++++++- src/gluelayer.d | 21 ++- src/hdrgen.d | 5 + src/hooks.d | 19 +++ src/idgen.d | 28 ++++ src/inline.d | 5 +- src/ldcbindings.d | 73 +++++++++ src/ldcbindings.h | 78 +++++++++ src/lexer.d | 15 +- src/mars.d | 194 +++++++++++++++++++++- src/mars.h | 8 + src/module.h | 32 +++- src/mtype.d | 71 +++++++- src/mtype.h | 22 ++- src/root/array.h | 128 +++++++++++++++ src/root/ctfloat.d | 59 ++++++- src/root/ctfloat.h | 27 ++++ src/root/longdouble.h | 3 +- src/root/newdelete.c | 2 +- src/root/object.h | 2 + src/root/port.d | 44 +++++ src/root/port.h | 9 ++ src/root/root.h | 10 ++ src/scope.h | 4 + src/statement.d | 110 ++++++++++++- src/statement.h | 67 +++++++- src/statementsem.d | 105 +++++++++++- src/target.d | 89 ++++++++++ src/target.h | 34 +++- src/template.h | 4 + src/tokens.h | 1 - src/traits.d | 8 + src/typinf.d | 21 ++- 54 files changed, 2444 insertions(+), 85 deletions(-) create mode 100644 src/hooks.d create mode 100644 src/ldcbindings.d create mode 100644 src/ldcbindings.h diff --git a/src/aggregate.d b/src/aggregate.d index 169633833827..026dee13f69c 100644 --- a/src/aggregate.d +++ b/src/aggregate.d @@ -252,6 +252,17 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol return 1; // unresolvable forward reference auto ad = cast(AggregateDeclaration)param; + version(IN_LLVM) + { + for (size_t i = 0; i < ad.fields.dim; i++) + { + if (ad.fields[i] == v) + { + // already a field + return 0; + } + } + } ad.fields.push(v); if (v.storage_class & STCref) diff --git a/src/arrayop.d b/src/arrayop.d index ef60aa422f9c..c6cd05111432 100644 --- a/src/arrayop.d +++ b/src/arrayop.d @@ -29,6 +29,7 @@ import ddmd.visitor; /************************************** * Hash table of array op functions already generated or known about. */ +version(IN_LLVM) {} else private __gshared FuncDeclaration[void*] arrayfuncs; @@ -200,6 +201,10 @@ extern (C++) Expression arrayOp(BinExp e, Scope* sc) auto ident = Identifier.idPool(buf.peekSlice()); + version(IN_LLVM) + { + auto arrayfuncs = sc._module.arrayfuncs; + } FuncDeclaration* pFd = cast(void*)ident in arrayfuncs; FuncDeclaration fd; if (pFd) diff --git a/src/attrib.d b/src/attrib.d index aa41548c67ae..d5d5facdfc8b 100644 --- a/src/attrib.d +++ b/src/attrib.d @@ -37,6 +37,12 @@ import ddmd.utf; import ddmd.utils; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} + + /*********************************************************** */ extern (C++) abstract class AttribDeclaration : Dsymbol @@ -917,6 +923,21 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration } return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); } + else if (IN_LLVM && ident == Id.LDC_profile_instr) { + bool emitInstr = true; + if (!args || args.dim != 1 || !DtoCheckProfileInstrPragma((*args)[0], emitInstr)) { + error("pragma(LDC_profile_instr, true or false) expected"); + (*args)[0] = new ErrorExp(); + } else { + // Only create a new scope if the emitInstrumentation flag is changed + if (sc.emitInstrumentation != emitInstr) { + auto newscope = sc.copy(); + newscope.emitInstrumentation = emitInstr; + return newscope; + } + } + } + return sc; } @@ -924,6 +945,13 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + + version(IN_LLVM) + { + LDCPragma llvm_internal = LDCPragma.LLVMnone; + const(char)* arg1str = null; + } + if (ident == Id.msg) { if (args) @@ -1075,6 +1103,11 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration } } } + // IN_LLVM + else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LDCPragma.LLVMnone) + { + // nothing to do anymore + } else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) @@ -1087,6 +1120,12 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration for (size_t i = 0; i < args.dim; i++) { Expression e = (*args)[i]; + version(IN_LLVM) + { + // ignore errors in ignored pragmas. + global.gag++; + uint errors_save = global.errors; + } sc = sc.startCTFE(); e = e.semantic(sc); e = resolveProperties(sc, e); @@ -1097,14 +1136,20 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration else fprintf(global.stdmsg, ","); fprintf(global.stdmsg, "%s", e.toChars()); + version(IN_LLVM) + { + // restore error state. + global.gag--; + global.errors = errors_save; + } } if (args.dim) fprintf(global.stdmsg, ")"); } fprintf(global.stdmsg, "\n"); } - goto Lnodecl; - } + static if (!IN_LLVM) + goto Lnodecl; } else error("unrecognized pragma(%s)", ident.toChars()); Ldecl: @@ -1128,6 +1173,11 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration error("can only apply to a single declaration"); } } + // IN_LLVM: add else clause + else + { + DtoCheckPragma(this, s, llvm_internal, arg1str); + } } if (sc2 != sc) sc2.pop(); diff --git a/src/attrib.h b/src/attrib.h index 43c0f02bc7e4..107beecc78f7 100644 --- a/src/attrib.h +++ b/src/attrib.h @@ -45,7 +45,7 @@ class AttribDeclaration : public Dsymbol void semantic2(Scope *sc); void semantic3(Scope *sc); void addComment(const utf8_t *comment); - const char *kind() const; + const char *kind(); bool oneMember(Dsymbol **ps, Identifier *ident); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); bool hasPointers(); @@ -114,7 +114,7 @@ class ProtDeclaration : public AttribDeclaration Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind() const; + const char *kind(); const char *toPrettyChars(bool unused); void accept(Visitor *v) { v->visit(this); } }; @@ -147,7 +147,7 @@ class AnonDeclaration : public AttribDeclaration void setScope(Scope *sc); void semantic(Scope *sc); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - const char *kind() const; + const char *kind(); AnonDeclaration *isAnonDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; @@ -160,7 +160,7 @@ class PragmaDeclaration : public AttribDeclaration Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void semantic(Scope *sc); - const char *kind() const; + const char *kind(); void accept(Visitor *v) { v->visit(this); } }; @@ -190,7 +190,7 @@ class StaticIfDeclaration : public ConditionalDeclaration void setScope(Scope *sc); void importAll(Scope *sc); void semantic(Scope *sc); - const char *kind() const; + const char *kind(); void accept(Visitor *v) { v->visit(this); } }; @@ -209,7 +209,7 @@ class CompileDeclaration : public AttribDeclaration void setScope(Scope *sc); void compileIt(Scope *sc); void semantic(Scope *sc); - const char *kind() const; + const char *kind(); void accept(Visitor *v) { v->visit(this); } }; @@ -229,7 +229,7 @@ class UserAttributeDeclaration : public AttribDeclaration void semantic2(Scope *sc); static Expressions *concat(Expressions *udas1, Expressions *udas2); Expressions *getAttributes(); - const char *kind() const; + const char *kind(); void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/builtin.d b/src/builtin.d index 27e7d8b2ea1d..cba159e69244 100644 --- a/src/builtin.d +++ b/src/builtin.d @@ -22,6 +22,9 @@ import ddmd.mtype; import ddmd.root.ctfloat; import ddmd.root.stringtable; import ddmd.tokens; +version(IN_LLVM) { + import ddmd.dtemplate; +} private: @@ -124,6 +127,252 @@ extern (C++) Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* argum return new IntegerExp(loc, k, Type.tint32); } +version(IN_LLVM) +{ + +private Type getTypeOfOverloadedIntrinsic(FuncDeclaration fd) +{ + // Depending on the state of the code generation we have to look at + // the template instance or the function declaration. + assert(fd.parent && "function declaration requires parent"); + TemplateInstance tinst = fd.parent.isTemplateInstance(); + if (tinst) + { + // See DtoOverloadedIntrinsicName + assert(tinst.tdtypes.dim == 1); + return cast(Type) tinst.tdtypes.data[0]; + } + else + { + assert(fd.type.ty == Tfunction); + TypeFunction tf = cast(TypeFunction) fd.type; + assert(tf.parameters.dim >= 1); + return tf.parameters.data[0].type; + } +} + +private int getBitsizeOfType(Loc loc, Type type) +{ + switch (type.toBasetype().ty) + { + case Tint64: + case Tuns64: return 64; + case Tint32: + case Tuns32: return 32; + case Tint16: + case Tuns16: return 16; + case Tint128: + case Tuns128: + error(loc, "cent/ucent not supported"); + break; + default: + error(loc, "unsupported type"); + break; + } + return 32; // in case of error +} + +extern (C++) Expression eval_llvmsin(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.sin(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmcos(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.cos(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmsqrt(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmlog(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.log(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmfabs(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.fabs(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmminnum(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + Expression arg1 = (*arguments)[1]; + assert(arg1.op == TOKfloat64); + return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), type); +} + +extern (C++) Expression eval_llvmmaxnum(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + Expression arg1 = (*arguments)[1]; + assert(arg1.op == TOKfloat64); + return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), type); +} + +extern (C++) Expression eval_llvmfloor(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.floor(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmceil(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.ceil(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmtrunc(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.trunc(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmround(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.round(arg0.toReal()), type); +} + +extern (C++) Expression eval_cttz(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKint64); + uinteger_t x = arg0.toInteger(); + + int n = getBitsizeOfType(loc, type); + + if (x == 0) + { + if ((*arguments)[1].toInteger()) + error(loc, "llvm.cttz.i#(0) is undefined"); + } + else + { + int c = n >> 1; + n -= 1; + const uinteger_t mask = (uinteger_t(1L) << n) | (uinteger_t(1L) << n)-1; + do { + uinteger_t y = (x << c) & mask; + if (y != 0) { n -= c; x = y; } + c = c >> 1; + } while (c != 0); + } + + return new IntegerExp(loc, n, type); +} + +extern (C++) Expression eval_ctlz(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKint64); + uinteger_t x = arg0.toInteger(); + if (x == 0 && (*arguments)[1].toInteger()) + error(loc, "llvm.ctlz.i#(0) is undefined"); + + int n = getBitsizeOfType(loc, type); + int c = n >> 1; + do { + uinteger_t y = x >> c; if (y != 0) { n -= c; x = y; } + c = c >> 1; + } while (c != 0); + + return new IntegerExp(loc, n - x, type); +} + +extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKint64); + uinteger_t n = arg0.toInteger(); + enum ulong BYTEMASK = 0x00FF00FF00FF00FF; + enum ulong SHORTMASK = 0x0000FFFF0000FFFF; + enum ulong INTMASK = 0x00000000FFFFFFFF; + switch (type.toBasetype().ty) + { + case Tint64: + case Tuns64: + // swap high and low uints + n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32); + goto case Tuns32; + case Tint32: + case Tuns32: + // swap adjacent ushorts + n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16); + goto case Tuns16; + case Tint16: + case Tuns16: + // swap adjacent ubytes + n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 ); + break; + case Tint128: + case Tuns128: + error(loc, "cent/ucent not supported"); + break; + default: + error(loc, "unsupported type"); + break; + } + return new IntegerExp(loc, n, type); +} + +extern (C++) Expression eval_ctpop(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + // FIXME Does not work for cent/ucent + Type type = getTypeOfOverloadedIntrinsic(fd); + + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKint64); + uinteger_t n = arg0.toInteger(); + int cnt = 0; + while (n) + { + cnt += (n & 1); + n >>= 1; + } + return new IntegerExp(loc, cnt, type); +} + +} +else // !IN_LLVM +{ + extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments) { Expression arg0 = (*arguments)[0]; @@ -143,6 +392,8 @@ extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arg return new IntegerExp(loc, n, arg0.type); } +} // !IN_LLVM + extern (C++) Expression eval_popcnt(Loc loc, FuncDeclaration fd, Expressions* arguments) { Expression arg0 = (*arguments)[0]; @@ -184,8 +435,15 @@ extern (C++) Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* ar } public extern (C++) void builtin_init() +{ +version(IN_LLVM) +{ + builtins._init(127); // Prime number like default value +} +else { builtins._init(47); +} // @safe @nogc pure nothrow real function(real) add_builtin("_D4core4math3sinFNaNbNiNfeZe", &eval_sin); add_builtin("_D4core4math3cosFNaNbNiNfeZe", &eval_cos); @@ -266,6 +524,114 @@ public extern (C++) void builtin_init() } // @safe @nogc pure nothrow long function(real) add_builtin("_D3std4math6rndtolFNaNbNiNfeZl", &eval_unimp); + +version(IN_LLVM) +{ + // intrinsic llvm.sin.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.sin.f32", &eval_llvmsin); + add_builtin("llvm.sin.f64", &eval_llvmsin); + add_builtin("llvm.sin.f80", &eval_llvmsin); + add_builtin("llvm.sin.f128", &eval_llvmsin); + add_builtin("llvm.sin.ppcf128", &eval_llvmsin); + + // intrinsic llvm.cos.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.cos.f32", &eval_llvmcos); + add_builtin("llvm.cos.f64", &eval_llvmcos); + add_builtin("llvm.cos.f80", &eval_llvmcos); + add_builtin("llvm.cos.f128", &eval_llvmcos); + add_builtin("llvm.cos.ppcf128", &eval_llvmcos); + + // intrinsic llvm.sqrt.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.sqrt.f32", &eval_llvmsqrt); + add_builtin("llvm.sqrt.f64", &eval_llvmsqrt); + add_builtin("llvm.sqrt.f80", &eval_llvmsqrt); + add_builtin("llvm.sqrt.f128", &eval_llvmsqrt); + add_builtin("llvm.sqrt.ppcf128", &eval_llvmsqrt); + + // intrinsic llvm.log.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.log.f32", &eval_llvmlog); + add_builtin("llvm.log.f64", &eval_llvmlog); + add_builtin("llvm.log.f80", &eval_llvmlog); + add_builtin("llvm.log.f128", &eval_llvmlog); + add_builtin("llvm.log.ppcf128", &eval_llvmlog); + + // intrinsic llvm.fabs.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.fabs.f32", &eval_llvmfabs); + add_builtin("llvm.fabs.f64", &eval_llvmfabs); + add_builtin("llvm.fabs.f80", &eval_llvmfabs); + add_builtin("llvm.fabs.f128", &eval_llvmfabs); + add_builtin("llvm.fabs.ppcf128", &eval_llvmfabs); + + // intrinsic llvm.minnum.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.minnum.f32", &eval_llvmminnum); + add_builtin("llvm.minnum.f64", &eval_llvmminnum); + add_builtin("llvm.minnum.f80", &eval_llvmminnum); + add_builtin("llvm.minnum.f128", &eval_llvmminnum); + add_builtin("llvm.minnum.ppcf128", &eval_llvmminnum); + + // intrinsic llvm.maxnum.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.maxnum.f32", &eval_llvmmaxnum); + add_builtin("llvm.maxnum.f64", &eval_llvmmaxnum); + add_builtin("llvm.maxnum.f80", &eval_llvmmaxnum); + add_builtin("llvm.maxnum.f128", &eval_llvmmaxnum); + add_builtin("llvm.maxnum.ppcf128", &eval_llvmmaxnum); + + // intrinsic llvm.floor.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.floor.f32", &eval_llvmfloor); + add_builtin("llvm.floor.f64", &eval_llvmfloor); + add_builtin("llvm.floor.f80", &eval_llvmfloor); + add_builtin("llvm.floor.f128", &eval_llvmfloor); + add_builtin("llvm.floor.ppcf128", &eval_llvmfloor); + + // intrinsic llvm.ceil.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.ceil.f32", &eval_llvmceil); + add_builtin("llvm.ceil.f64", &eval_llvmceil); + add_builtin("llvm.ceil.f80", &eval_llvmceil); + add_builtin("llvm.ceil.f128", &eval_llvmceil); + add_builtin("llvm.ceil.ppcf128", &eval_llvmceil); + + // intrinsic llvm.trunc.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.trunc.f32", &eval_llvmtrunc); + add_builtin("llvm.trunc.f64", &eval_llvmtrunc); + add_builtin("llvm.trunc.f80", &eval_llvmtrunc); + add_builtin("llvm.trunc.f128", &eval_llvmtrunc); + add_builtin("llvm.trunc.ppcf128", &eval_llvmtrunc); + + // intrinsic llvm.round.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.round.f32", &eval_llvmround); + add_builtin("llvm.round.f64", &eval_llvmround); + add_builtin("llvm.round.f80", &eval_llvmround); + add_builtin("llvm.round.f128", &eval_llvmround); + add_builtin("llvm.round.ppcf128", &eval_llvmround); + + // intrinsic llvm.bswap.i16/i32/i64/i128 + add_builtin("llvm.bswap.i16", &eval_bswap); + add_builtin("llvm.bswap.i32", &eval_bswap); + add_builtin("llvm.bswap.i64", &eval_bswap); + add_builtin("llvm.bswap.i128", &eval_bswap); + + // intrinsic llvm.cttz.i8/i16/i32/i64/i128 + add_builtin("llvm.cttz.i8", &eval_cttz); + add_builtin("llvm.cttz.i16", &eval_cttz); + add_builtin("llvm.cttz.i32", &eval_cttz); + add_builtin("llvm.cttz.i64", &eval_cttz); + add_builtin("llvm.cttz.i128", &eval_cttz); + + // intrinsic llvm.ctlz.i8/i16/i32/i64/i128 + add_builtin("llvm.ctlz.i8", &eval_ctlz); + add_builtin("llvm.ctlz.i16", &eval_ctlz); + add_builtin("llvm.ctlz.i32", &eval_ctlz); + add_builtin("llvm.ctlz.i64", &eval_ctlz); + add_builtin("llvm.ctlz.i128", &eval_ctlz); + + // intrinsic llvm.ctpop.i8/i16/i32/i64/i128 + add_builtin("llvm.ctpop.i8", &eval_ctpop); + add_builtin("llvm.ctpop.i16", &eval_ctpop); + add_builtin("llvm.ctpop.i32", &eval_ctpop); + add_builtin("llvm.ctpop.i64", &eval_ctpop); + add_builtin("llvm.ctpop.i128", &eval_ctpop); +} + // @safe @nogc pure nothrow int function(uint) add_builtin("_D4core5bitop3bsfFNaNbNiNfkZi", &eval_bsf); add_builtin("_D4core5bitop3bsrFNaNbNiNfkZi", &eval_bsr); diff --git a/src/complex_t.h b/src/complex_t.h index a1ad38890c70..633001de93fb 100644 --- a/src/complex_t.h +++ b/src/complex_t.h @@ -22,7 +22,7 @@ struct complex_t real_t re; real_t im; - complex_t(real_t re) : re(re), im(ldouble(0)) {} + complex_t(real_t re) : re(re), im(0) {} complex_t(real_t re, real_t im) : re(re), im(im) {} complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); } @@ -54,7 +54,7 @@ struct complex_t int operator != (complex_t y) { return re != y.re || im != y.im; } private: - complex_t() : re(ldouble(0)), im(ldouble(0)) {} + complex_t() : re(0), im(0) {} }; inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; } diff --git a/src/cond.d b/src/cond.d index 634b3394dba1..b04f85df9a79 100644 --- a/src/cond.d +++ b/src/cond.d @@ -297,6 +297,8 @@ extern (C++) final class VersionCondition : DVCondition "MIPS_HardFloat", "NVPTX", "NVPTX64", + "RISCV32", + "RISCV64", "SPARC", "SPARC_V8Plus", "SPARC_SoftFloat", diff --git a/src/constfold.d b/src/constfold.d index 510e8fc328eb..2e116181eade 100644 --- a/src/constfold.d +++ b/src/constfold.d @@ -29,6 +29,11 @@ import ddmd.target; import ddmd.tokens; import ddmd.utf; +version(IN_LLVM) +{ + import gen.dpragma; +} + private enum LOG = false; extern (C++) Expression expType(Type type, Expression e) @@ -54,6 +59,17 @@ extern (C++) int isConst(Expression e) case TOKnull: return 0; case TOKsymoff: +version(IN_LLVM) +{ + // We don't statically know anything about the address of a weak symbol + // if there is no offset. With an offset, we can at least say that it is + // non-zero. + SymOffExp soe = cast(SymOffExp) e; + if (soe.var.llvmInternal == LDCPragma.LLVMextern_weak && !soe.offset) + { + return 0; + } +} return 2; default: return 0; diff --git a/src/cppmangle.d b/src/cppmangle.d index 385d082ac687..0301a3714e6e 100644 --- a/src/cppmangle.d +++ b/src/cppmangle.d @@ -27,6 +27,10 @@ import ddmd.root.rootobject; import ddmd.target; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) { + import ddmd.errors; + import gen.llvmhelpers; +} /* Do mangling for C++ linkage. * No attempt is made to support mangling of templates, operator @@ -37,7 +41,7 @@ import ddmd.visitor; * ABI has no concept of. These affect every D mangled name, * so nothing would be compatible anyway. */ -static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) +static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) { /* * Follows Itanium C++ ABI 1.86 @@ -922,6 +926,7 @@ static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TAR } } +version(IN_LLVM) {} else { extern (C++) const(char)* toCppMangle(Dsymbol s) { //printf("toCppMangle(%s)\n", s.toChars()); @@ -936,7 +941,9 @@ static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TAR return v.mangle_typeinfo(s); } } -else static if (TARGET_WINDOS) + +} +static if (IN_LLVM || TARGET_WINDOS) { // Windows DMC and Microsoft Visual C++ mangling enum VC_SAVED_TYPE_CNT = 10u; @@ -1962,6 +1969,21 @@ else static if (TARGET_WINDOS) } } +version(IN_LLVM) { + extern (C++) const(char)* toCppMangle(Dsymbol s) + { + if (isTargetWindowsMSVC()) + { + scope VisualCPPMangler v = new VisualCPPMangler(false); + return v.mangleOf(s); + } + else + { + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangleOf(s); + } + } +} else { extern (C++) const(char)* toCppMangle(Dsymbol s) { scope VisualCPPMangler v = new VisualCPPMangler(!global.params.mscoff); @@ -1974,6 +1996,7 @@ else static if (TARGET_WINDOS) assert(0); } } +} else { static assert(0, "fix this"); diff --git a/src/declaration.h b/src/declaration.h index 35c61d3c195e..2ed170e92005 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -31,6 +31,9 @@ class ExpInitializer; class StructDeclaration; struct InterState; struct CompiledCtfeFunction; +#if IN_LLVM +struct Symbol; +#endif enum LINK; enum TOK; @@ -179,6 +182,10 @@ class TupleDeclaration : public Declaration TupleDeclaration *isTupleDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } + +#if IN_LLVM + void semantic3(Scope *sc); +#endif }; /**************************************************************/ @@ -492,6 +499,26 @@ class FuncDeclaration : public Declaration const char *mangleString; // mangled symbol created from mangleExact() +#if IN_LLVM + // Argument lists for the __require/__ensure calls. NULL if not a virtual + // function with contracts. + Expressions *fdrequireParams; + Expressions *fdensureParams; + + const char *intrinsicName; + uint32_t priority; + + // true if overridden with the pragma(LDC_allow_inline); statement + bool allowInlining; + + // true if set with the pragma(LDC_never_inline); statement + bool neverInline; + + // Whether to emit instrumentation code if -fprofile-instr-generate is specified, + // the value is set with pragma(LDC_profile_instr, true|false) + bool emitInstrumentation; +#endif + Identifier *outId; // identifier for out statement VarDeclaration *vresult; // variable corresponding to outId LabelDsymbol *returnLabel; // where the return goes @@ -624,8 +651,13 @@ class FuncDeclaration : public Declaration bool checkClosure(); bool hasNestedFrameRefs(); void buildResultVar(Scope *sc, Type *tret); +#if IN_LLVM + Statement *mergeFrequire(Statement *, Expressions *params = nullptr); + Statement *mergeFensure(Statement *, Identifier *oid, Expressions *params = nullptr); +#else Statement *mergeFrequire(Statement *); Statement *mergeFensure(Statement *, Identifier *oid); +#endif Parameters *getParameters(int *pvarargs); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); diff --git a/src/dmodule.d b/src/dmodule.d index 3592056be298..37dcbf0368bb 100644 --- a/src/dmodule.d +++ b/src/dmodule.d @@ -27,6 +27,11 @@ import ddmd.globals; import ddmd.id; import ddmd.identifier; import ddmd.parse; +version(IN_LLVM) { + import ddmd.root.aav; + import ddmd.root.array; + import ddmd.root.rmem; +} import ddmd.root.file; import ddmd.root.filename; import ddmd.root.outbuffer; @@ -393,7 +398,25 @@ extern (C++) final class Module : Package if(!FileName.absolute(srcfilename)) { srcfilePath = getcwd(null, 0); } +version(IN_LLVM) +{ + const(char)* objExt; + if (global.params.output_o) + objExt = global.obj_ext; + else if (global.params.output_bc) + objExt = global.bc_ext; + else if (global.params.output_ll) + objExt = global.ll_ext; + else if (global.params.output_s) + objExt = global.s_ext; + + if (objExt) + objfile = setOutfile(global.params.objname, global.params.objdir, filename, objExt); +} +else +{ objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext); +} if (doDocComment) setDocfile(); if (doHdrGen) @@ -532,6 +555,23 @@ extern (C++) final class Module : Package argdoc = arg; else argdoc = FileName.name(arg); + version (IN_LLVM) + { + if (global.params.fullyQualifiedObjectFiles) + { + const fqn = md ? md.toChars() : toChars(); + argdoc = FileName.replaceName(argdoc, fqn); + + // add ext, otherwise forceExt will make nested.module into nested. + const len = strlen(argdoc); + const extlen = strlen(ext); + char* s = cast(char*)mem.xmalloc(len + 1 + extlen + 1); + memcpy(s, argdoc, len); + s[len] = '.'; + memcpy(s + len + 1, ext, extlen + 1); // incl. terminating null + argdoc = s; + } + } // If argdoc doesn't have an absolute path, make it relative to dir if (!FileName.absolute(argdoc)) { @@ -562,8 +602,17 @@ extern (C++) final class Module : Package if (!strcmp(srcfile.toChars(), "object.d")) { .error(loc, "cannot find source code for runtime library file 'object.d'"); +version(IN_LLVM) +{ + errorSupplemental(loc, "ldc2 might not be correctly installed."); + errorSupplemental(loc, "Please check your ldc2.conf configuration file."); + errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC."); +} +else +{ errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); errorSupplemental(loc, "config file: %s", FileName.canonicalName(global.inifilename)); +} } else { @@ -1129,6 +1178,9 @@ extern (C++) final class Module : Package int needModuleInfo() { //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); +version(IN_LLVM) + return needmoduleinfo; +else return needmoduleinfo || global.params.cov; } @@ -1374,6 +1426,25 @@ extern (C++) final class Module : Package Symbol* munittest; // module unittest failure function Symbol* marray; // module array bounds function + version(IN_LLVM) + { + //llvm::Module* genLLVMModule(llvm::LLVMContext& context); + void checkAndAddOutputFile(File* file); + void makeObjectFilenameUnique(); + + bool llvmForceLogging; + bool noModuleInfo; /// Do not emit any module metadata. + + // array ops emitted in this module already + import ddmd.func; + FuncDeclaration[void*] arrayfuncs; + + // Coverage analysis + void* d_cover_valid; // llvm::GlobalVariable* --> private immutable size_t[] _d_cover_valid; + void* d_cover_data; // llvm::GlobalVariable* --> private uint[] _d_cover_data; + Array!size_t d_cover_valid_init; // initializer for _d_cover_valid + } + override inout(Module) isModule() inout { return this; diff --git a/src/doc.d b/src/doc.d index ee6ab64ce4c1..bc8340414463 100644 --- a/src/doc.d +++ b/src/doc.d @@ -359,6 +359,10 @@ extern (C++) __gshared const(char)* ddoc_decl_dd_e = ")\n"; */ extern (C++) void gendocfile(Module m) { + version (IN_LLVM) + { + m.checkAndAddOutputFile(m.docfile); + } static __gshared OutBuffer mbuf; static __gshared int mbuf_done; OutBuffer buf; diff --git a/src/dscope.d b/src/dscope.d index 9df51c500cbe..38ea4bb692bf 100644 --- a/src/dscope.d +++ b/src/dscope.d @@ -169,6 +169,11 @@ struct Scope // user defined attributes UserAttributeDeclaration userAttribDecl; +version(IN_LLVM) +{ + bool emitInstrumentation = true; // whether to emit instrumentation with -fprofile-instr-generate +} + DocComment* lastdc; /// documentation comment for last symbol at this scope uint[void*] anchorCounts; /// lookup duplicate anchor name count Identifier prevAnchor; /// qualified symbol name of last doc anchor @@ -393,8 +398,15 @@ struct Scope { size_t dim = fieldinit_dim; fi = cast(uint*)mem.xmalloc(uint.sizeof * dim); +version(IN_LLVM) +{ // ASan + memcpy(fi, fieldinit, (*fi).sizeof * dim); +} +else +{ for (size_t i = 0; i < dim; i++) fi[i] = fieldinit[i]; +} } return fi; } diff --git a/src/dstruct.d b/src/dstruct.d index 62855a618921..911d384843be 100644 --- a/src/dstruct.d +++ b/src/dstruct.d @@ -27,9 +27,13 @@ import ddmd.identifier; import ddmd.mtype; import ddmd.opover; import ddmd.tokens; -import ddmd.typinf; +// IN_LLVM import ddmd.typinf; import ddmd.visitor; +version(IN_LLVM) { + import gen.typinf; +} + /*************************************** * Search toString member function for TypeInfo_Struct. * string toString(); diff --git a/src/dsymbol.d b/src/dsymbol.d index ee2858df6863..dbb8c9da1881 100644 --- a/src/dsymbol.d +++ b/src/dsymbol.d @@ -47,6 +47,13 @@ import ddmd.statement; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) +{ + // Functions to construct/destruct Dsymbol.ir + extern (C++) void* newIrDsymbol(); + extern (C++) void deleteIrDsymbol(void*); +} + struct Ungag { uint oldgag; @@ -208,10 +215,22 @@ extern (C++) class Dsymbol : RootObject // (only use this with ddoc) UnitTestDeclaration ddocUnittest; + version(IN_LLVM) + { + // llvm stuff + uint llvmInternal; + + void* ir; // IrDsymbol* + } + final extern (D) this() { //printf("Dsymbol::Dsymbol(%p)\n", this); this.semanticRun = PASSinit; + version(IN_LLVM) + { + this.ir = newIrDsymbol(); + } } final extern (D) this(Identifier ident) @@ -219,6 +238,19 @@ extern (C++) class Dsymbol : RootObject //printf("Dsymbol::Dsymbol(%p, ident)\n", this); this.ident = ident; this.semanticRun = PASSinit; + version(IN_LLVM) + { + this.ir = newIrDsymbol(); + } + } + + version(IN_LLVM) + { + extern (D) ~this() + { + deleteIrDsymbol(this.ir); + this.ir = null; + } } static Dsymbol create(Identifier ident) diff --git a/src/dsymbol.h b/src/dsymbol.h index 7dde6d515164..9fb7d02714ab 100644 --- a/src/dsymbol.h +++ b/src/dsymbol.h @@ -23,6 +23,16 @@ #include "arraytypes.h" #include "visitor.h" +#if IN_LLVM +# if defined(_MSC_VER) +# undef min +# undef max +# endif +#include +#include "../ir/irdsymbol.h" +#endif + + class Identifier; struct Scope; class DsymbolTable; @@ -166,6 +176,13 @@ class Dsymbol : public RootObject UserAttributeDeclaration *userAttribDecl; // user defined attributes UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc) +#if IN_LLVM + // llvm stuff + uint32_t llvmInternal; + + IrDsymbol *ir; +#endif + static Dsymbol *create(Identifier *); const char *toChars(); virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments diff --git a/src/dtemplate.d b/src/dtemplate.d index 31f6af1a1fda..2392d2c58132 100644 --- a/src/dtemplate.d +++ b/src/dtemplate.d @@ -41,6 +41,11 @@ import ddmd.root.rootobject; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) +{ +import gen.llvmhelpers; +} + private enum LOG = false; enum IDX_NOTFOUND = 0x12345678; @@ -432,6 +437,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; +version(IN_LLVM) { + const(char)* intrinsicName; +} + extern (D) this(Loc loc, Identifier id, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { super(id); @@ -487,7 +496,18 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol for (size_t i = 0; i < p.dim; i++) (*p)[i] = (*parameters)[i].syntaxCopy(); } +version(IN_LLVM) +{ + auto td = new TemplateDeclaration(loc, ident, p, + constraint ? constraint.syntaxCopy() : null, + Dsymbol.arraySyntaxCopy(members), ismixin, literal); + td.intrinsicName = intrinsicName ? strdup(intrinsicName) : null; + return td; +} +else +{ return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal); +} } override void semantic(Scope* sc) @@ -6324,6 +6344,16 @@ extern (C++) class TemplateInstance : ScopeDsymbol //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); aliasdecl = s; + version(IN_LLVM) + { + // LDC propagate internal information + if (tempdecl.llvmInternal != 0) { + s.llvmInternal = tempdecl.llvmInternal; + if (FuncDeclaration fd = s.isFuncDeclaration()) { + DtoSetFuncDeclIntrinsicName(this, tempdecl, fd); + } + } + } } } @@ -6492,7 +6522,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol while (ti && !ti.deferred && ti.tinst) { ti = ti.tinst; - if (++nest > 500) + // IN_LLVM replaced: if (++nest > 500) + if (++nest > global.params.nestedTmpl) // LDC_FIXME: add testcase for this { global.gag = 0; // ensure error message gets printed error("recursive expansion"); @@ -8277,7 +8308,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol static __gshared int nest; // extracted to a function to allow windows SEH to work without destructors in the same function //printf("%d\n", nest); - if (++nest > 500) + // IN_LLVM replaced: if (++nest > 500) + if (++nest > global.params.nestedTmpl) // LDC_FIXME: add testcase for this { global.gag = 0; // ensure error message gets printed error("recursive expansion"); @@ -8641,7 +8673,8 @@ extern (C++) final class TemplateMixin : TemplateInstance static __gshared int nest; //printf("%d\n", nest); - if (++nest > 500) + // IN_LLVM replaced: if (++nest > 500) + if (++nest > global.params.nestedTmpl) // LDC_FIXME: add testcase for this { global.gag = 0; // ensure error message gets printed error("recursive expansion"); diff --git a/src/expression.d b/src/expression.d index f3546c470f0b..c262e581b3be 100644 --- a/src/expression.d +++ b/src/expression.d @@ -66,11 +66,17 @@ import ddmd.sideeffect; import ddmd.target; import ddmd.tokens; import ddmd.traits; -import ddmd.typinf; +// IN_LLVM import ddmd.typinf; import ddmd.utf; import ddmd.utils; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; + import gen.typinf; +} + enum LOGSEMANTIC = false; void emplaceExp(T : Expression, Args...)(void* p, Args args) { @@ -135,6 +141,14 @@ L1: { //printf("rewriting e1 to %s's this\n", f.toChars()); n++; + version(IN_LLVM) + { + // LDC seems dmd misses it sometimes here :/ + if (f.isMember2()) { + f.vthis.nestedrefs.push(sc.parent.isFuncDeclaration()); + f.closureVars.push(f.vthis); + } + } e1 = new VarExp(loc, f.vthis); } else @@ -1745,7 +1759,9 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t { // These will be the trailing ... arguments // If not D linkage, do promotions - if (tf.linkage != LINKd) + // IN_LLVM: don't do promotions on intrinsics + // IN_LLVM replaced: if (tf.linkage != LINKd) + if (tf.linkage != LINKd && (!fd || !DtoIsIntrinsic(fd))) { // Promote bytes, words, etc., to ints arg = integralPromotions(arg, sc); @@ -1976,7 +1992,7 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); // If D linkage and variadic, add _arguments[] as first argument - if (tf.linkage == LINKd && tf.varargs == 1) + if (!IN_LLVM && tf.linkage == LINKd && tf.varargs == 1) { assert(arguments.dim >= nparams); @@ -2489,7 +2505,8 @@ enum WANTexpand = 1; // expand const/immutable variables if possible /*********************************************************** */ -extern (C++) abstract class Expression : RootObject +// LDC: Instantiated in gen/asm-x86.h (`Handled = createExpression(...)`). +extern (C++) /* IN_LLVM abstract */ class Expression : RootObject { Loc loc; // file location Type type; // !=null means that semantic() has been run @@ -5355,6 +5372,18 @@ extern (C++) final class StructLiteralExp : Expression Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip Type stype; /// final type of result (can be different from sd's type) + version(IN_LLVM) + { + // With the introduction of pointers returned from CTFE, struct literals can + // now contain pointers to themselves. While in toElem, contains a pointer + // to the memory used to build the literal for resolving such references. + void* inProgressMemory; // llvm::Value* + + // A global variable for taking the address of this struct literal constant, + // if it already exists. Used to resolve self-references. + void* globalVar; // llvm::GlobalVariable* + } + bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol Symbol* sym; /// back end symbol to initialize with literal @@ -6474,6 +6503,15 @@ extern (C++) final class SymOffExp : SymbolExp override bool isBool(bool result) { +version(IN_LLVM) +{ + // For a weak symbol, we only statically know that it is non-null if the + // offset is non-zero. + if (var.llvmInternal == LDCPragma.LLVMextern_weak) + { + return result && offset != 0; + } +} return result ? true : false; } @@ -7066,6 +7104,8 @@ extern (C++) final class FuncExp : Expression // Bugzilla 12508: Tweak function body for covariant returns. (*presult).fd.modifyReturns(sc, tof.next); + version(IN_LLVM) + (*presult).fd.type = tof; // Also, update function return type. } } else if (!flag) @@ -10693,6 +10733,14 @@ extern (C++) final class AddrExp : UnaExp FuncDeclaration f = ve.var.isFuncDeclaration(); if (f) { + version(IN_LLVM) + { + if (DtoIsIntrinsic(f)) + { + error("cannot take the address of intrinsic function %s", e1.toChars()); + return this; + } + } /* Because nested functions cannot be overloaded, * mark here that we took its address because castTo() * may not be called with an exact match. diff --git a/src/expression.h b/src/expression.h index 72bc4785ea4b..bdd2377fcaa4 100644 --- a/src/expression.h +++ b/src/expression.h @@ -50,6 +50,13 @@ class StringExp; class ArrayExp; class SliceExp; struct UnionExp; +#if IN_LLVM +class SymbolDeclaration; +namespace llvm { + class GlobalVariable; + class Value; +} +#endif void initPrecedence(); @@ -128,7 +135,7 @@ class Expression : public RootObject unsigned char size; // # of bytes in Expression so we can copy() it unsigned char parens; // if this is a parenthesized expression - static void init(); + static void _init(); Expression *copy(); virtual Expression *syntaxCopy(); virtual Expression *semantic(Scope *sc); @@ -363,6 +370,16 @@ class StringExp : public Expression Expression *modifiableLvalue(Scope *sc, Expression *e); unsigned charAt(uinteger_t i) const; void accept(Visitor *v) { v->visit(this); } +#if IN_LLVM + // The D version returns a slice. + const char *toStringz() const + { + auto nbytes = len * sz; + char* s = (char*)mem.xmalloc(nbytes + sz); + writeTo(s, true); + return s; + } +#endif size_t numberOfCodeUnits(int tynto = 0) const; void writeTo(void* dest, bool zero, int tyto = 0) const; char *toPtr(); @@ -443,6 +460,17 @@ class StructLiteralExp : public Expression Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip Type *stype; // final type of result (can be different from sd's type) +#if IN_LLVM + // With the introduction of pointers returned from CTFE, struct literals can + // now contain pointers to themselves. While in toElem, contains a pointer + // to the memory used to build the literal for resolving such references. + llvm::Value* inProgressMemory; + + // A global variable for taking the address of this struct literal constant, + // if it already exists. Used to resolve self-references. + llvm::GlobalVariable *globalVar; +#endif + bool useStaticInit; // if this is true, use the StructDeclaration's init symbol Symbol *sym; // back end symbol to initialize with literal diff --git a/src/func.d b/src/func.d index edbd0be23abb..08c1e9187a31 100644 --- a/src/func.d +++ b/src/func.d @@ -415,6 +415,27 @@ extern (C++) class FuncDeclaration : Declaration const(char)* mangleString; /// mangled symbol created from mangleExact() + version(IN_LLVM) + { + // Argument lists for the __require/__ensure calls. NULL if not a virtual + // function with contracts. + Expressions* fdrequireParams; + Expressions* fdensureParams; + + const(char)* intrinsicName; + uint priority; + + // true if overridden with the pragma(LDC_allow_inline); statement + bool allowInlining = false; + + // true if set with the pragma(LDC_never_inline); statement + bool neverInline = false; + + // Whether to emit instrumentation code if -fprofile-instr-generate is specified, + // the value is set with pragma(LDC_profile_instr, true|false) + bool emitInstrumentation = true; + } + Identifier outId; /// identifier for out statement VarDeclaration vresult; /// variable corresponding to outId LabelDsymbol returnLabel; /// where the return goes @@ -522,9 +543,36 @@ extern (C++) class FuncDeclaration : Declaration f.fensure = fensure ? fensure.syntaxCopy() : null; f.fbody = fbody ? fbody.syntaxCopy() : null; assert(!fthrows); // deprecated + version(IN_LLVM) + { + f.intrinsicName = intrinsicName ? strdup(intrinsicName) : null; + } return f; } + version(IN_LLVM) + { + final private Parameters* outToRef(Parameters* params) + { + auto result = new Parameters(); + + int outToRefDg(size_t n, Parameter p) + { + if (p.storageClass & STCout) + { + p = p.syntaxCopy(); + p.storageClass &= ~STCout; + p.storageClass |= STCref; + } + result.push(p); + return 0; + } + + Parameter._foreach(params, &outToRefDg); + return result; + } + } + /// Do the semantic analysis on the external interface to the function. override void semantic(Scope* sc) { @@ -602,6 +650,10 @@ extern (C++) class FuncDeclaration : Declaration inlining = sc.inlining; protection = sc.protection; userAttribDecl = sc.userAttribDecl; + version(IN_LLVM) + { + emitInstrumentation = sc.emitInstrumentation; + } if (!originalType) originalType = type.syntaxCopy(); @@ -1197,13 +1249,33 @@ extern (C++) class FuncDeclaration : Declaration */ if (frequire) { - /* in { ... } - * becomes: - * void __require() { ... } - * __require(); - */ + version(IN_LLVM) + { + /* In LDC, we can't rely on the codegen hacks DMD has to be able + * to just magically call the contract function parameterless with + * the parameters being picked up from the outer stack frame. + * + * Thus, we actually pass all the function parameters to the + * __require call, rewriting out parameters to ref ones because + * they have already been zeroed in the outer function. + * + * Also initialize fdrequireParams here - it will get filled in + * in semantic3. + */ + fdrequireParams = new Expressions(); + auto params = outToRef((cast(TypeFunction)type).parameters); + auto tf = new TypeFunction(params, Type.tvoid, 0, LINKd); + } + else + { + /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + auto tf = new TypeFunction(null, Type.tvoid, 0, LINKd); + } Loc loc = frequire.loc; - auto tf = new TypeFunction(null, Type.tvoid, 0, LINKd); tf.isnothrow = f.isnothrow; tf.isnogc = f.isnogc; tf.purity = f.purity; @@ -1211,7 +1283,14 @@ extern (C++) class FuncDeclaration : Declaration auto fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf); fd.fbody = frequire; Statement s1 = new ExpStatement(loc, fd); - Expression e = new CallExp(loc, new VarExp(loc, fd, false), cast(Expressions*)null); + version(IN_LLVM) + { + Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams); + } + else + { + Expression e = new CallExp(loc, new VarExp(loc, fd, false), cast(Expressions*)null); + } Statement s2 = new ExpStatement(loc, e); frequire = new CompoundStatement(loc, s1, s2); fdrequire = fd; @@ -1219,21 +1298,45 @@ extern (C++) class FuncDeclaration : Declaration if (!outId && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid) outId = Id.result; // provide a default - - if (fensure) + version(IN_LLVM) { - /* out (result) { ... } - * becomes: - * void __ensure(ref tret result) { ... } - * __ensure(result); + /* We need to initialize fdensureParams here and not in the block below + * to have the parameter available when calling a base class ensure(), + * even if this functions doesn't have an out contract. */ + fdensureParams = new Expressions(); + if (outId) + fdensureParams.push(new IdentifierExp(loc, outId)); + } + if (fensure) + { + version(IN_LLVM) + { + /* Same as for in contracts, see above. */ + auto fparams = outToRef((cast(TypeFunction)type).parameters); + } + else + { + /* out (result) { ... } + * becomes: + * void __ensure(ref tret result) { ... } + * __ensure(result); + */ + auto fparams = new Parameters(); + } Loc loc = fensure.loc; - auto fparams = new Parameters(); Parameter p = null; if (outId) { p = new Parameter(STCref | STCconst, f.nextOf(), outId, null); - fparams.push(p); + version(IN_LLVM) + { + fparams.insert(0, p); + } + else + { + fparams.push(p); + } } auto tf = new TypeFunction(fparams, Type.tvoid, 0, LINKd); tf.isnothrow = f.isnothrow; @@ -1243,10 +1346,17 @@ extern (C++) class FuncDeclaration : Declaration auto fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf); fd.fbody = fensure; Statement s1 = new ExpStatement(loc, fd); - Expression eresult = null; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression e = new CallExp(loc, new VarExp(loc, fd, false), eresult); + version(IN_LLVM) + { + Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams); + } + else + { + Expression eresult = null; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression e = new CallExp(loc, new VarExp(loc, fd, false), eresult); + } Statement s2 = new ExpStatement(loc, e); fensure = new CompoundStatement(loc, s1, s2); fdensure = fd; @@ -1261,7 +1371,16 @@ extern (C++) class FuncDeclaration : Declaration initInferAttributes(); Module.dprogress++; - semanticRun = PASSsemanticdone; + version(IN_LLVM) + { + //LDC relies on semanticRun variable not being reset here + if(semanticRun < PASSsemanticdone) + semanticRun = PASSsemanticdone; + } + else + { + semanticRun = PASSsemanticdone; + } /* Save scope for possible later use (if we need the * function internals) @@ -1499,7 +1618,10 @@ extern (C++) class FuncDeclaration : Declaration if (f.linkage == LINKd || (f.parameters && Parameter.dim(f.parameters))) { // Declare _argptr - Type t = Type.tvalist; + version (IN_LLVM) + Type t = Type.tvalist.semantic(loc, sc); + else + Type t = Type.tvalist; // Init is handled in FuncDeclaration_toObjFile v_argptr = new VarDeclaration(Loc(), t, Id._argptr, new VoidInitializer(loc)); v_argptr.storage_class |= STCtemp; @@ -1509,6 +1631,32 @@ extern (C++) class FuncDeclaration : Declaration } } + version(IN_LLVM) + { + // Make sure semantic analysis has been run on argument types. This is + // e.g. needed for TypeTuple!(int, int) to be picked up as two int + // parameters by the Parameter functions. + if (f.parameters) + { + for (size_t i = 0; i < Parameter.dim(f.parameters); i++) + { + Parameter arg = Parameter.getNth(f.parameters, i); + Type nw = arg.type.semantic(Loc(), sc); + if (arg.type != nw) + { + arg.type = nw; + // Examine this index again. + // This is important if it turned into a tuple. + // In particular, the empty tuple should be handled or the + // next parameter will be skipped. + // LDC_FIXME: Maybe we only need to do this for tuples, + // and can add tuple.length after decrement? + i--; + } + } + } + } + /* Declare all the function parameters as variables * and install them in parameters[] */ @@ -1550,6 +1698,13 @@ extern (C++) class FuncDeclaration : Declaration parameters.push(v); localsymtab.insert(v); v.parent = this; + version(IN_LLVM) + { + if (fdrequireParams) + fdrequireParams.push(new VarExp(loc, v)); + if (fdensureParams) + fdensureParams.push(new VarExp(loc, v)); + } } } @@ -2014,6 +2169,9 @@ extern (C++) class FuncDeclaration : Declaration } } +// we'll handle variadics ourselves +static if (!IN_LLVM) +{ if (_arguments) { /* Advance to elements[] member of TypeInfo_Tuple with: @@ -2028,6 +2186,7 @@ extern (C++) class FuncDeclaration : Declaration auto de = new DeclarationExp(Loc(), _arguments); a.push(new ExpStatement(Loc(), de)); } +} // Merge contracts together with body into one compound statement @@ -2057,8 +2216,26 @@ extern (C++) class FuncDeclaration : Declaration if (f.next.ty != Tvoid && vresult) { +version(IN_LLVM) +{ + Expression e = null; + if (isCtorDeclaration()) + { + ThisExp te = new ThisExp(Loc()); + te.type = vthis.type; + te.var = vthis; + e = te; + } + else + { + e = new VarExp(Loc(), vresult); + } +} +else +{ // Create: return vresult; Expression e = new VarExp(Loc(), vresult); +} if (tintro) { e = e.implicitCastTo(sc, tintro.nextOf()); @@ -2331,8 +2508,16 @@ extern (C++) class FuncDeclaration : Declaration TemplateInstance spec = isSpeculative(); uint olderrs = global.errors; uint oldgag = global.gag; +version (IN_LLVM) +{ + if (global.gag && !spec && !global.gaggedForInlining) + global.gag = 0; +} +else +{ if (global.gag && !spec) global.gag = 0; +} semantic3(_scope); global.gag = oldgag; @@ -3784,8 +3969,12 @@ extern (C++) class FuncDeclaration : Declaration * Merge into this function the 'in' contracts of all it overrides. * 'in's are OR'd together, i.e. only one of them needs to pass. */ - final Statement mergeFrequire(Statement sf) + // IN_LLVM replaced: final Statement mergeFrequire(Statement sf) + final Statement mergeFrequire(Statement sf, Expressions *params = null) { + if (params is null) + params = fdrequireParams; + /* If a base function and its override both have an IN contract, then * only one of them needs to succeed. This is done by generating: * @@ -3802,6 +3991,12 @@ extern (C++) class FuncDeclaration : Declaration * If base.in() throws, then derived.in()'s body is executed. */ +version(IN_LLVM) +{ + /* In LDC, we can't rely on these codegen hacks - we explicitly pass + * parameters on to the contract functions. + */ +} else { /* Implementing this is done by having the overriding function call * nested functions (the fdrequire functions) nested inside the overridden * function. This requires that the stack layout of the calling function's @@ -3818,6 +4013,7 @@ extern (C++) class FuncDeclaration : Declaration * a stack local, allocate that local immediately following the exception * handler block, so it is always at the same offset from EBP. */ +} for (size_t i = 0; i < foverrides.dim; i++) { FuncDeclaration fdv = foverrides[i]; @@ -3834,6 +4030,9 @@ extern (C++) class FuncDeclaration : Declaration sc.pop(); } +version(IN_LLVM) + sf = fdv.mergeFrequire(sf, params); +else sf = fdv.mergeFrequire(sf); if (sf && fdv.fdrequire) { @@ -3842,8 +4041,13 @@ extern (C++) class FuncDeclaration : Declaration * try { __require(); } * catch (Throwable) { frequire; } */ +version(IN_LLVM) + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params); +else +{ Expression eresult = null; Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), eresult); +} Statement s2 = new ExpStatement(loc, e); auto c = new Catch(loc, getThrowable(), null, sf); @@ -3862,8 +4066,15 @@ extern (C++) class FuncDeclaration : Declaration * Merge into this function the 'out' contracts of all it overrides. * 'out's are AND'd together, i.e. all of them need to pass. */ - final Statement mergeFensure(Statement sf, Identifier oid) + // IN_LLVM replaced: final Statement mergeFensure(Statement sf, Identifier oid) + final Statement mergeFensure(Statement sf, Identifier oid, Expressions *params = null) { + version(IN_LLVM) + { + if (params is null) + params = fdensureParams; + } + /* Same comments as for mergeFrequire(), except that we take care * of generating a consistent reference to the 'result' local by * explicitly passing 'result' to the nested function as a reference @@ -3889,6 +4100,9 @@ extern (C++) class FuncDeclaration : Declaration sc.pop(); } +version(IN_LLVM) + sf = fdv.mergeFensure(sf, oid, params); +else sf = fdv.mergeFensure(sf, oid); if (fdv.fdensure) { @@ -3897,9 +4111,18 @@ extern (C++) class FuncDeclaration : Declaration Expression eresult = null; if (outId) { +version(IN_LLVM) + eresult = (*params)[0]; +else eresult = new IdentifierExp(loc, oid); Type t1 = fdv.type.nextOf().toBasetype(); +version(IN_LLVM) +{ + // We actually check for matching types in CommaExp::toElem, + // 'testcontract' breaks without this. + t1 = t1.constOf(); +} Type t2 = this.type.nextOf().toBasetype(); if (t1.isBaseOf(t2, null)) { @@ -3915,7 +4138,16 @@ extern (C++) class FuncDeclaration : Declaration eresult = new CommaExp(Loc(), de, ve); } } +version(IN_LLVM) +{ + if (eresult !is null) + (*params)[0] = eresult; + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params); +} +else +{ Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), eresult); +} Statement s2 = new ExpStatement(loc, e); if (sf) @@ -4097,6 +4329,14 @@ extern (C++) Expression addInvariant(Loc loc, Scope* sc, AggregateDeclaration ad ad.inv.functionSemantic(); } // Call invariant virtually +version(IN_LLVM) +{ + // We actually need a valid 'var' for codegen. + auto tv = new ThisExp(Loc()); + tv.var = vthis; + Expression v = tv; +} +else Expression v = new ThisExp(Loc()); v.type = vthis.type; if (ad.isStructDeclaration()) diff --git a/src/globals.d b/src/globals.d index a2bc67b05cdb..64a38274d9b9 100644 --- a/src/globals.d +++ b/src/globals.d @@ -29,6 +29,8 @@ private string stripRight(string s) } enum IN_GCC = xversion!`IN_GCC`; +enum IN_LLVM = xversion!`IN_LLVM`; +enum IN_LLVM_MSVC = xversion!`IN_LLVM_MSVC`; enum TARGET_LINUX = xversion!`linux`; enum TARGET_OSX = xversion!`OSX`; @@ -37,6 +39,19 @@ enum TARGET_OPENBSD = xversion!`OpenBSD`; enum TARGET_SOLARIS = xversion!`Solaris`; enum TARGET_WINDOS = xversion!`Windows`; +version(IN_LLVM) +{ + enum OUTPUTFLAG : int + { + OUTPUTFLAGno, + OUTPUTFLAGdefault, // for the .o default + OUTPUTFLAGset // for -output + } + alias OUTPUTFLAGno = OUTPUTFLAG.OUTPUTFLAGno; + alias OUTPUTFLAGdefault = OUTPUTFLAG.OUTPUTFLAGdefault; + alias OUTPUTFLAGset = OUTPUTFLAG.OUTPUTFLAGset; +} + enum BOUNDSCHECK : int { BOUNDSCHECKdefault, // initial value @@ -197,6 +212,36 @@ struct Param const(char)* resfile; const(char)* exefile; const(char)* mapfile; + + version(IN_LLVM) + { + Array!(const(char)*)* bitcodeFiles; // LLVM bitcode files passed on cmdline + + uint nestedTmpl; // maximum nested template instantiations + + // LDC stuff + OUTPUTFLAG output_ll; + OUTPUTFLAG output_bc; + OUTPUTFLAG output_s; + OUTPUTFLAG output_o; + bool useInlineAsm; + bool verbose_cg; + bool fullyQualifiedObjectFiles; + bool cleanupObjectFiles; + + // Profile-guided optimization: + bool genInstrProf; // Whether to generate PGO instrumented code + const(char)* datafileInstrProf; // Either the input or output file for PGO data + + // target stuff + const(void)* targetTriple; // const llvm::Triple* + + // Codegen cl options + bool disableRedZone; + uint dwarfVersion; + + uint hashThreshold; // MD5 hash symbols larger than this threshold (0 = no hashing) + } } struct Compiler @@ -215,6 +260,16 @@ struct Global const(char)* inifilename; const(char)* mars_ext; const(char)* obj_ext; + version(IN_LLVM) + { + const(char)* ll_ext; + const(char)* bc_ext; + const(char)* s_ext; + const(char)* ldc_version; + const(char)* llvm_version; + + bool gaggedForInlining; // Set for functionSemantic3 for external inlining candidates + } const(char)* lib_ext; const(char)* dll_ext; const(char)* doc_ext; // for Ddoc generated files @@ -284,6 +339,15 @@ struct Global ddoc_ext = "ddoc"; json_ext = "json"; map_ext = "map"; +version(IN_LLVM) +{ + obj_ext = "o"; + ll_ext = "ll"; + bc_ext = "bc"; + s_ext = "s"; +} +else +{ static if (TARGET_WINDOS) { obj_ext = "obj"; @@ -337,10 +401,18 @@ struct Global { static assert(0, "fix this"); } +} copyright = "Copyright (c) 1999-2016 by Digital Mars"; written = "written by Walter Bright"; +version(IN_LLVM) +{ + compiler.vendor = "LDC"; +} +else +{ _version = ('v' ~ stripRight(import("verstr.h"))[1 .. $ - 1] ~ '\0').ptr; compiler.vendor = "Digital Mars D"; +} stdmsg = stdout; main_d = "__main.d"; errorLimit = 20; diff --git a/src/globals.h b/src/globals.h index cd0205ba1512..f7b9d5e121f6 100644 --- a/src/globals.h +++ b/src/globals.h @@ -23,6 +23,21 @@ // Can't include arraytypes.h here, need to declare these directly. template struct Array; +#if IN_LLVM +#include "llvm/ADT/Triple.h" +#include + +enum OUTPUTFLAG +{ + OUTPUTFLAGno, + OUTPUTFLAGdefault, // for the .o default + OUTPUTFLAGset // for -output +}; + +using ubyte = uint8_t; +#endif + + // The state of array bounds checking enum BOUNDSCHECK { @@ -65,10 +80,18 @@ struct Param bool verbose; // verbose compile bool showColumns; // print character (column) numbers in diagnostics bool vtls; // identify thread local variables +#if !IN_LLVM char vgc; // identify gc usage +#else + bool vgc; // identify gc usage +#endif bool vfield; // identify non-mutable field variables bool vcomplex; // identify complex/imaginary type usage +#if !IN_LLVM char symdebug; // insert debug symbolic information +#else + ubyte symdebug; // insert debug symbolic information +#endif bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer bool map; // generate linker .map file @@ -85,7 +108,11 @@ struct Param // 0: don't allow use of deprecated features // 1: silently allow use of deprecated features // 2: warn about the use of deprecated features +#if !IN_LLVM char useDeprecated; +#else + ubyte useDeprecated; +#endif bool useAssert; // generate runtime code for assert()'s bool useInvariants; // generate class invariant checks bool useIn; // generate precondition checks @@ -100,7 +127,11 @@ struct Param // 0: disable warnings // 1: warnings as errors // 2: informational warnings (no errors) +#if !IN_LLVM char warnings; +#else + ubyte warnings; +#endif bool pic; // generate position-independent-code for shared libs bool color; // use ANSI colors in console output bool cov; // generate code coverage data @@ -173,6 +204,34 @@ struct Param const char *resfile; const char *exefile; const char *mapfile; + +#if IN_LLVM + Array *bitcodeFiles; // LLVM bitcode files passed on cmdline + + uint32_t nestedTmpl; // maximum nested template instantiations + + // LDC stuff + OUTPUTFLAG output_ll; + OUTPUTFLAG output_bc; + OUTPUTFLAG output_s; + OUTPUTFLAG output_o; + bool useInlineAsm; + bool verbose_cg; + bool fullyQualifiedObjectFiles; + bool cleanupObjectFiles; + + // Profile-guided optimization: + bool genInstrProf; // Whether to generate PGO instrumented code + const char *datafileInstrProf; // Either the input or output file for PGO data + + const llvm::Triple *targetTriple; + + // Codegen cl options + bool disableRedZone; + uint32_t dwarfVersion; + + uint32_t hashThreshold; // MD5 hash symbols larger than this threshold (0 = no hashing) +#endif }; struct Compiler @@ -190,6 +249,15 @@ struct Global const char *inifilename; const char *mars_ext; const char *obj_ext; +#if IN_LLVM + const char *ll_ext; + const char *bc_ext; + const char *s_ext; + const char *ldc_version; + const char *llvm_version; + + bool gaggedForInlining; // Set for functionSemantic3 for external inlining candidates +#endif const char *lib_ext; const char *dll_ext; const char *doc_ext; // for Ddoc generated files @@ -232,7 +300,7 @@ struct Global */ void increaseErrorCount(); - void init(); + void _init(); }; extern Global global; @@ -285,7 +353,12 @@ struct Loc filename = NULL; } +#if IN_LLVM + Loc(const char *filename, unsigned linnum, unsigned charnum) + : filename(filename), linnum(linnum), charnum(charnum) {} +#else Loc(const char *filename, unsigned linnum, unsigned charnum); +#endif const char *toChars() const; bool equals(const Loc& loc); diff --git a/src/gluelayer.d b/src/gluelayer.d index c0d0c7d674d4..58ed16309cfd 100644 --- a/src/gluelayer.d +++ b/src/gluelayer.d @@ -13,12 +13,29 @@ module ddmd.gluelayer; import ddmd.dmodule; import ddmd.dscope; import ddmd.dsymbol; -import ddmd.lib; +// IN_LLVM import ddmd.lib; import ddmd.mtype; import ddmd.statement; import ddmd.root.file; -version (NoBackend) +version (IN_LLVM) +{ + struct Symbol; + struct code; + struct block; + struct Blockx; + struct elem; + struct TYPE; + alias type = TYPE; + + extern (C++) + { + Statement asmSemantic(AsmStatement s, Scope* sc); + RET retStyle(TypeFunction tf); + void objc_initSymbols(); // in gen/objcgen.cpp + } +} +else version (NoBackend) { struct Symbol; struct code; diff --git a/src/hdrgen.d b/src/hdrgen.d index 234c754f8f4e..2876d1ca50a4 100644 --- a/src/hdrgen.d +++ b/src/hdrgen.d @@ -63,6 +63,11 @@ enum TEST_EMIT_ALL = 0; extern (C++) void genhdrfile(Module m) { + version (IN_LLVM) + { + // FIXME: DMD overwrites header files. This should be done only in a DMD mode. + // m.checkAndAddOutputFile(m.hdrfile); + } OutBuffer buf; buf.doindent = 1; buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); diff --git a/src/hooks.d b/src/hooks.d new file mode 100644 index 000000000000..be83d1282086 --- /dev/null +++ b/src/hooks.d @@ -0,0 +1,19 @@ +// Compiler implementation of the D programming language +// Copyright (c) 1999-2016 by Digital Mars +// All Rights Reserved +// http://www.digitalmars.com +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +module ddmd.hooks; + +import ddmd.dscope; +import ddmd.expression; + +import gen.ldctraits; + +/// Returns `null` when the __trait was not recognized. +Expression semanticTraitsHook(TraitsExp e, Scope* sc) +{ + return semanticTraitsLDC(e, sc); +} diff --git a/src/idgen.d b/src/idgen.d index 36de26e7a75a..ba183fa9e471 100644 --- a/src/idgen.d +++ b/src/idgen.d @@ -369,6 +369,34 @@ Msgtable[] msgtable = // Compiler recognized UDA's { "udaSelector", "selector" }, + + // IN_LLVM: LDC-specific pragmas. + { "LDC_intrinsic" }, + { "LDC_no_typeinfo" }, + { "LDC_no_moduleinfo" }, + { "LDC_alloca" }, + { "LDC_va_start" }, + { "LDC_va_copy" }, + { "LDC_va_end" }, + { "LDC_va_arg" }, + { "LDC_verbose" }, + { "LDC_allow_inline" }, + { "LDC_never_inline" }, + { "LDC_inline_asm" }, + { "LDC_inline_ir" }, + { "LDC_fence" }, + { "LDC_atomic_load" }, + { "LDC_atomic_store" }, + { "LDC_atomic_cmp_xchg" }, + { "LDC_atomic_rmw" }, + { "LDC_global_crt_ctor" }, + { "LDC_global_crt_dtor" }, + { "LDC_extern_weak" }, + { "LDC_profile_instr" }, + + // IN_LLVM: LDC-specific traits. + { "targetCPU" }, + { "targetHasFeature" }, ]; diff --git a/src/inline.d b/src/inline.d index bf67671ce505..337b777d87ea 100644 --- a/src/inline.d +++ b/src/inline.d @@ -401,8 +401,9 @@ public: // can't handle that at present. if (e.e1.op == TOKdotvar && (cast(DotVarExp)e.e1).e1.op == TOKsuper) cost = COST_MAX; - else if (e.f && e.f.ident == Id.__alloca && e.f.linkage == LINKc && !allowAlloca) - cost = COST_MAX; // inlining alloca may cause stack overflows + // IN_LLVM: In LDC, we only use the inliner for default arguments, so remove the "else if": + //else if (e.f && e.f.ident == Id.__alloca && e.f.linkage == LINKc && !allowAlloca) + // cost = COST_MAX; // inlining alloca may cause stack overflows else cost++; } diff --git a/src/ldcbindings.d b/src/ldcbindings.d new file mode 100644 index 000000000000..c7bb77b450c6 --- /dev/null +++ b/src/ldcbindings.d @@ -0,0 +1,73 @@ +//===-- ldcbindings.d -----------------------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// + +module ddmd.ldcbindings; + +import ddmd.expression; +import ddmd.globals; +import ddmd.identifier; +import ddmd.mtype; +import ddmd.declaration; +import ddmd.dsymbol; +import ddmd.tokens; +import std.traits; +import std.stdio; +import std.string; +import std.conv; + +/+ This mixin defines "createClassName" functions for all constructors of T, returning T*. + + createClassName(...) must be used in C++ code instead of "new ClassName(...)". + + For structs it returns a T (non-ptr). + + Many thanks to Chris Wright for authoring the initial version. + +/ +private string factory(T)() { + string s; + int count = __traits(getOverloads, T, "__ctor").length; + if (count == 0) { + s = `ClassName createClassName() { return new ClassName(); }`; + } else { + for (int i = 0; i < count; i++) { + s ~= `ClassName createClassName(Parameters!(__traits(getOverloads, ClassName, "__ctor")[OVERLOAD]) params) { + return new ClassName(params); + } + `.replace("OVERLOAD", i.to!string); + } + } + static if (is(T == struct)) { + s = s.replace("new", ""); + } + return s.replace("ClassName", T.stringof.split('.')[$-1]); +} +// helper functions to create D objects +extern(C++): +mixin(factory!IntegerExp); +mixin(factory!AndAndExp); +mixin(factory!EqualExp); +mixin(factory!CmpExp); +mixin(factory!ShlExp); +mixin(factory!ShrExp); +mixin(factory!UshrExp); +mixin(factory!OrOrExp); +mixin(factory!NotExp); +mixin(factory!ComExp); +mixin(factory!OrExp); +mixin(factory!AndExp); +mixin(factory!XorExp); +mixin(factory!ModExp); +mixin(factory!MulExp); +mixin(factory!DivExp); +mixin(factory!AddExp); +mixin(factory!MinExp); +mixin(factory!NegExp); +mixin(factory!AddrExp); +mixin(factory!RealExp); +mixin(factory!DsymbolExp); +mixin(factory!Expression); +mixin(factory!TypeDelegate); +mixin(factory!TypeIdentifier); diff --git a/src/ldcbindings.h b/src/ldcbindings.h new file mode 100644 index 000000000000..70173d863d91 --- /dev/null +++ b/src/ldcbindings.h @@ -0,0 +1,78 @@ +//===-- ldcbindings.h -----------------------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LDC_DDMD_LDCBINDINGS_H +#define LDC_DDMD_LDCBINDINGS_H + +#include "expression.h" +#include + +using uint = uint32_t; + +// Classes +IntegerExp *createIntegerExp(Loc loc, dinteger_t value, Type *type); +IntegerExp *createIntegerExp(dinteger_t value); +EqualExp *createEqualExp(TOK, Loc, Expression *, Expression *); +CmpExp *createCmpExp(TOK, Loc, Expression *, Expression *); +ShlExp *createShlExp(Loc, Expression *, Expression *); +ShrExp *createShrExp(Loc, Expression *, Expression *); +UshrExp *createUshrExp(Loc, Expression *, Expression *); +AndAndExp *createAndAndExp(Loc, Expression *, Expression *); +OrOrExp *createOrOrExp(Loc, Expression *, Expression *); +OrExp *createOrExp(Loc, Expression *, Expression *); +AndExp *createAndExp(Loc, Expression *, Expression *); +XorExp *createXorExp(Loc, Expression *, Expression *); +ModExp *createModExp(Loc, Expression *, Expression *); +MulExp *createMulExp(Loc, Expression *, Expression *); +DivExp *createDivExp(Loc, Expression *, Expression *); +AddExp *createAddExp(Loc, Expression *, Expression *); +MinExp *createMinExp(Loc, Expression *, Expression *); +RealExp *createRealExp(Loc, real_t, Type *); +NotExp *createNotExp(Loc, Expression *); +ComExp *createComExp(Loc, Expression *); +NegExp *createNegExp(Loc, Expression *); +AddrExp *createAddrExp(Loc, Expression *); +DsymbolExp *createDsymbolExp(Loc, Dsymbol *, bool = false); +Expression *createExpression(Loc loc, TOK op, int size); +TypeDelegate *createTypeDelegate(Type *t); +TypeIdentifier *createTypeIdentifier(Loc loc, Identifier *ident); + +// Structs +//Loc createLoc(const char * filename, uint linnum, uint charnum); + +/* + * Define bindD::create(...) templated functions, to create D objects in templated code (class type is template parameter). + * Used e.g. in toir.cpp + */ +template struct bindD { + template T *create(Args...) { + assert(0 && "newD<> not implemented for this type"); + } +}; +#define NEWD_TEMPLATE(T) \ + template <> struct bindD { \ + template static T *create(Args... args) { \ + return create##T(args...); \ + } \ + }; +NEWD_TEMPLATE(ShlExp) +NEWD_TEMPLATE(ShrExp) +NEWD_TEMPLATE(UshrExp) +NEWD_TEMPLATE(AndAndExp) +NEWD_TEMPLATE(OrOrExp) +NEWD_TEMPLATE(OrExp) +NEWD_TEMPLATE(AndExp) +NEWD_TEMPLATE(XorExp) +NEWD_TEMPLATE(ModExp) +NEWD_TEMPLATE(MulExp) +NEWD_TEMPLATE(DivExp) +NEWD_TEMPLATE(AddExp) +NEWD_TEMPLATE(MinExp) + +#endif // LDC_DDMD_LDCBINDINGS_H diff --git a/src/lexer.d b/src/lexer.d index b8bc0780f7e5..75483b5ff587 100644 --- a/src/lexer.d +++ b/src/lexer.d @@ -2008,6 +2008,7 @@ class Lexer { assert(*p == '.' || isdigit(*p)); } + bool isWellformedString = true; stringbuffer.reset(); auto pstart = p; bool hex = false; @@ -2069,12 +2070,18 @@ class Lexer continue; } if (!anyexp) + { error("missing exponent"); + isWellformedString = false; + } break; } } else if (hex) + { error("exponent required for hex float"); + isWellformedString = false; + } --p; while (pstart < p) { @@ -2086,17 +2093,19 @@ class Lexer auto sbufptr = cast(const(char)*)stringbuffer.data; TOK result; bool isOutOfRange = false; - t.floatvalue = CTFloat.parse(sbufptr, &isOutOfRange); + t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, &isOutOfRange) : CTFloat.zero); switch (*p) { case 'F': case 'f': - isOutOfRange = (isOutOfRange || Port.isFloat32LiteralOutOfRange(sbufptr)); + if (isWellformedString && !isOutOfRange) + isOutOfRange = Port.isFloat32LiteralOutOfRange(sbufptr); result = TOKfloat32v; p++; break; default: - isOutOfRange = (isOutOfRange || Port.isFloat64LiteralOutOfRange(sbufptr)); + if (isWellformedString && !isOutOfRange) + isOutOfRange = Port.isFloat64LiteralOutOfRange(sbufptr); result = TOKfloat64v; break; case 'l': diff --git a/src/mars.d b/src/mars.d index 06dbc477f18e..8bd8a9a2f336 100644 --- a/src/mars.d +++ b/src/mars.d @@ -39,8 +39,8 @@ import ddmd.id; import ddmd.identifier; import ddmd.inline; import ddmd.json; -import ddmd.lib; -import ddmd.link; +// IN_LLVM import ddmd.lib; +// IN_LLVM import ddmd.link; import ddmd.mtype; import ddmd.objc; import ddmd.parse; @@ -48,7 +48,7 @@ import ddmd.root.file; import ddmd.root.filename; import ddmd.root.man; import ddmd.root.outbuffer; -import ddmd.root.response; +// IN_LLVM import ddmd.root.response; import ddmd.root.rmem; import ddmd.root.stringtable; import ddmd.target; @@ -56,6 +56,23 @@ import ddmd.tokens; import ddmd.utils; +version(IN_LLVM) +{ + extern (C++): + + void genCmain(Scope* sc); + // in driver/main.cpp + void addDefaultVersionIdentifiers(); + void codegenModules(ref Modules modules); + // in driver/linker.cpp + int linkObjToBinary(); + int createStaticLibrary(); + void deleteExeFile(); + int runProgram(); +} +else +{ + /** * Print DMD's logo on stdout */ @@ -1103,6 +1120,14 @@ Language changes listed by -transition=id: global.params.useAssert = true; if (!global.params.obj || global.params.lib) global.params.link = false; + + return mars_mainBody(files, libmodules); +} + +} // !IN_LLVM + +extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules) +{ if (global.params.link) { global.params.exefile = global.params.objname; @@ -1132,9 +1157,12 @@ Language changes listed by -transition=id: { global.params.libname = global.params.objname; global.params.objname = null; + version (IN_LLVM) {} else + { // Haven't investigated handling these options with multiobj if (!global.params.cov && !global.params.trace) global.params.multiobj = true; + } } else { @@ -1148,9 +1176,12 @@ Language changes listed by -transition=id: // Predefined version identifiers addDefaultVersionIdentifiers(); + version (IN_LLVM) {} else + { objc_tryMain_dObjc(); setDefaultLibrary(); + } // Initialization Type._init(); @@ -1161,12 +1192,15 @@ Language changes listed by -transition=id: objc_tryMain_init(); builtin_init(); + version (IN_LLVM) {} else + { if (global.params.verbose) { fprintf(global.stdmsg, "binary %s\n", global.params.argv0); fprintf(global.stdmsg, "version %s\n", global._version); fprintf(global.stdmsg, "config %s\n", global.inifilename ? global.inifilename : "(none)"); } + } //printf("%d source files\n",files.dim); // Build import search path @@ -1200,14 +1234,24 @@ Language changes listed by -transition=id: // Create Modules Modules modules; modules.reserve(files.dim); + version (IN_LLVM) + { + size_t firstModuleObjectFileIndex = size_t.max; + } + else + { bool firstmodule = true; + } for (size_t i = 0; i < files.dim; i++) { const(char)* name; + version (IN_LLVM) {} else + { version (Windows) { files[i] = toWinPath(files[i]); } + } const(char)* p = files[i]; p = FileName.name(p); // strip path const(char)* ext = FileName.ext(p); @@ -1222,12 +1266,22 @@ Language changes listed by -transition=id: libmodules.push(files[i]); continue; } + version (IN_LLVM) + { + // Detect LLVM bitcode files on commandline + if (FileName.equals(ext, global.bc_ext)) { + global.params.bitcodeFiles.push(files[i]); + continue; + } + } if (FileName.equals(ext, global.lib_ext)) { global.params.libfiles.push(files[i]); libmodules.push(files[i]); continue; } + version (IN_LLVM) {} else + { static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) { if (FileName.equals(ext, global.dll_ext)) @@ -1237,6 +1291,7 @@ Language changes listed by -transition=id: continue; } } + } if (strcmp(ext, global.ddoc_ext) == 0) { global.params.ddocfiles.push(files[i]); @@ -1253,7 +1308,8 @@ Language changes listed by -transition=id: global.params.mapfile = files[i]; continue; } - static if (TARGET_WINDOS) + // IN_LLVM replaced: static if (TARGET_WINDOS) + if (global.params.isWindows) { if (FileName.equals(ext, "res")) { @@ -1306,12 +1362,37 @@ Language changes listed by -transition=id: auto id = Identifier.idPool(name, strlen(name)); auto m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); modules.push(m); + version (IN_LLVM) + { + if (!global.params.oneobj || firstModuleObjectFileIndex == size_t.max) + { + global.params.objfiles.push(cast(const(char)*)m); // defer to a later stage after parsing + if (firstModuleObjectFileIndex == size_t.max) + firstModuleObjectFileIndex = global.params.objfiles.dim - 1; + } + } + else + { if (firstmodule) { global.params.objfiles.push(m.objfile.name.str); firstmodule = false; } + } + } + version (IN_LLVM) + { + if (global.params.oneobj && modules.dim < 2) + global.params.oneobj = false; + // global.params.oneobj => move object file for first source file to + // beginning of object files list + if (global.params.oneobj && firstModuleObjectFileIndex != 0) + { + auto fn = (*global.params.objfiles)[firstModuleObjectFileIndex]; + global.params.objfiles.remove(firstModuleObjectFileIndex); + global.params.objfiles.insert(0, fn); } + } // Read files /* Start by "reading" the dummy main.d file */ @@ -1362,8 +1443,11 @@ Language changes listed by -transition=id: if (!Module.rootModule) Module.rootModule = m; m.importedFrom = m; // m.isRoot() == true + version (IN_LLVM) {} else + { if (!global.params.oneobj || modi == 0 || m.isDocFile) m.deleteObjFile(); + } static if (ASYNCREAD) { if (aw.read(filei)) @@ -1373,6 +1457,39 @@ Language changes listed by -transition=id: } } m.parse(); + version (IN_LLVM) + { + // Finalize output filenames. Update if `-oq` was specified (only feasible after parsing). + if (global.params.fullyQualifiedObjectFiles && m.md) + { + m.objfile = m.setOutfile(global.params.objname, global.params.objdir, m.arg, FileName.ext(m.objfile.name.str)); + if (m.docfile) + m.setDocfile(); + if (m.hdrfile) + m.hdrfile = m.setOutfile(global.params.hdrname, global.params.hdrdir, m.arg, global.hdr_ext); + } + + // If `-run` is passed, the obj file is temporary and is removed after execution. + // Make sure the name does not collide with other files from other processes by + // creating a unique filename. + if (global.params.run) + m.makeObjectFilenameUnique(); + + // Set object filename in global.params.objfiles. + for (size_t j = 0; j < global.params.objfiles.dim; j++) + { + if ((*global.params.objfiles)[j] == cast(const(char)*)m) + { + (*global.params.objfiles)[j] = m.objfile.name.str; + if (!m.isDocFile && global.params.obj) + m.checkAndAddOutputFile(m.objfile); + break; + } + } + + if (!global.params.oneobj || modi == 0 || m.isDocFile) + m.deleteObjFile(); + } if (m.isDocFile) { anydocfiles = true; @@ -1434,7 +1551,10 @@ Language changes listed by -transition=id: if (global.errors) fatal(); + version (IN_LLVM) {} else + { backend_init(); + } // Do semantic analysis for (size_t i = 0; i < modules.dim; i++) @@ -1482,6 +1602,8 @@ Language changes listed by -transition=id: if (global.errors) fatal(); + version (IN_LLVM) {} else + { // Scan for functions to inline if (global.params.useInline) { @@ -1493,6 +1615,7 @@ Language changes listed by -transition=id: inlineScanModule(m); } } + } // Do not attempt to generate output files if errors or warnings occurred if (global.errors || global.warnings) fatal(); @@ -1507,6 +1630,12 @@ Language changes listed by -transition=id: auto deps = File(global.params.moduleDepsFile); deps.setbuffer(cast(void*)ob.data, ob.offset); writeFile(Loc(), &deps); + version (IN_LLVM) + { + // fix LDC issue #1625 + global.params.moduleDeps = null; + global.params.moduleDepsFile = null; + } } else printf("%.*s", cast(int)ob.offset, ob.data); @@ -1514,6 +1643,8 @@ Language changes listed by -transition=id: printCtfePerformanceStats(); + version (IN_LLVM) {} else + { Library library = null; if (global.params.lib) { @@ -1526,6 +1657,7 @@ Language changes listed by -transition=id: library.addObject(p, null); } } + } // Generate output files if (global.params.doJsonGeneration) { @@ -1572,6 +1704,12 @@ Language changes listed by -transition=id: gendocfile(m); } } + version (IN_LLVM) + { + codegenModules(modules); + } + else + { if (!global.params.obj) { } @@ -1613,18 +1751,50 @@ Language changes listed by -transition=id: if (global.params.lib && !global.errors) library.write(); backend_term(); + } if (global.errors) fatal(); int status = EXIT_SUCCESS; if (!global.params.objfiles.dim) { + version (IN_LLVM) + { if (global.params.link) error(Loc(), "no object files to link"); + else if (global.params.lib) + error(Loc(), "no object files"); + } + else + { + if (global.params.link) + error(Loc(), "no object files to link"); + } } else { + version (IN_LLVM) + { + if (global.params.link) + status = linkObjToBinary(); + else if (global.params.lib) + status = createStaticLibrary(); + + if (status == EXIT_SUCCESS && + (global.params.cleanupObjectFiles || global.params.run)) + { + for (size_t i = 0; i < modules.dim; i++) + { + modules[i].deleteObjFile(); + if (global.params.oneobj) + break; + } + } + } + else + { if (global.params.link) status = runLINK(); + } if (global.params.run) { if (!status) @@ -1632,12 +1802,15 @@ Language changes listed by -transition=id: status = runProgram(); /* Delete .obj files and .exe file */ + version (IN_LLVM) {} else + { for (size_t i = 0; i < modules.dim; i++) { modules[i].deleteObjFile(); if (global.params.oneobj) break; } + } remove(global.params.exefile); } } @@ -1646,6 +1819,9 @@ Language changes listed by -transition=id: } +version (IN_LLVM) {} else +{ + /** * Entry point which forwards to `tryMain`. * @@ -2022,7 +2198,10 @@ private void addDefaultVersionIdentifiers() printPredefinedVersions(); } -private void printPredefinedVersions() +} // !IN_LLVM + +// IN_LLVM replaced: `private` by `extern (C++)` +extern (C++) void printPredefinedVersions() { if (global.params.verbose && global.params.versionids) { @@ -2034,6 +2213,9 @@ private void printPredefinedVersions() } +version (IN_LLVM) {} else +{ + /**************************************** * Determine the instruction set to be used. * Params: @@ -2079,3 +2261,5 @@ private CPU setTargetCPU(CPU cpu) } return cpu; } + +} // !IN_LLVM diff --git a/src/mars.h b/src/mars.h index 9ec4ed62ea0f..cf2b1593b7d4 100644 --- a/src/mars.h +++ b/src/mars.h @@ -63,6 +63,9 @@ the target object file format: #include #include #include +#if IN_LLVM +#include +#endif #ifdef __DMC__ #ifdef DEBUG @@ -96,6 +99,11 @@ void readFile(Loc loc, File *f); void writeFile(Loc loc, File *f); void ensurePathToNameExists(Loc loc, const char *name); +#if IN_LLVM +int mars_mainBody(Strings &files, Strings &libmodules); +void printPredefinedVersions(); +#endif + const char *importHint(const char *s); /// Little helper function for writing out deps. void escapePath(OutBuffer *buf, const char *fname); diff --git a/src/module.h b/src/module.h index 7699761e0c33..ea823435824d 100644 --- a/src/module.h +++ b/src/module.h @@ -26,6 +26,18 @@ struct Escape; class VarDeclaration; class Library; +#if IN_LLVM +#include +class DValue; +namespace llvm { + class LLVMContext; + class Module; + class GlobalVariable; + class StructType; +} +#endif + + enum PKG { PKGunknown, // not yet determined whether it's a package.d or not @@ -65,7 +77,7 @@ class Module : public Package static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them static unsigned dprogress; // progress resolving the deferred list - static void init(); + static void _init(); static AggregateDeclaration *moduleinfo; @@ -167,6 +179,24 @@ class Module : public Package Symbol *munittest; // module unittest failure function Symbol *marray; // module array bounds function +#if IN_LLVM + // LDC + llvm::Module* genLLVMModule(llvm::LLVMContext& context); + void checkAndAddOutputFile(File *file); + void makeObjectFilenameUnique(); + + bool llvmForceLogging; + bool noModuleInfo; /// Do not emit any module metadata. + + // array ops emitted in this module already + AA *arrayfuncs; + + // Coverage analysis + llvm::GlobalVariable* d_cover_valid; // private immutable size_t[] _d_cover_valid; + llvm::GlobalVariable* d_cover_data; // private uint[] _d_cover_data; + Array d_cover_valid_init; // initializer for _d_cover_valid +#endif + Module *isModule() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/mtype.d b/src/mtype.d index 872339cff2f1..d81b568a40e7 100644 --- a/src/mtype.d +++ b/src/mtype.d @@ -53,6 +53,10 @@ import ddmd.target; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) { + import gen.llvmhelpers; +} + enum LOGDOTEXP = 0; // log ::dotExp() enum LOGDEFAULTINIT = 0; // log ::defaultInit() @@ -2773,17 +2777,37 @@ extern (C++) abstract class Type : RootObject // Allocate buffer on stack, fail over to using malloc() char[128] namebuf; + + // Hash long symbol names + char* name; + int length; + if (IN_LLVM && global.params.hashThreshold && (slice.length > global.params.hashThreshold)) + { + import std.digest.md; + auto md5hash = md5Of(slice); + auto hashedname = toHexString(md5hash); + static assert(hashedname.length < namebuf.length-30); + name = namebuf.ptr; + length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", + cast(ulong)9 + hashedname.length, hashedname.length, hashedname.ptr); + } + else + { + // else path is DDMD original: + const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; - auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)malloc(namelen); + name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)malloc(namelen); assert(name); - const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", + length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); assert(0 < length && length < namelen); // don't overflow the buffer + } + int off = 0; - static if (!IN_GCC) + static if (!IN_GCC && !IN_LLVM) { if (global.params.isOSX || global.params.isWindows && !global.params.is64bit) ++off; // C mangling will add '_' back in @@ -3636,6 +3660,19 @@ extern (C++) final class TypeBasic : Type return Target.alignsize(this); } +version(IN_LLVM) +{ + override structalign_t alignment() + { + if ( (ty == Tfloat80 || ty == Timaginary80) && (size(Loc()) > 8) + && isArchx86_64() ) + { + return 16; + } + return Type.alignment(); + } +} + override Expression getProperty(Loc loc, Identifier ident, int flag) { Expression e; @@ -4394,10 +4431,17 @@ extern (C++) final class TypeVector : Type } if (ident == Id.array) { +version(IN_LLVM) +{ + e = e.castTo(sc, basetype); +} +else +{ //e = e.castTo(sc, basetype); // Keep lvalue-ness e = e.copy(); e.type = basetype; +} return e; } if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof) @@ -4760,7 +4804,7 @@ extern (C++) final class TypeSArray : TypeArray if (d1 != d2) { Loverflow: - error(loc, "%s size %llu * %llu exceeds 16MiB size limit for static array", toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1); + error(loc, "%s size %llu * %llu exceeds the size limit for static arrays (overflow)", toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1); goto Lerror; } Type tbx = tbn.baseElemOf(); @@ -4776,8 +4820,20 @@ extern (C++) final class TypeSArray : TypeArray * run on them for the size, since they may be forward referenced. */ bool overflow = false; +version(IN_LLVM) +{ + /+ The size limit that DMD imposes here is only there to work around an optlink bug, which doesn't apply to LDC. + + https://issues.dlang.org/show_bug.cgi?id=14859 + +/ + auto _ = mulu(tbn.size(loc), d2, overflow); + if (overflow) + goto Loverflow; +} +else +{ if (mulu(tbn.size(loc), d2, overflow) >= 0x100_0000 || overflow) // put a 'reasonable' limit on it goto Loverflow; +} } } switch (tbn.ty) @@ -8206,6 +8262,13 @@ extern (C++) final class TypeStruct : Type AliasThisRec att = RECfwdref; CPPMANGLE cppmangle = CPPMANGLE.def; + version(IN_LLVM) + { + // cache the hasUnalignedFields check + // 0 = not checked, 1 = aligned, 2 = unaligned + int unaligned; + } + extern (D) this(StructDeclaration sym) { super(Tstruct); diff --git a/src/mtype.h b/src/mtype.h index ae9c09c2f674..0cae2a4eca8b 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -24,6 +24,10 @@ #include "expression.h" #include "visitor.h" +#if IN_LLVM +#include +#endif + struct Scope; class Identifier; class Expression; @@ -42,6 +46,8 @@ class Parameter; // Back end #ifdef IN_GCC typedef union tree_node type; +#elif IN_LLVM +typedef class IrType type; #else typedef struct TYPE type; #endif @@ -240,7 +246,7 @@ class Type : public RootObject int covariant(Type *t, StorageClass *pstc = NULL); const char *toChars(); char *toPrettyChars(bool QualifyTypes = false); - static void init(); + static void _init(); d_uns64 size(); virtual d_uns64 size(Loc loc); @@ -341,8 +347,9 @@ class Type : public RootObject virtual bool needsNested(); void checkComplexTransition(Loc loc); - static void error(Loc loc, const char *format, ...); - static void warning(Loc loc, const char *format, ...); + // IN_LLVM: added IS_PRINTF(2); + static void error(Loc loc, const char *format, ...) IS_PRINTF(2); + static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); // For eliminating dynamic_cast virtual TypeBasic *isTypeBasic(); @@ -395,6 +402,9 @@ class TypeBasic : public Type Type *syntaxCopy(); d_uns64 size(Loc loc) /*const*/; unsigned alignsize(); +#if IN_LLVM + structalign_t alignment(); +#endif Expression *getProperty(Loc loc, Identifier *ident, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); bool isintegral(); @@ -746,6 +756,12 @@ class TypeStruct : public Type AliasThisRec att; CPPMANGLE cppmangle; +#if IN_LLVM + // cache the hasUnalignedFields check + // 0 = not checked, 1 = aligned, 2 = unaligned + int32_t unaligned; +#endif + const char *kind(); d_uns64 size(Loc loc); unsigned alignsize(); diff --git a/src/root/array.h b/src/root/array.h index 69b585166910..49a320ed0395 100644 --- a/src/root/array.h +++ b/src/root/array.h @@ -18,6 +18,11 @@ #include #include +#if IN_LLVM +#include "llvm/Support/Compiler.h" +#include +#endif + #include "object.h" #include "rmem.h" @@ -28,7 +33,9 @@ struct Array TYPE *data; private: +#if !IN_LLVM Array(const Array&); +#endif d_size_t allocdim; #define SMALLARRAYCAP 1 @@ -213,6 +220,127 @@ struct Array memcpy(a->data, data, dim * sizeof(*data)); return a; } + +#if IN_LLVM + // Define members and types like std::vector + typedef size_t size_type; + + Array(const Array &a) : dim(0), data(0), allocdim(0) + { + setDim(a.dim); + memcpy(data, a.data, dim * sizeof(*data)); + } + + Array &operator=(Array &a) + { + setDim(a.dim); + memcpy(data, a.data, dim * sizeof(*data)); + return *this; + } + +#if LLVM_HAS_RVALUE_REFERENCES + Array(Array &&a) + { + if (data != &smallarray[0]) + mem.xfree(data); + dim = a.dim; + allocdim = a.allocdim; + if (a.data == &a.smallarray[0]) + { + data = &smallarray[0]; + memcpy(data, a.data, dim * sizeof(*data)); + } + else + { + data = a.data; + a.data = 0; + } + a.dim = 0; + a.allocdim = 0; + } + + Array &operator=(Array &&a) + { + if (data != &smallarray[0]) + mem.xfree(data); + dim = a.dim; + allocdim = a.allocdim; + if (a.data == &a.smallarray[0]) + { + data = &smallarray[0]; + memcpy(data, a.data, dim * sizeof(*data)); + } + else + { + data = a.data; + a.data = 0; + } + a.dim = 0; + a.allocdim = 0; + return *this; + } +#endif // LLVM_HAS_RVALUE_REFERENCES + + size_type size() + { + return static_cast(dim); + } + + bool empty() + { + return dim == 0; + } + + TYPE front() + { + return data[0]; + } + + TYPE back() + { + return data[dim-1]; + } + + void push_back(TYPE a) + { + push(a); + } + + void pop_back() + { + pop(); + } + + typedef TYPE *iterator; + typedef std::reverse_iterator reverse_iterator; + + iterator begin() + { + return static_cast(&data[0]); + } + + iterator end() + { + return static_cast(&data[dim]); + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + iterator erase(iterator pos) + { + size_t index = pos - &data[0]; + remove(index); + return static_cast(&data[index]); + } +#endif // IN_LLVM }; struct BitArray diff --git a/src/root/ctfloat.d b/src/root/ctfloat.d index cdeef7e5235d..3718fa7ca8ea 100644 --- a/src/root/ctfloat.d +++ b/src/root/ctfloat.d @@ -15,13 +15,17 @@ import core.stdc.stdlib; import core.stdc.string; // Type used by the front-end for compile-time reals -alias real_t = real; +version(IN_LLVM_MSVC) + alias real_t = double; +else + alias real_t = real; private { version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint; - version(CRuntime_Microsoft) extern (C++) + // IN_LLVM replaced: version(CRuntime_Microsoft) extern (C++) + version(none) extern (C++) { struct longdouble { real_t r; } size_t ld_sprint(char* str, int fmt, longdouble x); @@ -32,7 +36,8 @@ private // Compile-time floating-point helper extern (C++) struct CTFloat { - version(DigitalMars) + // IN_LLVM replaced: version(DigitalMars) + version(none) { static __gshared bool yl2x_supported = true; static __gshared bool yl2xp1_supported = true; @@ -65,6 +70,24 @@ extern (C++) struct CTFloat static real_t sqrt(real_t x) { return core.math.sqrt(x); } static real_t fabs(real_t x) { return core.math.fabs(x); } + version(IN_LLVM) + { + static import std.math; + + static real_t log(real_t x) { return std.math.log(x); } + static real_t fmin(real_t l, real_t r) { return std.math.fmin(l, r); } + static real_t fmax(real_t l, real_t r) { return std.math.fmax(l, r); } + static real_t floor(real_t x) { return std.math.floor(x); } + static real_t ceil(real_t x) { return std.math.ceil(x); } + static real_t trunc(real_t x) { return std.math.trunc(x); } + static real_t round(real_t x) { return std.math.round(x); } + + static void _init(); + + static bool isFloat32LiteralOutOfRange(const(char)* literal); + static bool isFloat64LiteralOutOfRange(const(char)* literal); + } + static bool isIdentical(real_t a, real_t b) { // don't compare pad bytes in extended precision @@ -79,13 +102,17 @@ extern (C++) struct CTFloat static bool isSNaN(real_t r) { - return isNaN(r) && !(((cast(ubyte*)&r)[7]) & 0x40); + static if (real_t.sizeof == 8) + return isNaN(r) && !(((cast(ubyte*)&r)[6]) & 8); + else + return isNaN(r) && !(((cast(ubyte*)&r)[7]) & 0x40); } // the implementation of longdouble for MSVC is a struct, so mangling // doesn't match with the C++ header. // add a wrapper just for isSNaN as this is the only function called from C++ - version(CRuntime_Microsoft) + // IN_LLVM replaced: version(CRuntime_Microsoft) + version(none) static bool isSNaN(longdouble ld) { return isSNaN(ld.r); @@ -96,6 +123,13 @@ extern (C++) struct CTFloat return r is real_t.infinity || r is -real_t.infinity; } +version (IN_LLVM) +{ + // implemented in gen/ctfloat.cpp + static real_t parse(const(char)* literal, bool* isOutOfRange = null); +} +else +{ static real_t parse(const(char)* literal, bool* isOutOfRange = null) { errno = 0; @@ -104,7 +138,8 @@ extern (C++) struct CTFloat auto save = __locale_decpoint; __locale_decpoint = "."; } - version(CRuntime_Microsoft) + // IN_LLVM replaced: version(CRuntime_Microsoft) + version(none) auto r = strtold_dm(literal, null).r; else auto r = strtold(literal, null); @@ -113,10 +148,12 @@ extern (C++) struct CTFloat *isOutOfRange = (errno == ERANGE); return r; } +} static int sprint(char* str, char fmt, real_t x) { - version(CRuntime_Microsoft) + // IN_LLVM replaced: version(CRuntime_Microsoft) + version(none) { return cast(int)ld_sprint(str, fmt, longdouble(x)); } @@ -146,3 +183,11 @@ extern (C++) struct CTFloat static __gshared real_t minusone = real_t(-1); static __gshared real_t half = real_t(0.5); } + +version (IN_LLVM) +{ + shared static this() + { + CTFloat._init(); + } +} diff --git a/src/root/ctfloat.h b/src/root/ctfloat.h index 529b8a8316d7..a5ff08f75eba 100644 --- a/src/root/ctfloat.h +++ b/src/root/ctfloat.h @@ -13,7 +13,17 @@ #include "longdouble.h" // Type used by the front-end for compile-time reals +#if IN_LLVM && _MSC_VER +// Make sure LDC built with MSVC uses double-precision compile-time reals, +// independent of whether it was built with DMD (80-bit reals) or LDC. +typedef double real_t; +#else typedef longdouble real_t; +#endif + +#if IN_LLVM +namespace llvm { class APFloat; } +#endif // Compile-time floating-point helper struct CTFloat @@ -30,6 +40,23 @@ struct CTFloat static real_t sqrt(real_t x); static real_t fabs(real_t x); +#if IN_LLVM + static real_t log(real_t x); + static real_t fmin(real_t l, real_t r); + static real_t fmax(real_t l, real_t r); + static real_t floor(real_t x); + static real_t ceil(real_t x); + static real_t trunc(real_t x); + static real_t round(real_t x); + + // implemented in gen/ctfloat.cpp + static void _init(); + static void toAPFloat(real_t src, llvm::APFloat &dst); + + static bool isFloat32LiteralOutOfRange(const char *literal); + static bool isFloat64LiteralOutOfRange(const char *literal); +#endif + static bool isIdentical(real_t a, real_t b); static bool isNaN(real_t r); static bool isSNaN(real_t r); diff --git a/src/root/longdouble.h b/src/root/longdouble.h index 86240701f1e6..e49690ad646b 100644 --- a/src/root/longdouble.h +++ b/src/root/longdouble.h @@ -11,7 +11,8 @@ #ifndef __LONG_DOUBLE_H__ #define __LONG_DOUBLE_H__ -#if !_MSC_VER // has native 10 byte doubles +// LDC: Don't provide 'manual' x87 longdouble when compiling with MS compiler. +#if IN_LLVM || !_MSC_VER // has native 10 byte doubles #include typedef long double longdouble; typedef volatile long double volatile_longdouble; diff --git a/src/root/newdelete.c b/src/root/newdelete.c index 3c8c40ac7f5a..46dcbcf7aca2 100644 --- a/src/root/newdelete.c +++ b/src/root/newdelete.c @@ -19,7 +19,7 @@ # define USE_ASAN_NEW_DELETE #endif -#if !defined(USE_ASAN_NEW_DELETE) +#if !defined(USE_ASAN_NEW_DELETE) && !defined(IN_LLVM) #if 1 diff --git a/src/root/object.h b/src/root/object.h index 254ed8e4be83..38a3c3849933 100644 --- a/src/root/object.h +++ b/src/root/object.h @@ -10,7 +10,9 @@ #ifndef OBJECT_H #define OBJECT_H +#if !IN_LLVM #define POSIX (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun) +#endif #if __DMC__ #pragma once diff --git a/src/root/port.d b/src/root/port.d index 1d2d013438b8..790235627b34 100644 --- a/src/root/port.d +++ b/src/root/port.d @@ -67,6 +67,13 @@ extern (C++) struct Port static bool isFloat32LiteralOutOfRange(const(char)* s) { + version (IN_LLVM) + { + import ddmd.root.ctfloat; + return CTFloat.isFloat32LiteralOutOfRange(s); + } + else + { errno = 0; version (CRuntime_DigitalMars) { @@ -86,10 +93,18 @@ extern (C++) struct Port } version (CRuntime_DigitalMars) __locale_decpoint = save; return errno == ERANGE; + } } static bool isFloat64LiteralOutOfRange(const(char)* s) { + version (IN_LLVM) + { + import ddmd.root.ctfloat; + return CTFloat.isFloat64LiteralOutOfRange(s); + } + else + { errno = 0; version (CRuntime_DigitalMars) { @@ -109,6 +124,7 @@ extern (C++) struct Port } version (CRuntime_DigitalMars) __locale_decpoint = save; return errno == ERANGE; + } } // Little endian @@ -159,6 +175,34 @@ extern (C++) struct Port return (p[0] << 8) | p[1]; } + version (IN_LLVM) + { + // LDC_FIXME: Move this into our C++ code, since only driver/gen is + // still using this. + static int stricmp(const(char)* s1, const(char)* s2) + { + int result = 0; + for (;;) + { + char c1 = *s1; + char c2 = *s2; + + result = c1 - c2; + if (result) + { + result = toupper(c1) - toupper(c2); + if (result) + break; + } + if (!c1) + break; + s1++; + s2++; + } + return result; + } + } + static void valcpy(void *dst, ulong val, size_t size) { switch (size) diff --git a/src/root/port.h b/src/root/port.h index b17c64b18585..6f68f0c78f5f 100644 --- a/src/root/port.h +++ b/src/root/port.h @@ -13,7 +13,11 @@ // Portable wrapper around compiler/system specific things. // The idea is to minimize #ifdef's in the app code. +#if IN_LLVM +#include +#else #include // for alloca +#endif #include #if _MSC_VER @@ -41,6 +45,11 @@ struct Port static unsigned readlongBE(void *buffer); static unsigned readwordLE(void *buffer); static unsigned readwordBE(void *buffer); + +#ifdef IN_LLVM + static int stricmp(const char *s1, const char *s2); +#endif + static void valcpy(void *dst, uint64_t val, size_t size); }; diff --git a/src/root/root.h b/src/root/root.h index bea105303e0d..714188b1b906 100644 --- a/src/root/root.h +++ b/src/root/root.h @@ -14,6 +14,16 @@ #pragma once #endif +#if IN_LLVM +#ifndef IS_PRINTF +# ifdef __GNUC__ +# define IS_PRINTF(FMTARG) __attribute((__format__(__printf__, (FMTARG), (FMTARG)+1))) +# else +# define IS_PRINTF(FMTARG) +# endif +#endif +#endif + #include "object.h" #include "filename.h" diff --git a/src/scope.h b/src/scope.h index a6d3bfb3fe8a..fc266a4ab93d 100644 --- a/src/scope.h +++ b/src/scope.h @@ -123,6 +123,10 @@ struct Scope UserAttributeDeclaration *userAttribDecl; // user defined attributes +#if IN_LLVM + bool emitInstrumentation; // whether to emit instrumentation with -fprofile-instr-generate +#endif + DocComment *lastdc; // documentation comment for last symbol at this scope AA *anchorCounts; // lookup duplicate anchor name count Identifier *prevAnchor; // qualified symbol name of last doc anchor diff --git a/src/statement.d b/src/statement.d index 67e86d28f9af..eb2aa6ccd48d 100644 --- a/src/statement.d +++ b/src/statement.d @@ -42,6 +42,10 @@ import ddmd.sideeffect; import ddmd.staticassert; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} extern (C++) Identifier fixupLabelName(Scope* sc, Identifier ident) { @@ -387,6 +391,20 @@ extern (C++) abstract class Statement : RootObject { v.visit(this); } + + version(IN_LLVM) + { + CompoundAsmStatement isCompoundAsmBlockStatement() + { + return null; + } + + CompoundAsmStatement endsWithAsm() + { + // does not end with inline asm + return null; + } + } } /*********************************************************** @@ -859,7 +877,8 @@ extern (C++) class CompoundStatement : Statement return cast(inout)s; } - override final inout(CompoundStatement) isCompoundStatement() inout nothrow pure + // IN_LLVM removed: final + override inout(CompoundStatement) isCompoundStatement() inout nothrow pure { return this; } @@ -868,6 +887,22 @@ extern (C++) class CompoundStatement : Statement { v.visit(this); } + + version(IN_LLVM) + { + override CompoundAsmStatement endsWithAsm() + { + // make the last inner statement decide + if (statements && statements.dim) { + size_t last = statements.dim - 1; + Statement s = (*statements)[last]; + if (s) { + return s.endsWithAsm(); + } + } + return null; + } + } } /*********************************************************** @@ -1398,6 +1433,10 @@ extern (C++) final class SwitchStatement : Statement int hasNoDefault; // !=0 if no default statement int hasVars; // !=0 if has variable case values VarDeclaration lastVar; +version(IN_LLVM) +{ + bool hasGotoDefault; // true iff there is a `goto default` statement for this switch +} extern (D) this(Loc loc, Expression c, Statement b, bool isFinal) { @@ -1473,6 +1512,11 @@ extern (C++) final class CaseStatement : Statement int index; // which case it is (since we sort this) VarDeclaration lastVar; + version(IN_LLVM) + { + bool gototarget; // true iff this is the target of a 'goto case' + } + extern (D) this(Loc loc, Expression exp, Statement s) { super(loc); @@ -1537,6 +1581,11 @@ extern (C++) final class DefaultStatement : Statement Statement statement; VarDeclaration lastVar; + version(IN_LLVM) + { + bool gototarget; // true iff this is the target of a 'goto default' + } + extern (D) this(Loc loc, Statement s) { super(loc); @@ -1593,6 +1642,11 @@ extern (C++) final class GotoCaseStatement : Statement Expression exp; // null, or which case to goto CaseStatement cs; // case statement it resolves to + version(IN_LLVM) + { + SwitchStatement sw; + } + extern (D) this(Loc loc, Expression exp) { super(loc); @@ -1665,6 +1719,12 @@ extern (C++) final class BreakStatement : Statement { Identifier ident; + version(IN_LLVM) + { + // LDC: only set if ident is set: label statement to jump to + LabelStatement target; + } + extern (D) this(Loc loc, Identifier ident) { super(loc); @@ -1693,6 +1753,12 @@ extern (C++) final class ContinueStatement : Statement { Identifier ident; + version(IN_LLVM) + { + // LDC: only set if ident is set: label statement to jump to + LabelStatement target; + } + extern (D) this(Loc loc, Identifier ident) { super(loc); @@ -2061,7 +2127,8 @@ extern (C++) final class GotoStatement : Statement } } - if (label.statement.tf != tf) + // IN_LLVM replaced: if (label.statement.tf != tf) + if ( (label.statement !is null) && label.statement.tf != tf) { error("cannot goto in or out of finally block"); return true; @@ -2211,6 +2278,12 @@ extern (C++) final class AsmStatement : Statement bool refparam; // true if function parameter is referenced bool naked; // true if function is to be naked + version(IN_LLVM) + { + // non-zero if this is a branch, contains the target label + LabelDsymbol isBranchToLabel; + } + extern (D) this(Loc loc, Token* tokens) { super(loc); @@ -2219,7 +2292,17 @@ extern (C++) final class AsmStatement : Statement override Statement syntaxCopy() { +version(IN_LLVM) +{ + auto a_s = new AsmStatement(loc, tokens); + a_s.refparam = refparam; + a_s.naked = naked; + return a_s; +} +else +{ return new AsmStatement(loc, tokens); +} } override void accept(Visitor v) @@ -2235,6 +2318,11 @@ extern (C++) final class CompoundAsmStatement : CompoundStatement { StorageClass stc; // postfix attributes like nothrow/pure/@trusted + version(IN_LLVM) + { + void* abiret; // llvm::Value* + } + extern (D) this(Loc loc, Statements* s, StorageClass stc) { super(loc, s); @@ -2261,6 +2349,24 @@ extern (C++) final class CompoundAsmStatement : CompoundStatement { v.visit(this); } + + version(IN_LLVM) + { + override final inout(CompoundStatement) isCompoundStatement() inout nothrow pure + { + return null; + } + override final CompoundAsmStatement isCompoundAsmBlockStatement() + { + return this; + } + + override final CompoundAsmStatement endsWithAsm() + { + // yes this is inline asm + return this; + } + } } /*********************************************************** diff --git a/src/statement.h b/src/statement.h index 0638d0e165a0..c64759b64404 100644 --- a/src/statement.h +++ b/src/statement.h @@ -49,8 +49,21 @@ class CaseStatement; class DefaultStatement; class LabelStatement; +#if IN_LLVM +namespace llvm +{ + class Value; + class BasicBlock; + class ConstantInt; +} +class DValue; +typedef DValue elem; +struct AsmCode; +typedef AsmCode code; +#else // Back end struct code; +#endif bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply); bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply); @@ -110,6 +123,11 @@ class Statement : public RootObject virtual BreakStatement *isBreakStatement() { return NULL; } virtual DtorExpStatement *isDtorExpStatement() { return NULL; } virtual void accept(Visitor *v) { v->visit(this); } + +#if IN_LLVM + virtual CompoundAsmStatement *isCompoundAsmBlockStatement() { return NULL; } + virtual CompoundAsmStatement *endsWithAsm(); +#endif }; /** Any Statement that fails semantic() or has a component that is an ErrorExp or @@ -183,6 +201,10 @@ class CompoundStatement : public Statement CompoundStatement *isCompoundStatement() { return this; } void accept(Visitor *v) { v->visit(this); } + +#if IN_LLVM + virtual CompoundAsmStatement *endsWithAsm(); +#endif }; class CompoundDeclarationStatement : public CompoundStatement @@ -324,9 +346,8 @@ class IfStatement : public Statement Expression *condition; Statement *ifbody; Statement *elsebody; - Loc endloc; // location of closing curly bracket - VarDeclaration *match; // for MatchExpression results + Loc endloc; // location of closing curly bracket Statement *syntaxCopy(); IfStatement *isIfStatement() { return this; } @@ -384,6 +405,10 @@ class SwitchStatement : public Statement int hasVars; // !=0 if has variable case values VarDeclaration *lastVar; +#if IN_LLVM + bool hasGotoDefault; // true iff there is a `goto default` statement for this switch +#endif + Statement *syntaxCopy(); bool hasBreak(); bool checkLabel(); @@ -400,6 +425,10 @@ class CaseStatement : public Statement int index; // which case it is (since we sort this) VarDeclaration *lastVar; +#if IN_LLVM + bool gototarget; // true iff this is the target of a 'goto case' +#endif + Statement *syntaxCopy(); int compare(RootObject *obj); CaseStatement *isCaseStatement() { return this; } @@ -426,6 +455,10 @@ class DefaultStatement : public Statement Statement *statement; VarDeclaration *lastVar; +#if IN_LLVM + bool gototarget; // true iff this is the target of a 'goto default' +#endif + Statement *syntaxCopy(); DefaultStatement *isDefaultStatement() { return this; } @@ -449,6 +482,10 @@ class GotoCaseStatement : public Statement Expression *exp; // NULL, or which case to goto CaseStatement *cs; // case statement it resolves to +#if IN_LLVM + SwitchStatement *sw; +#endif + Statement *syntaxCopy(); GotoCaseStatement *isGotoCaseStatement() { return this; } @@ -479,6 +516,11 @@ class BreakStatement : public Statement public: Identifier *ident; +#if IN_LLVM + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +#endif + Statement *syntaxCopy(); BreakStatement *isBreakStatement() { return this; } @@ -490,6 +532,11 @@ class ContinueStatement : public Statement public: Identifier *ident; +#if IN_LLVM + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +#endif + Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } @@ -655,6 +702,11 @@ class AsmStatement : public Statement bool refparam; // true if function parameter is referenced bool naked; // true if function is to be naked +#if IN_LLVM + // non-zero if this is a branch, contains the target label + LabelDsymbol* isBranchToLabel; +#endif + Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } @@ -666,10 +718,21 @@ class CompoundAsmStatement : public CompoundStatement public: StorageClass stc; // postfix attributes like nothrow/pure/@trusted +#if IN_LLVM + llvm::Value *abiret; +#endif + CompoundAsmStatement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } + +#if IN_LLVM + CompoundStatement *isCompoundStatement() { return NULL; } + CompoundAsmStatement *isCompoundAsmBlockStatement() { return this; } + + CompoundAsmStatement* endsWithAsm(); +#endif }; class ImportStatement : public Statement diff --git a/src/statementsem.d b/src/statementsem.d index 4a64202c8f4a..a68552fa80f7 100644 --- a/src/statementsem.d +++ b/src/statementsem.d @@ -47,6 +47,10 @@ import ddmd.statement; import ddmd.target; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} private extern (C++) final class StatementSemanticVisitor : Visitor { @@ -276,7 +280,8 @@ private extern (C++) final class StatementSemanticVisitor : Visitor goto Lagain; } } - if (cs.statements.dim == 1) + // IN_LLVM replaced: if (cs.statements.dim == 1) + if (cs.statements.dim == 1 && !cs.isCompoundAsmBlockStatement()) { result = (*cs.statements)[0]; return; @@ -1225,6 +1230,11 @@ private extern (C++) final class StatementSemanticVisitor : Visitor p.type = p.type.semantic(loc, sc2); p.type = p.type.addStorageClass(p.storageClass); +version(IN_LLVM) +{ + // Type of parameter may be different; see below + auto para_type = p.type; +} if (tfld) { Parameter prm = Parameter.getNth(tfld.parameters, i); @@ -1254,12 +1264,39 @@ private extern (C++) final class StatementSemanticVisitor : Visitor LcopyArg: id = Identifier.generateId("__applyArg", cast(int)i); +version(IN_LLVM) +{ + // In case of a foreach loop on an array the index passed + // to the delegate is always of type size_t. The type of + // the parameter must be changed to size_t and a cast to + // the type used must be inserted. Otherwise the index is + // always 0 on a big endian architecture. This fixes + // issue #326. + Initializer ie; + if (dim == 2 && i == 0 && (tab.ty == Tarray || tab.ty == Tsarray)) + { + para_type = Type.tsize_t; + ie = new ExpInitializer(Loc(), + new CastExp(Loc(), + new IdentifierExp(Loc(), id), p.type)); + } + else + { + ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id)); + } +} +else +{ Initializer ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id)); +} auto v = new VarDeclaration(Loc(), p.type, p.ident, ie); v.storage_class |= STCtemp; s = new ExpStatement(Loc(), v); fs._body = new CompoundStatement(loc, s, fs._body); } +version(IN_LLVM) + params.push(new Parameter(stc, para_type, id, null)); +else params.push(new Parameter(stc, p.type, id, null)); } // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable. @@ -1891,6 +1928,36 @@ else } } } + // IN_LLVM. FIXME Move to pragma.cpp + else if (ps.ident == Id.LDC_allow_inline) + { + sc.func.allowInlining = true; + } + // IN_LLVM. FIXME Move to pragma.cpp + else if (ps.ident == Id.LDC_never_inline) + { + sc.func.neverInline = true; + } + // IN_LLVM. FIXME Move to pragma.cpp + else if (ps.ident == Id.LDC_profile_instr) + { + bool emitInstr = true; + if (!ps.args || ps.args.dim != 1 || !DtoCheckProfileInstrPragma((*ps.args)[0], emitInstr)) + { + ps.error("pragma(LDC_profile_instr, true or false) expected"); + goto Lerror; + } + else + { + FuncDeclaration fd = sc.func; + if (fd is null) + { + ps.error("pragma(LDC_profile_instr, ...) is not inside a function"); + goto Lerror; + } + fd.emitInstrumentation = emitInstr; + } + } else if (ps.ident == Id.startaddress) { if (!ps.args || ps.args.dim != 1) @@ -2075,6 +2142,10 @@ else if (cs.exp.equals(gcs.exp)) { gcs.cs = cs; +version(IN_LLVM) +{ + cs.gototarget = true; +} goto Lfoundcase; } } @@ -2146,6 +2217,18 @@ else if (ss.checkLabel()) goto Lerror; +version(IN_LLVM) +{ + /+ hasGotoDefault is set by GotoDefaultStatement.semantic + + at which point sdefault may still be null, therefore + + set sdefault.gototarget here. + +/ + if (ss.hasGotoDefault) { + assert(ss.sdefault); + ss.sdefault.gototarget = true; + } +} + sc.pop(); result = ss; return; @@ -2397,6 +2480,12 @@ else gds.error("goto default not allowed in final switch statement"); return setError(); } + +version(IN_LLVM) +{ + gds.sw.hasGotoDefault = true; +} + result = gds; } @@ -2407,6 +2496,10 @@ else gcs.error("goto case not in switch statement"); return setError(); } + version(IN_LLVM) + { + gcs.sw = sc.sw; + } if (gcs.exp) { @@ -2796,6 +2889,9 @@ else bs.error("cannot break out of finally block"); else { + version(IN_LLVM) + bs.target = ls; + ls.breaks = true; result = bs; return; @@ -2877,6 +2973,9 @@ else cs.error("cannot continue out of finally block"); else { + version(IN_LLVM) + cs.target = ls; + result = cs; return; } @@ -3015,6 +3114,10 @@ else s = new CompoundStatement(ss.loc, cs); result = s.semantic(sc); + version(IN_LLVM) // backport alignment fix for issue #1955 + { + tmp.alignment = Target.ptrsize; // must be set after semantic() + } return; } Lbody: diff --git a/src/target.d b/src/target.d index b13b0070c1f4..3e994c79f53d 100644 --- a/src/target.d +++ b/src/target.d @@ -18,6 +18,93 @@ import ddmd.mtype; import ddmd.root.ctfloat; import ddmd.root.outbuffer; +version(IN_LLVM) +{ + +extern(C++): + +struct Target +{ + static __gshared int ptrsize; + static __gshared int realsize; // size a real consumes in memory + static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize + static __gshared int realalignsize; // alignment for reals + static __gshared bool realislongdouble; // distinguish between C 'long double' and '__float128' + static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order + static __gshared bool cppExceptions; // set if catching C++ exceptions is supported + static __gshared int c_longsize; // size of a C 'long' or 'unsigned long' type + static __gshared int c_long_doublesize; // size of a C 'long double' + static __gshared int classinfosize; // size of 'ClassInfo' + + extern(D) static struct FPTypeProperties(T) + { + static real_t max() { return real_t(T.max); } + static real_t min_normal() { return real_t(T.min_normal); } + static real_t nan() { return real_t(T.nan); } + static real_t snan() { return real_t(T.init); } + static real_t infinity() { return real_t(T.infinity); } + static real_t epsilon() { return real_t(T.epsilon); } + + enum : long + { + dig = T.dig, + mant_dig = T.mant_dig, + max_exp = T.max_exp, + min_exp = T.min_exp, + max_10_exp = T.max_10_exp, + min_10_exp = T.min_10_exp + } + } + + alias FloatProperties = FPTypeProperties!float; + alias DoubleProperties = FPTypeProperties!double; + + static struct RealProperties + { + // implemented in gen/target.cpp + static real_t max(); + static real_t min_normal(); + static real_t nan(); + static real_t snan(); + static real_t infinity(); + static real_t epsilon(); + + static real_t host_max() { return real_t.max; } + static real_t host_min_normal() { return real_t.min_normal; } + static real_t host_nan() { return real_t.nan; } + static real_t host_snan() { return real_t.init; } + static real_t host_infinity() { return real_t.infinity; } + static real_t host_epsilon() { return real_t.epsilon; } + + static __gshared + { + long dig = real_t.dig; + long mant_dig = real_t.mant_dig; + long max_exp = real_t.max_exp; + long min_exp = real_t.min_exp; + long max_10_exp = real_t.max_10_exp; + long min_10_exp = real_t.min_10_exp; + } + } + + static void _init(); + // Type sizes and support. + static uint alignsize(Type type); + static uint fieldalign(Type type); + static uint critsecsize(); + static Type va_listType(); // get type of va_list + static int checkVectorType(int sz, Type type); + // CTFE support for cross-compilation. + static Expression paintAsType(Expression e, Type type); + // ABI and backend. + static void loadModule(Module m); + static void prefixName(OutBuffer *buf, LINK linkage); +} + +} +else // !IN_LLVM +{ + /*********************************************************** */ struct Target @@ -412,3 +499,5 @@ extern (C++) static Expression decodeReal(Loc loc, Type type, ubyte* buffer) } return new RealExp(loc, value, type); } + +} // !IN_LLVM diff --git a/src/target.h b/src/target.h index 7a254268a3f1..0b8ff5c4a0bc 100644 --- a/src/target.h +++ b/src/target.h @@ -28,16 +28,44 @@ struct Target static int realsize; // size a real consumes in memory static int realpad; // 'padding' added to the CPU real size to bring it up to realsize static int realalignsize; // alignment for reals + static bool realislongdouble; // distinguish between C 'long double' and '__float128' static bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order static bool cppExceptions; // set if catching C++ exceptions is supported static int c_longsize; // size of a C 'long' or 'unsigned long' type static int c_long_doublesize; // size of a C 'long double' static int classinfosize; // size of 'ClassInfo' - static void init(); +#ifdef IN_LLVM + struct RealProperties + { + // implemented in gen/target.cpp + static real_t max(); + static real_t min_normal(); + static real_t nan(); + static real_t snan(); + static real_t infinity(); + static real_t epsilon(); + + static real_t host_max(); + static real_t host_min_normal(); + static real_t host_nan(); + static real_t host_snan(); + static real_t host_infinity(); + static real_t host_epsilon(); + + static int64_t dig; + static int64_t mant_dig; + static int64_t max_exp; + static int64_t min_exp; + static int64_t max_10_exp; + static int64_t min_10_exp; + }; +#endif + + static void _init(); // Type sizes and support. - static unsigned alignsize(Type* type); - static unsigned fieldalign(Type* type); + static unsigned alignsize(Type *type); + static unsigned fieldalign(Type *type); static unsigned critsecsize(); static Type *va_listType(); // get type of va_list static int checkVectorType(int sz, Type *type); diff --git a/src/template.h b/src/template.h index 31f3c518a1cc..eb10fe251732 100644 --- a/src/template.h +++ b/src/template.h @@ -83,6 +83,10 @@ class TemplateDeclaration : public ScopeDsymbol TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack +#if IN_LLVM + const char *intrinsicName; +#endif + Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); bool overloadInsert(Dsymbol *s); diff --git a/src/tokens.h b/src/tokens.h index 6708cbf22641..832782df41fe 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -216,7 +216,6 @@ struct Token Identifier *ident; }; - static const char *tochars[TOKMAX]; static void initTokens(); static Token *freelist; diff --git a/src/traits.d b/src/traits.d index beaeeba8fec8..6d2196c4c8a1 100644 --- a/src/traits.d +++ b/src/traits.d @@ -34,6 +34,10 @@ import ddmd.root.speller; import ddmd.root.stringtable; import ddmd.tokens; import ddmd.visitor; +version (IN_LLVM) +{ + import ddmd.hooks; +} enum LOGSEMANTIC = false; @@ -1204,6 +1208,10 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc) { return pointerBitmap(e); } + if (Expression ret = semanticTraitsHook(e, sc)) + { + return ret; + } extern (D) void* trait_search_fp(const(char)* seed, ref int cost) { diff --git a/src/typinf.d b/src/typinf.d index 4810ad8261a1..2889bf5d779b 100644 --- a/src/typinf.d +++ b/src/typinf.d @@ -21,6 +21,12 @@ import ddmd.gluelayer; import ddmd.mtype; import ddmd.visitor; +version (IN_LLVM) +{ + import ddmd.dsymbol; + extern (C++) void Declaration_codegen(Dsymbol decl); +} + /**************************************************** * Get the exact TypeInfo. */ @@ -62,7 +68,10 @@ extern (C++) void genTypeInfo(Type torig, Scope* sc) } else // if in obj generation pass { - toObjFile(t.vtinfo, global.params.multiobj); + version (IN_LLVM) + Declaration_codegen(t.vtinfo); + else + toObjFile(t.vtinfo, global.params.multiobj); } } } @@ -232,8 +241,18 @@ extern (C++) bool isSpeculativeType(Type t) */ extern (C++) static bool builtinTypeInfo(Type t) { + version (IN_LLVM) + { + // FIXME: if I enable for Tclass, the way LDC does typeinfo will cause + // a bunch of linker errors to missing ClassInfo init symbols. + if (t.isTypeBasic() || t.ty == Tnull) + return !t.mod; + } + else + { if (t.isTypeBasic() || t.ty == Tclass || t.ty == Tnull) return !t.mod; + } if (t.ty == Tarray) { Type next = t.nextOf();