Issue 4397 - const/CTFE does not work
Summary: const/CTFE does not work
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other All
: P1 major
Assignee: No Owner
URL:
Keywords: CTFE, performance, wrong-code
Depends on: 9953
Blocks:
  Show dependency treegraph
 
Reported: 2010-06-27 10:30 UTC by nfxjfg
Modified: 2019-05-11 17:00 UTC (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description nfxjfg 2010-06-27 10:30:32 UTC
In the following example, foo() will create an array literal on each call, instead of returning a statically shared / compile time value. On D2, the same may happen when using enum instead of const (I didn't test it).

In many cases, this codegen bug may go unnoticed, which makes it just worse.

$ cat rtz.d
struct X {
    int[] a;
}

const cX = X([1,2]);

X foo() {
    return cX;
}

$ dmd -c rtz.d
$ objdump -d -Mintel rtz.o -r
...
00000000 <_D3rtz3fooFZS3rtz1X>:
   0:   55                      push   ebp
   1:   8b ec                   mov    ebp,esp
   3:   83 ec 08                sub    esp,0x8
   6:   53                      push   ebx
   7:   6a 02                   push   0x2
   9:   6a 01                   push   0x1
   b:   6a 02                   push   0x2
   d:   b8 00 00 00 00          mov    eax,0x0
                        e: R_386_32     _D11TypeInfo_Ai6__initZ
  12:   50                      push   eax
  13:   e8 fc ff ff ff          call   14 <_D3rtz3fooFZS3rtz1X+0x14>
                        14: R_386_PC32  _d_arrayliteralT
  18:   89 c1                   mov    ecx,eax
  1a:   bb 02 00 00 00          mov    ebx,0x2
  1f:   89 5d f8                mov    DWORD PTR [ebp-0x8],ebx
  22:   89 4d fc                mov    DWORD PTR [ebp-0x4],ecx
  25:   8b 55 fc                mov    edx,DWORD PTR [ebp-0x4]
  28:   8b 45 f8                mov    eax,DWORD PTR [ebp-0x8]
  2b:   83 c4 10                add    esp,0x10
  2e:   5b                      pop    ebx
  2f:   c9                      leave  
  30:   c3                      ret
Comment 1 nfxjfg 2010-07-11 22:02:35 UTC
Does anyone know a workaround for this?
It's starting to get annoying, and Walter probably died, so it will take a while until this is fixed.
Comment 2 nfxjfg 2010-07-11 22:04:16 UTC
(Wrong code on v2.046 too, when switching const with enum.)
Comment 3 Don 2010-07-26 01:25:23 UTC
This generated code is identical on 1.020: this is not a regression. Downgrading to major.
I don't see any evidence that it's wrong-code, either: it seems to be a performance issue. Finally, it looks like a duplicate of bug 2356.
Comment 4 anonymous4 2010-07-28 12:04:59 UTC
Shouldn't literals be immutable and the code - invalid?
Comment 5 Don 2010-07-28 12:29:57 UTC
(In reply to comment #4)
> Shouldn't literals be immutable and the code - invalid?

I think they *should*. I argued strongly for immutable array literals. But I lost.
So the code is valid, but likely to be very slow for a very long time.
Comment 6 nfxjfg 2010-07-28 13:05:25 UTC
It's not valid. This is a systems programming language, and the compiler can't just randomly insert memory allocations. What if you wrote a kernel in D? I insist on the wrong-code keyword.
Comment 7 nfxjfg 2010-07-28 13:06:29 UTC
>and the compiler can't just randomly insert memory allocations.
Add "that are not supposed to be there".
Comment 8 anonymous4 2010-07-28 19:57:40 UTC
Well... there can be a problem with immutable literals because immutability is transitive... hmm...
Even if literals aren't immutable, compiler can still catch assignment of literal to mutable array and report error.
Comment 9 Don 2010-07-28 23:01:36 UTC
(In reply to comment #8)
> Well... there can be a problem with immutable literals because immutability is
> transitive... hmm...
> Even if literals aren't immutable, compiler can still catch assignment of
> literal to mutable array and report error.

But it is EXPLICITLY LEGAL to assign a literal to a mutable array. There is an invisible dup by design. I don't like this, I argued strongly against it, but it's in there. This isn't wrong code.
(Similarly, you can write const C x = new C; The C will be allocated on the heap, even though it will never change afterwards).
Comment 10 Christian Kamm 2010-07-29 07:40:11 UTC
The main problem from my point of view is that this fails:

struct X {
    int[] a;
}

const cX = X([1,2]);

void main()
{
  assert(cX.a.ptr is cX.a.ptr);
}

Which is an issue very similar to bug 2526 .
Comment 11 nfxjfg 2010-09-01 12:34:43 UTC
Btw. this is a CTFE problem, and the first example is in D1. I don't know what the hell is with D2 and immutable and implicit dups, but to get the same behavior on D2, replace const with enum.

The array should be on the *datsegment*, not somehow constructed on the fly.

Not sure about the exact testcase in bug 2356, but it's definitely different from writing "int[3] x; x[] = [1,2,3];".
Comment 12 nfxjfg 2010-10-23 06:58:06 UTC
I just noticed that the wrong-code keyword is gone.
Sorry that's just bullshit.
Comment 13 yebblies 2012-02-01 20:32:18 UTC

*** This issue has been marked as a duplicate of issue 2526 ***
Comment 14 Don 2012-02-02 06:16:18 UTC
This isn't the same as bug 2526, which is an accepts-invalid bug. This has nothing to do with templates.

The glue layer needs to detect when a constant is being initialized with an array literal, and when that happens, change it into a value on the static data segment (ie, it needs to create an XXXinit initializer). Doing this would also help with bug 2356, but it isn't the same. (Bug 2356 will often need to create values at runtime, so it will need to copy data from the initializer).
Comment 15 Don 2013-03-19 04:51:15 UTC
It passes if you specify the type in the const/enum.

The reason is, that in declaration.c, VarDeclaration::semantic(), we see this code:

else if (storage_class & (STCconst | STCimmutable | STCmanifest) ||
                 type->isConst() || type->isImmutable())
        {
            /* Because we may need the results of a const declaration in a
             * subsequent type, such as an array dimension, before semantic2()
             * gets ordinarily run, try to run semantic2() now.
             * Ignore failure.
             */
            if (!global.errors && !inferred)
                 ....

If we're inferring type inference, then semantic2 doesn't get run on the variable declaration (cX in the original bug report).

So when it runs semantic on "return cx;", DsymbolExp::semantic() for cx, returns cx->init, which hasn't had semantic run on it yet. So it behaves like a copy-and-paste of the initializer.
Comment 16 Don 2013-04-18 01:54:50 UTC
There is no compiler bug here, it is working as designed, at least for D2.
However, the design doesn't make sense. I have opened bug 9953 for the design change.

It would be possible to give the desired behaviour in D1, though it's hardly worthwhile. In D2 I think it is a logical impossibility. IMHO this should just fail to compile. You should write "static const" instead of "enum" when you want to declare a constant of a reference type.
Comment 17 Mathias LANG 2019-05-11 17:00:39 UTC
This works fine in D2: `enum` gives you a new value every time, but `[static] immutable` does what you expect.