Skip to content

Commit

Permalink
Optimize AliasAssign tuple building
Browse files Browse the repository at this point in the history
  • Loading branch information
BorisCarvajal authored and dlang-bot committed Jul 28, 2022
1 parent cac3f6b commit 10d62fc
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 12 deletions.
18 changes: 16 additions & 2 deletions compiler/src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,9 @@ extern (C++) abstract class Declaration : Dsymbol
extern (C++) final class TupleDeclaration : Declaration
{
Objects* objects;
bool isexp; // true: expression tuple
TypeTuple tupletype; // !=null if this is a type tuple
bool isexp; // true: expression tuple
bool building; // it's growing in AliasAssign semantic

extern (D) this(const ref Loc loc, Identifier ident, Objects* objects)
{
Expand All @@ -588,7 +589,7 @@ extern (C++) final class TupleDeclaration : Declaration
*/

//printf("TupleDeclaration::getType() %s\n", toChars());
if (isexp)
if (isexp || building)
return null;
if (!tupletype)
{
Expand Down Expand Up @@ -931,6 +932,19 @@ extern (C++) final class AliasDeclaration : Declaration
}
else
{
// stop AliasAssign tuple building
if (aliassym)
{
if (auto td = aliassym.isTupleDeclaration())
{
if (td.building)
{
td.building = false;
semanticRun = PASS.semanticdone;
return td;
}
}
}
if (_import && _import._scope)
{
/* If this is an internal alias for selective/renamed import,
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ class TupleDeclaration final : public Declaration
{
public:
Objects *objects;
bool isexp; // true: expression tuple

TypeTuple *tupletype; // !=NULL if this is a type tuple
bool isexp; // true: expression tuple
bool building; // it's growing in AliasAssign semantic

TupleDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
Expand Down
151 changes: 150 additions & 1 deletion compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -6332,6 +6332,10 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
* resolve the alias of eponymous member.
*/
tempinst.aliasdecl = tempinst.aliasdecl.toAlias2();

// stop AliasAssign tuple building
if (auto td = tempinst.aliasdecl.isTupleDeclaration())
td.building = false;
}

Laftersemantic:
Expand Down Expand Up @@ -6726,13 +6730,28 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
*/

const errors = global.errors;
Dsymbol s;

// Try AliasSeq optimization
if (auto ti = ds.type.isTypeInstance())
{
if (!ti.tempinst.findTempDecl(sc, null))
return errorRet();
if (auto tempinst = isAliasSeq(sc, ti))
{
s = aliasAssignInPlace(sc, tempinst, aliassym);
if (!s)
return errorRet();
goto Lsymdone;
}
}

/* This section is needed because Type.resolve() will:
* const x = 3;
* alias y = x;
* try to convert identifier x to 3.
*/
auto s = ds.type.toDsymbol(sc);
s = ds.type.toDsymbol(sc);
if (errors != global.errors)
return errorRet();
if (s == aliassym)
Expand Down Expand Up @@ -6784,6 +6803,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)

if (s) // it's a symbolic alias
{
Lsymdone:
//printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
aliassym.type = null;
aliassym.aliassym = s;
Expand Down Expand Up @@ -6812,6 +6832,135 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
ds.semanticRun = PASS.semanticdone;
}

/***************************************
* Expands template instance arguments inside 'alias assign' target declaration (aliassym),
* instead of inside 'tempinst.tiargs' every time.
* Params:
* tempinst = AliasSeq instance
* aliassym = the AliasDeclaration corresponding to AliasAssign
* Returns:
* null.
*/
private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst,
AliasDeclaration aliassym)
{
// Mark instance with semantic done, not needed but just in case.
tempinst.inst = tempinst;
tempinst.semanticRun = PASS.semanticdone;
TupleDeclaration td;
if (aliassym.type)
{
// Convert TypeTuple to TupleDeclaration to avoid back and forth allocations
// in the assignment process
if (auto tt = aliassym.type.isTypeTuple())
{
auto objs = new Objects(tt.arguments.length);
foreach (i, p; *tt.arguments)
(*objs)[i] = p.type;
td = new TupleDeclaration(tempinst.loc, aliassym.ident, objs);
td.storage_class |= STC.templateparameter;
td.building = true;
aliassym.type = null;
}
else if (aliassym.type.isTypeError())
return null;

}
else if (auto otd = aliassym.aliassym.isTupleDeclaration())
{
if (otd.building)
td = otd;
else
{
td = new TupleDeclaration(tempinst.loc, aliassym.ident, otd.objects.copy());
td.storage_class |= STC.templateparameter;
td.building = true;
}
}
// If starting from single element in aliassym (td == null) we need to build the tuple
// after semanticTiargs to keep same semantics (for example a FuncLiteraldeclaration
// template argument is converted to FuncExp)
if (td)
aliassym.aliassym = td;
aliassym.semanticRun = PASS.semanticdone;
if (!TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td))
{
tempinst.errors = true;
return null;
}
// The alias will stop tuple 'building' mode when used (in AliasDeclaration.toAlias(),
// then TupleDeclaration.getType() will work again)
aliassym.semanticRun = PASS.initial;
if (!td)
{
td = new TupleDeclaration(tempinst.loc, aliassym.ident, tempinst.tiargs);
td.storage_class |= STC.templateparameter;
td.building = true;
return td;
}

auto tiargs = tempinst.tiargs;
size_t oldlen = td.objects.length;
size_t origstart;
size_t insertidx;
size_t insertlen;
foreach (i, o; *tiargs)
{
if (o !is td)
{
++insertlen;
continue;
}
// tuple contains itself (tuple = AliasSeq!(..., tuple, ...))
if (insertlen) // insert any left element before
{
td.objects.insert(insertidx, (*tiargs)[i - insertlen .. i]);
if (insertidx == 0) // reset original tuple start point
origstart = insertlen;
insertlen = 0;
}
if (insertidx) // insert tuple if found more than one time
{
td.objects.reserve(oldlen); // reserve first to assert a valid slice
td.objects.pushSlice((*td.objects)[origstart .. origstart + oldlen]);
}
insertidx = td.objects.length;
}
if (insertlen)
{
if (insertlen != tiargs.length) // insert any left element
td.objects.pushSlice((*tiargs)[$ - insertlen .. $]);
else
// just assign tiargs if tuple = AliasSeq!(nottuple, nottuple...)
td.objects = tempinst.tiargs;
}
return td;
}

/***************************************
* Check if a template instance is a trivial AliasSeq but without other overloads.
* We can only be 100% sure of being AliasSeq after running semanticTiargs()
* and findBestMatch() but this optimization must happen before that.
*/
private TemplateInstance isAliasSeq(Scope* sc, TypeInstance ti)
{
auto tovers = ti.tempinst.tempdecl.isOverloadSet();
foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
{
Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempinst.tempdecl;
int r = overloadApply(dstart, (Dsymbol s)
{
auto td = s.isTemplateDeclaration();
if (!td || !td.isTrivialAliasSeq)
return 1;
return 0;
});
if (r)
return null;
}
return ti.tempinst;
}

/***************************************
* Find all instance fields in `ad`, then push them into `fields`.
*
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -6564,10 +6564,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* tiargs array of template arguments
* flags 1: replace const variables with their initializers
* 2: don't devolve Parameter to Type
* atd tuple being optimized. If found, it's not expanded here
* but in AliasAssign semantic.
* Returns:
* false if one or more arguments have errors.
*/
extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags)
extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
{
// Run semantic on each argument, place results in tiargs[]
//printf("+TemplateInstance.semanticTiargs()\n");
Expand Down Expand Up @@ -6767,6 +6769,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol
TupleDeclaration d = sa.toAlias().isTupleDeclaration();
if (d)
{
if (d is atd)
{
(*tiargs)[j] = d;
continue;
}
// Expand tuple
tiargs.remove(j);
tiargs.insert(j, d.objects);
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -5787,8 +5787,9 @@ class TupleDeclaration final : public Declaration
{
public:
Array<RootObject* >* objects;
bool isexp;
TypeTuple* tupletype;
bool isexp;
bool building;
TupleDeclaration* syntaxCopy(Dsymbol* s) override;
const char* kind() const override;
Type* getType() override;
Expand Down
18 changes: 18 additions & 0 deletions compiler/src/dmd/root/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,16 @@ public:
}
}

extern (D) void insert(size_t index, T[] a) pure nothrow
{
size_t d = a.length;
reserve(d);
if (length != index)
memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof);
memcpy(data.ptr + index, a.ptr, d * T.sizeof);
length += d;
}

void insert(size_t index, T ptr) pure nothrow
{
reserve(1);
Expand Down Expand Up @@ -414,6 +424,14 @@ unittest
arrayA.zero();
foreach(e; arrayA)
assert(e == 0);

arrayA.setDim(0);
arrayA.pushSlice([5, 6]);
arrayA.insert(1, [1, 2]);
assert(arrayA[] == [5, 1, 2, 6]);
arrayA.insert(0, [7, 8]);
arrayA.insert(arrayA.length, [0, 9]);
assert(arrayA[] == [7, 8, 5, 1, 2, 6, 0, 9]);
}

/**
Expand Down
Loading

0 comments on commit 10d62fc

Please sign in to comment.