Re: Using C++ Classes From D: dmd cannot link, while ldc segfault

2023-06-19 Thread mw via Digitalmars-d-learn

If I use array:

```
extern(C++) {

void getInts(core.stdcpp.array.array!(int, 10) vec) {
  foreach (int i; 0 .. 10) {
vec.at(i) = i;
  }
}

}
```

```
#include 
using namespace std;

void getInts(array* vector);
```

Both DMD and LDC has link error:

base.cpp:42: undefined reference to `getInts(std::array10ul>*)'


Re: Using C++ Classes From D: dmd cannot link, while ldc segfault

2023-06-19 Thread Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn

On 19/06/2023 5:54 PM, mw wrote:
Ha, I saw vector.d there, So I can use this vector.d as the D side of 
C++'s std::vector?


Probably, I just don't know how well tested it is.

But worth a go!


Re: Using C++ Classes From D: dmd cannot link, while ldc segfault

2023-06-19 Thread mw via Digitalmars-d-learn
On Monday, 19 June 2023 at 05:56:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

On 19/06/2023 5:54 PM, mw wrote:
Ha, I saw vector.d there, So I can use this vector.d as the D 
side of C++'s std::vector?


Probably, I just don't know how well tested it is.

But worth a go!


```
import core.stdcpp.vector;

extern(C++) {

void getInts(core.stdcpp.vector.vector!(int) vec) {
  foreach (int i; 0 .. 10) {
vec.push_back(i);
  }
}

}
```

dmd v2.104.0 failed:

```
/usr/include/dmd/druntime/import/core/stdcpp/vector.d(58): Error: 
undefined identifier `size`, did you mean alias `size_t`?
/usr/include/dmd/druntime/import/core/stdcpp/vector.d(33): Error: 
template instance `core.stdcpp.vector.vector!(int, 
allocator!int)` error instantiating

main.d(32):instantiated from here: `vector!int`
```

LDC - the LLVM D compiler (1.32.2):
```
main.d(32): Error: undefined identifier `vector` in module 
`core.stdcpp.vector`, did you mean enum member `MIctor`?

```

So what's wrong the LDC? how do I write 
`core.stdcpp.vector.vector` then?


Re: How does D’s ‘import’ work?

2023-06-19 Thread rempas via Digitalmars-d-learn

On Sunday, 18 June 2023 at 20:24:10 UTC, Cecil Ward wrote:


I wasn’t intending to use DMD, rather ldc if possible or GDC 
because of their excellent optimisation, in which DMD seems 
lacking, is that fair? (Have only briefly looked at dmd+x86 and 
haven’t given DMD’s back end a fair trial.)


Other than the execution runtime, one other very important 
problem with DMD that wasn't refered is that is only support x86 
and x86_64. LDC and GDC support LLVM's and GCC's architectures 
respectively.


Re: How does D’s ‘import’ work?

2023-06-19 Thread rempas via Digitalmars-d-learn

On Sunday, 18 June 2023 at 20:17:50 UTC, Cecil Ward wrote:


target.obj: target.c include1.h include2.h cc.exe
cc target.c

and you either have to pray that you have kept the list of .h 
files that are mentioned inside target.c and other .h files 
referenced recursively from within these .h files etc. I listed 
the compiler as a dependency too, and I should really have a 
pseudo-target somehow that depends on the nature of the command 
line because changing the command line affects the generated 
code. If you have an automaking compiler that will generate the 
list of .h files then that’s so, so much safer.


First of all, If we are talking about C files, D can import and 
compile them so you don't even need a Makefile! Now, if you need 
to compile C++ files and then either link or create a library 
(and link with it from the D project), then you can just run Dub 
in the end of the job in your make file! You can then have a 
variable called `DUB_FLAGS` in your Makefile and this is where 
the arguments that will be passed for the Dub will be. Will this 
be good enough for you?


Re: How does D’s ‘import’ work?

2023-06-19 Thread Cecil Ward via Digitalmars-d-learn

On Monday, 19 June 2023 at 08:46:31 UTC, rempas wrote:

On Sunday, 18 June 2023 at 20:17:50 UTC, Cecil Ward wrote:


target.obj: target.c include1.h include2.h cc.exe
cc target.c

and you either have to pray that you have kept the list of .h 
files that are mentioned inside target.c and other .h files 
referenced recursively from within these .h files etc. I 
listed the compiler as a dependency too, and I should really 
have a pseudo-target somehow that depends on the nature of the 
command line because changing the command line affects the 
generated code. If you have an automaking compiler that will 
generate the list of .h files then that’s so, so much safer.


First of all, If we are talking about C files, D can import and 
compile them so you don't even need a Makefile! Now, if you 
need to compile C++ files and then either link or create a 
library (and link with it from the D project), then you can 
just run Dub in the end of the job in your make file! You can 
then have a variable called `DUB_FLAGS` in your Makefile and 
this is where the arguments that will be passed for the Dub 
will be. Will this be good enough for you?


If I have sources to all the library routines, not libraries or 
.obj files. I am simply completely ignorant about the D tools 
including DUB, so off to do some reading. I’ve just been seeing 
how good LDC and GDC are, and the answer is extremely, especially 
LDC, which perhaps has a slight edge in code generation quality. 
I haven’t looked at AAarch64 code yet, only AMD64. Very impressed 
with all the work!


Re: SIMD c = a op b

2023-06-19 Thread Guillaume Piolat via Digitalmars-d-learn

On Sunday, 18 June 2023 at 05:01:16 UTC, Cecil Ward wrote:

On Sunday, 18 June 2023 at 04:54:08 UTC, Cecil Ward wrote:

Is it true that this doesn’t always work (in either branch)?

float4 a,b;
static if (__traits(compiles, a/b))
c = a / b;
else
c[] = a[] / b[];



It's because SIMD stuff doesn't always works that 
intel-intrinsics was created. It insulates you from the compiler 
underneath.



import inteli.emmintrin;

void main()
{
float4 a, b, c;
c = a / b;// _always_ works
c = _mm_div_ps(a, b); // _always_ works
}

Sure in some case it may emulate those vectors, but for vector of 
float it's only in DMD -m32. It relies on excellent __vector work 
made a long time ago, and supplements it.


For 32-byte vectors such as __vector(float[8]), you will have 
trouble on GDC when -mavx isn't there, or with DMD.


Do you think the builtin __vector support the same operations 
across the compilers? The answer is "it's getting there", in the 
meanwhile using intel-intrinsics will lower your exposure to the 
compiler woes.
If you want to use DMD and -O -inline, you should also expect 
much more problems unless working extra in order to have SIMD.






Re: How does D’s ‘import’ work?

2023-06-19 Thread rempas via Digitalmars-d-learn

On Monday, 19 June 2023 at 12:48:26 UTC, Cecil Ward wrote:


If I have sources to all the library routines, not libraries or 
.obj files. I am simply completely ignorant about the D tools 
including DUB, so off to do some reading. I’ve just been seeing 
how good LDC and GDC are, and the answer is extremely, 
especially LDC, which perhaps has a slight edge in code 
generation quality. I haven’t looked at AAarch64 code yet, only 
AMD64. Very impressed with all the work!


Of course, DMD uses it's own custom backend so it's only fair to 
not expect for it to have the same runtime performance and 
optimizations as the other two compilers than use LLVM and GCC. 
If you only use x86_64, DMD will be amazing for your debug cycles!


GC doesn't collect where expected

2023-06-19 Thread axricard via Digitalmars-d-learn
I'm doing some experiments with ldc2 GC, by instrumenting it and 
printing basic information (what is allocated and freed)


My first tests are made on this sample :

```

cat test2.d

import core.memory;

class Bar { int bar; }

class Foo {

  this()
  {
this.bar = new Bar;
  }

  Bar bar;
}


void func()
{
  Foo f2 = new Foo;
}

int main()
{
  Foo f = new Foo;

  func();
  GC.collect();

  return 0;
}

```

When trying to run the instrumented druntime, I get a strange 
behavior : the first collection (done with GC.collect) doesn't 
sweep anything (in particular, it doesn't sweep memory allocated 
in _func()_). The whole sweeping is done when program finish, at 
cleanup. I don't understand why : memory allocated in _func()_ 
shouldn't be accessible from any root at first collection, right ?


```
╰─> /instrumented-ldc2 -g -O0 test2.d --disable-gc2stack 
--disable-d-passes --of test2  &&  ./test2 
"--DRT-gcopt=cleanup:collect fork:0 parallel:0 verbose:2"



[test2.d:26] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d000
[test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d020
[test2.d:21] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d040
[test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d060

 COLLECTION  =
= MARKING ==
marking range: [0x7fff22337a60..0x7fff22339000] (0x15a0)
range: [0x7f3a0454d000..0x7f3a0454d020] (0x20)
range: [0x7f3a0454d040..0x7f3a0454d060] (0x20)
marking range: [0x7f3a0464d720..0x7f3a0464d8b9] (0x199)
marking range: [0x46c610..0x47b3b8] (0xeda8)
= SWEEPING ==
=


 COLLECTION  =
= MARKING ==
marking range: [0x46c610..0x47b3b8] (0xeda8)
= SWEEPING ==
Freeing test2.Foo (test2.d:26; 24 bytes) 
(0x7f3a0454d000). AGE :  1/2
Freeing test2.Bar (test2.d:10; 20 bytes) 
(0x7f3a0454d020). AGE :  1/2
Freeing test2.Foo (test2.d:21; 24 bytes) 
(0x7f3a0454d040). AGE :  1/2
Freeing test2.Bar (test2.d:10; 20 bytes) 
(0x7f3a0454d060). AGE :  1/2

=
```



Re: GC doesn't collect where expected

2023-06-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/23 12:13 PM, axricard wrote:
I'm doing some experiments with ldc2 GC, by instrumenting it and 
printing basic information (what is allocated and freed)


My first tests are made on this sample :

```

cat test2.d

import core.memory;

class Bar { int bar; }

class Foo {

   this()
   {
     this.bar = new Bar;
   }

   Bar bar;
}


void func()
{
   Foo f2 = new Foo;
}

int main()
{
   Foo f = new Foo;

   func();
   GC.collect();

   return 0;
}

```

When trying to run the instrumented druntime, I get a strange behavior : 
the first collection (done with GC.collect) doesn't sweep anything (in 
particular, it doesn't sweep memory allocated in _func()_). The whole 
sweeping is done when program finish, at cleanup. I don't understand why 
: memory allocated in _func()_ shouldn't be accessible from any root at 
first collection, right ?


```
╰─> /instrumented-ldc2 -g -O0 test2.d --disable-gc2stack 
--disable-d-passes --of test2  &&  ./test2 "--DRT-gcopt=cleanup:collect 
fork:0 parallel:0 verbose:2"



[test2.d:26] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d000
[test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d020
[test2.d:21] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d040
[test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d060

 COLLECTION  =
     = MARKING ==
     marking range: [0x7fff22337a60..0x7fff22339000] (0x15a0)
     range: [0x7f3a0454d000..0x7f3a0454d020] (0x20)
     range: [0x7f3a0454d040..0x7f3a0454d060] (0x20)
     marking range: [0x7f3a0464d720..0x7f3a0464d8b9] (0x199)
     marking range: [0x46c610..0x47b3b8] (0xeda8)
     = SWEEPING ==
=


 COLLECTION  =
     = MARKING ==
     marking range: [0x46c610..0x47b3b8] (0xeda8)
     = SWEEPING ==
     Freeing test2.Foo (test2.d:26; 24 bytes) (0x7f3a0454d000). AGE 
:  1/2
     Freeing test2.Bar (test2.d:10; 20 bytes) (0x7f3a0454d020). AGE 
:  1/2
     Freeing test2.Foo (test2.d:21; 24 bytes) (0x7f3a0454d040). AGE 
:  1/2
     Freeing test2.Bar (test2.d:10; 20 bytes) (0x7f3a0454d060). AGE 
:  1/2

=
```



In general, the language does not guarantee when the GC will collect 
your item.


In this specific case, most likely it's a stale register or stack 
reference. One way I usually use to ensure such things is to call a 
function that destroys the existing stack:


```d
void clobber()
{
   int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 on the stack.

-Steve


Re: GC doesn't collect where expected

2023-06-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/23 12:51 PM, Anonymouse wrote:

On Monday, 19 June 2023 at 16:43:30 UTC, Steven Schveighoffer wrote:


In this specific case, most likely it's a stale register or stack 
reference. One way I usually use to ensure such things is to call a 
function that destroys the existing stack:


```d
void clobber()
{
   int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 on the 
stack.


Could you elaborate on how you use this? When do you call it? Just, ever 
so often, or is there thought behind it?


Just before forcing a collect.

The stack is *always* scanned conservatively, and even though really the 
stack data should be blown away by the next function call (probably 
GC.collect), it doesn't always work out that way. Indeed, even just 
declaring `x` might not do it if the compiler decides it doesn't 
actually have to.


But I've found that seems to help.

-Steve


Re: GC doesn't collect where expected

2023-06-19 Thread axricard via Digitalmars-d-learn
On Monday, 19 June 2023 at 16:43:30 UTC, Steven Schveighoffer 
wrote:
In general, the language does not guarantee when the GC will 
collect your item.


In this specific case, most likely it's a stale register or 
stack reference. One way I usually use to ensure such things is 
to call a function that destroys the existing stack:


```d
void clobber()
{
   int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 
on the stack.


-Steve


All clear, thank you !


Re: GC doesn't collect where expected

2023-06-19 Thread Anonymouse via Digitalmars-d-learn
On Monday, 19 June 2023 at 16:43:30 UTC, Steven Schveighoffer 
wrote:


In this specific case, most likely it's a stale register or 
stack reference. One way I usually use to ensure such things is 
to call a function that destroys the existing stack:


```d
void clobber()
{
   int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 
on the stack.


-Steve


Could you elaborate on how you use this? When do you call it? 
Just, ever so often, or is there thought behind it?


Re: GC doesn't collect where expected

2023-06-19 Thread axricard via Digitalmars-d-learn
On Monday, 19 June 2023 at 16:43:30 UTC, Steven Schveighoffer 
wrote:


In general, the language does not guarantee when the GC will 
collect your item.


In this specific case, most likely it's a stale register or 
stack reference. One way I usually use to ensure such things is 
to call a function that destroys the existing stack:


```d
void clobber()
{
   int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 
on the stack.


-Steve


Does it mean that if my function _func()_ is as following (say I 
don't use clobber), I could keep a lot of memory for a very long 
time (until the stack is fully erased by other function calls) ?



```
void func()
{
   Foo[2048] x;
   foreach(i; 0 .. 2048)
 x[i] = new Foo;
}
```



is ref inout redundant in: ref inout(T) opIndex(size_t index)

2023-06-19 Thread mw via Digitalmars-d-learn

Hi, I just saw this line:

https://github.com/dlang/dmd/blob/master/druntime/src/core/stdcpp/vector.d#LL66C5-L66C39
```
66:ref inout(T) opIndex(size_t index) inout pure nothrow 
@safe @nogc   { return as_array[index]; }

```

I'm wondering if the `ref` and `inout` redundant here? They both 
mean the same thing? in C++ terms both return the reference of 
the i-th element? so only one of them should be enough?


If not, can someone help to explain the difference? the following 
4 return types:


1) `ref T` alone
2) `inout T` alone
3) `ref inout(T)`
4) `inout ref(T)`


BTW, what does the second `inout` before `pure` do? it's also 
redundant?


Thanks.



Re: GC doesn't collect where expected

2023-06-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/23 2:01 PM, axricard wrote:



Does it mean that if my function _func()_ is as following (say I don't 
use clobber), I could keep a lot of memory for a very long time (until 
the stack is fully erased by other function calls) ?



```
void func()
{
    Foo[2048] x;
    foreach(i; 0 .. 2048)
  x[i] = new Foo;
}
```



When the GC stops all threads, each of them registers their *current* 
stack as the target to scan, so most likely not.


However, the compiler/optimizer is not trying to zero out stack 
unnecessarily, and likely this leads in some cases to false pointers. 
Like I said, even the "clobber" function might not actually zero out any 
stack because the compiler decides writing zeros to the stack that will 
never be read is a "dead store" and just omit that.


This question comes up somewhat frequently "why isn't the GC collecting 
the garbage I gave it!", and the answer is mostly "don't worry about 
it". There is no real good way to guarantee an interaction between the 
compiler, the optimizer, and the runtime to make sure something happens 
one way or another. The only thing you really should care about is if 
you have a reference to an item and it's prematurely collected. Then 
there is a bug. Other than that, just don't worry about it.


-Steve


Re: is ref inout redundant in: ref inout(T) opIndex(size_t index)

2023-06-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/23 2:19 PM, mw wrote:

Hi, I just saw this line:

https://github.com/dlang/dmd/blob/master/druntime/src/core/stdcpp/vector.d#LL66C5-L66C39
```
66:    ref inout(T) opIndex(size_t index) inout pure nothrow @safe 
@nogc   { return as_array[index]; }

```

I'm wondering if the `ref` and `inout` redundant here? They both mean 
the same thing? in C++ terms both return the reference of the i-th 
element? so only one of them should be enough?


No, they do not both mean the same thing. inout is a form of mutability 
that is unique to D. It does *not* mean the same as `ref` like other 
languages (or even D1).


What `inout` does is forward the mutability of the parameter to the 
return type.




If not, can someone help to explain the difference? the following 4 
return types:


1) `ref T` alone


a reference to a T.


2) `inout T` alone


An inout T passed by value. Sorry for the recursive definition, but 
inout is kinda unique with D.



3) `ref inout(T)`


A reference to an inout T.


4) `inout ref(T)`


I'm not sure that's valid. `ref` is a storage class, not a type modifier.


BTW, what does the second `inout` before `pure` do? it's also redundant?


This is the qualifier put onto the `this` parameter (i.e. the `vector` 
in this case).


Because of this, you get the mutability of the parameter forwarded to 
the return type.


```d
const vector!int c;
immutable vector!int i;
vector!int m;

static assert(is(typeof(c[0]) == const(int)));
static assert(is(typeof(i[0]) == immutable(int)));
static assert(is(typeof(m[0]) == int));
```

I gave a presentation on const/inout, which you might find helpful.

https://dconf.org/2016/talks/schveighoffer.html

-Steve