Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Static array and array literal improvements #375

Merged
merged 5 commits into from almost 2 years ago

5 participants

Hara Kenji Don Clugston Trass3r Daniel Murphy Walter Bright
Hara Kenji
Collaborator
  • Issue 3703 - static array assignment
    Check static-array length matching on assign expression.

  • Issue 5290 - Static array literals with too few elements
    Check static-array length matching on initialiging.

  • Issue 6470 - postblits not called on arrays of structs
    Call postblits of array literal elements correctly.

  • Issue 2356 - array literal as non static initializer generates horribly inefficient code
    If array literal is used as static-array initializer, the initializing is converted as initializings of elements.
    An initializing of static-array
    S[n] sa = [e0, e1, ..., en-1];
    is converted to
    sa[0] = e0, sa[1] = e1, ..., sa[n-1] = en-1;

  • Issue 6636 - Destructors of static array elements are not called on function parameter

  • Issue 6637 - Postblits of static array elements are not called on function argument

Don Clugston
Collaborator

Your fix for bug 2356 is good when the array is small (length <= about 8), but a full fix would check if all elements are compile-time constants. If they are, create a const initializer, and blit it across.
There are some other optimization opportunities (eg, if most members of the array literals are zeros, or if there are only a couple of non-constants, perform a blit or zero-init first, and then fill in the gaps).

Also note that CTFE can create an array literal as well, so the transformation needs to happen in the glue layer, not in expression.c.

Hara Kenji
Collaborator

Also note that CTFE can create an array literal as well, so the transformation needs to happen in the glue layer, not in expression.c.

I was able to move static array construction codes into AssignExp::toElem(), but I wasn't able to work the interpret() correctly.
Currently, it is difficult to me changing codes of interpret.c.

Don Clugston
Collaborator

Interpret.c should not be changed. Array literals MUST survive until the glue layer.

Hara Kenji
Collaborator

glue layer == e2ir.c ? (I think expression.c is front-end, and src/backend is backend layer.)
If so, I was able to survive array literals until the glue layer, see commit 662b5a3. But I that also means that survives array literals until interpret layer. At least, I had to change interpret.c to compile small sample code.

Hara Kenji
Collaborator

Remove fixing 5290. Because it is not bug fix, it is enhancement.

Trass3r

What prevents this from being merged?
Have all of Don's suggestions been implemented?

Hara Kenji
Collaborator

Have all of Don's suggestions been implemented?

No, and I have no schedule to implement it in near future.

Daniel Murphy
Collaborator

Could you please split this into several pull requests so the smaller issues can be fixed?

added some commits August 26, 2011
Scanning past comma on AssignExp::e2 is not need, because it is alrea…
…dy processed at the starting of semantic.
aa7e809
Issue 3703 - static array assignment 6dfdd2d
Issue 6636 - Destructors of static array elements are not called on f…
…unction parameter

Call dtor of static array parameter at function scope end.
57d7f41
Issue 6637 - Postblits of static array elements are not called on fun…
…ction argument

call element postblits of static array on function argument
2f09427
Issue 6470 - postblits not called on arrays of structs
- Call postblits on array slice assign
- Call postblits on array literal elements
26aacf0
Hara Kenji
Collaborator
9rnsr commented May 05, 2012

Remove commit for bug 2356, and reconstructed commits.
Now, there are fixes for only postblit/destructor and array literal/static array problems.

Walter Bright WalterBright merged commit 385fd46 into from May 07, 2012
Walter Bright WalterBright closed this May 07, 2012
Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 5 unique commits by 1 author.

May 05, 2012
Scanning past comma on AssignExp::e2 is not need, because it is alrea…
…dy processed at the starting of semantic.
aa7e809
Issue 3703 - static array assignment 6dfdd2d
Issue 6636 - Destructors of static array elements are not called on f…
…unction parameter

Call dtor of static array parameter at function scope end.
57d7f41
Issue 6637 - Postblits of static array elements are not called on fun…
…ction argument

call element postblits of static array on function argument
2f09427
Issue 6470 - postblits not called on arrays of structs
- Call postblits on array slice assign
- Call postblits on array literal elements
26aacf0
This page is out of date. Refresh to see the latest.
2  src/e2ir.c
@@ -2753,7 +2753,7 @@ elem *AssignExp::toElem(IRState *irs)
2753 2753
             /* Determine if we need to do postblit
2754 2754
              */
2755 2755
             int postblit = 0;
2756  
-            if (needsPostblit(t1))
  2756
+            if (needsPostblit(t1->nextOf()))
2757 2757
                 postblit = 1;
2758 2758
 
2759 2759
             assert(e2->type->ty != Tpointer);
103  src/expression.c
@@ -770,24 +770,41 @@ void valueNoDtor(Expression *e)
770 770
 #if DMDV2
771 771
 Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope)
772 772
 {
  773
+    if (e->op == TOKarrayliteral)
  774
+    {
  775
+        ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
  776
+        for (size_t i = 0; i < ae->elements->dim; i++)
  777
+        {
  778
+            ae->elements->tdata()[i] =
  779
+                callCpCtor(loc, sc, ae->elements->tdata()[i], noscope);
  780
+        }
  781
+        e = ae->semantic(sc);
  782
+        return e;
  783
+    }
  784
+
773 785
     Type *tb = e->type->toBasetype();
774  
-    assert(tb->ty == Tstruct);
775  
-    StructDeclaration *sd = ((TypeStruct *)tb)->sym;
776  
-    if (sd->cpctor)
777  
-    {
778  
-        /* Create a variable tmp, and replace the argument e with:
779  
-         *      (tmp = e),tmp
780  
-         * and let AssignExp() handle the construction.
781  
-         * This is not the most efficent, ideally tmp would be constructed
782  
-         * directly onto the stack.
783  
-         */
784  
-        Identifier *idtmp = Lexer::uniqueId("__cpcttmp");
785  
-        VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e));
786  
-        tmp->storage_class |= STCctfe;
787  
-        tmp->noscope = noscope;
788  
-        Expression *ae = new DeclarationExp(loc, tmp);
789  
-        e = new CommaExp(loc, ae, new VarExp(loc, tmp));
790  
-        e = e->semantic(sc);
  786
+    Type *tv = tb;
  787
+    while (tv->ty == Tsarray)
  788
+        tv = tv->nextOf()->toBasetype();
  789
+    if (tv->ty == Tstruct)
  790
+    {
  791
+        StructDeclaration *sd = ((TypeStruct *)tv)->sym;
  792
+        if (sd->cpctor)
  793
+        {
  794
+            /* Create a variable tmp, and replace the argument e with:
  795
+             *      (tmp = e),tmp
  796
+             * and let AssignExp() handle the construction.
  797
+             * This is not the most efficent, ideally tmp would be constructed
  798
+             * directly onto the stack.
  799
+             */
  800
+            Identifier *idtmp = Lexer::uniqueId("__cpcttmp");
  801
+            VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e));
  802
+            tmp->storage_class |= STCctfe;
  803
+            tmp->noscope = noscope;
  804
+            Expression *ae = new DeclarationExp(loc, tmp);
  805
+            e = new CommaExp(loc, ae, new VarExp(loc, tmp));
  806
+            e = e->semantic(sc);
  807
+        }
791 808
     }
792 809
     return e;
793 810
 }
@@ -1077,15 +1094,22 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
1077 1094
             }
1078 1095
 
1079 1096
             Type *tb = arg->type->toBasetype();
1080  
-#if !SARRAYVALUE
1081  
-            // Convert static arrays to pointers
1082  
-            if (tb->ty == Tsarray)
  1097
+            if (arg->op == TOKarrayliteral)
1083 1098
             {
1084  
-                arg = arg->checkToPointer();
  1099
+                arg = callCpCtor(loc, sc, arg, 1);
1085 1100
             }
  1101
+            else if (tb->ty == Tsarray)
  1102
+            {
  1103
+#if !SARRAYVALUE
  1104
+                // Convert static arrays to pointers
  1105
+                arg = arg->checkToPointer();
  1106
+#else
  1107
+                // call copy constructor of each element
  1108
+                arg = callCpCtor(loc, sc, arg, 1);
1086 1109
 #endif
  1110
+            }
1087 1111
 #if DMDV2
1088  
-            if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout)))
  1112
+            else if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout)))
1089 1113
             {
1090 1114
                 if (arg->op == TOKcall)
1091 1115
                 {
@@ -10361,16 +10385,6 @@ Expression *AssignExp::semantic(Scope *sc)
10361 10385
                 sd->cpctor)
10362 10386
             {   /* We have a copy constructor for this
10363 10387
                  */
10364  
-                // Scan past commma's
10365  
-                Expression *ec = NULL;
10366  
-                while (e2->op == TOKcomma)
10367  
-                {   CommaExp *ecomma = (CommaExp *)e2;
10368  
-                    e2 = ecomma->e2;
10369  
-                    if (ec)
10370  
-                        ec = new CommaExp(ecomma->loc, ec, ecomma->e1);
10371  
-                    else
10372  
-                        ec = ecomma->e1;
10373  
-                }
10374 10388
                 if (e2->op == TOKquestion)
10375 10389
                 {   /* Write as:
10376 10390
                      *  a ? e1 = b : e1 = c;
@@ -10381,8 +10395,6 @@ Expression *AssignExp::semantic(Scope *sc)
10381 10395
                     AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2);
10382 10396
                     ea2->op = op;
10383 10397
                     Expression *e = new CondExp(loc, econd->econd, ea1, ea2);
10384  
-                    if (ec)
10385  
-                        e = new CommaExp(loc, ec, e);
10386 10398
                     return e->semantic(sc);
10387 10399
                 }
10388 10400
                 else if (e2->op == TOKvar ||
@@ -10398,8 +10410,6 @@ Expression *AssignExp::semantic(Scope *sc)
10398 10410
 
10399 10411
                     Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0);
10400 10412
                     e = new CallExp(loc, e, e2);
10401  
-                    if (ec)
10402  
-                        e = new CommaExp(loc, ec, e);
10403 10413
                     return e->semantic(sc);
10404 10414
                 }
10405 10415
                 else if (e2->op == TOKcall)
@@ -10424,6 +10434,21 @@ Expression *AssignExp::semantic(Scope *sc)
10424 10434
 
10425 10435
     if (t1->ty == Tsarray && !refinit)
10426 10436
     {
  10437
+        Type *t2 = e2->type->toBasetype();
  10438
+
  10439
+        if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf()))
  10440
+        {   // static array assignment should check their lengths
  10441
+            TypeSArray *tsa1 = (TypeSArray *)t1;
  10442
+            TypeSArray *tsa2 = (TypeSArray *)t2;
  10443
+            uinteger_t dim1 = tsa1->dim->toInteger();
  10444
+            uinteger_t dim2 = tsa2->dim->toInteger();
  10445
+            if (dim1 != dim2)
  10446
+            {
  10447
+                error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
  10448
+                return new ErrorExp();
  10449
+            }
  10450
+        }
  10451
+
10427 10452
         if (e1->op == TOKindex &&
10428 10453
             ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
10429 10454
         {
@@ -10435,7 +10460,6 @@ Expression *AssignExp::semantic(Scope *sc)
10435 10460
         }
10436 10461
         else
10437 10462
         {
10438  
-            Type *t2 = e2->type->toBasetype();
10439 10463
             // Convert e2 to e2[], unless e2-> e1[0]
10440 10464
             if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf()))
10441 10465
             {
@@ -10454,6 +10478,11 @@ Expression *AssignExp::semantic(Scope *sc)
10454 10478
     if (!e2->rvalue())
10455 10479
         return new ErrorExp();
10456 10480
 
  10481
+    if (e2->op == TOKarrayliteral)
  10482
+    {
  10483
+        e2 = callCpCtor(loc, sc, e2, 1);
  10484
+    }
  10485
+
10457 10486
     if (e1->op == TOKarraylength)
10458 10487
     {
10459 10488
         // e1 is not an lvalue, but we let code generator handle it
2  src/func.c
@@ -1577,12 +1577,14 @@ void FuncDeclaration::semantic3(Scope *sc)
1577 1577
                     if (v->storage_class & (STCref | STCout))
1578 1578
                         continue;
1579 1579
 
  1580
+#if !SARRAYVALUE
1580 1581
                     /* Don't do this for static arrays, since static
1581 1582
                      * arrays are called by reference. Remove this
1582 1583
                      * when we change them to call by value.
1583 1584
                      */
1584 1585
                     if (v->type->toBasetype()->ty == Tsarray)
1585 1586
                         continue;
  1587
+#endif
1586 1588
 
1587 1589
                     if (v->noscope)
1588 1590
                         continue;
9  test/fail_compilation/fail3703.d
... ...
@@ -0,0 +1,9 @@
  1
+// Issue 3703 - static array assignment
  2
+
  3
+void main()
  4
+{
  5
+    int[1] a = [1];
  6
+    int[2] b;
  7
+
  8
+    b = a;  // should make compile error
  9
+}
75  test/runnable/sdtor.d
@@ -1878,6 +1878,78 @@ void test6177()
1878 1878
 
1879 1879
 
1880 1880
 /**********************************/
  1881
+// 6470
  1882
+
  1883
+struct S6470
  1884
+{
  1885
+    static int spblit;
  1886
+
  1887
+    this(this){ ++spblit; }
  1888
+}
  1889
+
  1890
+void test6470()
  1891
+{
  1892
+    S6470[] a1;
  1893
+    S6470[] a2;
  1894
+    a1.length = 3;
  1895
+    a2.length = 3;
  1896
+    a1[] = a2[];
  1897
+    assert(S6470.spblit == 3);
  1898
+
  1899
+    S6470 s;
  1900
+
  1901
+    S6470[] a3;
  1902
+    a3.length = 3;
  1903
+    a3 = [s, s, s];
  1904
+    assert(S6470.spblit == 6);
  1905
+
  1906
+    void func(S6470[] a){}
  1907
+    func([s, s, s]);
  1908
+    assert(S6470.spblit == 9);
  1909
+}
  1910
+
  1911
+/**********************************/
  1912
+// 6636
  1913
+
  1914
+struct S6636
  1915
+{
  1916
+    ~this()
  1917
+    {
  1918
+        ++sdtor;
  1919
+    }
  1920
+}
  1921
+
  1922
+void func6636(S6636[3] sa) {}
  1923
+
  1924
+void test6636()
  1925
+{
  1926
+    sdtor = 0;
  1927
+
  1928
+    S6636[3] sa;
  1929
+    func6636(sa);
  1930
+    assert(sdtor == 3);
  1931
+}
  1932
+
  1933
+/**********************************/
  1934
+// 6637
  1935
+
  1936
+struct S6637
  1937
+{
  1938
+    static int spblit;
  1939
+
  1940
+    this(this){ ++spblit; }
  1941
+}
  1942
+
  1943
+void test6637()
  1944
+{
  1945
+    void func(S6637[3] sa){}
  1946
+
  1947
+    S6637[3] sa;
  1948
+    func(sa);
  1949
+    assert(S6637.spblit == 3);
  1950
+}
  1951
+
  1952
+/**********************************/
1881 1953
 // 7353
1882 1954
 
1883 1955
 struct S7353
@@ -1984,6 +2056,9 @@ int main()
1984 2056
     test60();
1985 2057
     test4316();
1986 2058
     test6177();
  2059
+    test6470();
  2060
+    test6636();
  2061
+    test6637();
1987 2062
     test7353();
1988 2063
 
1989 2064
     printf("Success\n");
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.