From a24a2201f1e801c5ea99067a4f14292b30eb9ca5 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Thu, 28 May 2009 02:14:01 +0200 Subject: [PATCH 01/22] Teach -dgc2stack to preserve the call graph. This should allow for more efficient execution by the pass manager. --- gen/passes/GarbageCollect2Stack.cpp | 54 +++++++++++++++++++---------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index b59eb0a1..1938a0d4 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Target/TargetData.h" @@ -43,24 +44,40 @@ STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas"); STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas"); STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); + +namespace { + struct Analysis { + TargetData& TD; + const Module& M; + CallGraph* CG; + CallGraphNode* CGNode; + + const Type* getTypeFor(Value* typeinfo) const; + }; +} + //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// -void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len) { +void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len, + const Analysis& A) { Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); Module *M = B.GetInsertBlock()->getParent()->getParent(); const Type* Tys[1]; Tys[0] = Len->getType(); - Value *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); + Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); Value *Align = ConstantInt::get(Type::Int32Ty, 1); - B.CreateCall4(MemSet, Dst, Val, Len, Align); + CallSite CS = B.CreateCall4(MemSet, Dst, Val, Len, Align); + if (A.CGNode) + A.CGNode->addCalledFunction(CS, A.CG->getOrInsertFunction(MemSet)); } -static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) { - EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len); +static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len, + const Analysis& A) { + EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len, A); } @@ -69,13 +86,6 @@ static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) { //===----------------------------------------------------------------------===// namespace { - struct Analysis { - TargetData& TD; - const Module& M; - - const Type* getTypeFor(Value* typeinfo) const; - }; - class FunctionInfo { protected: const Type* Ty; @@ -174,7 +184,7 @@ namespace { // Use the original B to put initialization at the // allocation site. Value* Size = B.CreateMul(TypeSize, arrSize); - EmitMemZero(B, alloca, Size); + EmitMemZero(B, alloca, Size, A); } return alloca; @@ -259,6 +269,7 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); + AU.addPreserved(); } }; char GarbageCollect2Stack::ID = 0; @@ -284,8 +295,9 @@ GarbageCollect2Stack::GarbageCollect2Stack() KnownFunctions["_d_allocclass"] = &AllocClass; } -static void RemoveCall(Instruction* Inst) { - if (InvokeInst* Invoke = dyn_cast(Inst)) { +static void RemoveCall(CallSite CS, const Analysis& A) { + if (CS.isInvoke()) { + InvokeInst* Invoke = cast(CS.getInstruction()); // If this was an invoke instruction, we need to do some extra // work to preserve the control flow. @@ -296,7 +308,9 @@ static void RemoveCall(Instruction* Inst) { BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent()); } // Remove the runtime call. - Inst->eraseFromParent(); + if (A.CGNode) + A.CGNode->removeCallEdgeFor(CS); + CS.getInstruction()->eraseFromParent(); } /// runOnFunction - Top level algorithm. @@ -306,8 +320,10 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) { TargetData &TD = getAnalysis(); const LoopInfo &LI = getAnalysis(); + CallGraph* CG = getAnalysisIfAvailable(); + CallGraphNode* CGNode = CG ? (*CG)[&F] : NULL; - Analysis A = { TD, *M }; + Analysis A = { TD, *M, CG, CGNode }; BasicBlock& Entry = F.getEntryBlock(); @@ -351,7 +367,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) { if (Inst->use_empty() && info->SafeToDelete) { Changed = true; NumDeleted++; - RemoveCall(Inst); + RemoveCall(CS, A); continue; } @@ -374,7 +390,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) { newVal = Builder.CreateBitCast(newVal, Inst->getType()); Inst->replaceAllUsesWith(newVal); - RemoveCall(Inst); + RemoveCall(CS, A); } } From b06fa1f05ef05e91434220a3f329ad8a65fd1989 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Thu, 28 May 2009 02:28:30 +0200 Subject: [PATCH 02/22] I ran into another issue like the one fixed by r1318, so update all of `tests/mini/norun_debug*` to hopefully keep crashing using the same trick. --- tests/mini/norun_debug1.d | 2 +- tests/mini/norun_debug10.d | 2 +- tests/mini/norun_debug12.d | 2 +- tests/mini/norun_debug2.d | 2 +- tests/mini/norun_debug3.d | 2 +- tests/mini/norun_debug4.d | 2 +- tests/mini/norun_debug5.d | 2 +- tests/mini/norun_debug6.d | 2 +- tests/mini/norun_debug7.d | 2 +- tests/mini/norun_debug8.d | 2 +- tests/mini/norun_debug9.d | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/mini/norun_debug1.d b/tests/mini/norun_debug1.d index 637ce7d5..44267fe2 100644 --- a/tests/mini/norun_debug1.d +++ b/tests/mini/norun_debug1.d @@ -2,7 +2,7 @@ module mini.norun_debug1; void main() { - int* ptr; + int* ptr = cast(int*) 1; // all these should be inspectable int i = 1; diff --git a/tests/mini/norun_debug10.d b/tests/mini/norun_debug10.d index 8169dd6b..35cb4e97 100644 --- a/tests/mini/norun_debug10.d +++ b/tests/mini/norun_debug10.d @@ -16,6 +16,6 @@ void main() void func(Vec2 v2, ref Vec2 rv2, char[] str, out int i, ref float f) { - int* fail; + int* fail = cast(int*) 1; *fail = 0; } diff --git a/tests/mini/norun_debug12.d b/tests/mini/norun_debug12.d index b6bebf7f..0be7f655 100644 --- a/tests/mini/norun_debug12.d +++ b/tests/mini/norun_debug12.d @@ -19,6 +19,6 @@ void main() scope c = new C; I i = c; - int* fail; + int* fail = cast(int*) 1; *fail = 0; } diff --git a/tests/mini/norun_debug2.d b/tests/mini/norun_debug2.d index 49b73e2b..8491fb95 100644 --- a/tests/mini/norun_debug2.d +++ b/tests/mini/norun_debug2.d @@ -8,7 +8,7 @@ void main() while (iter < 25) { if (rand() % 20 == 10) - *cast(int*)null = 0; + *cast(int*)1 = 0; ++iter; } assert(0); diff --git a/tests/mini/norun_debug3.d b/tests/mini/norun_debug3.d index 07e5889c..236ebdd5 100644 --- a/tests/mini/norun_debug3.d +++ b/tests/mini/norun_debug3.d @@ -5,6 +5,6 @@ void main() int i = 42; int* ip = &i; - int* fail; + int* fail = cast(int*) 1; *fail = 0; } diff --git a/tests/mini/norun_debug4.d b/tests/mini/norun_debug4.d index 792236a2..850303a2 100644 --- a/tests/mini/norun_debug4.d +++ b/tests/mini/norun_debug4.d @@ -6,6 +6,6 @@ void main() wchar wc = 'w'; dchar dc = 'd'; - int* fail; + int* fail = cast(int*) 1; *fail = 32; } diff --git a/tests/mini/norun_debug5.d b/tests/mini/norun_debug5.d index 4f8f4edc..a6e44330 100644 --- a/tests/mini/norun_debug5.d +++ b/tests/mini/norun_debug5.d @@ -10,6 +10,6 @@ void main() void func(int i, real r, real* p) { - int* fail; + int* fail = cast(int*) 1; *fail = 666; } diff --git a/tests/mini/norun_debug6.d b/tests/mini/norun_debug6.d index e09cf20b..9740a651 100644 --- a/tests/mini/norun_debug6.d +++ b/tests/mini/norun_debug6.d @@ -4,6 +4,6 @@ void main() { char[] str = "hello world :)"; - int* fail; + int* fail = cast(int*) 1; *fail = 32; } diff --git a/tests/mini/norun_debug7.d b/tests/mini/norun_debug7.d index 69703cc6..8db36d6e 100644 --- a/tests/mini/norun_debug7.d +++ b/tests/mini/norun_debug7.d @@ -4,6 +4,6 @@ int gi; void main() { - int* fail; + int* fail = cast(int*) 1; *fail = 0; } diff --git a/tests/mini/norun_debug8.d b/tests/mini/norun_debug8.d index 3a0be722..c77b0b52 100644 --- a/tests/mini/norun_debug8.d +++ b/tests/mini/norun_debug8.d @@ -26,6 +26,6 @@ void main() foo.bar.y = 3.1415; foo.bar.foo = &foo; - int* fail; + int* fail = cast(int*) 1; *fail = 0; } diff --git a/tests/mini/norun_debug9.d b/tests/mini/norun_debug9.d index 3c28e91d..acc5ce0e 100644 --- a/tests/mini/norun_debug9.d +++ b/tests/mini/norun_debug9.d @@ -6,7 +6,7 @@ struct Foo void func() { - int* fail; + int* fail = cast(int*) 1; *fail = 0; } } From 803156b0356dc28005a7a07e52587d2d7894a8e3 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Thu, 28 May 2009 20:26:26 +0200 Subject: [PATCH 03/22] Allow complex -> integral casts. --- gen/complex.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gen/complex.cpp b/gen/complex.cpp index 08c46f63..731e45d5 100644 --- a/gen/complex.cpp +++ b/gen/complex.cpp @@ -438,11 +438,19 @@ DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to) DImValue* im = new DImValue(to, impart); return DtoCastFloat(loc, im, to); } - else if (to->isfloating()) { + else if (to->isfloating() || to->isintegral()) { // FIXME: this loads both values, even when we only need one LLValue* v = val->getRVal(); LLValue* repart = gIR->ir->CreateExtractValue(v, 0, ".re_part"); - DImValue* re = new DImValue(to, repart); + Type *extractty; + if (vty->ty == Tcomplex32) { + extractty = Type::tfloat32; + } else if (vty->ty == Tcomplex64) { + extractty = Type::tfloat64; + } else if (vty->ty == Tcomplex80) { + extractty = Type::tfloat80; + } + DImValue* re = new DImValue(extractty, repart); return DtoCastFloat(loc, re, to); } else if (to->ty == Tbool) { From e03a897bad8645002ec50209838c3a6333254cb6 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Thu, 28 May 2009 21:45:14 +0200 Subject: [PATCH 04/22] Make sure complex -> integral casts are not used when casting to bool. Error instead of assert on unimplemented cast. --- gen/complex.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gen/complex.cpp b/gen/complex.cpp index 731e45d5..852e743b 100644 --- a/gen/complex.cpp +++ b/gen/complex.cpp @@ -410,7 +410,7 @@ LLValue* DtoComplexEquals(Loc& loc, TOK op, DValue* lhs, DValue* rhs) DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to) { Type* to = _to->toBasetype(); - Type* vty = val->getType(); + Type* vty = val->getType()->toBasetype(); if (to->iscomplex()) { if (vty->size() == to->size()) return val; @@ -438,6 +438,9 @@ DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to) DImValue* im = new DImValue(to, impart); return DtoCastFloat(loc, im, to); } + else if (to->ty == Tbool) { + return new DImValue(_to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty))); + } else if (to->isfloating() || to->isintegral()) { // FIXME: this loads both values, even when we only need one LLValue* v = val->getRVal(); @@ -453,10 +456,7 @@ DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to) DImValue* re = new DImValue(extractty, repart); return DtoCastFloat(loc, re, to); } - else if (to->ty == Tbool) { - return new DImValue(_to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty))); - } else - assert(0); + error(loc, "Don't know how to cast %s to %s", vty->toChars(), to->toChars()); } From 5d4fe64ac27811e5ded7aede20e8d8248f0319bd Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Thu, 28 May 2009 22:00:08 +0200 Subject: [PATCH 05/22] Get rid of old phobos-based tests. --- tests/mini/phobos/bug57.d | 10 ---------- tests/mini/phobos/bug58.d | 10 ---------- tests/mini/phobos/bug66.d | 5 ----- tests/mini/phobos/bug71.d | 20 -------------------- tests/mini/phobos/bug79.d | 9 --------- tests/mini/phobos/imports2.d | 6 ------ tests/mini/phobos/stdiotest.d | 28 ---------------------------- tests/mini/phobos/stdiotest2.d | 22 ---------------------- tests/mini/phobos/strings2.d | 15 --------------- 9 files changed, 125 deletions(-) delete mode 100644 tests/mini/phobos/bug57.d delete mode 100644 tests/mini/phobos/bug58.d delete mode 100644 tests/mini/phobos/bug66.d delete mode 100644 tests/mini/phobos/bug71.d delete mode 100644 tests/mini/phobos/bug79.d delete mode 100644 tests/mini/phobos/imports2.d delete mode 100644 tests/mini/phobos/stdiotest.d delete mode 100644 tests/mini/phobos/stdiotest2.d delete mode 100644 tests/mini/phobos/strings2.d diff --git a/tests/mini/phobos/bug57.d b/tests/mini/phobos/bug57.d deleted file mode 100644 index fd6bb25a..00000000 --- a/tests/mini/phobos/bug57.d +++ /dev/null @@ -1,10 +0,0 @@ -import std.stdio; -class Foo {} -void func3() -{ - Foo[1] test=[new Foo]; - writefln(test); -} -void main() { - func3(); -} diff --git a/tests/mini/phobos/bug58.d b/tests/mini/phobos/bug58.d deleted file mode 100644 index 25cb7593..00000000 --- a/tests/mini/phobos/bug58.d +++ /dev/null @@ -1,10 +0,0 @@ -module bug58; -import std.stdio; -void main() -{ - int[16] arr = [1,16,2,15,3,14,4,13,5,12,6,11,7,10,8,9]; - writefln("arr = ",arr); - arr.sort; - writefln("arr.sort = ",arr); - assert(arr == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]); -} diff --git a/tests/mini/phobos/bug66.d b/tests/mini/phobos/bug66.d deleted file mode 100644 index cdf8b64b..00000000 --- a/tests/mini/phobos/bug66.d +++ /dev/null @@ -1,5 +0,0 @@ -module bug66; -import std.stdio; -class Scene { string name() { return "Scene"; } } -class Group : Scene { this () { } } -void main() { writefln((new Group).name); } diff --git a/tests/mini/phobos/bug71.d b/tests/mini/phobos/bug71.d deleted file mode 100644 index a24d7cad..00000000 --- a/tests/mini/phobos/bug71.d +++ /dev/null @@ -1,20 +0,0 @@ -module bug71; - -void main() -{ - static TypeInfo skipCI(TypeInfo valti) - { - while (1) - { - if (valti.classinfo.name.length == 18 && - valti.classinfo.name[9..18] == "Invariant") - valti = (cast(TypeInfo_Invariant)valti).next; - else if (valti.classinfo.name.length == 14 && - valti.classinfo.name[9..14] == "Const") - valti = (cast(TypeInfo_Const)valti).next; - else - break; - } - return valti; - } -} \ No newline at end of file diff --git a/tests/mini/phobos/bug79.d b/tests/mini/phobos/bug79.d deleted file mode 100644 index 5b981f89..00000000 --- a/tests/mini/phobos/bug79.d +++ /dev/null @@ -1,9 +0,0 @@ -module bug79; -import std.c.linux.linux; -void main() -{ - timespec ts; - ts.tv_nsec -= 1; - //auto t = ts.tv_nsec - 1; - //t -= 1; -} diff --git a/tests/mini/phobos/imports2.d b/tests/mini/phobos/imports2.d deleted file mode 100644 index 7f8bff58..00000000 --- a/tests/mini/phobos/imports2.d +++ /dev/null @@ -1,6 +0,0 @@ -module imports2; -import std.stdio; - -void main() { - writefln("Hello world!"[]); -} diff --git a/tests/mini/phobos/stdiotest.d b/tests/mini/phobos/stdiotest.d deleted file mode 100644 index 4f337a0c..00000000 --- a/tests/mini/phobos/stdiotest.d +++ /dev/null @@ -1,28 +0,0 @@ -module stdiotest; - -import std.stdio; - -T typed(T)(T x) -{ - return x; -} - -void main() -{ - /*char[] str = "hello"; - writefln(str); - - writefln("hello world");*/ - - char[] fmt = "%s"; - writefln(2.0f); - - /*{writefln(typed!(byte)(1));} - {writefln(typed!(short)(2));} - {writefln(typed!(int)(3));} - {writefln(typed!(long)(-4));} - {writefln(typed!(ulong)(5));} - {writefln("%f", typed!(float)(6));} - {writefln("%f", typed!(double)(7));} - {writefln("%f", typed!(real)(8));}*/ -} diff --git a/tests/mini/phobos/stdiotest2.d b/tests/mini/phobos/stdiotest2.d deleted file mode 100644 index 50fa0d27..00000000 --- a/tests/mini/phobos/stdiotest2.d +++ /dev/null @@ -1,22 +0,0 @@ -module stdiotest2; -import std.stdio; -void main() -{ - int[4] v = [1,2,3,4]; - { - writefln("%s", v); - { - int[] dv = v; - {writefln("%s", dv);} - } - } - - { - writefln(v); - { - //int[] dv = v; - //{writefln(dv);} - } - } - //writefln(1,2,3,4.56,"hello",v); -} diff --git a/tests/mini/phobos/strings2.d b/tests/mini/phobos/strings2.d deleted file mode 100644 index 8331dccf..00000000 --- a/tests/mini/phobos/strings2.d +++ /dev/null @@ -1,15 +0,0 @@ -module strings2; - -import std.string; -import std.stdio; - -void main() -{ - int i = 32; - auto str = format(i); - writefln(str); - - long l = 123123; - str = format(l); - writefln(str); -} From 01c608f457a50c6cda19c42a7c7564f12e582735 Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Fri, 29 May 2009 01:08:39 -0600 Subject: [PATCH 06/22] Fix - add Path.native for mingw support...thanks mp4/jaffa --- tests/runminitest.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runminitest.d b/tests/runminitest.d index 047be333..36a30812 100644 --- a/tests/runminitest.d +++ b/tests/runminitest.d @@ -69,7 +69,7 @@ int main(char[][] args) compilefailed ~= c.toString; } else if (cl == RUN || cl == NORUN) { - if (system(toStringz("obj/" ~ testname)) != 0) { + if (system(toStringz(Path.native("obj/" ~ testname))) != 0) { if (cl == RUN) runfailed ~= c.toString; } From 750260070a1323f846329363541cda37630cfbc8 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Sat, 30 May 2009 12:47:35 +0200 Subject: [PATCH 07/22] Define __C99FEATURES__ in lexer.c for Solaris. Fixes #313. --- dmd/lexer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dmd/lexer.c b/dmd/lexer.c index 248f16b6..0866a387 100644 --- a/dmd/lexer.c +++ b/dmd/lexer.c @@ -8,6 +8,10 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. +#if __sun && __SVR4 +#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more, LDC#313 +#endif + #if IN_LLVM #include #endif From a05ed9a1715bd5711977a267d667e5f3a53851a8 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Sat, 30 May 2009 12:58:04 +0200 Subject: [PATCH 08/22] Fix #309: allow -of with multiple source files if -singleobj is given. --- gen/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/main.cpp b/gen/main.cpp index 86e6477b..02e404d6 100644 --- a/gen/main.cpp +++ b/gen/main.cpp @@ -369,7 +369,7 @@ int main(int argc, char** argv) } else { - if (global.params.objname && files.dim > 1) + if (global.params.objname && files.dim > 1 && !singleObj) { error("multiple source files, but only one .obj name"); fatal(); From da593c99dc01b393ab082baadce0e6de34df49ac Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sat, 30 May 2009 13:04:49 +0200 Subject: [PATCH 09/22] Remove code duplication for vtable loads and improve instruction naming to make bitcode with virtual calls easier to read. --- gen/classes.cpp | 10 ++++++++-- gen/classes.h | 2 +- gen/toir.cpp | 20 +++----------------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/gen/classes.cpp b/gen/classes.cpp index 2ac7be9f..ec20de4d 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -514,7 +514,7 @@ LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) ////////////////////////////////////////////////////////////////////////////////////////// -LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl) +LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name) { // sanity checks assert(fdecl->isVirtual()); @@ -533,7 +533,9 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl) // load vtbl ptr funcval = DtoLoad(funcval); // index vtbl - funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toChars()); + std::string vtblname = name; + vtblname.append("@vtbl"); + funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str()); // load funcptr funcval = DtoAlignedLoad(funcval); @@ -542,6 +544,10 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl) // cast to final funcptr type funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); + + // postpone naming until after casting to get the name in call instructions + funcval->setName(name); + if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; diff --git a/gen/classes.h b/gen/classes.h index 558fe9f5..4c65084f 100644 --- a/gen/classes.h +++ b/gen/classes.h @@ -32,6 +32,6 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* to); LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* sd, VarDeclaration* vd); -LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl); +LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name); #endif diff --git a/gen/toir.cpp b/gen/toir.cpp index 06cdb226..be72c50b 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1134,22 +1134,8 @@ DValue* DotVarExp::toElem(IRState* p) assert(funcval); } else { - assert(fdecl->vtblIndex > 0); - assert(e1type->ty == Tclass); - - LLValue* zero = DtoConstUint(0); - size_t vtblidx = fdecl->vtblIndex; - if (Logger::enabled()) - Logger::cout() << "vthis: " << *vthis << '\n'; - funcval = DtoGEP(vthis, zero, zero); - funcval = DtoLoad(funcval); - Logger::println("vtblidx = %lu", vtblidx); - funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars()); - funcval = DtoLoad(funcval); - - funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); - if (Logger::enabled()) - Logger::cout() << "funcval casted: " << *funcval << '\n'; + DImValue vthis3(e1type, vthis); + funcval = DtoVirtualFunctionPointer(&vthis3, fdecl, toChars()); } return new DFuncValue(fdecl, funcval, vthis2); @@ -2031,7 +2017,7 @@ DValue* DelegateExp::toElem(IRState* p) LLValue* castfptr; if (func->isVirtual() && !func->isFinal()) - castfptr = DtoVirtualFunctionPointer(u, func); + castfptr = DtoVirtualFunctionPointer(u, func, toChars()); else if (func->isAbstract()) assert(0 && "TODO delegate to abstract method"); else if (func->toParent()->isInterfaceDeclaration()) From 71477fcb8c1ed1efb32e21884763bd7bc8fff6c4 Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Sat, 30 May 2009 14:35:03 -0600 Subject: [PATCH 10/22] Forgot one windows underscore for asm output --- gen/asm-x86-32.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gen/asm-x86-32.h b/gen/asm-x86-32.h index 75afc559..0b9ab5c2 100644 --- a/gen/asm-x86-32.h +++ b/gen/asm-x86-32.h @@ -1528,9 +1528,8 @@ namespace AsmParserx8632 } // osx needs an extra underscore - if ( global.params.os == OSMacOSX ) - insnTemplate << "_"; - + if ( global.params.os == OSMacOSX || global.params.os == OSWindows ) + insnTemplate << "_"; // print out the mangle insnTemplate << vd->mangle(); vd->nakedUse = true; From 2e6e578ea1514a5748c2aebe150ddfadc8c2ef2a Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Sat, 30 May 2009 14:57:48 -0600 Subject: [PATCH 11/22] Fix test for mingw --- tests/mini/m.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mini/m.d b/tests/mini/m.d index 5d504e69..9e91e3ae 100644 --- a/tests/mini/m.d +++ b/tests/mini/m.d @@ -9,6 +9,9 @@ extern(C): version(darwin) { int* __error(); alias __error __errno_location; +} else version (mingw32) { + int* strerror(); + alias strerror __errno_location; } else { int* __errno_location(); } From c8b10643f9fe32147ee0bc23d80ceb19242c1b90 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sat, 30 May 2009 23:48:22 +0200 Subject: [PATCH 12/22] Add some missing returns. --- gen/abi.cpp | 2 +- gen/passes/GarbageCollect2Stack.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gen/abi.cpp b/gen/abi.cpp index 4be4f3a2..4551c1ce 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -132,7 +132,7 @@ struct X86_struct_to_register : ABIRewrite assert(dv->isLVal()); LLValue* mem = dv->getLVal(); const LLType* t = LLIntegerType::get(dty->size()*8); - DtoLoad(DtoBitCast(mem, getPtrToType(t))); + return DtoLoad(DtoBitCast(mem, getPtrToType(t))); } const LLType* type(Type* t, const LLType*) { diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index 1938a0d4..6d1bf555 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -262,6 +262,7 @@ namespace { bool doInitialization(Module &M) { this->M = &M; + return false; } bool runOnFunction(Function &F); From 3718bd23fb0d4d0481d59f1a1c7e98b589f44f8c Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sun, 31 May 2009 10:41:20 +0200 Subject: [PATCH 13/22] Add `nest` attribute to `this` parameters on x86-64. This is a free extra parameter register :). --- gen/abi-x86-64.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 6d7fb285..fa8b983a 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -677,6 +677,13 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf) { } } + if (fty.arg_this) { + fty.arg_this->attrs |= llvm::Attribute::Nest; + } + if (fty.arg_nest) { + fty.arg_nest->attrs |= llvm::Attribute::Nest; + } + Logger::println("x86-64 D ABI: Transforming arguments"); LOG_SCOPE; From a517adb426a1f7f94373212886ce0df68956279b Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sun, 31 May 2009 14:27:01 +0200 Subject: [PATCH 14/22] Adjust runtime for recent ABI change on x86-64, since member functions are no longer equivalent to regular functions with `this` as their first argument. (They weren't anyway, but it happened to work as long as there was no `sret` parameter) --- runtime/internal/genobj.d | 8 +++++--- runtime/internal/invariant.d | 5 ++++- runtime/internal/lifetime.d | 6 ++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/runtime/internal/genobj.d b/runtime/internal/genobj.d index dd1f72cc..4adfd7b9 100644 --- a/runtime/internal/genobj.d +++ b/runtime/internal/genobj.d @@ -153,7 +153,7 @@ class ClassInfo : Object Interface[] interfaces; /// interfaces this class implements ClassInfo base; /// base class void* destructor; - void function(Object) classInvariant; + void* classInvariant; uint flags; // 1: // IUnknown // 2: // has no possible pointers into GC memory @@ -198,8 +198,10 @@ class ClassInfo : Object if (flags & 8 && defaultConstructor) { - auto ctor = cast(Object function(Object))defaultConstructor; - return ctor(o); + Object delegate() ctor; + ctor.ptr = cast(void*)o; + ctor.funcptr = cast(Object function())defaultConstructor; + return ctor(); } return o; } diff --git a/runtime/internal/invariant.d b/runtime/internal/invariant.d index f706c84e..6c96ede9 100644 --- a/runtime/internal/invariant.d +++ b/runtime/internal/invariant.d @@ -18,7 +18,10 @@ extern(C) void _d_invariant(Object o) { if (c.classInvariant) { - (*c.classInvariant)(o); + void delegate() inv; + inv.ptr = cast(void*) o; + inv.funcptr = c.classInvariant; + inv(); } c = c.base; } while (c); diff --git a/runtime/internal/lifetime.d b/runtime/internal/lifetime.d index f068d4ec..206a2568 100644 --- a/runtime/internal/lifetime.d +++ b/runtime/internal/lifetime.d @@ -560,8 +560,10 @@ extern (C) void rt_finalize(void* p, bool det = true) if (c.destructor) { debug(PRINTF) printf("calling dtor of %.*s\n", c.name.length, c.name.ptr); - fp_t fp = cast(fp_t)c.destructor; - (*fp)(cast(Object)p); // call destructor + void delegate() dg; + dg.ptr = p; + dg.funcptr = cast(void function()) c.destructor; + dg(); // call destructor } c = c.base; } while (c); From 78aa98fdfbe3faacd562759e0862692972b7c203 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Sun, 31 May 2009 15:07:04 +0200 Subject: [PATCH 15/22] Error on invalid array cast. See DMD3041. --- gen/arrays.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 3da0d4e1..7818952e 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -894,7 +894,10 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to) Type* totype = to->toBasetype(); Type* fromtype = u->getType()->toBasetype(); - assert(fromtype->ty == Tarray || fromtype->ty == Tsarray); + if (fromtype->ty != Tarray && fromtype->ty != Tsarray) { + error(loc, "can't cast %s to %s", u->getType()->toChars(), to->toChars()); + fatal(); + } LLValue* rval; LLValue* rval2; From 46cd6504fa73a1812ce665632d51d9a86cc4640c Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sun, 31 May 2009 15:27:01 +0200 Subject: [PATCH 16/22] Adjust some more code that was depending on the function and delegate calling conventions being equal. There's also an instance in `tango.text.convert.Layout` that should be adjusted: {{{ Index: tango/text/convert/Layout.d =================================================================== --- tango/text/convert/Layout.d (revision 4578) +++ tango/text/convert/Layout.d (working copy) -660,8 +660,12 @@ case TypeCode.STRUCT: auto s = cast(TypeInfo_Struct) type; - if (s.xtoString) - return Utf.fromString8 (s.xtoString(p), result); + if (s.xtoString) { + char[] delegate() toString; + toString.ptr = p; + toString.funcptr = cast(char[] function()) s.xtoString; + return Utf.fromString8 (toString(), result); + } goto default; case TypeCode.INTERFACE: }}} --- runtime/internal/genobj.d | 42 ++++++++++++++++++++++----------------- tests/mini/typeinfo10.d | 5 ++++- tests/mini/vararg6.d | 7 +++++-- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/runtime/internal/genobj.d b/runtime/internal/genobj.d index 4adfd7b9..5b179c74 100644 --- a/runtime/internal/genobj.d +++ b/runtime/internal/genobj.d @@ -152,8 +152,8 @@ class ClassInfo : Object void*[] vtbl; /// virtual function pointer table Interface[] interfaces; /// interfaces this class implements ClassInfo base; /// base class - void* destructor; - void* classInvariant; + void* destructor; // Only use as delegate.funcptr! + void* classInvariant; // Only use as delegate.funcptr! uint flags; // 1: // IUnknown // 2: // has no possible pointers into GC memory @@ -162,7 +162,7 @@ class ClassInfo : Object // 32: // has typeinfo void* deallocator; OffsetTypeInfo[] offTi; - void* defaultConstructor; // default Constructor + void* defaultConstructor; // default Constructor. Only use as delegate.funcptr! TypeInfo typeinfo; /** @@ -764,7 +764,10 @@ class TypeInfo_Struct : TypeInfo assert(p); if (xtoHash) { debug(PRINTF) printf("getHash() using xtoHash\n"); - h = (*xtoHash)(p); + hash_t delegate() toHash; + toHash.ptr = p; + toHash.funcptr = xtoHash; + h = toHash(); } else { @@ -787,9 +790,12 @@ class TypeInfo_Struct : TypeInfo c = 1; else if (!p1 || !p2) c = 0; - else if (xopEquals) - c = (*xopEquals)(p1, p2); - else + else if (xopEquals) { + int delegate(void*) opEquals; + opEquals.ptr = p1; + opEquals.funcptr = xopEquals; + c = opEquals(p2); + } else // BUG: relies on the GC not moving objects c = (memcmp(p1, p2, m_init.length) == 0); return c; @@ -805,13 +811,12 @@ class TypeInfo_Struct : TypeInfo if (p1) { if (!p2) c = 1; - else if (xopCmp) - // the x86 D calling conv requires the this arg to be last here - version(X86) - c = (*xopCmp)(p2, p1); - else - c = (*xopCmp)(p1, p2); - else + else if (xopCmp) { + int delegate(void*) opCmp; + opCmp.ptr = p1; + opCmp.funcptr = xopCmp; + c = opCmp(p2); + } else // BUG: relies on the GC not moving objects c = memcmp(p1, p2, m_init.length); } @@ -833,10 +838,11 @@ class TypeInfo_Struct : TypeInfo char[] name; void[] m_init; // initializer; never null - hash_t function(void*) xtoHash; - int function(void*,void*) xopEquals; - int function(void*,void*) xopCmp; - char[] function(void*) xtoString; + // These are ONLY for use as a delegate.funcptr! + hash_t function() xtoHash; + int function(void*) xopEquals; + int function(void*) xopCmp; + char[] function() xtoString; uint m_flags; } diff --git a/tests/mini/typeinfo10.d b/tests/mini/typeinfo10.d index 949d84fc..1d375c2b 100644 --- a/tests/mini/typeinfo10.d +++ b/tests/mini/typeinfo10.d @@ -58,7 +58,10 @@ void main() assert(ti.compare(&v,&u) > 0); { auto tis = cast(TypeInfo_Struct)ti; - assert(tis.xtoString(&s) == s.toString()); + char[] delegate() structToString; + structToString.ptr = &s; + structToString.funcptr = tis.xtoString; + assert(structToString() == s.toString()); } } } diff --git a/tests/mini/vararg6.d b/tests/mini/vararg6.d index a7dd62ed..24b5db12 100644 --- a/tests/mini/vararg6.d +++ b/tests/mini/vararg6.d @@ -1,5 +1,5 @@ // tries to implement a fairly complete variadic print function -module tangotests.vararg3; +module tangotests.vararg6; extern(C) int printf(char*, ...); @@ -179,7 +179,10 @@ void print(TypeInfo ti, void* arg) { if (sti.xtoString !is null) { - char[] str = sti.xtoString(arg); + char[] delegate() toString; + toString.ptr = arg; + toString.funcptr = sti.xtoString; + char[] str = toString(); printf("%.*s", str.length, str.ptr); } else From 06a0322478b2158b315b039942713fe67dfb5c8d Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sun, 31 May 2009 15:47:59 +0200 Subject: [PATCH 17/22] Update patch for Tango 0.99.8 --- tango-0.99.8.patch | 52 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/tango-0.99.8.patch b/tango-0.99.8.patch index 6fa055e1..8a90be2f 100644 --- a/tango-0.99.8.patch +++ b/tango-0.99.8.patch @@ -1,8 +1,15 @@ Index: object.di =================================================================== ---- object.di (revision 4655) +--- object.di (revision 4578) +++ object.di (working copy) -@@ -41,9 +41,11 @@ +@@ -35,15 +35,17 @@ + Interface[] interfaces; + ClassInfo base; + void* destructor; +- void(*classInvariant)(Object); ++ void* classInvariant; + uint flags; + // 1: // IUnknown // 2: // has no possible pointers into GC memory // 4: // has offTi[] member // 8: // has constructors @@ -14,9 +21,25 @@ Index: object.di static ClassInfo find(char[] classname); Object create(); +@@ -127,10 +129,11 @@ + char[] name; + void[] m_init; + +- uint function(void*) xtoHash; +- int function(void*,void*) xopEquals; +- int function(void*,void*) xopCmp; +- char[] function(void*) xtoString; ++ // These are ONLY for use as a delegate.funcptr! ++ hash_t function() xtoHash; ++ int function(void*) xopEquals; ++ int function(void*) xopCmp; ++ char[] function() xtoString; + + uint m_flags; + } Index: lib/common/tango/core/Thread.d =================================================================== ---- lib/common/tango/core/Thread.d (revision 4655) +--- lib/common/tango/core/Thread.d (revision 4578) +++ lib/common/tango/core/Thread.d (working copy) @@ -295,7 +295,7 @@ } @@ -38,7 +61,7 @@ Index: lib/common/tango/core/Thread.d movq r12[RBP], R12 ; Index: lib/gc/basic/gcx.d =================================================================== ---- lib/gc/basic/gcx.d (revision 4655) +--- lib/gc/basic/gcx.d (revision 4578) +++ lib/gc/basic/gcx.d (working copy) @@ -2198,7 +2198,7 @@ } @@ -58,9 +81,28 @@ Index: lib/gc/basic/gcx.d movq r10[RBP], R10 ; movq r11[RBP], R11 ; movq r12[RBP], R12 ; +Index: tango/text/convert/Layout.d +=================================================================== +--- tango/text/convert/Layout.d (revision 4578) ++++ tango/text/convert/Layout.d (working copy) +@@ -660,8 +660,12 @@ + + case TypeCode.STRUCT: + auto s = cast(TypeInfo_Struct) type; +- if (s.xtoString) +- return Utf.fromString8 (s.xtoString(p), result); ++ if (s.xtoString) { ++ char[] delegate() toString; ++ toString.ptr = p; ++ toString.funcptr = cast(char[] function()) s.xtoString; ++ return Utf.fromString8 (toString(), result); ++ } + goto default; + + case TypeCode.INTERFACE: Index: tango/net/Socket.d =================================================================== ---- tango/net/Socket.d (revision 4655) +--- tango/net/Socket.d (revision 4578) +++ tango/net/Socket.d (working copy) @@ -1545,10 +1545,10 @@ From 008d81afb0ee3912ff0f2039531b48c938d47e7c Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Sun, 31 May 2009 09:10:33 -0600 Subject: [PATCH 18/22] Fix "garbage at end of line" errors on mingw...shouldn't affect linux/macosx --- gen/rttibuilder.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gen/rttibuilder.cpp b/gen/rttibuilder.cpp index a18fc554..7aa6fe3f 100644 --- a/gen/rttibuilder.cpp +++ b/gen/rttibuilder.cpp @@ -76,7 +76,7 @@ void RTTIBuilder::push_void_array(uint64_t dim, llvm::Constant* ptr) void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* mangle_sym) { std::string initname(mangle_sym->mangle()); - initname.append(".rtti.void[].data"); + initname.append(".rtti.voidarr.data"); LLGlobalVariable* G = new llvm::GlobalVariable( CI->getType(), true, TYPEINFO_LINKAGE_TYPE, CI, initname, gIR->module); @@ -87,9 +87,14 @@ void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* ma void RTTIBuilder::push_array(llvm::Constant * CI, uint64_t dim, Type* valtype, Dsymbol * mangle_sym) { - std::string initname(mangle_sym?mangle_sym->mangle():".ldc"); + std::string tmpStr(valtype->arrayOf()->toChars()); + tmpStr.erase( remove( tmpStr.begin(), tmpStr.end(), '[' ), tmpStr.end() ); + tmpStr.erase( remove( tmpStr.begin(), tmpStr.end(), ']' ), tmpStr.end() ); + tmpStr.append("arr"); + + std::string initname(mangle_sym?mangle_sym->mangle():".ldc"); initname.append(".rtti."); - initname.append(valtype->arrayOf()->toChars()); + initname.append(tmpStr); initname.append(".data"); LLGlobalVariable* G = new llvm::GlobalVariable( From 2fe8f2cd7441a7c8be4ef112453a5b7ed8388e02 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Sun, 31 May 2009 12:43:59 +0200 Subject: [PATCH 19/22] Improve ABI conformance on x86 by passing the `sret` parameter in EAX if there's no `this`. --- gen/abi.cpp | 10 +++++++++- gen/tocall.cpp | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/gen/abi.cpp b/gen/abi.cpp index 4551c1ce..130e49f1 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -196,8 +196,16 @@ struct X86TargetABI : TargetABI Logger::println("Putting context ptr in register"); fty.arg_nest->attrs = llvm::Attribute::InReg; } + else if (IrFuncTyArg* sret = fty.arg_sret) + { + Logger::println("Putting sret ptr in register"); + // sret and inreg are incompatible, but the ABI requires the + // sret parameter to be in EAX in this situation... + sret->attrs = (sret->attrs | llvm::Attribute::InReg) + & ~llvm::Attribute::StructRet; + } // otherwise try to mark the last param inreg - else if (!fty.arg_sret && !fty.args.empty()) + else if (!fty.args.empty()) { // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met: // * It fits in EAX. diff --git a/gen/tocall.cpp b/gen/tocall.cpp index fea5e91a..62b373d8 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -322,7 +322,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // add attrs for hidden ptr Attr.Index = 1; Attr.Attrs = tf->fty.arg_sret->attrs; - assert((Attr.Attrs & llvm::Attribute::StructRet) && "Sret arg not sret?"); + assert((Attr.Attrs & (llvm::Attribute::StructRet | llvm::Attribute::InReg)) + && "Sret arg not sret or inreg?"); attrs.push_back(Attr); } From 23919b4de40f4135258440672e6c1670d14c8b18 Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Sun, 31 May 2009 11:01:02 -0600 Subject: [PATCH 20/22] fix assembly code for mingw32 in minitests --- tests/mini/callingconv1.d | 35 ++++++++++++++++++++++++++--------- tests/mini/naked_asm5.d | 14 +++++++++++--- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/tests/mini/callingconv1.d b/tests/mini/callingconv1.d index 6a584ece..9bd840fc 100644 --- a/tests/mini/callingconv1.d +++ b/tests/mini/callingconv1.d @@ -15,15 +15,32 @@ void main() version(D_InlineAsm_X86) { - asm - { - mov EAX, [a]; - push EAX; - mov EAX, [b]; - push EAX; - call foo; - fstp c; - } + version(mingw32) + { + asm + { + movss XMM0, [a]; + movss XMM1, [b]; + movss [ESP], XMM1; + movss [ESP]+4, XMM0; + call foo; + fstp [c]-4; + movss XMM0, [c]-4; + movss [c], XMM0; + } + } else + { + + asm + { + mov EAX, [a]; + push EAX; + mov EAX, [b]; + push EAX; + call foo; + fstp c; + } + } } else version(D_InlineAsm_X86_64) { diff --git a/tests/mini/naked_asm5.d b/tests/mini/naked_asm5.d index db438acb..b9d527c7 100644 --- a/tests/mini/naked_asm5.d +++ b/tests/mini/naked_asm5.d @@ -3,9 +3,17 @@ int foo(int op)(int a, int b) version(X86) { const OP = (op == '+') ? "add" : "sub"; - asm { naked; } - mixin("asm{"~OP~" EAX, [ESP+4];}"); - asm { ret 4; } + version (mingw32) + { + asm { naked; } + mixin("asm{push EBP;mov EBP,ESP;sub ESP,8;mov ECX,[EBP+8];"~OP~" EAX, ECX;add ESP,8;pop EBP;}"); + asm { ret; } + } else + { + asm { naked; } + mixin("asm{"~OP~" EAX, [ESP+4];}"); + asm { ret 4; } + } } else version(X86_64) { From 19149bc54273381c46f381e943104c904bca9334 Mon Sep 17 00:00:00 2001 From: Kelly Wilson Date: Sun, 31 May 2009 11:20:26 -0600 Subject: [PATCH 21/22] change mingw32 versioning to version(Windows) --- tests/mini/callingconv1.d | 2 +- tests/mini/m.d | 2 +- tests/mini/naked_asm5.d | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mini/callingconv1.d b/tests/mini/callingconv1.d index 9bd840fc..9b0a92e4 100644 --- a/tests/mini/callingconv1.d +++ b/tests/mini/callingconv1.d @@ -15,7 +15,7 @@ void main() version(D_InlineAsm_X86) { - version(mingw32) + version(Windows) { asm { diff --git a/tests/mini/m.d b/tests/mini/m.d index 9e91e3ae..c1480207 100644 --- a/tests/mini/m.d +++ b/tests/mini/m.d @@ -9,7 +9,7 @@ extern(C): version(darwin) { int* __error(); alias __error __errno_location; -} else version (mingw32) { +} else version (Windows) { int* strerror(); alias strerror __errno_location; } else { diff --git a/tests/mini/naked_asm5.d b/tests/mini/naked_asm5.d index b9d527c7..c133fe24 100644 --- a/tests/mini/naked_asm5.d +++ b/tests/mini/naked_asm5.d @@ -3,7 +3,7 @@ int foo(int op)(int a, int b) version(X86) { const OP = (op == '+') ? "add" : "sub"; - version (mingw32) + version (Windows) { asm { naked; } mixin("asm{push EBP;mov EBP,ESP;sub ESP,8;mov ECX,[EBP+8];"~OP~" EAX, ECX;add ESP,8;pop EBP;}"); From 0a8db2289d10e26b46047c6b01a124974f566bb2 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Mon, 1 Jun 2009 01:28:18 +0200 Subject: [PATCH 22/22] Remove redundant null-check in member functions of structs that don't have an invariant. --- dmd/func.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dmd/func.c b/dmd/func.c index c60265a3..e4031ed7 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -1266,12 +1266,17 @@ void FuncDeclaration::semantic3(Scope *sc) } else { // Call invariant virtually - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - e = new AssertExp(loc, v, NULL); + // LDC: unless this is a struct without invariant + StructDeclaration* sd = ad->isStructDeclaration(); + if (!sd || sd->inv) + { + ThisExp *v = new ThisExp(0); + v->type = vthis->type; + e = new AssertExp(loc, v, NULL); + } // LDC: check for null this - v = new ThisExp(0); + ThisExp* v = new ThisExp(0); v->type = vthis->type; v->var = vthis;