www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - LLM's think we should have language tuples!

reply Manu <turkeyman gmail.com> writes:
I asked Grok to write me a portable 64x64->128 multiplication function in D
to get the pattern, and this is what it wrote:

// Multiplies two 64-bit unsigned integers, returning a 128-bit result as
(low, high)
(ulong, ulong) mul64x64to128(ulong x, ulong y) {
    // Split into 32-bit halves
    uint x_l = cast(uint)x;
    uint x_h = cast(uint)(x >> 32);
    uint y_l = cast(uint)y;
    uint y_h = cast(uint)(y >> 32);

    // Compute partial products
    ulong p_ll = cast(ulong)x_l * y_l;        // Bits 0-63
    ulong p_lh = cast(ulong)x_l * y_h;        // Bits 32-95
    ulong p_hl = cast(ulong)x_h * y_l;        // Bits 32-95
    ulong p_hh = cast(ulong)x_h * y_h;        // Bits 64-127

    ulong low = p_ll;                         // Lower 64 bits
    uint p_lh_low = cast(uint)p_lh;
    uint p_hl_low = cast(uint)p_hl;
    uint p_ll_high = cast(uint)(p_ll >> 32);

    // Compute carry from middle terms
    ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high;
    ulong carry = sum_mid >> 32;

    // Upper 64 bits
    ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry;

    return (low, high);
}


What I loved is that its function returned a pair of ulong's, because
apparently it made an assumption that we had in-language tuples! I wonder
where it got that idea?

We should learn from our AI overlords! :P
Mar 24
next sibling parent claptrap <clap trap.com> writes:
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication 
 function in D to get the pattern, and this is what it wrote:

 // Multiplies two 64-bit unsigned integers, returning a 128-bit 
 result as
 (low, high)
 (ulong, ulong) mul64x64to128(ulong x, ulong y) {
     // Split into 32-bit halves
     uint x_l = cast(uint)x;
     uint x_h = cast(uint)(x >> 32);
     uint y_l = cast(uint)y;
     uint y_h = cast(uint)(y >> 32);

     // Compute partial products
     ulong p_ll = cast(ulong)x_l * y_l;        // Bits 0-63
     ulong p_lh = cast(ulong)x_l * y_h;        // Bits 32-95
     ulong p_hl = cast(ulong)x_h * y_l;        // Bits 32-95
     ulong p_hh = cast(ulong)x_h * y_h;        // Bits 64-127

     ulong low = p_ll;                         // Lower 64 bits
     uint p_lh_low = cast(uint)p_lh;
     uint p_hl_low = cast(uint)p_hl;
     uint p_ll_high = cast(uint)(p_ll >> 32);

     // Compute carry from middle terms
     ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high;
     ulong carry = sum_mid >> 32;

     // Upper 64 bits
     ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry;

     return (low, high);
 }


 What I loved is that its function returned a pair of ulong's, 
 because apparently it made an assumption that we had 
 in-language tuples! I wonder where it got that idea?

 We should learn from our AI overlords! :P
Yeah but not on how to multiply integers. It never adds the low 32 bits of "sum_mid", to the upper 32 bits of "low", plus it would also need to check if that overflowed. something like... ulong tmp = low + (sum_mid << 32); bool carry_from_low = (tmp < low); //** low = tmp; then later: if (carry_from_low) high++; **: if the result of the addition is lower than the initial value then it overflowed
Mar 25
prev sibling next sibling parent Kagamin <spam here.lot> writes:
Well, yes: 
https://forum.dlang.org/post/nydunscuwdcinamqails forum.dlang.org
Mar 25
prev sibling next sibling parent Kagamin <spam here.lot> writes:
Also LLM can be poisoned if it's given fake data: 
https://blog.cloudflare.com/ai-labyrinth/
Mar 26
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/24/2025 9:44 PM, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication function in D to 
 get the pattern, and this is what it wrote:
Cool! Now ask it to write an 80 bit IEEE floating point multiply! (So we can cross compile from Arm to X86!)
Mar 27
parent reply Manu <turkeyman gmail.com> writes:
On Fri, 28 Mar 2025 at 02:16, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On 3/24/2025 9:44 PM, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication function
in D to
 get the pattern, and this is what it wrote:
Cool! Now ask it to write an 80 bit IEEE floating point multiply! (So we can cross compile from Arm to X86!)
I thought we had an arbitrary width float kicking around? I'm sure I've got one floating about somewhere...
Mar 30
parent reply Tim <tim.dlang t-online.de> writes:
On Sunday, 30 March 2025 at 09:25:56 UTC, Manu wrote:
 On Fri, 28 Mar 2025 at 02:16, Walter Bright via Digitalmars-d < 
 digitalmars-d puremagic.com> wrote:
 Cool! Now ask it to write an 80 bit IEEE floating point 
 multiply!

 (So we can cross compile from Arm to X86!)
I thought we had an arbitrary width float kicking around? I'm sure I've got one floating about somewhere...
Do you mean this: https://dlang.org/library/std/numeric/custom_float.html
Mar 30
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/30/2025 4:04 AM, Tim wrote:
 Do you mean this: https://dlang.org/library/std/numeric/custom_float.html
Not good enough: "These formats are for storage only; all operations on them are performed by first implicitly extracting them to real first."
Mar 31
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
Can also just scale up the long arithmetic asm routines that implement 32 bit 
arithmetic on the 16 bit x86.
Mar 27
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/27/2025 9:15 AM, Walter Bright wrote:
 Can also just scale up the long arithmetic asm routines that implement 32 bit 
 arithmetic on the 16 bit x86.
https://github.com/DigitalMars/dmc/blob/master/src/CORE16/LMATH.ASM
Mar 27
parent ryuukk_ <ryuukk.dev gmail.com> writes:
On Thursday, 27 March 2025 at 17:31:54 UTC, Walter Bright wrote:
 On 3/27/2025 9:15 AM, Walter Bright wrote:
 Can also just scale up the long arithmetic asm routines that 
 implement 32 bit arithmetic on the 16 bit x86.
https://github.com/DigitalMars/dmc/blob/master/src/CORE16/LMATH.ASM
here is what deepseek came up with: To convert the provided x86 assembly code for 32-bit arithmetic operations to AARCH64, we leverage ARM's efficient instruction set for multiplication, division, and comparison. Here's the equivalent implementation: ``` .section .text .align 2 .global _LMUL _LMUL : // Unsigned 32-bit multiply, result 64-bit in x0 umull x0, w0, w1 ret .global _ULDIV _ULDIV : // Check for division by zero beq div0_unsigned // Perform unsigned division udiv w2, w0, w1 // Quotient in w2 msub w3, w2, w1, w0 // Remainder in w3 mov w0, w2 // Return quotient mov w1, w3 // Return remainder ret div0_unsigned: // Handle division by zero: return (0xFFFFFFFF, 0) ret .global _LDIV _LDIV : // Check for division by zero beq div0_signed // Perform signed division sdiv w2, w0, w1 // Quotient in w2 msub w3, w2, w1, w0 // Remainder in w3 mov w0, w2 // Return quotient mov w1, w3 // Return remainder ret div0_signed: // Handle division by zero: return (-1, 0) ret .global _LCMP _LCMP : // Compare two signed 32-bit values cmp w0, w1 b.gt .greater b.lt .less ret .greater: ret .less: ret ```
Mar 27
prev sibling next sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication 
 function in D to get the pattern, and this is what it wrote:

 What I loved is that its function returned a pair of ulong's, 
 because apparently it made an assumption that we had 
 in-language tuples! I wonder where it got that idea?

 We should learn from our AI overlords! :P
Note: to get good results from AIs, ask them to write tests as well, then run the tests and post the answers and ask them to debug the issue. :) You have to handhold a bit.
Mar 27
parent reply Manu <turkeyman gmail.com> writes:
On Fri, 28 Mar 2025 at 06:35, FeepingCreature via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication
 function in D to get the pattern, and this is what it wrote:

 What I loved is that its function returned a pair of ulong's,
 because apparently it made an assumption that we had
 in-language tuples! I wonder where it got that idea?

 We should learn from our AI overlords! :P
Note: to get good results from AIs, ask them to write tests as well, then run the tests and post the answers and ask them to debug the issue. :) You have to handhold a bit.
I kinda feel like every commenter in this thread rather missed the point ;) I know how to multiply big numbers; I was just throwing random stuff at it trying to test its limits. The operation is not what I was interested in here; I just liked that it assumed we had tuples! It's right to do so as far as I'm concerned, and it's embarrassing that we don't.
Mar 30
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Sunday, 30 March 2025 at 09:33:26 UTC, Manu wrote:
 On Fri, 28 Mar 2025 at 06:35, FeepingCreature via Digitalmars-d
 Note: to get good results from AIs, ask them to write tests as 
 well, then run the tests and post the answers and ask them to 
 debug the issue. :) You have to handhold a bit.
I kinda feel like every commenter in this thread rather missed the point ;) I know how to multiply big numbers; I was just throwing random stuff at it trying to test its limits. The operation is not what I was interested in here; I just liked that it assumed we had tuples! It's right to do so as far as I'm concerned, and it's embarrassing that we don't.
To be clear, we should absolutely have tuples. :)
Mar 30
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Monday, 31 March 2025 at 05:50:13 UTC, FeepingCreature wrote:
 To be clear, we should absolutely have tuples. :)
Named tuples also, like in Typescript.
Mar 31
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication 
 function in D to get the pattern, and this is what it wrote:
I think it was aware of Int128 and Claude.ai replied as follows: ```d import std.int128; auto mul64x64to128(ulong x, ulong y) { uint x_low = cast(uint)x; uint x_high = cast(uint)(x >> 32); uint y_low = cast(uint)y; uint y_high = cast(uint)(y >> 32); ulong mul_ll = cast(ulong)x_low * y_low; ulong mul_lh = cast(ulong)x_low * y_high; ulong mul_hl = cast(ulong)x_high * y_low; ulong mul_hh = cast(ulong)x_high * y_high; ulong low = mul_ll; ulong high = mul_hh + (mul_hl >> 32) + (mul_lh >> 32); ulong mid = (mul_ll >> 32) + (mul_hl & 0xFFFFFFFF) + (mul_lh & 0xFFFFFFFF); low += (mid & 0xFFFFFFFF) << 32; high += mid >> 32; return Int128(high, low); } ``` SDB 79
Mar 30
prev sibling next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 What I loved is that its function returned a pair of ulong's, 
 because apparently it made an assumption that we had 
 in-language tuples! I wonder where it got that idea?

 We should learn from our AI overlords! :P
Looks like Timon was working on his tuple implementation in February: https://github.com/tgehr/dmd/commits/tuple-syntax/ Also: https://dconf.org/2023/slides/gehr.pdf#page=109
Mar 31
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 3/31/25 22:37, Nick Treleaven wrote:
 On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:
 What I loved is that its function returned a pair of ulong's, because 
 apparently it made an assumption that we had in-language tuples! I 
 wonder where it got that idea?

 We should learn from our AI overlords! :P
Looks like Timon was working on his tuple implementation in February: https://github.com/tgehr/dmd/commits/tuple-syntax/ Also: https://dconf.org/2023/slides/gehr.pdf#page=109
I was working a bit on unpacking, though I think it was mostly rebasing to master after that had undergone refactorings. It is more or less ready (and OpenD already pulled the current state), but there are various small things to finish. E.g.: - expanding a zero-element tuple does not work properly yet (in general, even unrelated to unpacking) https://github.com/dlang/dmd/issues/20842 I though I would have time to maybe fix this, but got sidetracked last time I attempted to see it through. - Unpacking does not yet support auto-expanding, for example: (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3); does not work yet. - I need to write an extensive test suite and address anything it may catch. - I have to write the DIP and suffer through the bikeshedding on the forum. Of course, one way to continue would be to just write tests for what works and pull this (e.g., behind a -preview switch) and to allow anyone who can spend the time required to take over the polishing effort. In general, I still fully intend to finish this, but I don't know when I will manage to get it over the finish line at the level of quality I think is perfect. It has already taken way too long, mostly because I have not been able to focus on this for any significant amount of time beside my day job and various other obligations.
Apr 01
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:
  It is more or less ready (and OpenD already pulled the current 
 state), but there are various small things to finish.
Good to hear.
 E.g.:

 - expanding a zero-element tuple does not work properly yet (in 
 general, even unrelated to unpacking)
   https://github.com/dlang/dmd/issues/20842
   I though I would have time to maybe fix this, but got 
 sidetracked last time I attempted to see it through.

 - Unpacking does not yet support auto-expanding, for example:

   (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3);

   does not work yet.
I built the branch and tried that sample and some variations, but they each get: ``` /home/nick/git/dmd/generated/linux/release/64/../../../../../pho os/std/json.d(144): Error: no property `Entry` for type `object.TypeInfo_AssociativeArray` JSONValue[string] unordered; ^ /home/nick/git/dmd/generated/linux/release/64/../../../../druntime/im ort/object.d(1289): class `TypeInfo_AssociativeArray` defined here class TypeInfo_AssociativeArray : TypeInfo ^ ``` And: ``` core.exception.AssertError src/dmd/typinf.d(112): Assertion failure ``` I'm not sure if it's something to do with my setup or not. My Phobos is recent git, probably that's why.
 - I need to write an extensive test suite and address anything 
 it may catch.

 - I have to write the DIP and suffer through the bikeshedding 
 on the forum.

 Of course, one way to continue would be to just write tests for 
 what works and pull this (e.g., behind a -preview switch) and 
 to allow anyone who can spend the time required to take over 
 the polishing effort.
A `-preview` switch would be great. Then with the tests devs will at least keep it up-to-date with master. I think people would be more likely to work on it too, or at least file bugs.
 In general, I still fully intend to finish this, but I don't 
 know when I will manage to get it over the finish line at the 
 level of quality I think is perfect. It has already taken way 
 too long, mostly because I have not been able to focus on this 
 for any significant amount of time beside my day job and 
 various other obligations.
Thanks for your work on this!
Apr 04
parent Nick Treleaven <nick geany.org> writes:
On Friday, 4 April 2025 at 12:25:03 UTC, Nick Treleaven wrote:
 I built the branch and tried that sample and some variations, 
 but they each get:
 ```
 /home/nick/git/dmd/generated/linux/release/64/../../../../../pho
os/std/json.d(144): Error: no property `Entry` for type
`object.TypeInfo_AssociativeArray`
                 JSONValue[string] unordered;
                                   ^
 /home/nick/git/dmd/generated/linux/release/64/../../../../druntime/im
ort/object.d(1289):        class `TypeInfo_AssociativeArray` defined here
 class TypeInfo_AssociativeArray : TypeInfo
 ^
 ```
 And:
 ```
 core.exception.AssertError src/dmd/typinf.d(112): Assertion 
 failure
 ```
 I'm not sure if it's something to do with my setup or not. My 
 Phobos is  recent git, probably that's why.
I was using `import std;`. Using single module imports (or avoiding std) works! ```d auto (x, y, z) = (1, 2, 3); void main() { import core.stdc.stdio; printf("%d %d %d\n", x,y,z); //import std.stdio; //writeln(x,y,z); } ``` Uncommenting writeln causes a link error for me though: ``` Error: undefined reference to `pure nothrow bool core.internal.gc.blockmeta.__setArrayAllocLengthImpl(ref core.memory.BlkInfo_, ulong, bool, ulong, ulong)` referenced from `pure nothrow bool core.internal.array.utils.__setArrayAllocLength!(char).__set rrayAllocLength(ref core.memory.BlkInfo_, ulong, bool, ulong)` ```
Apr 04
prev sibling next sibling parent reply user1234 <user1234 12.de> writes:
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:
 - Unpacking does not yet support auto-expanding, for example:

   (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3);

   does not work yet.
Why should this work ? From the type system point-of-view it's a bit like if you say that ```d ((int,int), int) a = (1,2,3); ``` has to work. You dont have to support that.
Apr 04
parent user1234 <user1234 12.de> writes:
On Friday, 4 April 2025 at 13:43:36 UTC, user1234 wrote:
 On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:
 - Unpacking does not yet support auto-expanding, for example:

   (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3);

   does not work yet.
Why should this work ? From the type system point-of-view it's a bit like if you say that ```d ((int,int), int) a = (1,2,3); ``` has to work. You dont have to support that.
Sorry for the noise, i see the thing now... `AliasSeq!(int. int)` __is not a tuple__, it's supposed to expand to two disctint VarDecls within the parent tuple.
Apr 04
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:
 - expanding a zero-element tuple does not work properly yet (in 
 general, even unrelated to unpacking)
   https://github.com/dlang/dmd/issues/20842
Assigning to a tuple literal seems to be a no-op ATM: ```d void main() { int a,b; (a, b) = (4, 5); printf("%d %d\n", a,b); // 0 0 auto t = (6, 7); printf("%d %d\n", t[0], t[1]); // 6 7 (a, b) = t; printf("%d %d\n", a,b); // 0 0 still } ```
Apr 04
parent Nick Treleaven <nick geany.org> writes:
On Friday, 4 April 2025 at 13:59:52 UTC, Nick Treleaven wrote:
 Assigning to a tuple literal seems to be a no-op ATM:
 ```d
 void main()
 {
     int a,b;
     (a, b) = (4, 5);
That line lowers to: ```d tuple(a, b).opAssign(tuple(4, 5)); ``` So it's assigning to a temporary tuple copy of a and b's data, rather than the fields by reference.
Apr 04
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 3/25/25 05:44, Manu wrote:
 I asked Grok to write me a portable 64x64->128 multiplication function 
 in D to get the pattern, and this is what it wrote:
 
 // Multiplies two 64-bit unsigned integers, returning a 128-bit result 
 as (low, high)
 (ulong, ulong) mul64x64to128(ulong x, ulong y) {
      // Split into 32-bit halves
      uint x_l = cast(uint)x;
      uint x_h = cast(uint)(x >> 32);
      uint y_l = cast(uint)y;
      uint y_h = cast(uint)(y >> 32);
 
      // Compute partial products
      ulong p_ll = cast(ulong)x_l * y_l;        // Bits 0-63
      ulong p_lh = cast(ulong)x_l * y_h;        // Bits 32-95
      ulong p_hl = cast(ulong)x_h * y_l;        // Bits 32-95
      ulong p_hh = cast(ulong)x_h * y_h;        // Bits 64-127
 
      ulong low = p_ll;                         // Lower 64 bits
      uint p_lh_low = cast(uint)p_lh;
      uint p_hl_low = cast(uint)p_hl;
      uint p_ll_high = cast(uint)(p_ll >> 32);
 
      // Compute carry from middle terms
      ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high;
      ulong carry = sum_mid >> 32;
 
      // Upper 64 bits
      ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry;
 
      return (low, high);
 }
 
 
 What I loved is that its function returned a pair of ulong's, because 
 apparently it made an assumption that we had in-language tuples! I 
 wonder where it got that idea?
 
 We should learn from our AI overlords! :P
Well, it seems first they should learn how to multiply numbers (`low = p_ll` is wrong of course): ``` import std; // Multiplies two 64-bit unsigned integers, returning a 128-bit result as (low, high) (ulong, ulong) mul64x64to128(ulong x, ulong y) { // Split into 32-bit halves uint x_l = cast(uint)x; uint x_h = cast(uint)(x >> 32); uint y_l = cast(uint)y; uint y_h = cast(uint)(y >> 32); // Compute partial products ulong p_ll = cast(ulong)x_l * y_l; // Bits 0-63 ulong p_lh = cast(ulong)x_l * y_h; // Bits 32-95 ulong p_hl = cast(ulong)x_h * y_l; // Bits 32-95 ulong p_hh = cast(ulong)x_h * y_h; // Bits 64-127 ulong low = p_ll; // Lower 64 bits uint p_lh_low = cast(uint)p_lh; uint p_hl_low = cast(uint)p_hl; uint p_ll_high = cast(uint)(p_ll >> 32); // Compute carry from middle terms ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high; ulong carry = sum_mid >> 32; // Upper 64 bits ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry; return (low, high); } void main(){ auto (low, high) = mul64x64to128(101010101010101010, 101010101010101010); assert((BigInt(high)<<64)+BigInt(low) == BigInt(101010101010101010)^^2); } ``` ``` $ ./dmd -run test_grok_tuple.d core.exception.AssertError test_grok_tuple.d(34): Assertion failure ---------------- ??:? _d_assertp [0x62dc8b38d148] ??:? _Dmain [0x62dc8b382d9c] ``` (With my freshly rebased DMD fork at: https://github.com/tgehr/dmd/tree/52c336591aac0a2023a715ba92e95efc8da0f9ad )
Apr 01