diff --git a/src/ddmd/aggregate.h b/src/ddmd/aggregate.h index d484ff153688..a0adfca3d112 100644 --- a/src/ddmd/aggregate.h +++ b/src/ddmd/aggregate.h @@ -191,7 +191,7 @@ class StructDeclaration : public AggregateDeclaration void semantic(Scope *sc); void semanticTypeInfoMembers(); Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly); - const char *kind(); + const char *kind() const; void finalizeSize(); bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype); bool isPOD(); @@ -204,7 +204,7 @@ class UnionDeclaration : public StructDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); + const char *kind() const; UnionDeclaration *isUnionDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -303,7 +303,7 @@ class ClassDeclaration : public AggregateDeclaration virtual bool isCPPinterface() const; bool isAbstract(); virtual int vtblOffset() const; - const char *kind(); + const char *kind() const; void addLocalClass(ClassDeclarations *); @@ -322,7 +322,7 @@ class InterfaceDeclaration : public ClassDeclaration void semantic(Scope *sc); bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); + const char *kind() const; int vtblOffset() const; bool isCPPinterface() const; bool isCOMinterface() const; diff --git a/src/ddmd/aliasthis.h b/src/ddmd/aliasthis.h index 0f94f7c7f0f7..206e82e8d420 100644 --- a/src/ddmd/aliasthis.h +++ b/src/ddmd/aliasthis.h @@ -28,7 +28,7 @@ class AliasThis : public Dsymbol Identifier *ident; Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; AliasThis *isAliasThis() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/ddmd/attrib.d b/src/ddmd/attrib.d index cef908d6ecac..9277d8f6ce0b 100644 --- a/src/ddmd/attrib.d +++ b/src/ddmd/attrib.d @@ -32,6 +32,12 @@ import ddmd.tokens; import ddmd.semantic; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} + + /*********************************************************** */ extern (C++) abstract class AttribDeclaration : Dsymbol @@ -806,6 +812,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; } diff --git a/src/ddmd/attrib.h b/src/ddmd/attrib.h index 529b4de3f6a9..37fbbae37e03 100644 --- a/src/ddmd/attrib.h +++ b/src/ddmd/attrib.h @@ -186,6 +186,7 @@ class StaticIfDeclaration : public ConditionalDeclaration void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); void importAll(Scope *sc); + void semantic(Scope *sc); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; @@ -199,10 +200,10 @@ class StaticForeachDeclaration : public ConditionalDeclaration Dsymbols *cache; Dsymbol *syntaxCopy(Dsymbol *s); - bool oneMember(Dsymbol *ps, Identifier *ident); + bool oneMember(Dsymbol **ps, Identifier *ident); Dsymbols *include(Scope *sc, ScopeDsymbol *sds); void addMember(Scope *sc, ScopeDsymbol *sds); - void addComment(const char *comment); + void addComment(const utf8_t *comment); void setScope(Scope *sc); void importAll(Scope *sc); const char *kind() const; diff --git a/src/ddmd/builtin.d b/src/ddmd/builtin.d index b02426e4ebc2..cd1d29b7a6a1 100644 --- a/src/ddmd/builtin.d +++ b/src/ddmd/builtin.d @@ -24,6 +24,9 @@ import ddmd.mtype; import ddmd.root.ctfloat; import ddmd.root.stringtable; import ddmd.tokens; +version(IN_LLVM) { + import ddmd.dtemplate; +} private: @@ -157,6 +160,306 @@ 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_llvmlog2(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.log2(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmlog10(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.log10(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_llvmrint(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.rint(arg0.toReal()), type); +} + +extern (C++) Expression eval_llvmnearbyint(Loc loc, FuncDeclaration fd, Expressions *arguments) +{ + Type type = getTypeOfOverloadedIntrinsic(fd); + Expression arg0 = (*arguments)[0]; + assert(arg0.op == TOKfloat64); + return new RealExp(loc, CTFloat.nearbyint(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_llvmfma(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); + Expression arg2 = (*arguments)[2]; + assert(arg2.op == TOKfloat64); + return new RealExp(loc, CTFloat.fma(arg0.toReal(), arg1.toReal(), arg2.toReal()), type); +} + +extern (C++) Expression eval_llvmcopysign(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.copysign(arg0.toReal(), arg1.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]; @@ -176,6 +479,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]; @@ -217,8 +522,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); @@ -243,6 +555,9 @@ public extern (C++) void builtin_init() add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp); if (CTFloat.yl2x_supported) { + version(IN_LLVM) // @trusted + add_builtin("_D4core4math4yl2xFNaNbNiNeeeZe", &eval_yl2x); + else add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); } else @@ -251,6 +566,9 @@ public extern (C++) void builtin_init() } if (CTFloat.yl2xp1_supported) { + version(IN_LLVM) // @trusted + add_builtin("_D4core4math6yl2xp1FNaNbNiNeeeZe", &eval_yl2xp1); + else add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); } else @@ -317,6 +635,155 @@ public extern (C++) void builtin_init() add_builtin("_D3std4math__T8isFiniteTdZQmFNaNbNiNedZb", &eval_isfinite); add_builtin("_D3std4math__T8isFiniteTfZQmFNaNbNiNefZb", &eval_isfinite); +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.log2.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.log2.f32", &eval_llvmlog2); + add_builtin("llvm.log2.f64", &eval_llvmlog2); + add_builtin("llvm.log2.f80", &eval_llvmlog2); + add_builtin("llvm.log2.f128", &eval_llvmlog2); + add_builtin("llvm.log2.ppcf128", &eval_llvmlog2); + + // intrinsic llvm.log10.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.log10.f32", &eval_llvmlog10); + add_builtin("llvm.log10.f64", &eval_llvmlog10); + add_builtin("llvm.log10.f80", &eval_llvmlog10); + add_builtin("llvm.log10.f128", &eval_llvmlog10); + add_builtin("llvm.log10.ppcf128", &eval_llvmlog10); + + // 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.rint.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.rint.f32", &eval_llvmrint); + add_builtin("llvm.rint.f64", &eval_llvmrint); + add_builtin("llvm.rint.f80", &eval_llvmrint); + add_builtin("llvm.rint.f128", &eval_llvmrint); + add_builtin("llvm.rint.ppcf128", &eval_llvmrint); + + // intrinsic llvm.nearbyint.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.nearbyint.f32", &eval_llvmnearbyint); + add_builtin("llvm.nearbyint.f64", &eval_llvmnearbyint); + add_builtin("llvm.nearbyint.f80", &eval_llvmnearbyint); + add_builtin("llvm.nearbyint.f128", &eval_llvmnearbyint); + add_builtin("llvm.nearbyint.ppcf128", &eval_llvmnearbyint); + + // 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.fma.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.fma.f32", &eval_llvmfma); + add_builtin("llvm.fma.f64", &eval_llvmfma); + add_builtin("llvm.fma.f80", &eval_llvmfma); + add_builtin("llvm.fma.f128", &eval_llvmfma); + add_builtin("llvm.fma.ppcf128", &eval_llvmfma); + + // intrinsic llvm.copysign.f32/f64/f80/f128/ppcf128 + add_builtin("llvm.copysign.f32", &eval_llvmcopysign); + add_builtin("llvm.copysign.f64", &eval_llvmcopysign); + add_builtin("llvm.copysign.f80", &eval_llvmcopysign); + add_builtin("llvm.copysign.f128", &eval_llvmcopysign); + add_builtin("llvm.copysign.ppcf128", &eval_llvmcopysign); + + // 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/ddmd/complex_t.h b/src/ddmd/complex_t.h index a1ad38890c70..633001de93fb 100644 --- a/src/ddmd/complex_t.h +++ b/src/ddmd/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/ddmd/constfold.d b/src/ddmd/constfold.d index 2fac4fa9fa30..b661f09c4187 100644 --- a/src/ddmd/constfold.d +++ b/src/ddmd/constfold.d @@ -31,6 +31,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) @@ -56,6 +61,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/ddmd/cppmangle.d b/src/ddmd/cppmangle.d index af60076bf3dd..bb0b9fef3c6a 100644 --- a/src/ddmd/cppmangle.d +++ b/src/ddmd/cppmangle.d @@ -1998,5 +1998,18 @@ extern (C++) const(char)* toCppMangleMSVC(Dsymbol s) extern (C++) const(char)* cppTypeInfoMangleMSVC(Dsymbol s) { //printf("cppTypeInfoMangle(%s)\n", s.toChars()); - assert(0); + version (IN_LLVM) + { + // Return the mangled name of the RTTI Type Descriptor. + // Reverse-engineered using a few C++ exception classes. + scope VisualCPPMangler v = new VisualCPPMangler(!global.params.mscoff); + v.buf.writestring("\1??_R0?AV"); + v.mangleIdent(s); + v.buf.writestring("@8"); + return v.buf.extractString(); + } + else + { + assert(0); + } } diff --git a/src/ddmd/dcast.d b/src/ddmd/dcast.d index 947cbe32d27f..fe87e850e94e 100644 --- a/src/ddmd/dcast.d +++ b/src/ddmd/dcast.d @@ -2387,7 +2387,16 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t) if (e2c != e.e2) { - result = new CommaExp(e.loc, e.e1, e2c); + version (IN_LLVM) + { + // Cast the CommaExp instead of the inner rhs; this fixes + // https://github.com/ldc-developers/ldc/issues/2415. + result = new CastExp(e.loc, e, e2c.type); + } + else + { + result = new CommaExp(e.loc, e.e1, e2c); + } result.type = e2c.type; } else diff --git a/src/ddmd/declaration.h b/src/ddmd/declaration.h index 2f128480302c..0957ef7ea8c8 100644 --- a/src/ddmd/declaration.h +++ b/src/ddmd/declaration.h @@ -32,6 +32,9 @@ class StructDeclaration; struct InterState; struct CompiledCtfeFunction; struct ObjcSelector; +#if IN_LLVM +struct Symbol; +#endif enum LINK; enum TOK; @@ -130,7 +133,7 @@ class Declaration : public Dsymbol int inuse; // used to detect cycles const char *mangleOverride; // overridden symbol with pragma(mangle, "...") - const char *kind(); + const char *kind() const; d_uns64 size(Loc loc); int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag); @@ -179,13 +182,17 @@ class TupleDeclaration : public Declaration TypeTuple *tupletype; // !=NULL if this is a type tuple Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; Type *getType(); Dsymbol *toAlias2(); bool needThis(); TupleDeclaration *isTupleDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } + +#if IN_LLVM + void semantic3(Scope *sc); +#endif }; /**************************************************************/ @@ -201,7 +208,7 @@ class AliasDeclaration : public Declaration Dsymbol *syntaxCopy(Dsymbol *); void aliasSemantic(Scope *sc); bool overloadInsert(Dsymbol *s); - const char *kind(); + const char *kind() const; Type *getType(); Dsymbol *toAlias(); Dsymbol *toAlias2(); @@ -220,7 +227,7 @@ class OverDeclaration : public Declaration Dsymbol *aliassym; bool hasOverloads; - const char *kind(); + const char *kind() const; bool equals(RootObject *o); bool overloadInsert(Dsymbol *s); @@ -263,7 +270,7 @@ class VarDeclaration : public Declaration Dsymbol *syntaxCopy(Dsymbol *); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - const char *kind(); + const char *kind() const; AggregateDeclaration *isThis(); bool needThis(); bool isExport(); @@ -497,6 +504,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,15 +651,20 @@ class FuncDeclaration : public Declaration virtual bool isFinalFunc(); virtual bool addPreInvariant(); virtual bool addPostInvariant(); - const char *kind(); + const char *kind() const; FuncDeclaration *isUnique(); bool checkNestedReference(Scope *sc, Loc loc); bool needsClosure(); 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); @@ -658,7 +690,7 @@ class FuncAliasDeclaration : public FuncDeclaration bool hasOverloads; FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); + const char *kind() const; FuncDeclaration *toAliasFunc(); void accept(Visitor *v) { v->visit(this); } @@ -683,7 +715,7 @@ class FuncLiteralDeclaration : public FuncDeclaration void modifyReturns(Scope *sc, Type *tret); FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); + const char *kind() const; const char *toPrettyChars(bool QualifyTypes = false); void accept(Visitor *v) { v->visit(this); } }; @@ -692,7 +724,7 @@ class CtorDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; const char *toChars(); bool isVirtual(); bool addPreInvariant(); @@ -719,7 +751,7 @@ class DtorDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; const char *toChars(); bool isVirtual(); bool addPreInvariant(); @@ -815,7 +847,7 @@ class NewDeclaration : public FuncDeclaration int varargs; Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; bool isVirtual(); bool addPreInvariant(); bool addPostInvariant(); @@ -831,7 +863,7 @@ class DeleteDeclaration : public FuncDeclaration Parameters *parameters; Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); + const char *kind() const; bool isDelete(); bool isVirtual(); bool addPreInvariant(); diff --git a/src/ddmd/dmodule.d b/src/ddmd/dmodule.d index e5a956009958..42be9ea0a90d 100644 --- a/src/ddmd/dmodule.d +++ b/src/ddmd/dmodule.d @@ -30,6 +30,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; @@ -421,7 +426,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) @@ -560,6 +583,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)) { @@ -590,8 +630,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 { @@ -1065,6 +1114,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; } @@ -1308,6 +1360,21 @@ extern (C++) final class Module : Package Symbol* stest; // module unit test Symbol* sfilename; // symbol for filename + 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. + + // 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/ddmd/doc.d b/src/ddmd/doc.d index 7bb5bbffceae..652e40f99deb 100644 --- a/src/ddmd/doc.d +++ b/src/ddmd/doc.d @@ -362,6 +362,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/ddmd/dscope.d b/src/ddmd/dscope.d index 87a62365d5b2..693accd131bb 100644 --- a/src/ddmd/dscope.d +++ b/src/ddmd/dscope.d @@ -174,6 +174,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 @@ -399,8 +404,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/ddmd/dsymbol.d b/src/ddmd/dsymbol.d index 8f717ec130ad..2008f91cd327 100644 --- a/src/ddmd/dsymbol.d +++ b/src/ddmd/dsymbol.d @@ -52,6 +52,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; @@ -213,10 +220,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) @@ -224,6 +243,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/ddmd/dsymbol.h b/src/ddmd/dsymbol.h index e7304c7db58d..7facd6d3f044 100644 --- a/src/ddmd/dsymbol.h +++ b/src/ddmd/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; @@ -81,6 +91,11 @@ typedef union tree_node Symbol; struct Symbol; #endif +// in dsymbolsem.d +void semantic(Dsymbol *dsym, Scope *sc); +void semantic2(Dsymbol *dsym, Scope *sc); +void semantic3(Dsymbol *dsym, Scope *sc); + struct Ungag { unsigned oldgag; @@ -168,6 +183,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 @@ -196,7 +218,7 @@ class Dsymbol : public RootObject virtual Identifier *getIdent(); virtual const char *toPrettyChars(bool QualifyTypes = false); - virtual const char *kind(); + virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); virtual int apply(Dsymbol_apply_ft_t fp, void *param); @@ -307,7 +329,7 @@ class ScopeDsymbol : public Dsymbol virtual bool isPackageAccessible(Package *p, Prot protection, int flags = 0); bool isforwardRef(); static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - const char *kind(); + const char *kind() const; FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); @@ -359,7 +381,7 @@ class OverloadSet : public Dsymbol void push(Dsymbol *s); OverloadSet *isOverloadSet() { return this; } - const char *kind(); + const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; @@ -373,7 +395,7 @@ class ForwardingScopeDsymbol : public ScopeDsymbol Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); void importScope(Dsymbol *s, Prot protection); void semantic(Scope *sc); - const char *kind(); + const char *kind() const; ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; } }; diff --git a/src/ddmd/dsymbolsem.d b/src/ddmd/dsymbolsem.d index 8625f45f01eb..8eaf14cdd71c 100644 --- a/src/ddmd/dsymbolsem.d +++ b/src/ddmd/dsymbolsem.d @@ -70,6 +70,12 @@ import ddmd.templateparamsem; import ddmd.typesem; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; + import gen.llvmhelpers; +} + enum LOG = false; /************************************* @@ -854,7 +860,10 @@ extern(C++) final class Semantic3Visitor : Visitor if (f.linkage == LINKd || (f.parameters && Parameter.dim(f.parameters))) { // Declare _argptr - Type t = Type.tvalist; + version (IN_LLVM) + Type t = Type.tvalist.typeSemantic(funcdecl.loc, sc); + else + Type t = Type.tvalist; // Init is handled in FuncDeclaration_toObjFile funcdecl.v_argptr = new VarDeclaration(Loc(), t, Id._argptr, new VoidInitializer(funcdecl.loc)); funcdecl.v_argptr.storage_class |= STCtemp; @@ -864,6 +873,32 @@ extern(C++) final class Semantic3Visitor : Visitor } } + 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.typeSemantic(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[] */ @@ -1396,6 +1431,9 @@ extern(C++) final class Semantic3Visitor : Visitor } } +// we'll handle variadics ourselves +static if (!IN_LLVM) +{ if (_arguments) { /* Advance to elements[] member of TypeInfo_Tuple with: @@ -1410,6 +1448,7 @@ extern(C++) final class Semantic3Visitor : Visitor auto de = new DeclarationExp(Loc(), _arguments); a.push(new ExpStatement(Loc(), de)); } +} // Merge contracts together with body into one compound statement @@ -1439,8 +1478,26 @@ extern(C++) final class Semantic3Visitor : Visitor if (f.next.ty != Tvoid && funcdecl.vresult) { +version(IN_LLVM) +{ + Expression e = null; + if (funcdecl.isCtorDeclaration()) + { + ThisExp te = new ThisExp(Loc()); + te.type = funcdecl.vthis.type; + te.var = funcdecl.vthis; + e = te; + } + else + { + e = new VarExp(Loc(), funcdecl.vresult); + } +} +else +{ // Create: return vresult; Expression e = new VarExp(Loc(), funcdecl.vresult); +} if (funcdecl.tintro) { e = e.implicitCastTo(sc, funcdecl.tintro.nextOf()); @@ -2859,6 +2916,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + + version(IN_LLVM) + { + LDCPragma llvm_internal = LDCPragma.LLVMnone; + const(char)* arg1str = null; + } + if (pd.ident == Id.msg) { if (pd.args) @@ -3010,6 +3074,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } } + // IN_LLVM + else if ((llvm_internal = DtoGetPragma(sc, pd, arg1str)) != LDCPragma.LLVMnone) + { + // nothing to do anymore + } else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) @@ -3022,6 +3091,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor for (size_t i = 0; i < pd.args.dim; i++) { Expression e = (*pd.args)[i]; + version(IN_LLVM) + { + // ignore errors in ignored pragmas. + global.gag++; + uint errors_save = global.errors; + } sc = sc.startCTFE(); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); @@ -3032,13 +3107,20 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else fprintf(global.stdmsg, ","); fprintf(global.stdmsg, "%s", e.toChars()); + version(IN_LLVM) + { + // restore error state. + global.gag--; + global.errors = errors_save; + } } if (pd.args.dim) fprintf(global.stdmsg, ")"); } fprintf(global.stdmsg, "\n"); } - goto Lnodecl; + static if (!IN_LLVM) + goto Lnodecl; } else pd.error("unrecognized `pragma(%s)`", pd.ident.toChars()); @@ -3063,6 +3145,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor pd.error("can only apply to a single declaration"); } } + // IN_LLVM: add else clause + else + { + DtoCheckPragma(pd, s, llvm_internal, arg1str); + } } if (sc2 != sc) sc2.pop(); @@ -3923,7 +4010,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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 tm.error("recursive expansion"); @@ -4104,6 +4192,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.inlining = sc.inlining; funcdecl.protection = sc.protection; funcdecl.userAttribDecl = sc.userAttribDecl; + version(IN_LLVM) + { + funcdecl.emitInstrumentation = sc.emitInstrumentation; + } if (!funcdecl.originalType) funcdecl.originalType = funcdecl.type.syntaxCopy(); @@ -4747,7 +4839,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.initInferAttributes(); Module.dprogress++; - funcdecl.semanticRun = PASSsemanticdone; + version(IN_LLVM) + { + // LDC relies on semanticRun variable not being reset here + if (funcdecl.semanticRun < PASSsemanticdone) + funcdecl.semanticRun = PASSsemanticdone; + } + else + { + funcdecl.semanticRun = PASSsemanticdone; + } /* Save scope for possible later use (if we need the * function internals) @@ -6670,6 +6771,16 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); tempinst.aliasdecl = s; + version(IN_LLVM) + { + // LDC propagate internal information + if (tempdecl.llvmInternal != 0) { + s.llvmInternal = tempdecl.llvmInternal; + if (FuncDeclaration fd = s.isFuncDeclaration()) { + DtoSetFuncDeclIntrinsicName(tempinst, tempdecl, fd); + } + } + } } } @@ -6838,7 +6949,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* 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 tempinst.error("recursive expansion"); diff --git a/src/ddmd/dtemplate.d b/src/ddmd/dtemplate.d index 2ddf23a652c3..31f216883ae5 100644 --- a/src/ddmd/dtemplate.d +++ b/src/ddmd/dtemplate.d @@ -521,6 +521,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); @@ -576,7 +580,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); +} } /********************************** @@ -7374,7 +7389,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"); diff --git a/src/ddmd/enum.h b/src/ddmd/enum.h index 8b53d3b703f4..45d85c9295a2 100644 --- a/src/ddmd/enum.h +++ b/src/ddmd/enum.h @@ -54,7 +54,7 @@ class EnumDeclaration : public ScopeDsymbol void setScope(Scope *sc); bool oneMember(Dsymbol **ps, Identifier *ident); Type *getType(); - const char *kind(); + const char *kind() const; Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly); bool isDeprecated(); // is Dsymbol deprecated? Prot prot(); @@ -88,7 +88,7 @@ class EnumMember : public VarDeclaration EnumDeclaration *ed; Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); + const char *kind() const; Expression *getVarExp(Loc loc, Scope *sc); EnumMember *isEnumMember() { return this; } diff --git a/src/ddmd/expression.d b/src/ddmd/expression.d index 05a70ba22eef..651b967efcd5 100644 --- a/src/ddmd/expression.d +++ b/src/ddmd/expression.d @@ -65,6 +65,8 @@ import ddmd.typesem; import ddmd.utf; import ddmd.visitor; +version(IN_LLVM) import gen.dpragma; + enum LOGSEMANTIC = false; void emplaceExp(T : Expression, Args...)(void* p, Args args) { @@ -133,6 +135,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 @@ -1955,7 +1965,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); @@ -2186,7 +2198,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); @@ -2701,7 +2713,8 @@ enum WANTexpand = 1; // expand const/immutable variables if possible /*********************************************************** * http://dlang.org/spec/expression.html#expression */ -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 @@ -4877,6 +4890,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::Constant* + } + bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol Symbol* sym; /// back end symbol to initialize with literal @@ -5320,6 +5345,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; } @@ -5700,6 +5734,8 @@ extern (C++) final class FuncExp : Expression // https://issues.dlang.org/show_bug.cgi?id=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) diff --git a/src/ddmd/expression.h b/src/ddmd/expression.h index 23e58e02775f..544bf63e1b76 100644 --- a/src/ddmd/expression.h +++ b/src/ddmd/expression.h @@ -55,6 +55,19 @@ typedef union tree_node Symbol; struct Symbol; // back end symbol #endif +void initPrecedence(); + +#if IN_LLVM +class SymbolDeclaration; +namespace llvm { + class Constant; + class Value; +} + +// in expressionsem.d +Expression *expressionSemantic(Expression *e, Scope *sc); +#endif + Expression *resolveProperties(Scope *sc, Expression *e); Expression *resolvePropertiesOnly(Scope *sc, Expression *e1); bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d); @@ -360,6 +373,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(); @@ -438,6 +461,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::Constant *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/ddmd/expressionsem.d b/src/ddmd/expressionsem.d index 6bc9d01e3f56..5da8ceaa70cb 100644 --- a/src/ddmd/expressionsem.d +++ b/src/ddmd/expressionsem.d @@ -65,6 +65,8 @@ import ddmd.utf; import ddmd.utils; import ddmd.visitor; +version(IN_LLVM) import gen.dpragma; + enum LOGSEMANTIC = false; private extern (C++) final class ExpressionSemanticVisitor : Visitor @@ -3718,6 +3720,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor FuncDeclaration f = ve.var.isFuncDeclaration(); if (f) { + version(IN_LLVM) + { + if (DtoIsIntrinsic(f)) + { + exp.error("cannot take the address of intrinsic function %s", exp.e1.toChars()); + result = new ErrorExp(); + return; + } + } /* 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/ddmd/func.d b/src/ddmd/func.d index 7def0c490ce0..0299a5ae575f 100644 --- a/src/ddmd/func.d +++ b/src/ddmd/func.d @@ -166,6 +166,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 @@ -278,9 +299,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; + } + } + /**************************************************** * Resolve forward reference of function signature - * parameter types, return type, and attributes. @@ -351,8 +399,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(this, _scope); global.gag = oldgag; @@ -1919,8 +1975,15 @@ 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) { + version(IN_LLVM) + { + 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: * @@ -1937,6 +2000,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 @@ -1953,6 +2022,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. */ +} foreach (fdv; foverrides) { /* The semantic pass on the contracts of the overridden functions must @@ -1968,6 +2038,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) { @@ -1976,8 +2049,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); @@ -2026,13 +2104,38 @@ extern (C++) class FuncDeclaration : Declaration if (frequire) { - /* in { ... } - * becomes: - * void __require() { ... } - * __require(); - */ - Loc loc = frequire.loc; - auto tf = new TypeFunction(null, Type.tvoid, 0, LINKd); + 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 set fdrequireParams here. + */ + Loc loc = frequire.loc; + fdrequireParams = new Expressions(); + if (parameters) + { + foreach (vd; *parameters) + fdrequireParams.push(new VarExp(loc, vd)); + } + auto fparams = outToRef((cast(TypeFunction)type).parameters); + auto tf = new TypeFunction(fparams, Type.tvoid, 0, LINKd); + } + else + { + /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + 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; @@ -2040,7 +2143,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; @@ -2049,20 +2159,47 @@ 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 set fdensureParams here and not in the block below to + * have the parameters available when calling a base class ensure(), + * even if this function doesn't have an out contract. */ - Loc loc = fensure.loc; - auto fparams = new Parameters(); + fdensureParams = new Expressions(); + if (outId) + fdensureParams.push(new IdentifierExp(loc, outId)); + if (parameters) + { + foreach (vd; *parameters) + fdensureParams.push(new VarExp(loc, vd)); + } + } + if (fensure) + { + version(IN_LLVM) + { + /* Same as for in contracts, see above. */ + Loc loc = fensure.loc; + auto fparams = outToRef((cast(TypeFunction)type).parameters); + } + else + { + /* out (result) { ... } + * becomes: + * void __ensure(ref tret result) { ... } + * __ensure(result); + */ + 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; @@ -2072,10 +2209,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; @@ -2086,8 +2230,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 @@ -2113,6 +2264,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) { @@ -2121,9 +2275,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)) { @@ -2140,7 +2303,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) diff --git a/src/ddmd/globals.d b/src/ddmd/globals.d index 052230d80232..dce8ede07217 100644 --- a/src/ddmd/globals.d +++ b/src/ddmd/globals.d @@ -24,6 +24,8 @@ template xversion(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`; @@ -32,6 +34,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 @@ -199,6 +214,38 @@ 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) + + bool outputSourceLocations; // if true, output line tables. + } } struct Compiler @@ -217,6 +264,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 @@ -288,6 +345,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"; @@ -341,10 +407,18 @@ struct Global { static assert(0, "fix this"); } +} copyright = "Copyright (c) 1999-2017 by Digital Mars"; written = "written by Walter Bright"; +version(IN_LLVM) +{ + compiler.vendor = "LDC"; +} +else +{ _version = (import("VERSION") ~ '\0').ptr; compiler.vendor = "Digital Mars D"; +} stdmsg = stdout; main_d = "__main.d"; errorLimit = 20; diff --git a/src/ddmd/globals.h b/src/ddmd/globals.h index f8f3a3bff371..c51d42ad0aa0 100644 --- a/src/ddmd/globals.h +++ b/src/ddmd/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 { @@ -66,10 +81,18 @@ struct Param bool vcg_ast; // write-out codegen-ast 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 symdebugref; // insert debug information for all referenced types, too bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer @@ -87,7 +110,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 @@ -102,7 +129,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 @@ -180,6 +211,36 @@ 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) + + bool outputSourceLocations; // if true, output line tables. +#endif }; struct Compiler @@ -197,6 +258,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 @@ -294,7 +364,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/ddmd/gluelayer.d b/src/ddmd/gluelayer.d index aa1a96f8c7c1..239007d7a696 100644 --- a/src/ddmd/gluelayer.d +++ b/src/ddmd/gluelayer.d @@ -19,7 +19,24 @@ 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() {} + } +} +else version (NoBackend) { import ddmd.lib : Library; diff --git a/src/ddmd/hdrgen.d b/src/ddmd/hdrgen.d index 95743537cb3c..f0ef317c365a 100644 --- a/src/ddmd/hdrgen.d +++ b/src/ddmd/hdrgen.d @@ -67,6 +67,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/ddmd/hooks.d b/src/ddmd/hooks.d new file mode 100644 index 000000000000..be83d1282086 --- /dev/null +++ b/src/ddmd/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/ddmd/id.d b/src/ddmd/id.d index cfa0df7de7c4..21584f14ad72 100644 --- a/src/ddmd/id.d +++ b/src/ddmd/id.d @@ -22,7 +22,8 @@ import ddmd.tokens; * * All static fields in this struct represents a specific predefined symbol. */ -struct Id +// IN_LLVM: added `extern(C++)` +extern(C++) struct Id { static __gshared: @@ -402,6 +403,55 @@ immutable Msgtable[] msgtable = { "TRUE" }, { "FALSE" }, { "unsigned" }, + + // 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" }, + + // IN_LLVM: LDC-specific attributes + { "ldc" }, + { "attributes" }, + { "udaAllocSize", "allocSize" }, + // fastmath is an AliasSeq of llvmAttr and llvmFastMathFlag + { "udaOptStrategy", "optStrategy" }, + { "udaLLVMAttr", "llvmAttr" }, + { "udaLLVMFastMathFlag", "llvmFastMathFlag" }, + { "udaSection", "section" }, + { "udaTarget", "target" }, + { "udaWeak", "_weak" }, + { "udaCompute", "compute" }, + { "udaKernel", "_kernel" }, + { "udaDynamicCompile", "_dynamicCompile" }, + { "udaDynamicCompileConst", "_dynamicCompileConst" }, + + // IN_LLVM: DCompute specific types and functionss + { "dcompute" }, + { "dcPointer", "Pointer" }, + { "dcReflect", "__dcompute_reflect" }, ]; diff --git a/src/ddmd/id.h b/src/ddmd/id.h new file mode 100644 index 000000000000..10da6c42ded2 --- /dev/null +++ b/src/ddmd/id.h @@ -0,0 +1,71 @@ +#ifndef DMD_ID_H +#define DMD_ID_H + +#include "identifier.h" + +struct Id +{ +public: + static Identifier *___in; + static Identifier *__int; + static Identifier *___out; + static Identifier *__LOCAL_SIZE; + static Identifier *dollar; + static Identifier *ptr; + static Identifier *offset; + static Identifier *offsetof; + static Identifier *__c_long; + static Identifier *__c_ulong; + static Identifier *__c_long_double; + static Identifier *lib; + static Identifier *ldc; + static Identifier *dcompute; + static Identifier *dcPointer; + static Identifier *object; + static Identifier *ensure; + static Identifier *require; + static Identifier *xopEquals; + static Identifier *xopCmp; + static Identifier *xtoHash; + static Identifier *empty; + static Identifier *ctfe; + static Identifier *_arguments; + static Identifier *_argptr; + static Identifier *LDC_intrinsic; + static Identifier *LDC_global_crt_ctor; + static Identifier *LDC_global_crt_dtor; + static Identifier *LDC_no_typeinfo; + static Identifier *LDC_no_moduleinfo; + static Identifier *LDC_alloca; + static Identifier *LDC_va_start; + static Identifier *LDC_va_copy; + static Identifier *LDC_va_end; + static Identifier *LDC_va_arg; + static Identifier *LDC_fence; + static Identifier *LDC_atomic_load; + static Identifier *LDC_atomic_store; + static Identifier *LDC_atomic_cmp_xchg; + static Identifier *LDC_atomic_rmw; + static Identifier *LDC_verbose; + static Identifier *LDC_inline_asm; + static Identifier *LDC_inline_ir; + static Identifier *LDC_extern_weak; + static Identifier *LDC_profile_instr; + static Identifier *dcReflect; + static Identifier *criticalenter; + static Identifier *criticalexit; + static Identifier *attributes; + static Identifier *udaSection; + static Identifier *udaOptStrategy; + static Identifier *udaTarget; + static Identifier *udaWeak; + static Identifier *udaAllocSize; + static Identifier *udaLLVMAttr; + static Identifier *udaLLVMFastMathFlag; + static Identifier *udaKernel; + static Identifier *udaCompute; + static Identifier *udaDynamicCompile; + static Identifier *udaDynamicCompileConst; +}; + +#endif /* DMD_ID_H */ diff --git a/src/ddmd/import.h b/src/ddmd/import.h index 2bd149b11fa0..9ec6b19060b2 100644 --- a/src/ddmd/import.h +++ b/src/ddmd/import.h @@ -47,7 +47,7 @@ class Import : public Dsymbol AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs void addAlias(Identifier *name, Identifier *alias); - const char *kind(); + const char *kind() const; Prot prot(); Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees void load(Scope *sc); diff --git a/src/ddmd/inlinecost.d b/src/ddmd/inlinecost.d index a39a593d64b3..945a336cf46c 100644 --- a/src/ddmd/inlinecost.d +++ b/src/ddmd/inlinecost.d @@ -444,8 +444,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/ddmd/ldcbindings.d b/src/ddmd/ldcbindings.d new file mode 100644 index 000000000000..29ea895630a5 --- /dev/null +++ b/src/ddmd/ldcbindings.d @@ -0,0 +1,72 @@ +//===-- 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!LogicalExp); +mixin(factory!EqualExp); +mixin(factory!CmpExp); +mixin(factory!ShlExp); +mixin(factory!ShrExp); +mixin(factory!UshrExp); +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/ddmd/ldcbindings.h b/src/ddmd/ldcbindings.h new file mode 100644 index 000000000000..4f773241a8ac --- /dev/null +++ b/src/ddmd/ldcbindings.h @@ -0,0 +1,76 @@ +//===-- 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 *); +LogicalExp *createLogicalExp(Loc, TOK op, 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(LogicalExp) +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/ddmd/mars.d b/src/ddmd/mars.d index 2b3499499c45..22cf15489464 100644 --- a/src/ddmd/mars.d +++ b/src/ddmd/mars.d @@ -43,8 +43,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; @@ -52,7 +52,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.semantic; @@ -64,6 +64,24 @@ import ddmd.utils; import core.stdc.config; extern(C) c_long strtol(inout(char)* nptr, inout(char)** endptr, int base); +version(IN_LLVM) +{ + import gen.semantic : extraLDCSpecificSemanticAnalysis; + extern (C++): + + // in driver/main.cpp + void addDefaultVersionIdentifiers(); + void codegenModules(ref Modules modules); + // in driver/archiver.cpp + int createStaticLibrary(); + // in driver/linker.cpp + int linkObjToBinary(); + void deleteExeFile(); + int runProgram(); +} +else +{ + /** * Print DMD's logo on stdout */ @@ -189,6 +207,8 @@ Where: ", FileName.canonicalName(global.inifilename), fpic, m32mscoff, mscrtlib); } +} // !IN_LLVM + /// DMD-generated module `__entrypoint` where the C main resides extern (C++) __gshared Module entrypoint = null; /// Module in which the D main is @@ -216,19 +236,40 @@ extern (C++) void genCmain(Scope* sc) /* The D code to be generated is provided as D source code in the form of a string. * Note that Solaris, for unknown reasons, requires both a main() and an _main() */ - immutable cmaincode = - q{ - extern(C) - { - int _d_run_main(int argc, char **argv, void* mainFunc); - int _Dmain(char[][] args); - int main(int argc, char **argv) + version(IN_LLVM) + { + immutable cmaincode = + q{ + pragma(LDC_profile_instr, false): + extern(C) { - return _d_run_main(argc, argv, &_Dmain); + int _d_run_main(int argc, char **argv, void* mainFunc); + int _Dmain(char[][] args); + int main(int argc, char **argv) + { + return _d_run_main(argc, argv, &_Dmain); + } + version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); } } - version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); } - } - }; + pragma(LDC_no_moduleinfo); + }; + } + else + { + immutable cmaincode = + q{ + extern(C) + { + int _d_run_main(int argc, char **argv, void* mainFunc); + int _Dmain(char[][] args); + int main(int argc, char **argv) + { + return _d_run_main(argc, argv, &_Dmain); + } + version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); } + } + }; + } Identifier id = Id.entrypoint; auto m = new Module("__entrypoint.d", id, 0, 0); scope p = new Parser!ASTCodegen(m, cmaincode, false); @@ -249,6 +290,8 @@ extern (C++) void genCmain(Scope* sc) rootHasMain = sc._module; } +version(IN_LLVM) {} else +{ /** * DMD's real entry point @@ -508,6 +551,20 @@ 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) +{ + version(IN_LLVM) + { + if (global.params.color) + global.console = Console.create(core.stdc.stdio.stderr); + } + if (global.params.link) { global.params.exefile = global.params.objname; @@ -537,9 +594,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 { @@ -554,7 +614,10 @@ Language changes listed by -transition=id: // Predefined version identifiers addDefaultVersionIdentifiers(); + version (IN_LLVM) {} else + { setDefaultLibrary(); + } // Initialization Type._init(); @@ -565,12 +628,15 @@ Language changes listed by -transition=id: Objc._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 @@ -604,14 +670,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); @@ -626,12 +702,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)) @@ -641,6 +727,7 @@ Language changes listed by -transition=id: continue; } } + } if (strcmp(ext, global.ddoc_ext) == 0) { global.params.ddocfiles.push(files[i]); @@ -657,7 +744,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")) { @@ -710,12 +798,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 */ @@ -765,8 +878,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)) @@ -776,6 +892,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; @@ -835,7 +984,10 @@ Language changes listed by -transition=id: if (global.errors) fatal(); + version (IN_LLVM) {} else + { backend_init(); + } // Do semantic analysis foreach (m; modules) @@ -880,6 +1032,12 @@ Language changes listed by -transition=id: if (global.errors) fatal(); + version (IN_LLVM) + { + extraLDCSpecificSemanticAnalysis(modules); + } + else + { // Scan for functions to inline if (global.params.useInline) { @@ -890,6 +1048,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(); @@ -907,6 +1066,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); @@ -914,6 +1079,8 @@ Language changes listed by -transition=id: printCtfePerformanceStats(); + version (IN_LLVM) {} else + { Library library = null; if (global.params.lib) { @@ -926,6 +1093,7 @@ Language changes listed by -transition=id: library.addObject(p, null); } } + } // Generate output files if (global.params.doJsonGeneration) { @@ -995,6 +1163,12 @@ Language changes listed by -transition=id: cgFile.write(); } } + version (IN_LLVM) + { + codegenModules(modules); + } + else + { if (!global.params.obj) { } @@ -1034,18 +1208,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) @@ -1053,12 +1259,15 @@ Language changes listed by -transition=id: status = runProgram(); /* Delete .obj files and .exe file */ + version (IN_LLVM) {} else + { foreach (m; modules) { m.deleteObjFile(); if (global.params.oneobj) break; } + } remove(global.params.exefile); } } @@ -1067,6 +1276,9 @@ Language changes listed by -transition=id: } +version (IN_LLVM) {} else +{ + /** * Entry point which forwards to `tryMain`. * @@ -1411,7 +1623,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) { @@ -1423,6 +1638,8 @@ private void printPredefinedVersions() } +version (IN_LLVM) {} else: + /**************************************** * Determine the instruction set to be used. * Params: @@ -2160,4 +2377,3 @@ private bool parseCommandLine(const ref Strings arguments, const size_t argc, re } return errors; } - diff --git a/src/ddmd/mars.h b/src/ddmd/mars.h index 9ec4ed62ea0f..cf2b1593b7d4 100644 --- a/src/ddmd/mars.h +++ b/src/ddmd/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/ddmd/module.h b/src/ddmd/module.h index 85e465b19057..df73ba282017 100644 --- a/src/ddmd/module.h +++ b/src/ddmd/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 @@ -40,7 +52,7 @@ class Package : public ScopeDsymbol unsigned tag; // auto incremented tag, used to mask package tree in scopes Module *mod; // != NULL if isPkgMod == PKGmodule - const char *kind(); + const char *kind() const; static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg); @@ -125,7 +137,7 @@ class Module : public Package static Module *load(Loc loc, Identifiers *packages, Identifier *ident); - const char *kind(); + const char *kind() const; File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext); void setDocfile(); bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. @@ -166,6 +178,21 @@ class Module : public Package Symbol *sfilename; // symbol for filename +#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. + + // 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/ddmd/mtype.d b/src/ddmd/mtype.d index cca3ab5c4173..48e86e9f17bc 100644 --- a/src/ddmd/mtype.d +++ b/src/ddmd/mtype.d @@ -58,6 +58,10 @@ import ddmd.tokens; import ddmd.typesem; import ddmd.visitor; +version(IN_LLVM) { + import gen.llvmhelpers; +} + enum LOGDOTEXP = 0; // log ::dotExp() enum LOGDEFAULTINIT = 0; // log ::defaultInit() @@ -2797,17 +2801,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 @@ -3658,6 +3682,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; @@ -4384,10 +4421,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) diff --git a/src/ddmd/mtype.h b/src/ddmd/mtype.h index 37d9dad77985..e33ceb82821d 100644 --- a/src/ddmd/mtype.h +++ b/src/ddmd/mtype.h @@ -24,6 +24,10 @@ #include "expression.h" #include "visitor.h" +#if IN_LLVM +#include +#endif + struct Scope; class Identifier; class Expression; @@ -42,10 +46,14 @@ 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 +Type *typeSemantic(Type *t, Loc loc, Scope *sc); +Type *merge(Type *type); void semanticTypeInfo(Scope *sc, Type *t); MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0); StorageClass ModToStc(unsigned mod); @@ -246,7 +254,6 @@ class Type : public RootObject virtual d_uns64 size(Loc loc); virtual unsigned alignsize(); Type *trySemantic(Loc loc, Scope *sc); - Type *merge(); Type *merge2(); void modToBuffer(OutBuffer *buf); char *modToChars(); @@ -340,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(); @@ -394,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(); diff --git a/src/ddmd/nspace.h b/src/ddmd/nspace.h index 1fe615191b32..2544e5f8e0e6 100644 --- a/src/ddmd/nspace.h +++ b/src/ddmd/nspace.h @@ -29,7 +29,7 @@ class Nspace : public ScopeDsymbol int apply(Dsymbol_apply_ft_t fp, void *param); bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - const char *kind(); + const char *kind() const; Nspace *isNspace() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/ddmd/objc.d b/src/ddmd/objc.d index d2d0a376ce64..cca333ec9b15 100644 --- a/src/ddmd/objc.d +++ b/src/ddmd/objc.d @@ -131,7 +131,8 @@ extern(C++) abstract class Objc { static void _init() { - if (global.params.isOSX && global.params.is64bit) + // IN_LLVM: if (global.params.isOSX && global.params.is64bit) + if (global.params.hasObjectiveC) _objc = new Supported; else _objc = new Unsupported; diff --git a/src/ddmd/root/array.h b/src/ddmd/root/array.h index afbd06ff5186..4e0524a2fab2 100644 --- a/src/ddmd/root/array.h +++ b/src/ddmd/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 @@ -219,6 +226,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/ddmd/root/ctfloat.d b/src/ddmd/root/ctfloat.d index 0e0b521f06ff..87a6b2a52c97 100644 --- a/src/ddmd/root/ctfloat.d +++ b/src/ddmd/root/ctfloat.d @@ -19,13 +19,22 @@ 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; + +version(IN_LLVM) + private enum LDC_host_has_yl2x = is(real_t == real) && __traits(compiles, core.math.yl2x(1.0L, 2.0L)); +else + private enum LDC_host_has_yl2x = false; 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); @@ -36,7 +45,8 @@ private // Compile-time floating-point helper extern (C++) struct CTFloat { - version(DigitalMars) + // IN_LLVM replaced: version(DigitalMars) + static if (LDC_host_has_yl2x) { static __gshared bool yl2x_supported = true; static __gshared bool yl2xp1_supported = true; @@ -49,7 +59,8 @@ extern (C++) struct CTFloat static void yl2x(const real_t* x, const real_t* y, real_t* res) { - version(DigitalMars) + // IN_LLVM replaced: version(DigitalMars) + static if (LDC_host_has_yl2x) *res = core.math.yl2x(*x, *y); else assert(0); @@ -57,7 +68,8 @@ extern (C++) struct CTFloat static void yl2xp1(const real_t* x, const real_t* y, real_t* res) { - version(DigitalMars) + // IN_LLVM replaced: version(DigitalMars) + static if (LDC_host_has_yl2x) *res = core.math.yl2xp1(*x, *y); else assert(0); @@ -70,6 +82,30 @@ extern (C++) struct CTFloat static real_t fabs(real_t x) { return core.math.fabs(x); } static real_t ldexp(real_t n, int exp) { return core.math.ldexp(n, exp); } + version(IN_LLVM) + { + static import std.math; + + static real_t log(real_t x) { return std.math.log(x); } + static real_t log2(real_t x) { return std.math.log2(x); } + static real_t log10(real_t x) { return std.math.log10(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 rint(real_t x) { return std.math.rint(x); } + static real_t nearbyint(real_t x) { return std.math.nearbyint(x); } + static real_t round(real_t x) { return std.math.round(x); } + static real_t fma(real_t x, real_t y, real_t z) { return std.math.fma(x, y, z); } + static real_t copysign(real_t to, real_t from) { return std.math.copysign(to, from); } + + 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 @@ -92,9 +128,19 @@ extern (C++) struct CTFloat return !(r == r); } + version(IN_LLVM) + { + // LDC doesn't need isSNaN(). The upstream implementation is tailored for + // DMD/x86 and only supports double-precision and x87 real_t types. + } + else + { 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 @@ -105,12 +151,20 @@ extern (C++) struct CTFloat { return isSNaN(ld.r); } + } static bool isInfinity(real_t r) { return isIdentical(fabs(r), 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; @@ -119,7 +173,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); @@ -128,10 +183,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)); } @@ -160,4 +217,19 @@ extern (C++) struct CTFloat static __gshared real_t one = real_t(1); static __gshared real_t minusone = real_t(-1); static __gshared real_t half = real_t(0.5); + version(IN_LLVM) + { + // Initialized via LLVM in C++. + static __gshared real_t initVal; + static __gshared real_t nan; + static __gshared real_t infinity; + } +} + +version (IN_LLVM) +{ + shared static this() + { + CTFloat._init(); + } } diff --git a/src/ddmd/root/ctfloat.h b/src/ddmd/root/ctfloat.h index ca20502c5378..d16ebd598bb3 100644 --- a/src/ddmd/root/ctfloat.h +++ b/src/ddmd/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 @@ -31,9 +41,35 @@ struct CTFloat static real_t fabs(real_t x); static real_t ldexp(real_t n, int exp); +#if IN_LLVM + static real_t log(real_t x); + static real_t log2(real_t x); + static real_t log10(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 rint(real_t x); + static real_t nearbyint(real_t x); + static real_t round(real_t x); + static real_t fma(real_t x, real_t y, real_t z); + static real_t copysign(real_t to, real_t from); + + // implemented in gen/ctfloat.cpp + static void _init(); + static void toAPFloat(real_t src, llvm::APFloat &dst); + static real_t fromAPFloat(const llvm::APFloat &src); + + 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); +#if !IN_LLVM static bool isSNaN(real_t r); +#endif static bool isInfinity(real_t r); static real_t parse(const char *literal, bool *isOutOfRange = NULL); @@ -46,6 +82,11 @@ struct CTFloat static real_t one; static real_t minusone; static real_t half; +#if IN_LLVM + static real_t initVal; + static real_t nan; + static real_t infinity; +#endif }; #endif diff --git a/src/ddmd/root/longdouble.c b/src/ddmd/root/longdouble.c deleted file mode 100644 index b3bb9e1c2e79..000000000000 --- a/src/ddmd/root/longdouble.c +++ /dev/null @@ -1,677 +0,0 @@ - -/* Copyright (c) 1999-2016 by Digital Mars - * All Rights Reserved, written by Rainer Schuetze - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) - * https://github.com/dlang/dmd/blob/master/src/root/longdouble.c - */ - -// 80 bit floating point value implementation for Microsoft compiler - -#if _MSC_VER -#include "longdouble.h" - -#include "assert.h" - -#include -#include -#include - -extern "C" -{ - // implemented in ldfpu.asm for _WIN64 - int ld_initfpu(int bits, int mask); - void ld_expl(longdouble* ld, int exp); - longdouble ld_add(longdouble ld1, longdouble ld2); - longdouble ld_sub(longdouble ld1, longdouble ld2); - longdouble ld_mul(longdouble ld1, longdouble ld2); - longdouble ld_div(longdouble ld1, longdouble ld2); - longdouble ld_mod(longdouble ld1, longdouble ld2); - bool ld_cmpb(longdouble ld1, longdouble ld2); - bool ld_cmpbe(longdouble ld1, longdouble ld2); - bool ld_cmpa(longdouble ld1, longdouble ld2); - bool ld_cmpae(longdouble ld1, longdouble ld2); - bool ld_cmpe(longdouble ld1, longdouble ld2); - bool ld_cmpne(longdouble ld1, longdouble ld2); - longdouble ld_sqrt(longdouble ld1); - longdouble ld_sin(longdouble ld1); - longdouble ld_cos(longdouble ld1); - longdouble ld_tan(longdouble ld1); -} - -bool initFPU() -{ -#ifdef _WIN64 -// int old_cw = ld_initfpu(_RC_NEAR); - int old_cw = ld_initfpu(0x300 /*_PC_64 | _RC_NEAR*/, // #defines NOT identical to CPU FPU control word! - 0xF00 /*_MCW_PC | _MCW_RC*/); -#else - int old_cw = _control87(_MCW_EM | _PC_64 | _RC_NEAR, - _MCW_EM | _MCW_PC | _MCW_RC); -#endif -#if _MSC_VER < 1900 - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - return true; -} -static bool doInitFPU = initFPU(); - -extern "C" -{ - -#ifndef _WIN64 -double ld_read(const longdouble* pthis) -{ - double res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fstp res - } - return res; -} -#endif // !_WIN64 - -long long ld_readll(const longdouble* pthis) -{ -#if 1 - return ld_readull(pthis); -#elif defined _WIN64 - return ld_readll(this); -#else - longdouble* pthis = this; - long long res; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fistp qword ptr res - } - return res; -#endif -} - -unsigned long long ld_readull(const longdouble* pthis) -{ -#if 1 - // somehow the FPU does not respect the CHOP mode of the rounding control - // in 64-bit mode - // so we roll our own conversion (it also allows the usual C wrap-around - // instead of the "invalid value" created by the FPU) - int expo = pthis->exponent - 0x3fff; - unsigned long long u; - if(expo < 0 || expo > 127) - return 0; - if(expo < 64) - u = pthis->mantissa >> (63 - expo); - else - u = pthis->mantissa << (expo - 63); - if(pthis->sign) - u = ~u + 1; - return u; -#else - longdouble* pthis = this; - long long res; // cannot use unsigned, VC will not generate "fistp qword" - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - mov eax, pthis - fld tbyte ptr [eax] - fld tbyte ptr twoPow63 - fsubp ST(1),ST(0) // move it into signed range - - lea eax, res - fistp qword ptr [eax] - } - res ^= (1LL << 63); - return res; -#endif -} - -#ifndef _WIN64 -int ld_statusfpu() -{ - int res = 0; - __asm - { - fstsw word ptr [res]; - } - return res; -} - -void ld_clearfpu() -{ - __asm - { - fclex - } -} - -void ld_set(longdouble* pthis, double d) -{ - __asm - { - mov eax, pthis - fld d - fstp tbyte ptr [eax] - } -} -void ld_setll(longdouble* pthis, long long d) -{ - __asm - { - fild qword ptr d - mov eax, pthis - fstp tbyte ptr [eax] - } -} -void ld_setull(longdouble* pthis, unsigned long long d) -{ - d ^= (1LL << 63); - longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; - __asm - { - fild qword ptr d - fld tbyte ptr twoPow63 - faddp ST(1),ST(0) - mov eax, pthis - fstp tbyte ptr [eax] - } -} -#endif // !_WIN64 - -} // extern "C" - -longdouble ldexpl(longdouble ld, int exp) -{ -#ifdef _WIN64 - ld_expl(&ld, exp); -#else - __asm - { - fild dword ptr exp - fld tbyte ptr ld - fscale // ST(0) = ST(0) * (2**ST(1)) - fstp ST(1) - fstp tbyte ptr ld - } -#endif - return ld; -} - -/////////////////////////////////////////////////////////////////////// -longdouble operator+(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_add(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fadd - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator-(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_sub(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fsub - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator*(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_mul(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fmul - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble operator/(longdouble ld1, longdouble ld2) -{ -#ifdef _WIN64 - return ld_div(ld1, ld2); -#else - longdouble res; - __asm - { - fld tbyte ptr ld1 - fld tbyte ptr ld2 - fdiv - fstp tbyte ptr res; - } - return res; -#endif -} - -bool operator< (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpb(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setb AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator<=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpbe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setbe AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator> (longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpa(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - seta AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator>=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpae(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setae AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator==(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpe(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - sete AL - setnp AH - and AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} -bool operator!=(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_cmpne(x, y); -#else - short sw; - bool res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y - fucomip ST(0),ST(1) - setne AL - setp AH - or AL,AH - mov res,AL - fstp ST(0) - } - return res; -#endif -} - - -int _isnan(longdouble ld) -{ - return (ld.exponent == 0x7fff && ld.mantissa != 0 && ld.mantissa != (1LL << 63)); // exclude pseudo-infinity and infinity, but not FP Indefinite -} - -longdouble fabsl(longdouble ld) -{ - ld.sign = 0; - return ld; -} - -longdouble sqrtl(longdouble ld) -{ -#ifdef _WIN64 - return ld_sqrt(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsqrt; - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble sinl (longdouble ld) -{ -#ifdef _WIN64 - return ld_sin(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fsin; // exact for |x|<=PI/4 - fstp tbyte ptr res - } - return res; -#endif -} -longdouble cosl (longdouble ld) -{ -#ifdef _WIN64 - return ld_cos(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fcos; // exact for |x|<=PI/4 - fstp tbyte ptr res; - } - return res; -#endif -} -longdouble tanl (longdouble ld) -{ -#ifdef _WIN64 - return ld_tan(ld); -#else - longdouble res; - __asm - { - fld tbyte ptr ld; - fptan; - fstp ST(0); // always 1 - fstp tbyte ptr res; - } - return res; -#endif -} - -longdouble fmodl(longdouble x, longdouble y) -{ -#ifdef _WIN64 - return ld_mod(x, y); -#else - short sw; - longdouble res; - __asm - { - fld tbyte ptr y - fld tbyte ptr x // ST = x, ST1 = y -FM1: // We don't use fprem1 because for some inexplicable - // reason we get -5 when we do _modulo(15, 10) - fprem // ST = ST % ST1 - fstsw word ptr sw - fwait - mov AH,byte ptr sw+1 // get msb of status word in AH - sahf // transfer to flags - jp FM1 // continue till ST < ST1 - fstp ST(1) // leave remainder on stack - fstp tbyte ptr res; - } - return res; -#endif -} - -////////////////////////////////////////////////////////////// - -longdouble ld_qnan = { 0xC000000000000000ULL, 0x7fff, 0 }; -longdouble ld_snan = { 0xC000000000000001ULL, 0x7fff, 0 }; -longdouble ld_inf = { 0x8000000000000000ULL, 0x7fff, 0 }; - -longdouble ld_zero = { 0, 0, 0 }; -longdouble ld_one = { 0x8000000000000000ULL, 0x3fff, 0 }; -longdouble ld_pi = { 0xc90fdaa22168c235ULL, 0x4000, 0 }; -longdouble ld_log2t = { 0xd49a784bcd1b8afeULL, 0x4000, 0 }; -longdouble ld_log2e = { 0xb8aa3b295c17f0bcULL, 0x3fff, 0 }; -longdouble ld_log2 = { 0x9a209a84fbcff799ULL, 0x3ffd, 0 }; -longdouble ld_ln2 = { 0xb17217f7d1cf79acULL, 0x3ffe, 0 }; - -longdouble ld_pi2 = ld_pi*2; -longdouble ld_piOver2 = ld_pi*0.5; -longdouble ld_piOver4 = ld_pi*0.25; - -////////////////////////////////////////////////////////////// - -#define LD_TYPE_OTHER 0 -#define LD_TYPE_ZERO 1 -#define LD_TYPE_INFINITE 2 -#define LD_TYPE_SNAN 3 -#define LD_TYPE_QNAN 4 - -int ld_type(longdouble x) -{ - if(x.exponent == 0) - return x.mantissa == 0 ? LD_TYPE_ZERO : LD_TYPE_OTHER; // dnormal if not zero - if(x.exponent != 0x7fff) - return LD_TYPE_OTHER; - if(x.mantissa == 0) - return LD_TYPE_INFINITE; - if(x.mantissa & (1LL << 63)) - return LD_TYPE_QNAN; - return LD_TYPE_SNAN; -} - -size_t ld_sprint(char* str, int fmt, longdouble x) -{ - // ensure dmc compatible strings for nan and inf - switch(ld_type(x)) - { - case LD_TYPE_QNAN: - case LD_TYPE_SNAN: - return sprintf(str, "nan"); - case LD_TYPE_INFINITE: - return sprintf(str, x.sign ? "-inf" : "inf"); - } - - // fmt is 'a','A','f' or 'g' - if(fmt != 'a' && fmt != 'A') - { - if (ldouble((unsigned long long)x) == x) - { // ((1.5 -> 1 -> 1.0) == 1.5) is false - // ((1.0 -> 1 -> 1.0) == 1.0) is true - // see http://en.cppreference.com/w/cpp/io/c/fprintf - char format[] = {'%', '#', 'L', (char)fmt, 0}; - return sprintf(str, format, ld_read(&x)); - } - char format[] = { '%', (char)fmt, 0 }; - return sprintf(str, format, ld_read(&x)); - } - - unsigned short exp = x.exponent; - unsigned long long mantissa = x.mantissa; - - if(ld_type(x) == LD_TYPE_ZERO) - return sprintf(str, fmt == 'a' ? "0x0.0L" : "0X0.0L"); - - size_t len = 0; - if(x.sign) - str[len++] = '-'; - str[len++] = '0'; - str[len++] = 'X' + fmt - 'A'; - str[len++] = mantissa & (1LL << 63) ? '1' : '0'; - str[len++] = '.'; - mantissa = mantissa << 1; - while(mantissa) - { - int dig = (mantissa >> 60) & 0xf; - dig += dig < 10 ? '0' : fmt - 10; - str[len++] = dig; - mantissa = mantissa << 4; - } - str[len++] = 'P' + fmt - 'A'; - if(exp < 0x3fff) - { - str[len++] = '-'; - exp = 0x3fff - exp; - } - else - { - str[len++] = '+'; - exp = exp - 0x3fff; - } - int exppos = len; - for(int i = 12; i >= 0; i -= 4) - { - int dig = (exp >> i) & 0xf; - if(dig != 0 || len > exppos || i == 0) - str[len++] = dig + (dig < 10 ? '0' : fmt - 10); - } - str[len] = 0; - return len; -} - -////////////////////////////////////////////////////////////// - -#if UNITTEST -static bool unittest() -{ - char buffer[32]; - ld_sprint(buffer, 'a', ld_pi); - assert(strcmp(buffer, "0x1.921fb54442d1846ap+1") == 0); - - ld_sprint(buffer, 'g', ldouble(2.0)); - assert(strcmp(buffer, "2.00000") == 0); - - ld_sprint(buffer, 'g', ldouble(1234567.89)); - assert(strcmp(buffer, "1.23457e+06") == 0); - - longdouble ldb = ldouble(0.4); - long long b = ldb; - assert(b == 0); - - b = ldouble(0.9); - assert(b == 0); - - long long x = 0x12345678abcdef78LL; - longdouble ldx = ldouble(x); - assert(ldx > 0); - long long y = ldx; - assert(x == y); - - x = -0x12345678abcdef78LL; - ldx = ldouble(x); - assert(ldx < 0); - y = ldx; - assert(x == y); - - unsigned long long u = 0x12345678abcdef78LL; - longdouble ldu = ldouble(u); - assert(ldu > 0); - unsigned long long v = ldu; - assert(u == v); - - u = 0xf234567812345678ULL; - ldu = ldouble(u); - assert(ldu > 0); - v = ldu; - assert(u == v); - - u = 0xf2345678; - ldu = ldouble(u); - ldu = ldu * ldu; - ldu = sqrt(ldu); - v = ldu; - assert(u == v); - - u = 0x123456789A; - ldu = ldouble(u); - ldu = ldu * (1LL << 23); - v = ldu; - u = u * (1LL << 23); - assert(u == v); - - return true; -} - -static bool runUnittest = unittest(); - -#endif // UNITTEST - -#endif // _MSC_VER - diff --git a/src/ddmd/root/longdouble.h b/src/ddmd/root/longdouble.h index 1cd5fbf3e97a..193637da7510 100644 --- a/src/ddmd/root/longdouble.h +++ b/src/ddmd/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/ddmd/root/newdelete.c b/src/ddmd/root/newdelete.c index 3c8c40ac7f5a..46dcbcf7aca2 100644 --- a/src/ddmd/root/newdelete.c +++ b/src/ddmd/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/ddmd/root/object.h b/src/ddmd/root/object.h index 629ec812ab08..fb6223ded7d2 100644 --- a/src/ddmd/root/object.h +++ b/src/ddmd/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/ddmd/root/port.d b/src/ddmd/root/port.d index 00d62bac7963..546c5f2de56a 100644 --- a/src/ddmd/root/port.d +++ b/src/ddmd/root/port.d @@ -69,6 +69,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) { @@ -88,10 +95,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) { @@ -111,6 +126,7 @@ extern (C++) struct Port } version (CRuntime_DigitalMars) __locale_decpoint = save; return errno == ERANGE; + } } // Little endian @@ -161,6 +177,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/ddmd/root/port.h b/src/ddmd/root/port.h index dacd9eff6364..076472088984 100644 --- a/src/ddmd/root/port.h +++ b/src/ddmd/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/ddmd/root/response.d b/src/ddmd/root/response.d deleted file mode 100644 index 620bf6fbe116..000000000000 --- a/src/ddmd/root/response.d +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Compiler implementation of the D programming language - * http://dlang.org - * This file is not shared with other compilers which use the DMD front-end. - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Some portions copyright (c) 1994-1995 by Symantec - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/root/response.d, root/_response.d) - */ - -module ddmd.root.response; - -// Online documentation: https://dlang.org/phobos/ddmd_root_response.html - -import core.stdc.stdio; -import core.stdc.stdlib; -import core.stdc.string; -import ddmd.root.file; -import ddmd.root.filename; - -/********************************* - * #include - * int response_expand(int *pargc,char ***pargv); - * - * Expand any response files in command line. - * Response files are arguments that look like: - * @NAME - * The name is first searched for in the environment. If it is not - * there, it is searched for as a file name. - * Arguments are separated by spaces, tabs, or newlines. These can be - * imbedded within arguments by enclosing the argument in '' or "". - * Recursively expands nested response files. - * - * To use, put the line: - * response_expand(&argc,&argv); - * as the first executable statement in main(int argc, char **argv). - * argc and argv are adjusted to be the new command line arguments - * after response file expansion. - * - * Digital Mars's MAKE program can be notified that a program can accept - * long command lines via environment variables by preceding the rule - * line for the program with a *. - * - * Returns: - * 0 success - * !=0 failure (argc, argv unchanged) - */ -bool response_expand(Strings* args) -{ - const(char)* cp; - int recurse = 0; - for (size_t i = 0; i < args.dim;) - { - cp = (*args)[i]; - if (*cp != '@') - { - ++i; - continue; - } - args.remove(i); - char* buffer; - char* bufend; - cp++; - if (auto p = getenv(cp)) - { - buffer = strdup(p); - if (!buffer) - goto noexpand; - bufend = buffer + strlen(buffer); - } - else - { - auto f = File(cp); - if (f.read()) - goto noexpand; - f._ref = 1; - buffer = cast(char*)f.buffer; - bufend = buffer + f.len; - } - // The logic of this should match that in setargv() - int comment = 0; - for (auto p = buffer; p < bufend; p++) - { - char* d; - char c, lastc; - ubyte instring; - int num_slashes, non_slashes; - switch (*p) - { - case 26: - /* ^Z marks end of file */ - goto L2; - case 0xD: - case '\n': - if (comment) - { - comment = 0; - } - goto case; - case 0: - case ' ': - case '\t': - continue; - // scan to start of argument - case '#': - comment = 1; - continue; - case '@': - if (comment) - { - continue; - } - recurse = 1; - goto default; - default: - /* start of new argument */ - if (comment) - { - continue; - } - args.insert(i, p); - ++i; - instring = 0; - c = 0; - num_slashes = 0; - for (d = p; 1; p++) - { - lastc = c; - if (p >= bufend) - { - *d = 0; - goto L2; - } - c = *p; - switch (c) - { - case '"': - /* - Yes this looks strange,but this is so that we are - MS Compatible, tests have shown that: - \\\\"foo bar" gets passed as \\foo bar - \\\\foo gets passed as \\\\foo - \\\"foo gets passed as \"foo - and \"foo gets passed as "foo in VC! - */ - non_slashes = num_slashes % 2; - num_slashes = num_slashes / 2; - for (; num_slashes > 0; num_slashes--) - { - d--; - *d = '\0'; - } - if (non_slashes) - { - *(d - 1) = c; - } - else - { - instring ^= 1; - } - break; - case 26: - *d = 0; // terminate argument - goto L2; - case 0xD: - // CR - c = lastc; - continue; - // ignore - case '@': - recurse = 1; - goto Ladd; - case ' ': - case '\t': - if (!instring) - { - case '\n': - case 0: - *d = 0; // terminate argument - goto Lnextarg; - } - goto default; - default: - Ladd: - if (c == '\\') - num_slashes++; - else - num_slashes = 0; - *d++ = c; - break; - } - } - break; - } - Lnextarg: - } - L2: - } - if (recurse) - { - /* Recursively expand @filename */ - if (response_expand(args)) - goto noexpand; - } - return false; /* success */ -noexpand: - /* error */ - /* BUG: any file buffers are not free'd */ - return true; -} diff --git a/src/ddmd/root/root.h b/src/ddmd/root/root.h index bea105303e0d..714188b1b906 100644 --- a/src/ddmd/root/root.h +++ b/src/ddmd/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/ddmd/root/thread.h b/src/ddmd/root/thread.h deleted file mode 100644 index f54173feaf98..000000000000 --- a/src/ddmd/root/thread.h +++ /dev/null @@ -1,20 +0,0 @@ - -/* Copyright (c) 2000-2014 by Digital Mars - * All Rights Reserved, written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) - * https://github.com/dlang/dmd/blob/master/src/root/thread.h - */ - -#ifndef THREAD_H -#define THREAD_H 1 - -typedef long ThreadId; - -struct Thread -{ - static ThreadId getId(); -}; - -#endif diff --git a/src/ddmd/scope.h b/src/ddmd/scope.h index 8bef4b081775..13fde8ff7359 100644 --- a/src/ddmd/scope.h +++ b/src/ddmd/scope.h @@ -124,6 +124,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/ddmd/statement.d b/src/ddmd/statement.d index 71526a395bae..8eccf5b86b33 100644 --- a/src/ddmd/statement.d +++ b/src/ddmd/statement.d @@ -47,6 +47,10 @@ import ddmd.sideeffect; import ddmd.staticassert; import ddmd.tokens; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} /***************************************** * CTFE requires FuncDeclaration::labtab for the interpretation. @@ -474,6 +478,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; + } + } } /*********************************************************** @@ -954,7 +972,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; } @@ -963,6 +982,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; + } + } } /*********************************************************** @@ -1675,6 +1710,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) { @@ -1750,6 +1789,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); @@ -1814,6 +1858,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); @@ -1870,6 +1919,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); @@ -1942,6 +1996,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); @@ -1970,6 +2030,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); @@ -2339,7 +2405,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; @@ -2489,6 +2556,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); @@ -2497,7 +2570,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) @@ -2513,6 +2596,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); @@ -2539,6 +2627,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/ddmd/statement.h b/src/ddmd/statement.h index c3acb7984c15..08168dc69c7d 100644 --- a/src/ddmd/statement.h +++ b/src/ddmd/statement.h @@ -50,8 +50,21 @@ class DefaultStatement; class LabelStatement; class StaticForeach; +#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); @@ -111,6 +124,11 @@ class Statement : public RootObject virtual DtorExpStatement *isDtorExpStatement() { return NULL; } virtual ForwardingStatement *isForwardingStatement() { 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 @@ -184,6 +202,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 @@ -341,9 +363,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; } @@ -412,6 +433,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(); @@ -428,6 +453,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; } @@ -454,6 +483,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; } @@ -477,6 +510,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; } @@ -507,6 +544,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; } @@ -518,6 +560,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); } @@ -687,6 +734,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); } @@ -698,10 +750,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/ddmd/statementsem.d b/src/ddmd/statementsem.d index 3eaa206b1376..21d366c6d522 100644 --- a/src/ddmd/statementsem.d +++ b/src/ddmd/statementsem.d @@ -52,6 +52,10 @@ import ddmd.tokens; import ddmd.typesem; import ddmd.semantic; import ddmd.visitor; +version(IN_LLVM) +{ + import gen.dpragma; +} // Performs semantic analysis in Statement AST nodes extern(C++) Statement statementSemantic(Statement s, Scope* sc) @@ -290,7 +294,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; @@ -1521,6 +1526,11 @@ private extern (C++) final class StatementSemanticVisitor : Visitor p.type = p.type.typeSemantic(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); @@ -1550,12 +1560,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)); } // https://issues.dlang.org/show_bug.cgi?id=13840 @@ -2186,6 +2223,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"); + return setError(); + } + else + { + FuncDeclaration fd = sc.func; + if (fd is null) + { + ps.error("pragma(LDC_profile_instr, ...) is not inside a function"); + return setError(); + } + fd.emitInstrumentation = emitInstr; + } + } else if (ps.ident == Id.startaddress) { if (!ps.args || ps.args.dim != 1) @@ -2371,6 +2438,10 @@ else if (cs.exp.equals(gcs.exp)) { gcs.cs = cs; +version(IN_LLVM) +{ + cs.gototarget = true; +} continue Lgotocase; } } @@ -2445,6 +2516,18 @@ else return setError(); } +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; } @@ -2714,6 +2797,12 @@ else gds.error("goto default not allowed in final switch statement"); return setError(); } + +version(IN_LLVM) +{ + gds.sw.hasGotoDefault = true; +} + result = gds; } @@ -2724,6 +2813,10 @@ else gcs.error("goto case not in switch statement"); return setError(); } + version(IN_LLVM) + { + gcs.sw = sc.sw; + } if (gcs.exp) { @@ -3118,6 +3211,9 @@ else bs.error("cannot break out of finally block"); else { + version(IN_LLVM) + bs.target = ls; + ls.breaks = true; result = bs; return; @@ -3203,6 +3299,9 @@ else cs.error("cannot continue out of finally block"); else { + version(IN_LLVM) + cs.target = ls; + result = cs; return; } @@ -3335,6 +3434,10 @@ else Expression e = new DotIdExp(ss.loc, new VarExp(ss.loc, tmp), Id.ptr); e = e.expressionSemantic(sc); e = new CallExp(ss.loc, new VarExp(ss.loc, fdenter, false), e); + + //IN_LLVM - dmd#6840 + (cast(CallExp)e).f = fdenter; + e.type = Type.tvoid; // do not run semantic on e cs.push(new ExpStatement(ss.loc, e)); @@ -3342,6 +3445,10 @@ else e = new DotIdExp(ss.loc, new VarExp(ss.loc, tmp), Id.ptr); e = e.expressionSemantic(sc); e = new CallExp(ss.loc, new VarExp(ss.loc, fdexit, false), e); + + //IN_LLVM - dmd#6840 + (cast(CallExp)e).f = fdexit; + e.type = Type.tvoid; // do not run semantic on e Statement s = new ExpStatement(ss.loc, e); s = new TryFinallyStatement(ss.loc, ss._body, s); diff --git a/src/ddmd/staticassert.h b/src/ddmd/staticassert.h index 47935191d146..b696fc9cdb5a 100644 --- a/src/ddmd/staticassert.h +++ b/src/ddmd/staticassert.h @@ -29,7 +29,7 @@ class StaticAssert : public Dsymbol Dsymbol *syntaxCopy(Dsymbol *s); void addMember(Scope *sc, ScopeDsymbol *sds); bool oneMember(Dsymbol **ps, Identifier *ident); - const char *kind(); + const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/ddmd/target.d b/src/ddmd/target.d index c6a0f2465d9a..6aacf9ab35b3 100644 --- a/src/ddmd/target.d +++ b/src/ddmd/target.d @@ -23,6 +23,9 @@ import ddmd.mtype; import ddmd.tokens : TOK; import ddmd.root.ctfloat; import ddmd.root.outbuffer; +version(IN_LLVM) { + import gen.llvmhelpers; +} /*********************************************************** */ @@ -39,6 +42,74 @@ struct Target extern (C++) static __gshared int classinfosize; // size of 'ClassInfo' extern (C++) static __gshared ulong maxStaticDataSize; // maximum size of static data + version(IN_LLVM) + { + extern (C++): + + struct FPTypeProperties + { + real_t max, min_normal, nan, snan, infinity, epsilon; + d_int64 dig, mant_dig, max_exp, min_exp, max_10_exp, min_10_exp; + + static FPTypeProperties fromDHostCompiler(T)() + { + FPTypeProperties p; + + p.max = T.max; + p.min_normal = T.min_normal; + p.nan = T.nan; + p.snan = T.init; + p.infinity = T.infinity; + p.epsilon = T.epsilon; + + p.dig = T.dig; + p.mant_dig = T.mant_dig; + p.max_exp = T.max_exp; + p.min_exp = T.min_exp; + p.max_10_exp = T.max_10_exp; + p.min_10_exp = T.min_10_exp; + + return p; + } + } + + static __gshared FPTypeProperties FloatProperties = FPTypeProperties.fromDHostCompiler!float(); + static __gshared FPTypeProperties DoubleProperties = FPTypeProperties.fromDHostCompiler!double(); + static __gshared FPTypeProperties RealProperties = FPTypeProperties.fromDHostCompiler!real_t(); + + // implemented in gen/target.cpp: + 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 isVectorTypeSupported(int sz, Type type); + static bool isVectorOpSupported(Type type, TOK op, Type t2 = null); + // 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); + + static const(char)* toCppMangle(Dsymbol s) + { + if (isTargetWindowsMSVC()) + return toCppMangleMSVC(s); + else + return toCppMangleItanium(s); + } + + static const(char)* cppTypeInfoMangle(ClassDeclaration cd) + { + if (isTargetWindowsMSVC()) + return cppTypeInfoMangleMSVC(cd); + else + return cppTypeInfoMangleItanium(cd); + } + } + else // !IN_LLVM + { extern (C++) struct FPTypeProperties(T) { static __gshared @@ -453,6 +524,7 @@ struct Target else static assert(0, "fix this"); } + } // !IN_LLVM /** * For a vendor-specific type, return a string containing the C++ mangling. @@ -472,6 +544,8 @@ struct Target } } +version(IN_LLVM) {} else { + /****************************** * Private helpers for Target::paintAsType. */ @@ -547,3 +621,5 @@ private Expression decodeReal(Loc loc, Type type, ubyte* buffer) } return new RealExp(loc, value, type); } + +} // !IN_LLVM diff --git a/src/ddmd/target.h b/src/ddmd/target.h index e1c52d3e3e2c..a9316a253eec 100644 --- a/src/ddmd/target.h +++ b/src/ddmd/target.h @@ -38,6 +38,17 @@ struct Target static int classinfosize; // size of 'ClassInfo' static unsigned long long maxStaticDataSize; // maximum size of static data +#if IN_LLVM + struct FPTypeProperties + { + real_t max, min_normal, nan, snan, infinity, epsilon; + d_int64 dig, mant_dig, max_exp, min_exp, max_10_exp, min_10_exp; + }; + + static FPTypeProperties FloatProperties; + static FPTypeProperties DoubleProperties; + static FPTypeProperties RealProperties; +#else template struct FPTypeProperties { @@ -59,11 +70,12 @@ struct Target typedef FPTypeProperties FloatProperties; typedef FPTypeProperties DoubleProperties; typedef FPTypeProperties RealProperties; +#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 isVectorTypeSupported(int sz, Type *type); diff --git a/src/ddmd/template.h b/src/ddmd/template.h index 8165221c5c75..952efc485eff 100644 --- a/src/ddmd/template.h +++ b/src/ddmd/template.h @@ -83,10 +83,14 @@ class TemplateDeclaration : public ScopeDsymbol TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack +#if IN_LLVM + const char *intrinsicName; +#endif + Dsymbol *syntaxCopy(Dsymbol *); bool overloadInsert(Dsymbol *s); bool hasStaticCtorOrDtor(); - const char *kind(); + const char *kind() const; const char *toChars(); Prot prot(); @@ -308,7 +312,7 @@ class TemplateInstance : public ScopeDsymbol static Objects *arraySyntaxCopy(Objects *objs); Dsymbol *syntaxCopy(Dsymbol *); Dsymbol *toAlias(); // resolve real symbol - const char *kind(); + const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); const char *toChars(); const char* toPrettyCharsHelper(); @@ -345,7 +349,7 @@ class TemplateMixin : public TemplateInstance Dsymbol *syntaxCopy(Dsymbol *s); void semantic2(Scope *sc); - const char *kind(); + const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); int apply(Dsymbol_apply_ft_t fp, void *param); bool hasPointers(); diff --git a/src/ddmd/traits.d b/src/ddmd/traits.d index b8da8e660f2d..a999f928bc63 100644 --- a/src/ddmd/traits.d +++ b/src/ddmd/traits.d @@ -39,6 +39,10 @@ import ddmd.semantic; import ddmd.tokens; import ddmd.typesem; import ddmd.visitor; +version (IN_LLVM) +{ + import ddmd.hooks; +} enum LOGSEMANTIC = false; @@ -1455,6 +1459,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/ddmd/typesem.d b/src/ddmd/typesem.d index f9cd473d0540..e5a5a580d845 100644 --- a/src/ddmd/typesem.d +++ b/src/ddmd/typesem.d @@ -1371,7 +1371,8 @@ private extern (C++) final class TypeSemanticVisitor : Visitor /************************************ */ -static Type merge(Type type) +// LLVM: added `extern(C++)` +extern(C++) Type merge(Type type) { if (type.ty == Terror) return type; diff --git a/src/ddmd/typinf.d b/src/ddmd/typinf.d index 3241097231b6..a43df94724ea 100644 --- a/src/ddmd/typinf.d +++ b/src/ddmd/typinf.d @@ -23,6 +23,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. */ @@ -64,7 +70,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); } } } @@ -233,10 +242,21 @@ extern (C++) bool isSpeculativeType(Type t) /* These decide if there's an instance for them already in std.typeinfo, * because then the compiler doesn't need to build one. */ -private bool builtinTypeInfo(Type t) +// IN_LLVM: replaced `private` with `extern(C++)` +extern(C++) 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(); diff --git a/src/ddmd/version.h b/src/ddmd/version.h index 174a15af634b..74f04a389fd9 100644 --- a/src/ddmd/version.h +++ b/src/ddmd/version.h @@ -27,7 +27,7 @@ class DebugSymbol : public Dsymbol const char *toChars(); void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind(); + const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; @@ -40,7 +40,7 @@ class VersionSymbol : public Dsymbol const char *toChars(); void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind(); + const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/ddmd/visitor.h b/src/ddmd/visitor.h index 190a23db5331..c489f89c7ab4 100644 --- a/src/ddmd/visitor.h +++ b/src/ddmd/visitor.h @@ -266,8 +266,7 @@ class UshrExp; class AndExp; class OrExp; class XorExp; -class OrOrExp; -class AndAndExp; +class LogicalExp; class CmpExp; class InExp; class RemoveExp; @@ -555,8 +554,7 @@ class Visitor virtual void visit(AndExp *e) { visit((BinExp *)e); } virtual void visit(OrExp *e) { visit((BinExp *)e); } virtual void visit(XorExp *e) { visit((BinExp *)e); } - virtual void visit(OrOrExp *e) { visit((BinExp *)e); } - virtual void visit(AndAndExp *e) { visit((BinExp *)e); } + virtual void visit(LogicalExp *e) { visit((BinExp *)e); } virtual void visit(CmpExp *e) { visit((BinExp *)e); } virtual void visit(InExp *e) { visit((BinExp *)e); } virtual void visit(RemoveExp *e) { visit((BinExp *)e); }