July 31, 2014
On Thursday, 31 July 2014 at 07:42:16 UTC, Walter Bright wrote:
> On 7/30/2014 6:16 PM, Dicebot wrote:
>> On Wednesday, 30 July 2014 at 23:50:51 UTC, H. S. Teoh via Digitalmars-d wrote:
>>> But if you don't want to check ever to be removed, currently you have to
>>> write:
>>>
>>>    if (!requiredCondition)
>>>        assert(0); // compiler never removes this
>>>
>>> which IMO is relatively clear, and the use of assert(0) for forceful
>>> termination is consistent with existing practice in D code.
>>
>> Not helping.
>>
>> ```
>> import std.stdio;
>>
>> void foo()
>> in { writeln("in contract"); }
>> body { }
>>
>> void main() { foo(); }
>> ```
>>
>> Compile with -release and check the output.
>
> What do you expect to happen?

It acts as defined in spec, nothing unexpected here. I was referring to H. S. Teoh proposed workaround to keep assertions in release mode - it does not work with contracts because those are eliminated completely, not just assertions inside.
July 31, 2014
On Thursday, 31 July 2014 at 15:37:23 UTC, Daniel Gibson wrote:
> If removing code makes my code faster, I can do it myself.

No, in general you can't. Opportunities for dead code elimination often only present themselves after inlining and/or in generic (as in templates) code.

David
July 31, 2014
Daniel Gibson:

>>    asm {"" : : "m" (*cast(typeof(password[0])[9999999]*)password.ptr); }
>
> inline asm is not portable

See:
https://d.puremagic.com/issues/show_bug.cgi?id=10661


> C11 defines a memset_s which is guaranteed not to be optimized away..
> that's 9 years after that bugreport and will probably never be supported by MSVC (they don't even support C99).

See:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366877%28v=vs.85%29.aspx

Bye,
bearophile
July 31, 2014
On 07/31/14 17:37, Daniel Gibson via Digitalmars-d wrote:
> Am 31.07.2014 17:26, schrieb Artur Skawina via Digitalmars-d:
>> On 07/31/14 15:44, Daniel Gibson via Digitalmars-d wrote:
>>> And don't forget this (rather old) case: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8537
>>> (I really don't get why anyone would want such an optimization: I want an optimizer to use clever inlining, use SSE etc where it makes sense and stuff like that - but not to remove code I wrote.)
>>
>> That is actually not a bug, but a perfectly valid optimization. The compiler isn't clairvoyant and can not know that some data that you wrote, but never read back, matters.
> 
> I don't want the compiler to care about that. When I tell it to write something, I want it to do that, even if it might look like nonsense (if anything, it could create a warning).

This approach becomes completely impractical once generic code (templates) enters the picture. But even for simple cases, it does not work. Keep in mind that D initializes every object by default...


>> The solution is to tell the compiler that you really need that newly
>> (over-)written data. Eg
>>
>>     asm {"" : : "m" (*cast(typeof(password[0])[9999999]*)password.ptr); }
> 
> inline asm is not portable

That's why a portable compiler barrier interface is needed.
But this was just an example showing a zero-cost solution. A portable
fallback is always possible (the bug report was about C code -- there,
a loop that reads the data and stores a copy into a volatile location
would work).

artur
July 31, 2014
On 7/31/14, 8:37 AM, Daniel Gibson wrote:
> When I tell it to write something, I want it to do that, even if it
> might look like nonsense (if anything, it could create a warning).

I'm afraid those days are long gone by now. -- Andrei
July 31, 2014
On Thursday, 31 July 2014 at 15:37:23 UTC, Daniel Gibson wrote:
> Am 31.07.2014 17:26, schrieb Artur Skawina via Digitalmars-d:
>> On 07/31/14 15:44, Daniel Gibson via Digitalmars-d wrote:
>>> And don't forget this (rather old) case: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8537
>>> (I really don't get why anyone would want such an optimization: I want an optimizer to use clever inlining, use SSE etc where it makes sense and stuff like that - but not to remove code I wrote.)
>>
>> That is actually not a bug, but a perfectly valid optimization. The
>> compiler isn't clairvoyant and can not know that some data that you
>> wrote, but never read back, matters.
>
> I don't want the compiler to care about that. When I tell it to write something, I want it to do that, even if it might look like nonsense (if anything, it could create a warning).
>
> The thing is: I don't want a compiler to remove code I wrote just because it "thinks" it's superfluous.

The idea that the compiler simply lowers your code to well-written assembly died decades ago. The job of an optimiser is to *not* use your code but instead to compile a program that is equivalent to yours but faster/smaller. What is equivalent is defined by the language spec.
July 31, 2014
On Thu, Jul 31, 2014 at 03:44:35PM +0200, Daniel Gibson via Digitalmars-d wrote: [...]
> And don't forget this (rather old) case:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8537
> (I really don't get why anyone would want such an optimization: I want
> an optimizer to use clever inlining, use SSE etc where it makes sense
> and stuff like that - but not to remove code I wrote.)
[...]

Modern compilers often have to deal with generated code (that isn't directly written by the programmer, e.g., expanded from a C++ template -- or, for that matter, generated by a code generator like lex / yacc). In this case, you *do* want dead code removal because the code generator may be written in a way that takes care of the general case, but in your specific case some of the generated code is redundant.  You don't want to penalize specific instances of the generic code pattern, after all.


T

-- 
The richest man is not he who has the most, but he who needs the least.
July 31, 2014
On Thursday, 31 July 2014 at 16:37:40 UTC, H. S. Teoh via Digitalmars-d wrote:
> On Thu, Jul 31, 2014 at 03:44:35PM +0200, Daniel Gibson via Digitalmars-d wrote:
> [...]
>> And don't forget this (rather old) case:
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8537
>> (I really don't get why anyone would want such an optimization: I want
>> an optimizer to use clever inlining, use SSE etc where it makes sense
>> and stuff like that - but not to remove code I wrote.)
> [...]
>
> Modern compilers often have to deal with generated code (that isn't
> directly written by the programmer, e.g., expanded from a C++ template
> -- or, for that matter, generated by a code generator like lex / yacc).
> In this case, you *do* want dead code removal because the code generator
> may be written in a way that takes care of the general case, but in your
> specific case some of the generated code is redundant.  You don't want
> to penalize specific instances of the generic code pattern, after all.

Both points of view make sense. The problem is that it's hard for the compiler to know when the code it elides was generated code or explicitly written. (Maybe this is solvable in dmd,  I don't know. But it's not a feature I've seen before.)


July 31, 2014
On Thu, Jul 31, 2014 at 02:05:29AM +0000, Tofu Ninja via Digitalmars-d wrote:
> On Wednesday, 30 July 2014 at 22:01:23 UTC, Walter Bright wrote:
> 
> >3. Use of assert to validate input is utterly wrong and will not be supported. Use such constructs at your own risk.
> 
> When exactly is it 'ok' to use assert then?
> 
> If asserts are not allowed to be used to verify inputs.... then by extension, they can not be used to verify any derivative of an input.

No that doesn't make sense. The idea behind input sanitization is that user-facing APIs receive arbitrary, unverified input from outside, and before you use that data, you scrub it. After scrubbing it, it's perfectly OK to use assert to verify its validity -- because if it's still invalid, there's a bug in your scrubbing algorithm. The scrubbed input *is* a derivative of the input, but you can't say that you can't use assert on it!

(And if you *don't* scrub your data before using it, your design is
flawed and should be fixed.)


> So by that definition, asserts are only ok to use on any thing known at compile time... that makes them utterly useless....

Your definition is wrong. ;-) The idea behind asserts is that you're verifying *program logic*, not checking arbitrary input data. If you have an algorithm that computes a square root, for example, you'd use an assert to verify that the square of the result equals the input -- because if not, that means something has gone wrong with your square root algorithm. But you shouldn't use an assert to verify that the input to the square root algorithm is a valid numerical string -- because the user could have typed "abc" instead of a number. Rather, you should scrub the user input and throw an exception when the input is invalid.

After scrubbing, however, it's perfectly valid to assert that the input must be a valid number -- because if not, it means the *logic* in your scrubbing algorithm is flawed (perhaps it missed a corner case).

It's true, however, that this simple idea is not always so simple in practice. One has to draw a line between "user input" and "internal state" somewhere, and it's not always obvious where that line falls. For example, viewed as a whole, the entire software application may be considered a system that takes input from outside, so "user input" means things like keystrokes, mouse movements, etc.. But internally, the system may consist of multiple components, and when data is passed between components, should they be treated as "internal state" or "user input"? Should library APIs treat application input as "external input" and vet it before use, or is it OK to use assert to enforce(!) the validity of data passed internally between the application's components? It's not always easy to decide, and sometimes judgment calls have to be made.


T

-- 
If creativity is stifled by rigid discipline, then it is not true creativity.
July 31, 2014
On Thursday, 31 July 2014 at 15:26:27 UTC, Artur Skawina via Digitalmars-d wrote:
> On 07/31/14 15:44, Daniel Gibson via Digitalmars-d wrote:
>> And don't forget this (rather old) case: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8537
>> (I really don't get why anyone would want such an optimization: I want an optimizer to use clever inlining, use SSE etc where it makes sense and stuff like that - but not to remove code I wrote.)
>
> That is actually not a bug, but a perfectly valid optimization. The
> compiler isn't clairvoyant and can not know that some data that you
> wrote, but never read back, matters.
>
> The solution is to tell the compiler that you really need that newly
> (over-)written data. Eg
>
>    asm {"" : : "m" (*cast(typeof(password[0])[9999999]*)password.ptr); }
>
> (yes, stdizing compiler barriers would be a good idea)
>
> artur

Any idea how dead store removal interacts with the modern C(++) memory model? Another thread could hold a reference to the memory being written to.