mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 16:11:08 +03:00
Fix regression for LDC-specific elide-scope-class-finalization optimization
`NewExp.type` can apparently newly be a yet-unresolved `TypeIdentifier`. Resolve it in that case to a `TypeClass` now. Also defer the has-dtor check for the whole class hierarchy of the *dynamic* type from that LDC-specific frontend addition to the glue layer, as I'm not sure we can rely on `ClassDeclaration.dtor` having been set at that time already. I've chosen to keep storing a single extra LDC-specific *bit* (`onstackWithMatchingDynType`) instead of storing the full dynamic class type. While this slightly weakens the optimization (no optimization for non-equivalent static/dynamic class types anymore), it doesn't increase the AST node size. And I think almost all cases use an equivalent type anyway (e.g., the DMD frontend itself only uses `scope` class allocations with equivalent types).
This commit is contained in:
parent
3541eaa03b
commit
153f8ccdce
7 changed files with 82 additions and 28 deletions
|
@ -1143,7 +1143,7 @@ extern (C++) class VarDeclaration : Declaration
|
|||
bool onstack;
|
||||
version (IN_LLVM)
|
||||
{
|
||||
bool onstackWithDtor; /// it is a class that was allocated on the stack and needs destruction
|
||||
bool onstackWithMatchingDynType; /// and dynamic type is equivalent to static type
|
||||
}
|
||||
|
||||
bool overlapped; /// if it is a field and has overlapping
|
||||
|
|
|
@ -267,8 +267,8 @@ public:
|
|||
bool onstack() const; // it is a class that was allocated on the stack
|
||||
bool onstack(bool v);
|
||||
#if IN_LLVM
|
||||
bool onstackWithDtor() const; // it is a class that was allocated on the stack and needs destruction
|
||||
bool onstackWithDtor(bool v);
|
||||
bool onstackWithMatchingDynType() const; // and dynamic type is equivalent to static type
|
||||
bool onstackWithMatchingDynType(bool v);
|
||||
#endif
|
||||
bool overlapped() const; // if it is a field and has overlapping
|
||||
bool overlapped(bool v);
|
||||
|
|
|
@ -1062,17 +1062,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
dsym.onstack = true;
|
||||
version (IN_LLVM)
|
||||
{
|
||||
bool hasDtor = false;
|
||||
auto cd = (cast(TypeClass) ne.newtype).sym;
|
||||
for (; cd; cd = cd.baseClass)
|
||||
auto tcStatic = dsym.type.toBasetype().isTypeClass();
|
||||
auto tcDynamic = ne.newtype.toBasetype().isTypeClass();
|
||||
if (!tcDynamic)
|
||||
{
|
||||
if (cd.dtor)
|
||||
{
|
||||
hasDtor = true;
|
||||
break;
|
||||
//printf(".: resolving %s\n", ne.newtype.toPrettyChars());
|
||||
ne.newtype = ne.newtype.typeSemantic(dsym.loc, sc);
|
||||
tcDynamic = ne.newtype.toBasetype().isTypeClass();
|
||||
assert(tcDynamic);
|
||||
}
|
||||
}
|
||||
dsym.onstackWithDtor = hasDtor;
|
||||
|
||||
dsym.onstackWithMatchingDynType = tcStatic.sym is tcDynamic.sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,9 +187,25 @@ void DtoFinalizeClass(const Loc &loc, LLValue *inst) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor) {
|
||||
llvm::Value* inst = DtoRVal(dval);
|
||||
if (!isOptimizationEnabled() || hasDtor) {
|
||||
void DtoFinalizeScopeClass(const Loc &loc, DValue *dval,
|
||||
bool dynTypeMatchesStaticType) {
|
||||
llvm::Value *inst = DtoRVal(dval);
|
||||
|
||||
if (!isOptimizationEnabled() || !dynTypeMatchesStaticType) {
|
||||
DtoFinalizeClass(loc, inst);
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasDtor = false;
|
||||
auto cd = dval->type->toBasetype()->isTypeClass()->sym;
|
||||
for (; cd; cd = cd->baseClass) {
|
||||
if (cd->dtor) {
|
||||
hasDtor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDtor) {
|
||||
DtoFinalizeClass(loc, inst);
|
||||
return;
|
||||
}
|
||||
|
@ -199,9 +215,10 @@ void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor) {
|
|||
llvm::BasicBlock *ifbb = gIR->insertBB("if");
|
||||
llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif");
|
||||
|
||||
llvm::StructType *st = getIrAggr(static_cast<TypeClass *>(dval->type)->sym)
|
||||
->getLLStructType();
|
||||
const auto monitor = DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor");
|
||||
llvm::StructType *st =
|
||||
getIrAggr(static_cast<TypeClass *>(dval->type)->sym)->getLLStructType();
|
||||
const auto monitor =
|
||||
DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor");
|
||||
const auto hasMonitor =
|
||||
gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor,
|
||||
getNullValue(monitor->getType()), ".hasMonitor");
|
||||
|
|
|
@ -29,7 +29,8 @@ void DtoResolveClass(ClassDeclaration *cd);
|
|||
DValue *DtoNewClass(const Loc &loc, TypeClass *type, NewExp *newexp);
|
||||
void DtoInitClass(TypeClass *tc, llvm::Value *dst);
|
||||
void DtoFinalizeClass(const Loc &loc, llvm::Value *inst);
|
||||
void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor);
|
||||
void DtoFinalizeScopeClass(const Loc &loc, DValue *dval,
|
||||
bool dynTypeMatchesStaticType);
|
||||
|
||||
DValue *DtoCastClass(const Loc &loc, DValue *val, Type *to);
|
||||
DValue *DtoDynamicCastObject(const Loc &loc, DValue *val, Type *to);
|
||||
|
|
|
@ -1644,7 +1644,8 @@ public:
|
|||
} else if (auto ve = e->e1->isVarExp()) {
|
||||
if (auto vd = ve->var->isVarDeclaration()) {
|
||||
if (vd->onstack()) {
|
||||
DtoFinalizeScopeClass(e->loc, dval, vd->onstackWithDtor());
|
||||
DtoFinalizeScopeClass(e->loc, dval,
|
||||
vd->onstackWithMatchingDynType());
|
||||
onstack = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,6 @@ class WithDtor : Base
|
|||
~this() {}
|
||||
}
|
||||
|
||||
class WithImplicitDtor : Base
|
||||
{
|
||||
static struct S { int val; ~this() {} }
|
||||
S s;
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} void @{{.*}}_D6gh251516noDtor_noMonitorFZv
|
||||
void noDtor_noMonitor()
|
||||
{
|
||||
|
@ -46,7 +40,18 @@ void noDtor_withMonitor()
|
|||
// CHECK: define{{.*}} void @{{.*}}_D6gh25158withDtorFZv
|
||||
void withDtor()
|
||||
{
|
||||
scope Base b = new WithDtor();
|
||||
scope b = new WithDtor();
|
||||
b.foo();
|
||||
printf("%d\n", b.val);
|
||||
// CHECK: _d_callfinalizer
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} void @{{.*}}_D6gh251517withInheritedDtorFZv
|
||||
void withInheritedDtor()
|
||||
{
|
||||
static class WithInheritedDtor : WithDtor {}
|
||||
scope b = new WithInheritedDtor();
|
||||
b.foo();
|
||||
printf("%d\n", b.val);
|
||||
// CHECK: _d_callfinalizer
|
||||
|
@ -56,7 +61,13 @@ void withDtor()
|
|||
// CHECK: define{{.*}} void @{{.*}}_D6gh251516withImplicitDtorFZv
|
||||
void withImplicitDtor()
|
||||
{
|
||||
scope Base b = new WithImplicitDtor();
|
||||
static class WithImplicitDtor : Base
|
||||
{
|
||||
static struct S { int val; ~this() {} }
|
||||
S s;
|
||||
}
|
||||
|
||||
scope b = new WithImplicitDtor();
|
||||
b.foo();
|
||||
printf("%d\n", b.val);
|
||||
// CHECK: _d_callfinalizer
|
||||
|
@ -64,6 +75,30 @@ void withImplicitDtor()
|
|||
}
|
||||
|
||||
|
||||
/* Test static vs. dynamic type mismatches. */
|
||||
|
||||
// CHECK: define{{.*}} void @{{.*}}_D6gh251529staticAndDynamicTypesMismatchFZv
|
||||
void staticAndDynamicTypesMismatch() // not optimized
|
||||
{
|
||||
static class NoDtor : Base {}
|
||||
|
||||
scope Base b = new NoDtor();
|
||||
b.foo();
|
||||
printf("%d\n", b.val);
|
||||
// CHECK: _d_callfinalizer
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} void @{{.*}}_D6gh251526typesMatchModuloQualifiersFZv
|
||||
void typesMatchModuloQualifiers() // different qualifiers don't prevent optimization
|
||||
{
|
||||
scope shared Base b = new Base();
|
||||
printf("%d\n", b.val);
|
||||
// CHECK-NOT: _d_callfinalizer
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
|
||||
/* Test a C++ class as well, which as of 2.077 isn't implicitly delete()d. */
|
||||
|
||||
extern(C++) class CppClass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue