www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Do you think if statement as expression would be nice to have in D?

reply Jack <jckj33 gmail.com> writes:
Rust does support it like that:

```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
```

do you think would be nice that in D as well? I find it can 
increase code reability...
Jun 03 2022
next sibling parent reply IGotD- <nise nise.com> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
No, I don't think it helps readability. D still has the conditional operator (bool ? trueval : falseval) like C though. People who like Rust, why not just use Rust?
Jun 03 2022
parent Jack <jckj33 gmail.com> writes:
On Friday, 3 June 2022 at 18:42:11 UTC, IGotD- wrote:
 On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
No, I don't think it helps readability. D still has the conditional operator (bool ? trueval : falseval) like C though. People who like Rust, why not just use Rust?
who knows, i don't like rust
Jun 03 2022
prev sibling next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
I don't particularly care about if expressions because we have the ternary operator but I do want pattern matching rather urgently.
Jun 03 2022
parent reply z <z z.com> writes:
On Friday, 3 June 2022 at 19:06:04 UTC, max haughton wrote:
 I don't particularly care about if expressions because we have 
 the ternary operator but I do want pattern matching rather 
 urgently.
why urgently? AFAIU pattern matching is equivalent to a bunch of `if(value1 == *specialvalue or enum*) *insert statement(s) here*;` There's a few ways to do them(switches) but my favorite is the one above because they are devilishly simple and easily generated both manually and programmatically(mixins...). Pattern matching as Haskell does it requires a single value too, which means more than one value requires a struct(tuple in haskell?). (but it's possible that i'm mistaken, i could not find an example of HS pattern matching with more than one value to match per case.)
Jun 03 2022
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Saturday, 4 June 2022 at 00:44:30 UTC, z wrote:
 (but it's possible that i'm mistaken, i could not find an 
 example of HS pattern matching with more than one value to 
 match per case.)
```swift let point = CGPoint(x: 7, y: 0) switch (point.x, point.y) { case (0,0): print("On the origin!") case (0,_): print("x=0: on Y-axis!") case (_,0): print("y=0: on X-axis!") case (let x, let y) where x == y: print("On y=x") default: print("Quite a random point here.") } ``` https://alisoftware.github.io/swift/pattern-matching/2016/03/30/pattern-matching-2/ this would be an example of what I expect
Jun 03 2022
next sibling parent Jack <jckj33 gmail.com> writes:
On Saturday, 4 June 2022 at 02:24:41 UTC, monkyyy wrote:
 On Saturday, 4 June 2022 at 00:44:30 UTC, z wrote:
 (but it's possible that i'm mistaken, i could not find an 
 example of HS pattern matching with more than one value to 
 match per case.)
```swift let point = CGPoint(x: 7, y: 0) switch (point.x, point.y) { case (0,0): print("On the origin!") case (0,_): print("x=0: on Y-axis!") case (_,0): print("y=0: on X-axis!") case (let x, let y) where x == y: print("On y=x") default: print("Quite a random point here.") } ``` https://alisoftware.github.io/swift/pattern-matching/2016/03/30/pattern-matching-2/ this would be an example of what I expect
that sounds also interesting
Jun 03 2022
prev sibling parent zjh <fqbqrr 163.com> writes:
On Saturday, 4 June 2022 at 02:24:41 UTC, monkyyy wrote:

 ```swift
 let point = CGPoint(x: 7, y: 0)
 switch (point.x, point.y) {
   case (0,0): print("On the origin!")
   case (0,_): print("x=0: on Y-axis!")
   case (_,0): print("y=0: on X-axis!")
   case (let x, let y) where x == y: print("On y=x")
   default: print("Quite a random point here.")
 }
 ```
 https://alisoftware.github.io/swift/pattern-matching/2016/03/30/pattern-matching-2/
 this would be an example of what I expect.
I think it's worth it. The more features, the better! Yes ,We are C++++!
Jun 03 2022
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 4 June 2022 at 00:44:30 UTC, z wrote:
 why urgently? AFAIU pattern matching is equivalent to a bunch 
 of `if(value1 == *specialvalue or enum*) *insert statement(s) 
 here*;`
Yes, it makes most sense if you can do nested matching. add(mul(_,0),$x) => $x; add(mul($x,1),$y) => add($x,$y); add(mul($x,$y),$z) => muladd($x,$y,$z);
Jun 03 2022
prev sibling next sibling parent forkit <forkit gmail.com> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
According to the policy laid down by Mike (in another post), it must provide a 'strong benefit', not just be something that is useful to increase code reliabiltiy/readability. It is neither useful, nor a strong benefit, to me ;-)
Jun 03 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/3/22 11:33, Jack wrote:
 Rust does support it like that:

 ```rust
      const limit:i32 = 30;
      let n = 10;
      let mut r = if n > limit { "big" } else { "small "};
      println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well?
It is consistent with the rest of Rust because I think all blocks are expressions in Rust. For example: https://doc.rust-lang.org/reference/expressions/block-expr.html Ali
Jun 03 2022
prev sibling next sibling parent Martin B <martin.brzenska googlemail.com> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 I find it can increase code reability...
I find it to be much noisier than e.g. `auto r = (n > limit) ? "big" : "small";`
Jun 04 2022
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/3/2022 11:33 AM, Jack wrote:
 Rust does support it like that:
 
 ```rust
      const limit:i32 = 30;
      let n = 10;
      let mut r = if n > limit { "big" } else { "small "};
      println!("{} is {} than {}", n, r, limit);
 ```
 
 do you think would be nice that in D as well? I find it can increase code 
 reability...
D has: auto r = (n > limit) ? "big" : "small"; which is more readable than Rust's :-)
Jun 04 2022
parent reply SealabJaster <sealabjaster gmail.com> writes:
On Saturday, 4 June 2022 at 09:56:52 UTC, Walter Bright wrote:
 D has:

     auto r = (n > limit) ? "big" : "small";

 which is more readable than Rust's :-)
While I do agree that's more readable, I wonder if the OP was thinking more along the lines of this, which is what you can see ``` auto number = 200; auto myVar = if (type == "as-is") { return number; } else { // Very complex algorithm number *= 2; number += 2; number /= 2; number = number > 300 ? 200 : 100; return number; } ``` expression, so you can even use pattern matching as an expression :D https://fsharpforfunandprofit.com/posts/match-expression/
Jun 04 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
I sometimes do occasionally run into a situation where I get the feeling it 
would be nice to embed a statement in the expression, but the feeling soon
passes.

Having loops embedded in an expression is not very readable.
Jun 04 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
Here is a question:

How much work would it take to make it work for lets just say if, 
foreach and switch?

Because this reminds me of the old removal of an if statement for 
imports story.
Jun 04 2022
next sibling parent Daniel N <no public.email> writes:
On Saturday, 4 June 2022 at 10:13:15 UTC, rikki cattermole wrote:
 Here is a question:

 How much work would it take to make it work for lets just say 
 if, foreach and switch?

 Because this reminds me of the old removal of an if statement 
 for imports story.
Even if it's easy to add... I think "immediately invoked lambda" is good enough.
Jun 04 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/4/2022 3:13 AM, rikki cattermole wrote:
 How much work would it take to make it work for lets just say if, foreach and 
 switch?
Using lambdas would be better.
Jun 04 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 05/06/2022 7:23 AM, Walter Bright wrote:
 On 6/4/2022 3:13 AM, rikki cattermole wrote:
 How much work would it take to make it work for lets just say if, 
 foreach and switch?
Using lambdas would be better.
Lol, I'll take that to mean its architecturally pretty far from where it needs to be.
Jun 04 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/4/2022 8:12 PM, rikki cattermole wrote:
 Lol, I'll take that to mean its architecturally pretty far from where it needs 
 to be.
Not really, I just never thought it was worth the effort.
Jun 07 2022
prev sibling next sibling parent reply user1234 <user1234 12.de> writes:
On Saturday, 4 June 2022 at 10:01:31 UTC, SealabJaster wrote:
 On Saturday, 4 June 2022 at 09:56:52 UTC, Walter Bright wrote:
 D has:

     auto r = (n > limit) ? "big" : "small";

 which is more readable than Rust's :-)
While I do agree that's more readable, I wonder if the OP was thinking more along the lines of this, which is what you can ``` auto number = 200; auto myVar = if (type == "as-is") { return number; } else { // Very complex algorithm number *= 2; number += 2; number /= 2; number = number > 300 ? 200 : 100; return number; } ``` expression, so you can even use pattern matching as an expression :D https://fsharpforfunandprofit.com/posts/match-expression/
Zig as well. And this creates many problems - https://github.com/ziglang/zig/issues/10349 - https://github.com/ziglang/zig/issues/10196 - https://github.com/ziglang/zig/issues/3988 - https://github.com/ziglang/zig/issues/5426 - https://github.com/ziglang/zig/issues/8640 I esitated yesterday to reply to this thread because this can appear as zig-bashing. The reality is that I find that mixing expressions and statements is not nice looking at all. From the last link: ``` const char = if (current < input.len) input[current] else break; ``` - So the `break` expression has a type ? And this type is compatible with the typê of `input[current]` ? wut ? - expressions introduce scopes - block terminators must be verified for each expressions - etc.
Jun 04 2022
next sibling parent zjh <fqbqrr 163.com> writes:
On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:

 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```
It's too ugly!
Jun 04 2022
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
Jun 04 2022
next sibling parent reply user1234 <user1234 12.de> writes:
On Saturday, 4 June 2022 at 16:15:26 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
I think this does not give intuitively what char value will be: undefined, 0 ? Well in this case a loop is exited and char is out of scope so that does not matter but what if char is a var owned by the loop outer scope.
Jun 04 2022
parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 4 June 2022 at 16:24:10 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:15:26 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
I think this does not give intuitively what char value will be: undefined, 0 ? Well in this case a loop is exited and char is out of scope so that does not matter but what if char is a var owned by the loop outer scope.
In that case, no assignment would occur. Control flow was interrupted before the assignment.
Jun 04 2022
parent reply user1234 <user1234 12.de> writes:
On Saturday, 4 June 2022 at 16:28:07 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 16:24:10 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:15:26 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
I think this does not give intuitively what char value will be: undefined, 0 ? Well in this case a loop is exited and char is out of scope so that does not matter but what if char is a var owned by the loop outer scope.
In that case, no assignment would occur. Control flow was interrupted before the assignment.
yes, this is what I observe ``` const std = import("std"); pub fn ert(input: []const u8) u8 { var ret: u8 = 0; var current: usize = 0; while (true) { ret = if (current < input.len - 1) input[current] else break; current += 1; } return ret; } pub fn main() void { const t : u8 = ert("ABC"); std.debug.print("{}\n", .{t}); } ```
 66
I had no idea. Not mind changing however.
Jun 04 2022
parent reply user1234 <user1234 12.de> writes:
On Saturday, 4 June 2022 at 16:55:37 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:28:07 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 16:24:10 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:15:26 UTC, Nick Treleaven 
 wrote:
 On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
I think this does not give intuitively what char value will be: undefined, 0 ? Well in this case a loop is exited and char is out of scope so that does not matter but what if char is a var owned by the loop outer scope.
In that case, no assignment would occur. Control flow was interrupted before the assignment.
yes, this is what I observe ``` const std = import("std"); pub fn ert(input: []const u8) u8 { var ret: u8 = 0; var current: usize = 0; while (true) { ret = if (current < input.len - 1) input[current] else break; current += 1; } return ret; } pub fn main() void { const t : u8 = ert("ABC"); std.debug.print("{}\n", .{t}); } ```
 66
I had no idea. Not mind changing however.
So actually there's not even something like a common type involved. The "then" part is used as assign rhs and the "else" part is just unrelated. well "Okay" let's say ;) What a strange language tho.
Jun 04 2022
parent user1234 <user1234 12.de> writes:
On Saturday, 4 June 2022 at 20:11:09 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:55:37 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:28:07 UTC, Nick Treleaven wrote:
 On Saturday, 4 June 2022 at 16:24:10 UTC, user1234 wrote:
 On Saturday, 4 June 2022 at 16:15:26 UTC, Nick Treleaven 
 wrote:
 On Saturday, 4 June 2022 at 11:35:41 UTC, user1234 wrote:
 ```
 const char = if (current < input.len)
             input[current]
         else
             break;
 ```

 - So the `break` expression has a type ? And this type is 
 compatible with the typê of `input[current]` ? wut ?
Just like `throw` is an expression in D now. It's type is noreturn, which implicitly converts to any type.
I think this does not give intuitively what char value will be: undefined, 0 ? Well in this case a loop is exited and char is out of scope so that does not matter but what if char is a var owned by the loop outer scope.
In that case, no assignment would occur. Control flow was interrupted before the assignment.
yes, this is what I observe ``` const std = import("std"); pub fn ert(input: []const u8) u8 { var ret: u8 = 0; var current: usize = 0; while (true) { ret = if (current < input.len - 1) input[current] else break; current += 1; } return ret; } pub fn main() void { const t : u8 = ert("ABC"); std.debug.print("{}\n", .{t}); } ```
 66
I had no idea. Not mind changing however.
So actually there's not even something like a common type involved. The "then" part is used as assign rhs and the "else" part is just unrelated. well "Okay" let's say ;) What a strange language tho.
imagine using a switch as assign lhs too: ``` int a,b,c; switch (cond) { case 0: a; break; case 1: b; break; default: c; } = 0; ``` that whole thing of mixing expressions and statements looks really absurd even if there are special cases that may appear appealing. In this last example you'd have to check that every case yields a compatible lvalue. So this bring the fact that statements also have a value category ! Now maybe you also want chained assignments. ``` int nope, a,b,c; nope = switch (cond) { case 0: a; break; case 1: b; break; default: c; } = 0; ``` No way.
Jun 04 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/4/2022 9:15 AM, Nick Treleaven wrote:
 Just like `throw` is an expression in D now. It's type is noreturn, which 
 implicitly converts to any type.
Which is causing unexpected problems :-/
Jun 04 2022
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 5 June 2022 at 00:48:04 UTC, Walter Bright wrote:
 On 6/4/2022 9:15 AM, Nick Treleaven wrote:
 Just like `throw` is an expression in D now. It's type is 
 noreturn, which implicitly converts to any type.
Which is causing unexpected problems :-/
Isn't that more to do with nothrow expressions rather than throw as an expression? If we support nothrow functions then we get nothrow expressions. I could only find one throw expression bug, and that seems like it's a nothrow issue.
Jun 05 2022
parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 5 June 2022 at 11:02:13 UTC, Nick Treleaven wrote:
 On Sunday, 5 June 2022 at 00:48:04 UTC, Walter Bright wrote:
 On 6/4/2022 9:15 AM, Nick Treleaven wrote:
 Just like `throw` is an expression in D now. It's type is 
 noreturn, which implicitly converts to any type.
Which is causing unexpected problems :-/
Isn't that more to do with nothrow expressions rather than throw as an expression? If we support nothrow functions then we get nothrow expressions. I could only find one throw expression bug, and that seems like it's a nothrow issue.
I meant noreturn expression, not nothrow!
Jun 05 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/5/2022 4:02 AM, Nick Treleaven wrote:
 I meant noreturn expression, not nothrow!
Not no how, not no way!
Jun 06 2022
prev sibling parent kdevel <kdevel vogtner.de> writes:
On Sunday, 5 June 2022 at 00:48:04 UTC, Walter Bright wrote:
 On 6/4/2022 9:15 AM, Nick Treleaven wrote:
 Just like `throw` is an expression in D now. It's type is 
 noreturn, which implicitly converts to any type.
Which is causing unexpected problems :-/
BTW: I would have expected try to become an expression such that one can write int v = try foo (...); catch (...) {...} ... as in Perl my $v = eval { foo (...); }; if ($ ) ...
Jun 05 2022
prev sibling parent reply Dukc <ajieskola gmail.com> writes:
On Saturday, 4 June 2022 at 10:01:31 UTC, SealabJaster wrote:
 While I do agree that's more readable, I wonder if the OP was 
 thinking more along the lines of this, which is what you can 


 ```
 auto number = 200;
 auto myVar = if (type == "as-is") {
     return number;
 } else {
     // Very complex algorithm
     number *= 2;
     number += 2;
     number /= 2;
     number = number > 300 ? 200 : 100;
     return number;
 }
 ```
```D auto number = 200; auto myVar = type == "as-is"? number: { number *= 2; number += 2; number /= 2; number = number > 300 ? 200 : 100; return number; }(); ```
Jun 04 2022
parent reply SealabJaster <sealabjaster gmail.com> writes:
On Saturday, 4 June 2022 at 19:54:48 UTC, Dukc wrote:
 ```D
 auto number = 200;
 auto myVar = type == "as-is"?
   number:
   { number *= 2;
     number += 2;
     number /= 2;
     number = number > 300 ? 200 : 100;
     return number;
   }();
 ```
This next question comes from a place of ignorance: What is the codegen like for this code? Would is allocate a closure on the GC before performing the execution, or are the compilers smart enough to inline the entire thing?
Jun 04 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Saturday, 4 June 2022 at 21:17:56 UTC, SealabJaster wrote:
 On Saturday, 4 June 2022 at 19:54:48 UTC, Dukc wrote:
 ```D
 auto number = 200;
 auto myVar = type == "as-is"?
   number:
   { number *= 2;
     number += 2;
     number /= 2;
     number = number > 300 ? 200 : 100;
     return number;
   }();
 ```
This next question comes from a place of ignorance: What is the codegen like for this code? Would is allocate a closure on the GC before performing the execution, or are the compilers smart enough to inline the entire thing?
LDC is able to inline the lambda and then optimize away the allocation. DMD is not. https://godbolt.org/z/5vMcz4s14
Jun 06 2022
next sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Mon, Jun 06, 2022 at 05:07:30PM +0000, deadalnix via Digitalmars-d wrote:
 On Saturday, 4 June 2022 at 21:17:56 UTC, SealabJaster wrote:
 On Saturday, 4 June 2022 at 19:54:48 UTC, Dukc wrote:
 ```D
 auto number = 200;
 auto myVar = type == "as-is"?
   number:
   { number *= 2;
     number += 2;
     number /= 2;
     number = number > 300 ? 200 : 100;
     return number;
   }();
 ```
This next question comes from a place of ignorance: What is the codegen like for this code? Would is allocate a closure on the GC before performing the execution, or are the compilers smart enough to inline the entire thing?
LDC is able to inline the lambda and then optimize away the allocation. DMD is not. https://godbolt.org/z/5vMcz4s14
Yeah, when in doubt, trust LDC to do the "right thing". :-P Well, that, and take a look at the generated assembly to see what it actually does. For questions of performance or codegen quality, I usually don't even bother looking at DMD output. T -- Unix was not designed to stop people from doing stupid things, because that would also stop them from doing clever things. -- Doug Gwyn
Jun 06 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Monday, 6 June 2022 at 17:43:47 UTC, H. S. Teoh wrote:
 On Mon, Jun 06, 2022 at 05:07:30PM +0000, deadalnix via 
 Digitalmars-d wrote:
 [...]

 LDC is able to inline the lambda and then optimize away the 
 allocation. DMD is not.
 
 https://godbolt.org/z/5vMcz4s14
Yeah, when in doubt, trust LDC to do the "right thing". :-P Well, that, and take a look at the generated assembly to see what it actually does. For questions of performance or codegen quality, I usually don't even bother looking at DMD output. T
I mean: ``` int example.foo(immutable(char)[]): cmp rdi, 5 jne .LBB0_3 mov eax, 1764586337 xor eax, dword ptr [rsi] movzx ecx, byte ptr [rsi + 4] xor ecx, 115 or ecx, eax je .LBB0_2 .LBB0_3: mov eax, 100 ret .LBB0_2: mov eax, 200 ret ``` It's amazing.
Jun 06 2022
parent SealabJaster <sealabjaster gmail.com> writes:
On Monday, 6 June 2022 at 20:31:06 UTC, deadalnix wrote:
 On Monday, 6 June 2022 at 17:43:47 UTC, H. S. Teoh wrote:
 On Mon, Jun 06, 2022 at 05:07:30PM +0000, deadalnix via 
 Digitalmars-d wrote:
 [...]

 LDC is able to inline the lambda and then optimize away the 
 allocation. DMD is not.
 
 https://godbolt.org/z/5vMcz4s14
Yeah, when in doubt, trust LDC to do the "right thing". :-P Well, that, and take a look at the generated assembly to see what it actually does. For questions of performance or codegen quality, I usually don't even bother looking at DMD output. T
I mean: ``` int example.foo(immutable(char)[]): cmp rdi, 5 jne .LBB0_3 mov eax, 1764586337 xor eax, dword ptr [rsi] movzx ecx, byte ptr [rsi + 4] xor ecx, 115 or ecx, eax je .LBB0_2 .LBB0_3: mov eax, 100 ret .LBB0_2: mov eax, 200 ret ``` It's amazing.
wow wtf :D
Jun 06 2022
prev sibling next sibling parent SealabJaster <sealabjaster gmail.com> writes:
On Monday, 6 June 2022 at 17:07:30 UTC, deadalnix wrote:
 On Saturday, 4 June 2022 at 21:17:56 UTC, SealabJaster wrote:
 On Saturday, 4 June 2022 at 19:54:48 UTC, Dukc wrote:
 ```D
 auto number = 200;
 auto myVar = type == "as-is"?
   number:
   { number *= 2;
     number += 2;
     number /= 2;
     number = number > 300 ? 200 : 100;
     return number;
   }();
 ```
This next question comes from a place of ignorance: What is the codegen like for this code? Would is allocate a closure on the GC before performing the execution, or are the compilers smart enough to inline the entire thing?
LDC is able to inline the lambda and then optimize away the allocation. DMD is not. https://godbolt.org/z/5vMcz4s14
Ah nice, then yeah I don't see any real downsides to just using lambdas like that :)
Jun 06 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/6/2022 10:07 AM, deadalnix wrote:
 LDC is able to inline the lambda and then optimize away the allocation. DMD is
not.
DMD can inline it now: https://issues.dlang.org/show_bug.cgi?id=23165 https://github.com/dlang/dmd/pull/14190 There is a persistent idea that there is something fundamentally wrong with DMD. There isn't. It's just that optimization involves an accumulation of a large number of special cases, and clang has a lot of people adding special cases. The not-special-case major optimization algorithms that do data flow analysis, dmd has.
Jun 06 2022
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 7 June 2022 at 01:24:07 UTC, Walter Bright wrote:
 There is a persistent idea that there is something 
 fundamentally wrong with DMD. There isn't. It's just that 
 optimization involves an accumulation of a large number of 
 special cases, and clang has a lot of people adding special 
 cases.
I have only ever used DMD, never bothered using anything else and it has never hindered any of my work or mattered in the slightest. Nothing I work with suffers from the difference in optimization as I don't have anything that's real-time sensitive. As long as the work is done in a reasonable amount of time (That of course depends on what it is.) then I'm fine with it. Typically the difference is in the milliseconds, which won't matter much for most enterprise work.
Jun 06 2022
next sibling parent reply Bruce Carneal <bcarneal gmail.com> writes:
On Tuesday, 7 June 2022 at 04:53:36 UTC, bauss wrote:
 On Tuesday, 7 June 2022 at 01:24:07 UTC, Walter Bright wrote:
 There is a persistent idea that there is something 
 fundamentally wrong with DMD. There isn't. It's just that 
 optimization involves an accumulation of a large number of 
 special cases, and clang has a lot of people adding special 
 cases.
I have only ever used DMD, never bothered using anything else and it has never hindered any of my work or mattered in the slightest. Nothing I work with suffers from the difference in optimization as I don't have anything that's real-time sensitive. As long as the work is done in a reasonable amount of time (That of course depends on what it is.) then I'm fine with it. Typically the difference is in the milliseconds, which won't matter much for most enterprise work.
Mileage varies of course. If watts and/or throughput is important, and you're working on something that admits data parallelism, ldc and gdc can help. Here's an example of a 32X speedup (16X if you cripple the target): https://godbolt.org/z/bT7qKnfMP
Jun 06 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
dmd doesn't do autovectorization.

However, you can write vector code using vector types if you wish.
Jun 07 2022
parent reply Bruce Carneal <bcarneal gmail.com> writes:
On Tuesday, 7 June 2022 at 07:05:04 UTC, Walter Bright wrote:
 dmd doesn't do autovectorization.

 However, you can write vector code using vector types if you 
 wish.
vector types are a great feature. That said, for readability I'm migrating my __vector code base to autovectorization for the CPU-only deployments and autovec+SIMT/dcompute for the rest. Fortunately the recent autovectorizer code performance equals or exceeds the "manual" code in many instances (more aggressive unrolling and better/finer-grain handling of intermediate lengths). OTOH, if perf drops,and SIMT is not available, __vector it is!
Jun 07 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 2:23 AM, Bruce Carneal wrote:
 On Tuesday, 7 June 2022 at 07:05:04 UTC, Walter Bright wrote:
 dmd doesn't do autovectorization.

 However, you can write vector code using vector types if you wish.
vector types are a great feature.  That said, for readability I'm migrating my __vector code base to autovectorization for the CPU-only deployments and autovec+SIMT/dcompute for the rest. Fortunately the recent autovectorizer code performance equals or exceeds the "manual" code in many instances (more aggressive unrolling and better/finer-grain handling of intermediate lengths).  OTOH, if perf drops,and SIMT is not available, __vector it is!
I've never much liked autovectorization: 1. you never know if it is going to vectorize or not. The vector instruction sets vary all over the place, and whether they line up with your loops or not is not determinable in general - you have to look at the assembler dump. 2. when autovectorization doesn't happen, the compiler reverts to non-vectorized slow code. Often, you're not aware this has happened, and the expected performance doesn't happen. You can usually refactor the loop so it will autovectorize, but that's something only an expert programmer can accomplish, but he can't do it if he doesn't *realize* the autovectorization didn't happen. You said it yourself: "if perf drops"! 3. it's fundamentally a backwards thing. The programmer writes low level code (explicit loops) and the compiler tries to work backwards to create high level code (vectors) for it! This is completely backwards to how compilers normally work - specify a high level construct, and the compiler converts it into low level. 4. with vector code, the compiler will tell you when the instruction set won't map onto it, so you have a chance to refactor it so it will.
Jun 07 2022
parent reply Bruce Carneal <bcarneal gmail.com> writes:
On Tuesday, 7 June 2022 at 18:21:57 UTC, Walter Bright wrote:
 On 6/7/2022 2:23 AM, Bruce Carneal wrote:
...
 I've never much liked autovectorization:
Same here, which is why my initial CPU-side implementation was all explicit __vector/intrinsics code (with corresponding static arrays to get a sane unaligned load/store capability).
 1. you never know if it is going to vectorize or not. The 
 vector instruction sets vary all over the place, and whether 
 they line up with your loops or not is not determinable in 
 general - you have to look at the assembler dump.
I now take this as an argument for auto vectorization.
 2. when autovectorization doesn't happen, the compiler reverts 
 to non-vectorized slow code. Often, you're not aware this has 
 happened, and the expected performance doesn't happen. You can 
 usually refactor the loop so it will autovectorize, but that's 
 something only an expert programmer can accomplish, but he 
 can't do it if he doesn't *realize* the autovectorization 
 didn't happen.  You said it yourself: "if perf drops"!
Well, presumably you're "unittesting" performance to know where the hot spots are so... It's always nicer to know things at compile time but for me it's acceptable at "unittest time" since the measurements will be part of any performance code development setup.
 3. it's fundamentally a backwards thing. The programmer writes 
 low level code (explicit loops) and the compiler tries to work 
 backwards to create high level code (vectors) for it! This is 
 completely backwards to how compilers normally work - specify a 
 high level construct, and the compiler converts it into low 
 level.
I see it as a choice on the "time to develop" <==> "performance achieved" axis. Fortunately autovectorization can be a win here: develop simple/correct code with an eye to compiler-visible indexing and hand-vectorize if there's a problem. (I actually went the other way, starting with hand optimized core functions, and discovered that auto-vectorization worked as well or better for many of those functions).
 4. with vector code, the compiler will tell you when the 
 instruction set won't map onto it, so you have a chance to 
 refactor it so it will.
Yes, better to know things at compile time but OK to know them at perf "unittest" time. Here are some of the reasons I'm migrating much of my code to auto-vectorization with perf regression tests from the initial __vector/intrinsic implementation: 1) It's more readable. 2) It is auto upgradeable (with target meta programming for the multi-target deployability) 3) It's measurably (slightly) faster in many instances (it helps that I can shape the operand flows for this app) 4) It fits more readily with upcoming CPU-centric vector arch (SVE, SVE2, RVV...), Cray vectors ride again! :-) 5) It aligns stylistically with SIMT (I think in terms of index spaces and memory subsystem blocking rather than HW details). SIMT is where I believe we should be looking for future, significant performance gains (the PCIe bottleneck is a stumbling block but SoCs and consoles have the right idea). The mid-range goal is to develop in an it-just-works, no-big-deal SIMT environment where the traditional SIMD awkwardness is in the rear view mirror and where we can surf the improving HW performance wave (clock increases were nice while they lasted but ...). dcompute is already a good ways down that road but it can be friendlier and more capable. As I've mentioned elsewhere, I already prefer it to CUDA. Finally, thanks for creating D. It's great.
Jun 07 2022
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 7 June 2022 at 21:09:08 UTC, Bruce Carneal wrote:
 3) It's measurably (slightly) faster in many instances (it 
 helps that I can shape the operand flows for this app)
Depends on the loop, for example LLVM can vectorize llvm_sqrt https://d.godbolt.org/z/6xaTKnn9z but not llvm_exp / llvm_cos / llvm_sin / llvm_log https://d.godbolt.org/z/Pc34967vc for such loops I have to go __vector
Jun 07 2022
next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Tuesday, 7 June 2022 at 21:48:10 UTC, Guillaume Piolat wrote:
 On Tuesday, 7 June 2022 at 21:09:08 UTC, Bruce Carneal wrote:
 3) It's measurably (slightly) faster in many instances (it 
 helps that I can shape the operand flows for this app)
Depends on the loop, for example LLVM can vectorize llvm_sqrt https://d.godbolt.org/z/6xaTKnn9z but not llvm_exp / llvm_cos / llvm_sin / llvm_log https://d.godbolt.org/z/Pc34967vc for such loops I have to go __vector
Which instructions are they supposed to lower to? Wouldn't that require the intrinsic-in-name-only intel math library stuff?
Jun 07 2022
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 7 June 2022 at 22:22:22 UTC, max haughton wrote:
 Which instructions are they supposed to lower to? Wouldn't that 
 require the intrinsic-in-name-only intel math library stuff?
I've ony seen that with Intel C++ compiler => https://godbolt.org/z/E39rc77fj It will replace transcendental function with a vectorized version that does 4 log/exp/pow/sin/cos at once, and yes that is faster.
Jun 07 2022
parent Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 7 June 2022 at 23:36:20 UTC, Guillaume Piolat wrote:
 On Tuesday, 7 June 2022 at 22:22:22 UTC, max haughton wrote:
 Which instructions are they supposed to lower to? Wouldn't 
 that require the intrinsic-in-name-only intel math library 
 stuff?
I've ony seen that with Intel C++ compiler => https://godbolt.org/z/E39rc77fj It will replace transcendental function with a vectorized version that does 4 log/exp/pow/sin/cos at once, and yes that is faster.
In LLVM, builtins that map to instructions that can be done with normal code are eventually removed. However, some of them stay forever in ldc.gcc_builtinsx86 (it has 894 builtins) because you can't cause the codegen to generate them else. For example it is impossible to have PMADDWD otherwise in LLVM. https://d.godbolt.org/z/vvqP5vzvo But, Intel C++ compiler can do it: https://godbolt.org/z/f37dzKzT3 that's why intel-intrinsics exist, not all autovectorizers are created equals.
Jun 07 2022
prev sibling parent Bruce Carneal <bcarneal gmail.com> writes:
On Tuesday, 7 June 2022 at 21:48:10 UTC, Guillaume Piolat wrote:
 On Tuesday, 7 June 2022 at 21:09:08 UTC, Bruce Carneal wrote:
 3) It's measurably (slightly) faster in many instances (it 
 helps that I can shape the operand flows for this app)
Depends on the loop, for example LLVM can vectorize llvm_sqrt https://d.godbolt.org/z/6xaTKnn9z but not llvm_exp / llvm_cos / llvm_sin / llvm_log https://d.godbolt.org/z/Pc34967vc for such loops I have to go __vector
Yes. I too definitely want __vector as a backstop when autovec isn't up to the job and SIMT math is not available. I also reach for __vector when conditionals become problematic.
Jun 07 2022
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/6/2022 9:53 PM, bauss wrote:
 Typically the difference is in the milliseconds, which won't matter much for 
 most enterprise work.
Thanks for the kind words! A few years ago, one person posted here that clang invented data flow analysis and I should add it to dmd. I replied with a link to the data flow analysis code in dmd, that was written in 1985 or so :-) Math is math, and DFA hasn't changed much in the last 40 years. One amusing thing about it is when my compiler acquired DFA, there was a C compiler benchmark roundup in one of the computer magazines. The results were thrown out for my compiler, as the journalist concluded it had a bug in it where it deleted the test suite code. He wrote lots of bad things as a result. What actually happened was the DFA deduced that the magazine's benchmark code did not use the result, so threw it away. The result of that article, though, destroyed my sales for a quarter or so. Then other compilers added DFA, and the benchmark code got fixed for the next compiler roundup. Sigh.
Jun 06 2022
next sibling parent zjh <fqbqrr 163.com> writes:
On Tuesday, 7 June 2022 at 06:22:00 UTC, Walter Bright wrote:
 On 6/6/2022 9:53 PM, bauss wrote:
 Typically the difference is in the milliseconds, which won't 
 matter much for most enterprise work.
Thanks for the kind words! A few years ago, one person posted here that clang invented data flow analysis and I should add it to dmd. I replied with a link to the data flow analysis code in dmd, that was written in 1985 or so :-)
 The result of that article, though, destroyed my sales for a 
 quarter or so. Then other compilers added DFA, and the 
 benchmark code got fixed for the next compiler roundup.

 Sigh.
Unfair, there are `bad` people! They are always coping.
Jun 07 2022
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/6/22 23:22, Walter Bright wrote:

 The
 results were thrown out for my compiler, as the journalist concluded it
 had a bug in it where it deleted the test suite code.
That's too funny. :) And that's why peer reviewed articles exist.
 He wrote lots of
 bad things as a result.
Anything more to the story? You should get more sales when they hopefully published the explanation with an apology. (?) Ali
Jun 07 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 6:16 AM, Ali Çehreli wrote:
 Anything more to the story? You should get more sales when they hopefully 
 published the explanation with an apology. (?)
They refused to publish a correction. They didn't give a fig, because I wasn't Microsoft and a big advertiser.
Jun 07 2022
parent reply matheus <matheus gmail.com> writes:
On Tuesday, 7 June 2022 at 18:22:55 UTC, Walter Bright wrote:
 On 6/7/2022 6:16 AM, Ali Çehreli wrote:
 Anything more to the story? You should get more sales when 
 they hopefully published the explanation with an apology. (?)
They refused to publish a correction. They didn't give a fig, because I wasn't Microsoft and a big advertiser.
What was the magazine? I'd like to search and read them. By the way, today those reviewers would have a nice lesson from the internet, like we see from time to time and those people make dumb affirmations/mistakes. Matheus.
Jun 07 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 11:36 AM, matheus wrote:
 What was the magazine? I'd like to search and read them.
I wish I remember. I was so angry about it I didn't save a copy, and eventually forgot which one it was :-(
Jun 07 2022
parent reply matheus <matheus gmail.com> writes:
On Wednesday, 8 June 2022 at 00:02:16 UTC, Walter Bright wrote:
 On 6/7/2022 11:36 AM, matheus wrote:
 What was the magazine? I'd like to search and read them.
I wish I remember. I was so angry about it I didn't save a copy, and eventually forgot which one it was :-(
Oh I see, do you happen to know at least in what year was this? Matheus.
Jun 10 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/10/2022 5:41 PM, matheus wrote:
 On Wednesday, 8 June 2022 at 00:02:16 UTC, Walter Bright wrote:
 On 6/7/2022 11:36 AM, matheus wrote:
 What was the magazine? I'd like to search and read them.
I wish I remember. I was so angry about it I didn't save a copy, and eventually forgot which one it was :-(
Oh I see, do you happen to know at least in what year was this? Matheus.
Pretty sure 1985.
Jun 12 2022
prev sibling parent reply max haughton <maxhaton gmail.com> writes:
On Tuesday, 7 June 2022 at 04:53:36 UTC, bauss wrote:
 On Tuesday, 7 June 2022 at 01:24:07 UTC, Walter Bright wrote:
 There is a persistent idea that there is something 
 fundamentally wrong with DMD. There isn't. It's just that 
 optimization involves an accumulation of a large number of 
 special cases, and clang has a lot of people adding special 
 cases.
I have only ever used DMD, never bothered using anything else and it has never hindered any of my work or mattered in the slightest. Nothing I work with suffers from the difference in optimization as I don't have anything that's real-time sensitive. As long as the work is done in a reasonable amount of time (That of course depends on what it is.) then I'm fine with it. Typically the difference is in the milliseconds, which won't matter much for most enterprise work.
Unfortunately the dmd optimizer and inliner are somewhat buggy so most "enterprise" users actually avoid them like the plague or have fairly hard-won scars. At least one of our libraries doesn't work with -O -inline, many others cases have similar issues. It's not just about performance, even if LLVM and GCC are much faster. optimization isn't just about adding special cases, the sheer amount of optimizations dmd would have to learn on top of an already horrific codebase in the backend (note that to start with the register allocator is pretty bad, but isn't easily replaced) means while it's technically possible it's practically just not realistic. The IR used by the backend is also quite annoying to work with. SSA is utterly dominant in compilers (and has been since the late 90s) for a reason. It's not it's fault because it's so old but the infrastructure and invariants you get from it are just nothing even close to being easy to work on versus even GCC before they realized LLVM was about to completely destroy them (almost no one does new research with GCC anymore mostly because LLVM is easier to work on). This IR and the lack of structure around operations on it is why dmd has so many bugs wrt things like SIMD code generation. GCC and LLVM learnt the hard way that you need to segment work into multiple passes and possibly different data structures entirely (either artificially, like LCSSA, or using an entirely different IR like GCC's rtl). These are not cheap things to do but paying for them also buys you correctness. dmd should just focus on being the debug compiler i.e. be fast. I would much rather have the codebase be clean enough that I could easily get it generating code on my AArch64 Mac than have it chase after being able to do xyz. I will never actually care about dmds ability to optimize something.
Jun 07 2022
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Tuesday, 7 June 2022 at 08:44:27 UTC, max haughton wrote:

 This IR and the lack of structure around operations on it is 
 why dmd has so many bugs wrt things like SIMD code generation. 
 GCC and LLVM learnt the hard way that you need to segment work 
 into multiple passes and possibly different data structures 
 entirely (either artificially, like LCSSA, or using an entirely 
 different IR like GCC's rtl). These are not cheap things to do 
 but paying for them also buys you correctness.

 dmd should just focus on being the debug compiler i.e. be fast. 
 I would much rather have the codebase be clean enough that I 
 could easily get it generating code on my AArch64 Mac than have 
 it chase after being able to do xyz. I will never actually care 
 about dmds ability to optimize something.
However, I hope `'DMD'` can work on the `back end`.` D` author can make use of his `back-end` knowledge, and do not have to follow the `'llvm''s` path! `Llvm` is not necessarily the best .
Jun 07 2022
parent zjh <fqbqrr 163.com> writes:
On Tuesday, 7 June 2022 at 09:41:34 UTC, zjh wrote:

 However, I hope `'DMD'` can work on the `back end`.` D` author 
 can make use of his `back-end` knowledge, and do not have to 
 follow the `'llvm''s` path!
 `Llvm` is not necessarily the best
 .
Moreover, I like to see the competition between `small companies or small languages` and `large companies`. I vote `small ones` very much. This is very exciting.
Jun 07 2022
prev sibling next sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 7 June 2022 at 08:44:27 UTC, max haughton wrote:
 dmd should just focus on being the debug compiler i.e. be fast. 
 I would much rather have the codebase be clean enough that I 
 could easily get it generating code on my AArch64 Mac than have 
 it chase after being able to do xyz. I will never actually care 
 about dmds ability to optimize something.
I did left DMD because of unreliable codegen. But I do miss the build times dearly. It seems to me things are actually getting better in DMD over time and my pan is to enable D_SIMD in intel-intrinsics ASAP (or at least try). The reason is that DMD generates surprisingly usable code in no time when you use D_SIMD. Builtins like in D_SIMD are interesting because they require less optimizer busy work, making it especially useful for debug builds. But, yeah, it's not sure the improved performance is worth the backend churn, just for debug builds, so not sure.
Jun 07 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
I thought I fixed the SIMD issues you were having? What is left undone?
Jun 07 2022
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 7 June 2022 at 18:28:29 UTC, Walter Bright wrote:
 I thought I fixed the SIMD issues you were having? What is left 
 undone?
I checked and my issues have been fixed indeed, thanks for that. Because it's an ongoing process, I'll come back later with a new set of Issues. The current status: - The usage of D_SIMD and core.simd is not yet enabled in intel-intrinsics with DMD because it disrupts Core and PR, so until now I've been doing it in several attempts to test the water and not distract too much people. But it will enabled be next time probably, probably in August. - Once core.simd is enabled for good, D_SIMD usage can be ramped up intel-intrinsics (currently, it is only SSE 1 instructions that use the D_SIMD _builtins_). I expect doing it for all other SIMD instructions will take a few months of spare work, and will expose about 4-5 new bugs and that will be it. If DMD test suite follows it should be hopefully set in stone. wishful.gif Until now, most of the issues came from regular vector types usage, not really D_SIMD builtins so I expect that last part to be less contentious. I'm curious how close we can get to optimized LDC codegen with DMD codegen in an entirely SIMD codebase, it will be somewhere between 0.5x and 1.0x. In small godbolt examples it can get pretty close.
Jun 07 2022
next sibling parent max haughton <maxhaton gmail.com> writes:
On Tuesday, 7 June 2022 at 21:16:22 UTC, Guillaume Piolat wrote:
 On Tuesday, 7 June 2022 at 18:28:29 UTC, Walter Bright wrote:
 [...]
I checked and my issues have been fixed indeed, thanks for that. Because it's an ongoing process, I'll come back later with a new set of Issues. [...]
It should be very close as long as the register allocator doesn't get it your way.
Jun 07 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 2:16 PM, Guillaume Piolat wrote:
 - The usage of D_SIMD and core.simd is not yet enabled in intel-intrinsics
with 
 DMD because it disrupts Core and PR, so until now I've been doing it in
several 
 attempts to test the water and not distract too much people. But it will
enabled 
 be next time probably, probably in August.
 
 - Once core.simd is enabled for good, D_SIMD usage can be ramped up 
 intel-intrinsics (currently, it is only SSE 1 instructions that use the D_SIMD 
 _builtins_).
    I expect doing it for all other SIMD instructions will take a few months
of 
 spare work, and will expose about 4-5 new bugs and that will be it. If DMD
test 
 suite follows it should be hopefully set in stone. wishful.gif
 
    Until now, most of the issues came from regular vector types usage, not 
 really D_SIMD builtins so I expect that last part to be less contentious.
 
 I'm curious how close we can get to optimized LDC codegen with DMD codegen in
an 
 entirely SIMD codebase, it will be somewhere between 0.5x and 1.0x. In small 
 godbolt examples it can get pretty close.
I'm looking forward to the progress you're making! As an aside, I am thinking about making D's array operations work more like APL does: https://en.wikipedia.org/wiki/APL_(programming_language) APL seems a good fit for SIMD. Look, Ma, no loops!
Jun 07 2022
parent zjh <fqbqrr 163.com> writes:
On Wednesday, 8 June 2022 at 00:07:14 UTC, Walter Bright wrote:
 On 6/7/2022 2:16 PM, Guillaume Piolat wrote:
 - The usage of D_SIMD and core.simd is not yet enabled in 
 intel-intrinsics with DMD because it disrupts Core and PR, so 
 until now I've been doing it in several attempts to test the 
 water and not distract too much people. But it will enabled be 
 next time probably, probably in August.
 
 - Once core.simd is enabled for good, D_SIMD usage can be 
 ramped up intel-intrinsics (currently, it is only SSE 1 
 instructions that use the D_SIMD _builtins_).
    I expect doing it for all other SIMD instructions will take 
 a few months of spare work, and will expose about 4-5 new bugs 
 and that will be it. If DMD test suite follows it should be 
 hopefully set in stone. wishful.gif
 
    Until now, most of the issues came from regular vector 
 types usage, not really D_SIMD builtins so I expect that last 
 part to be less contentious.
 
 I'm curious how close we can get to optimized LDC codegen with 
 DMD codegen in an entirely SIMD codebase, it will be somewhere 
 between 0.5x and 1.0x. In small godbolt examples it can get 
 pretty close.
I'm looking forward to the progress you're making! As an aside, I am thinking about making D's array operations work more like APL does: https://en.wikipedia.org/wiki/APL_(programming_language) APL seems a good fit for SIMD. Look, Ma, no loops!
`...` also has no loops.
Jun 07 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 1:44 AM, max haughton wrote:
 Unfortunately the dmd optimizer and inliner are somewhat buggy so most 
 "enterprise" users actually avoid them like the plague or have fairly hard-won 
 scars. At least one of our libraries doesn't work with -O -inline, many others 
 cases have similar issues.
I am not aware of this. Bugzilla issues, please?
 optimization isn't just about adding special cases, the sheer amount of 
 optimizations dmd would have to learn on top of an already horrific codebase
in 
 the backend (note that to start with the register allocator is pretty bad, but 
 isn't easily replaced) means while it's technically possible it's practically 
 just not realistic.
Everybody says that, but I just go and add the optimizations people want anyway.
 The IR used by the backend is also quite annoying to work with. SSA is utterly 
 dominant in compilers (and has been since the late 90s) for a reason. It's not 
 it's fault because it's so old but the infrastructure and invariants you get 
 from it are just nothing even close to being easy to work on versus even GCC 
 before they realized LLVM was about to completely destroy them (almost no one 
 does new research with GCC anymore mostly because LLVM is easier to work on).
Triples *are* SSA, in that each node can be considered an assignment to a temporary.
 This IR and the lack of structure around operations on it is why dmd has so
many 
 bugs wrt things like SIMD code generation.
SSA has nothing whatsoever to do with SIMD code generation. The SIMD problems have all turned out to be missed special cases (SIMD is very complex). If you look at the PRs I made to fix them, they're all small. Not indicative of any fundamental problem.
Jun 07 2022
parent reply max haughton <maxhaton gmail.com> writes:
On Tuesday, 7 June 2022 at 18:27:32 UTC, Walter Bright wrote:
 On 6/7/2022 1:44 AM, max haughton wrote:
 Unfortunately the dmd optimizer and inliner are somewhat buggy 
 so most "enterprise" users actually avoid them like the plague 
 or have fairly hard-won scars. At least one of our libraries 
 doesn't work with -O -inline, many others cases have similar 
 issues.
I am not aware of this. Bugzilla issues, please?
The main one we hit is NRVO issues with -inline. Mathias Lang also me showed an issue with it but I can't remember which project it was. They should already be filed I can find the issues if required but they should just a bugzilla search away.
 optimization isn't just about adding special cases, the sheer 
 amount of optimizations dmd would have to learn on top of an 
 already horrific codebase in the backend (note that to start 
 with the register allocator is pretty bad, but isn't easily 
 replaced) means while it's technically possible it's 
 practically just not realistic.
Everybody says that, but I just go and add the optimizations people want anyway.
Realistic for anyone other than you then ;) With the register allocator as a specific example my attention span is rather short but it was pretty impenetrable when I tried to explain to myself what algorithm it actually uses.
 The IR used by the backend is also quite annoying to work 
 with. SSA is utterly dominant in compilers (and has been since 
 the late 90s) for a reason. It's not it's fault because it's 
 so old but the infrastructure and invariants you get from it 
 are just nothing even close to being easy to work on versus 
 even GCC before they realized LLVM was about to completely 
 destroy them (almost no one does new research with GCC anymore 
 mostly because LLVM is easier to work on).
Triples *are* SSA, in that each node can be considered an assignment to a temporary.
Meanwhile I can assign to a variable in a loop? Or maybe you aren't supposed to be able to and that was a bug in some IR I generated? The trees locally are SSA but do you actually enforce SSA in overall dataflow? Similarly SSA applies across control flow boundaries, phi nodes? Anyway my point about SSA is more that one of the reasons it's prevalent is that it makes writing passes quite a lot easier. Implementing address sanitizer should be a doddle but it was not with the dmd backend so I had to give up. This is actually a really useful feature that we already link with at the moment on Linux so I can tell you exactly the lowering needed if required. You'll be able to do it within minutes I'm sure but I can't devote the time to working out and testing all the bitvectors for the DFA etc.
 This IR and the lack of structure around operations on it is 
 why dmd has so many bugs wrt things like SIMD code generation.
SSA has nothing whatsoever to do with SIMD code generation.
In the same way that structured programming has nothing to do with avoiding bugs. I'm not saying it's impossible to do without SSA it's just indicative of an IR that isn't very good compared to even simple modern ones. Within the backend I actually do think there is a elegant codebase trying to escape just that to achieve that it would need a few snips in the right place to make it feasible to extract.
 The SIMD problems have all turned out to be missed special 
 cases (SIMD is very complex). If you look at the PRs I made to 
 fix them, they're all small. Not indicative of any fundamental 
 problem.
They look like special cases, and maybe they are fundamentally, but other compilers simply do not have this rate of mistakes when it comes to SIMD instruction selection or code generation. It just smells really bad compared to GCC. LLVM tries to be fancy in this area so I wouldn't copy. I want to help with this and just today I have fixed a backend issue but I just wanted to say some things about it.
Jun 07 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2022 2:15 PM, max haughton wrote:
 They should already be filed I can find the  issues if required but they
should 
 just a bugzilla search away.
Generally speaking, when one writes about bugs, having a bugzilla reference handy says a lot.
 Realistic for anyone other than you then ;)
I've never looked at the code generator for gdc or ldc. I doubt either is easy to contribute to. The x86 line is *extremely* complex and making a change that will work with all the various models is never ever going to be simple.
 With the register allocator as a specific example my attention span is rather 
 short but it was pretty impenetrable when I tried to explain to myself what 
 algorithm it actually uses.
It uses the usual graph coloring algorithm for register allocation. The kludginess in it comes from the first 8 registers all being special cases.
 Triples *are* SSA, in that each node can be considered an assignment to a 
 temporary.
Meanwhile I can assign to a variable in a loop? Or maybe you aren't supposed to be able to and that was a bug in some IR I generated? The trees locally are SSA but do you actually enforce SSA in overall dataflow? Similarly SSA applies across control flow boundaries, phi nodes? Anyway my point about SSA is more that one of the reasons it's prevalent is that it makes writing passes quite a lot easier.
I don't know how you're trying to do things, but the optimizer generates variables all the time. Each node in the elem tree gets assigned exactly once and used exactly once.
 Implementing address sanitizer should be a doddle but it was not with the dmd 
 backend so I had to give up.
 
 This is actually a really useful feature that we already link with at the
moment 
 on Linux so I can tell you exactly the lowering needed if required. You'll be 
 able to do it within minutes I'm sure but I can't devote the time to working
out 
 and testing all the bitvectors for the DFA etc.
I'm sure it's not trivial, but I'm also sure it isn't trivial in ldc, either.
 In the same way that structured programming has nothing to do with avoiding 
 bugs. I'm not saying it's impossible to do without SSA it's just indicative of 
 an IR that isn't very good compared to even simple modern ones.
I looked into doing SSA, and realized it was pointless because the binary tree does the same thing.
 They look like special cases, and maybe they are fundamentally, but other 
 compilers simply do not have this rate of mistakes when it comes to SIMD 
 instruction selection or code generation.
Other compilers have a massive test suite that detects problems up front. We don't. I also do not work full time on the back end. This is not a structural problem, it's a resource problem.
 I want to help with this and just today I have fixed a backend issue but I
just 
 wanted to say some things about it.
That's fine, that's what the forums are for! And it gives me an opportunity to help out. The only structural problem with the backend I've discovered is it cannot embed goto nodes in the tree structure, so it can't inline loops. I doubt it is that big a problem, because loops intrinsically are hardly worth inlining.
Jun 07 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 6/8/22 03:30, Walter Bright wrote:
 
 I want to help with this and just today I have fixed a backend issue 
 but I just wanted to say some things about it.
That's fine, that's what the forums are for! And it gives me an opportunity to help out. The only structural problem with the backend I've discovered is it cannot embed goto nodes in the tree structure, so it can't inline loops. I doubt it is that big a problem, because loops intrinsically are hardly worth inlining.
Inlining a function (even with a loop) can enable further optimizations that depend on additional information that's available at the call site.
Jun 12 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/12/2022 11:13 AM, Timon Gehr wrote:
 On 6/8/22 03:30, Walter Bright wrote:
 The only structural problem with the backend I've discovered is it cannot 
 embed goto nodes in the tree structure, so it can't inline loops. I doubt it 
 is that big a problem, because loops intrinsically are hardly worth inlining.
Inlining a function (even with a loop) can enable further optimizations that depend on additional information that's available at the call site.
I agree, and there are some cases where the improvement can be dramatic, but there's just not a lot of oil in that well for loops.
Jun 12 2022
prev sibling next sibling parent Sergey <kornburn yandex.ru> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
Could you please provide more specific example, where if-expression could be useful? There is a ConditionExpression in D, like it was mentioned previously. https://dlang.org/spec/expression.html#conditional_expressions With fast googling I found only this argumentation: *The advantage of the inline if expression is that it's an expression, which means you can use it inside other expressions—list comprehensions, lambda functions, etc.* But it is also available for D expression! Python example: ```python arr = ["Even" if i % 2 == 0 else "Odd" for i in range(10)] ``` D example: ```d auto arr2 = iota(10) .map!(x => x % 2 ? "Odd" : "Even"); ```
Jun 04 2022
prev sibling next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 do you think would be nice that in D as well? I find it can 
 increase code reability...
No. The feature comes from Ocaml, where match, if, and any statements are expressions. Even there, it doesn't make things especially readable. It's more about an ideology that all statements must be expressions. Something that readable languages, like Python, Java, COBOL, BASIC... did not retain.
Jun 04 2022
prev sibling parent reply JN <666total wp.pl> writes:
On Friday, 3 June 2022 at 18:33:57 UTC, Jack wrote:
 Rust does support it like that:

 ```rust
     const limit:i32 = 30;
     let n = 10;
     let mut r = if n > limit { "big" } else { "small "};
     println!("{} is {} than {}", n, r, limit);
 ```

 do you think would be nice that in D as well? I find it can 
 increase code reability...
I like the Python version of it with is reordered compared to Rust/D: num_type = "even" if a % 2 = 0 else "odd"
Jun 04 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 4 June 2022 at 22:05:36 UTC, JN wrote:
 I like the Python version of it with is reordered compared to 
 Rust/D:

 num_type = "even" if a % 2 = 0 else "odd"
Yes, this is one is working well when the leftmost is the most common case and the right one is a fallback.
Jun 04 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 4 June 2022 at 22:21:12 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 4 June 2022 at 22:05:36 UTC, JN wrote:
 I like the Python version of it with is reordered compared to 
 Rust/D:

 num_type = "even" if a % 2 = 0 else "odd"
Yes, this is one is working well when the leftmost is the most common case and the right one is a fallback.
It is so far ahead of the D era that it needs to be focused on... For example (int i = 123_456_789;), the D feature that comes in ES12 has been there for years, but still no async/await in ES7! Anyway, will these features come one day?
 &&=
 ||=
 ??=
**Source:** https://www.pullrequest.com/blog/javascript-es2021-you-need-to-see-these-es12-features/
Jun 06 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 6 June 2022 at 14:30:28 UTC, Salih Dincer wrote:
 For example (int i = 123_456_789;), the D feature that comes in 
 ES12 has been there for years, but still no async/await in ES7! 
 Anyway, will these features come one day?
 &&=
 ||=
 ??=
Things that makes code *easier* to read is always something any language designer should be willing to consider IMO. I guess null-specific operators could qualify. Perhaps there is some generic way to do async/await, so developers could use it for custom Promises? Otherwise async/await is sort of out of place in system, but fits well in safe… In general it would be nice if high level syntax is interacting through protocols so that one can use it for generic programming (like for-loops do).
Jun 06 2022
prev sibling parent Jack <jckj33 gmail.com> writes:
On Monday, 6 June 2022 at 14:30:28 UTC, Salih Dincer wrote:
 On Saturday, 4 June 2022 at 22:21:12 UTC, Ola Fosheim Grøstad 
 wrote:
 On Saturday, 4 June 2022 at 22:05:36 UTC, JN wrote:
 I like the Python version of it with is reordered compared to 
 Rust/D:

 num_type = "even" if a % 2 = 0 else "odd"
Yes, this is one is working well when the leftmost is the most common case and the right one is a fallback.
It is so far ahead of the D era that it needs to be focused on... For example (int i = 123_456_789;), the D feature that comes in ES12 has been there for years, but still no async/await in ES7! Anyway, will these features come one day?
 &&=
 ||=
 ??=
that's really a nice set of operators to have...
 **Source:** 
 https://www.pullrequest.com/blog/javascript-es2021-you-need-to-see-these-es12-features/
Jun 06 2022