Skip to content

Commit 10d62fc

Browse files
BorisCarvajaldlang-bot
authored andcommitted
Optimize AliasAssign tuple building
1 parent cac3f6b commit 10d62fc

File tree

8 files changed

+329
-12
lines changed

8 files changed

+329
-12
lines changed

compiler/src/dmd/declaration.d

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,8 +563,9 @@ extern (C++) abstract class Declaration : Dsymbol
563563
extern (C++) final class TupleDeclaration : Declaration
564564
{
565565
Objects* objects;
566-
bool isexp; // true: expression tuple
567566
TypeTuple tupletype; // !=null if this is a type tuple
567+
bool isexp; // true: expression tuple
568+
bool building; // it's growing in AliasAssign semantic
568569

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

590591
//printf("TupleDeclaration::getType() %s\n", toChars());
591-
if (isexp)
592+
if (isexp || building)
592593
return null;
593594
if (!tupletype)
594595
{
@@ -931,6 +932,19 @@ extern (C++) final class AliasDeclaration : Declaration
931932
}
932933
else
933934
{
935+
// stop AliasAssign tuple building
936+
if (aliassym)
937+
{
938+
if (auto td = aliassym.isTupleDeclaration())
939+
{
940+
if (td.building)
941+
{
942+
td.building = false;
943+
semanticRun = PASS.semanticdone;
944+
return td;
945+
}
946+
}
947+
}
934948
if (_import && _import._scope)
935949
{
936950
/* If this is an internal alias for selective/renamed import,

compiler/src/dmd/declaration.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ class TupleDeclaration final : public Declaration
166166
{
167167
public:
168168
Objects *objects;
169-
bool isexp; // true: expression tuple
170-
171169
TypeTuple *tupletype; // !=NULL if this is a type tuple
170+
bool isexp; // true: expression tuple
171+
bool building; // it's growing in AliasAssign semantic
172172

173173
TupleDeclaration *syntaxCopy(Dsymbol *) override;
174174
const char *kind() const override;

compiler/src/dmd/dsymbolsem.d

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6332,6 +6332,10 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
63326332
* resolve the alias of eponymous member.
63336333
*/
63346334
tempinst.aliasdecl = tempinst.aliasdecl.toAlias2();
6335+
6336+
// stop AliasAssign tuple building
6337+
if (auto td = tempinst.aliasdecl.isTupleDeclaration())
6338+
td.building = false;
63356339
}
63366340

63376341
Laftersemantic:
@@ -6726,13 +6730,28 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
67266730
*/
67276731

67286732
const errors = global.errors;
6733+
Dsymbol s;
6734+
6735+
// Try AliasSeq optimization
6736+
if (auto ti = ds.type.isTypeInstance())
6737+
{
6738+
if (!ti.tempinst.findTempDecl(sc, null))
6739+
return errorRet();
6740+
if (auto tempinst = isAliasSeq(sc, ti))
6741+
{
6742+
s = aliasAssignInPlace(sc, tempinst, aliassym);
6743+
if (!s)
6744+
return errorRet();
6745+
goto Lsymdone;
6746+
}
6747+
}
67296748

67306749
/* This section is needed because Type.resolve() will:
67316750
* const x = 3;
67326751
* alias y = x;
67336752
* try to convert identifier x to 3.
67346753
*/
6735-
auto s = ds.type.toDsymbol(sc);
6754+
s = ds.type.toDsymbol(sc);
67366755
if (errors != global.errors)
67376756
return errorRet();
67386757
if (s == aliassym)
@@ -6784,6 +6803,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
67846803

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

6835+
/***************************************
6836+
* Expands template instance arguments inside 'alias assign' target declaration (aliassym),
6837+
* instead of inside 'tempinst.tiargs' every time.
6838+
* Params:
6839+
* tempinst = AliasSeq instance
6840+
* aliassym = the AliasDeclaration corresponding to AliasAssign
6841+
* Returns:
6842+
* null.
6843+
*/
6844+
private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst,
6845+
AliasDeclaration aliassym)
6846+
{
6847+
// Mark instance with semantic done, not needed but just in case.
6848+
tempinst.inst = tempinst;
6849+
tempinst.semanticRun = PASS.semanticdone;
6850+
TupleDeclaration td;
6851+
if (aliassym.type)
6852+
{
6853+
// Convert TypeTuple to TupleDeclaration to avoid back and forth allocations
6854+
// in the assignment process
6855+
if (auto tt = aliassym.type.isTypeTuple())
6856+
{
6857+
auto objs = new Objects(tt.arguments.length);
6858+
foreach (i, p; *tt.arguments)
6859+
(*objs)[i] = p.type;
6860+
td = new TupleDeclaration(tempinst.loc, aliassym.ident, objs);
6861+
td.storage_class |= STC.templateparameter;
6862+
td.building = true;
6863+
aliassym.type = null;
6864+
}
6865+
else if (aliassym.type.isTypeError())
6866+
return null;
6867+
6868+
}
6869+
else if (auto otd = aliassym.aliassym.isTupleDeclaration())
6870+
{
6871+
if (otd.building)
6872+
td = otd;
6873+
else
6874+
{
6875+
td = new TupleDeclaration(tempinst.loc, aliassym.ident, otd.objects.copy());
6876+
td.storage_class |= STC.templateparameter;
6877+
td.building = true;
6878+
}
6879+
}
6880+
// If starting from single element in aliassym (td == null) we need to build the tuple
6881+
// after semanticTiargs to keep same semantics (for example a FuncLiteraldeclaration
6882+
// template argument is converted to FuncExp)
6883+
if (td)
6884+
aliassym.aliassym = td;
6885+
aliassym.semanticRun = PASS.semanticdone;
6886+
if (!TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td))
6887+
{
6888+
tempinst.errors = true;
6889+
return null;
6890+
}
6891+
// The alias will stop tuple 'building' mode when used (in AliasDeclaration.toAlias(),
6892+
// then TupleDeclaration.getType() will work again)
6893+
aliassym.semanticRun = PASS.initial;
6894+
if (!td)
6895+
{
6896+
td = new TupleDeclaration(tempinst.loc, aliassym.ident, tempinst.tiargs);
6897+
td.storage_class |= STC.templateparameter;
6898+
td.building = true;
6899+
return td;
6900+
}
6901+
6902+
auto tiargs = tempinst.tiargs;
6903+
size_t oldlen = td.objects.length;
6904+
size_t origstart;
6905+
size_t insertidx;
6906+
size_t insertlen;
6907+
foreach (i, o; *tiargs)
6908+
{
6909+
if (o !is td)
6910+
{
6911+
++insertlen;
6912+
continue;
6913+
}
6914+
// tuple contains itself (tuple = AliasSeq!(..., tuple, ...))
6915+
if (insertlen) // insert any left element before
6916+
{
6917+
td.objects.insert(insertidx, (*tiargs)[i - insertlen .. i]);
6918+
if (insertidx == 0) // reset original tuple start point
6919+
origstart = insertlen;
6920+
insertlen = 0;
6921+
}
6922+
if (insertidx) // insert tuple if found more than one time
6923+
{
6924+
td.objects.reserve(oldlen); // reserve first to assert a valid slice
6925+
td.objects.pushSlice((*td.objects)[origstart .. origstart + oldlen]);
6926+
}
6927+
insertidx = td.objects.length;
6928+
}
6929+
if (insertlen)
6930+
{
6931+
if (insertlen != tiargs.length) // insert any left element
6932+
td.objects.pushSlice((*tiargs)[$ - insertlen .. $]);
6933+
else
6934+
// just assign tiargs if tuple = AliasSeq!(nottuple, nottuple...)
6935+
td.objects = tempinst.tiargs;
6936+
}
6937+
return td;
6938+
}
6939+
6940+
/***************************************
6941+
* Check if a template instance is a trivial AliasSeq but without other overloads.
6942+
* We can only be 100% sure of being AliasSeq after running semanticTiargs()
6943+
* and findBestMatch() but this optimization must happen before that.
6944+
*/
6945+
private TemplateInstance isAliasSeq(Scope* sc, TypeInstance ti)
6946+
{
6947+
auto tovers = ti.tempinst.tempdecl.isOverloadSet();
6948+
foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
6949+
{
6950+
Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempinst.tempdecl;
6951+
int r = overloadApply(dstart, (Dsymbol s)
6952+
{
6953+
auto td = s.isTemplateDeclaration();
6954+
if (!td || !td.isTrivialAliasSeq)
6955+
return 1;
6956+
return 0;
6957+
});
6958+
if (r)
6959+
return null;
6960+
}
6961+
return ti.tempinst;
6962+
}
6963+
68156964
/***************************************
68166965
* Find all instance fields in `ad`, then push them into `fields`.
68176966
*

compiler/src/dmd/dtemplate.d

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6564,10 +6564,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
65646564
* tiargs array of template arguments
65656565
* flags 1: replace const variables with their initializers
65666566
* 2: don't devolve Parameter to Type
6567+
* atd tuple being optimized. If found, it's not expanded here
6568+
* but in AliasAssign semantic.
65676569
* Returns:
65686570
* false if one or more arguments have errors.
65696571
*/
6570-
extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags)
6572+
extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
65716573
{
65726574
// Run semantic on each argument, place results in tiargs[]
65736575
//printf("+TemplateInstance.semanticTiargs()\n");
@@ -6767,6 +6769,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol
67676769
TupleDeclaration d = sa.toAlias().isTupleDeclaration();
67686770
if (d)
67696771
{
6772+
if (d is atd)
6773+
{
6774+
(*tiargs)[j] = d;
6775+
continue;
6776+
}
67706777
// Expand tuple
67716778
tiargs.remove(j);
67726779
tiargs.insert(j, d.objects);

compiler/src/dmd/frontend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5787,8 +5787,9 @@ class TupleDeclaration final : public Declaration
57875787
{
57885788
public:
57895789
Array<RootObject* >* objects;
5790-
bool isexp;
57915790
TypeTuple* tupletype;
5791+
bool isexp;
5792+
bool building;
57925793
TupleDeclaration* syntaxCopy(Dsymbol* s) override;
57935794
const char* kind() const override;
57945795
Type* getType() override;

compiler/src/dmd/root/array.d

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,16 @@ public:
222222
}
223223
}
224224

225+
extern (D) void insert(size_t index, T[] a) pure nothrow
226+
{
227+
size_t d = a.length;
228+
reserve(d);
229+
if (length != index)
230+
memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof);
231+
memcpy(data.ptr + index, a.ptr, d * T.sizeof);
232+
length += d;
233+
}
234+
225235
void insert(size_t index, T ptr) pure nothrow
226236
{
227237
reserve(1);
@@ -414,6 +424,14 @@ unittest
414424
arrayA.zero();
415425
foreach(e; arrayA)
416426
assert(e == 0);
427+
428+
arrayA.setDim(0);
429+
arrayA.pushSlice([5, 6]);
430+
arrayA.insert(1, [1, 2]);
431+
assert(arrayA[] == [5, 1, 2, 6]);
432+
arrayA.insert(0, [7, 8]);
433+
arrayA.insert(arrayA.length, [0, 9]);
434+
assert(arrayA[] == [7, 8, 5, 1, 2, 6, 0, 9]);
417435
}
418436

419437
/**

0 commit comments

Comments
 (0)