February 02, 2015
On 2/2/2015 10:44 AM, Iain Buclaw via Digitalmars-d wrote:
> On 2 February 2015 at 17:43, Andrei Alexandrescu via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 2/2/15 9:23 AM, Iain Buclaw via Digitalmars-d wrote:
>>>
>>> That code doesn't work with DMD.
>>>
>>> http://goo.gl/hgsHg0
>>
>>
>> Has that been filed yet? -- Andrei
>>
>
> https://issues.dlang.org/show_bug.cgi?id=14114

The optimizer is regarding as a "null" any value being dereferenced that is less than 4096.

Whether this is a bug or not is debatable.
February 02, 2015
On Monday, 2 February 2015 at 21:01:30 UTC, Johannes Pfau wrote:
> Am Mon, 02 Feb 2015 12:39:28 -0500
> schrieb Steven Schveighoffer <schveiguy@yahoo.com>:
>
>> On 2/2/15 12:06 PM, Johannes Pfau wrote:
>> > Am Mon, 02 Feb 2015 02:49:48 -0800
>> > schrieb Walter Bright <newshound2@digitalmars.com>:
>> 
>> >> Please try it before deciding it does not work.
>> >
>> > I guess one ad hominem wasn't enough?
>> 
>> Sorry, I'm not really vested in this discussion at all, but I don't think you realize what ad hominem means.
>> 
>> http://en.wikipedia.org/wiki/Ad_hominem
>> 
>> -Steve
>> 
>
> Ad hominem literally means 'to the person'. en/wikipedia reduces that
> to character but other definitions (de/wikipedia) include all arguments
> against a person instead of to the content of the arguments.
>
> Walter implicitly doubted my qualification in his last reply by
> claiming I don't understand how intrinsics work. Here he basically said
> I didn't even try to run the code and just making up issues. He's
> essentially saying I'm dishonest. He didn't respond to the content of my
> arguments. This is clearly not an argument, it's an attack on my
> reputation. So how is this not ad hominem?

I agree it was ad hominem, but I don't think Walter implied you were dishonest, so much as *ignorant* (i.e. of what would *really* happen if you just used the products as intended) - which implication is still bad, if proven false, but not quite as bad as calling you dishonest...
February 02, 2015
On 2/2/2015 9:06 AM, Johannes Pfau wrote:
> _Dmain:
> 	push   rbp
> 	mov    rbp,rsp
> 	sub    rsp,0x10
> 	mov    rax,0x5                      <==
> 	mov    QWORD PTR [rbp-0x8],rax
> 	mov    ecx,DWORD PTR [rax]          <== a register based load
>
> The instruction it should generate is
> mov ecx, [0x5]

In 64 bit mode, there is no direct addressing like that. The above would be relative to the instruction pointer, which is RIP, and is actually:

   mov ECX, 5[RIP]

So, to load address location 5, you would have to load it into a register first.

(You'd be right for 32 bit x86. But also, all 32 bit x86's have an MMU rather than direct addressing, and it would be strange to set up the x86 embedded system to use MMIO rather than the IO instructions, which are designed for that purpose.)


> Not sure if it's actually more efficient on X86 but it makes a huge
> difference on real microcontroller architectures.

What addressing mode is generated by the back end has nothing whatsoever to do with using volatileLoad() or pragma(address).

To reiterate, volatileLoad() and volatileStore() are not reordered by the optimizer, and replacing them with pragma(address) is not going to make for better code generation.

The only real issue is the forceinline one.
February 02, 2015
On Monday, 2 February 2015 at 21:19:05 UTC, Walter Bright wrote:
> On 2/2/2015 9:17 AM, H. S. Teoh via Digitalmars-d wrote:
>> Walter seems to dislike forced inlining for various reasons, preferring
>> inlining as a hint at the most, and he probably has a point in most
>> cases (let the compiler make the judgment). But in other cases, such as
>> the one in question, the user needs to override the compiler's decision.
>> Currently there's no way to do that, and it's a showstopper for those
>> users.
>
> This is a settled issue. After all, I wrote:
>
> http://wiki.dlang.org/DIP56

Erm. Quoting the DIP: "If a pragma specifies always inline, whether or not the target function(s) are actually inlined is implementation defined, although the implementation will be expected to inline it if practical."

This is exactly the absolutely unacceptable part that makes your DIP useless and last discussion has stalled (from my POV) exactly at the point where you refused to negotiate any compromises on that matter.
February 02, 2015
On 2/2/2015 1:24 PM, Johannes Pfau wrote:
> What's your argument?
> That it still generates 2 instructions in the simplest case? That's an
> X86 specific detail. On ARM and other RISC architectures there is a
> difference between loading a literal (code into the instruction) or
> loading a runtime value. On AVR gcc can even rewrite bit-sized stores
> into set-bit and loads into read-bit instructions, but it needs to
> know the addresses at compile time. If you don't believe me get an
> AVR/ARM compiler and try it.

A code generator for a specific architecture will naturally generate code that caters to it. volatileLoad()/Store() does not impede that, and a pragma(address) will not help.

February 02, 2015
On Mon, Feb 02, 2015 at 09:53:43PM +0000, Dicebot via Digitalmars-d wrote:
> On Monday, 2 February 2015 at 21:19:05 UTC, Walter Bright wrote:
> >On 2/2/2015 9:17 AM, H. S. Teoh via Digitalmars-d wrote:
> >>Walter seems to dislike forced inlining for various reasons, preferring inlining as a hint at the most, and he probably has a point in most cases (let the compiler make the judgment). But in other cases, such as the one in question, the user needs to override the compiler's decision.  Currently there's no way to do that, and it's a showstopper for those users.
> >
> >This is a settled issue. After all, I wrote:
> >
> >http://wiki.dlang.org/DIP56
> 
> Erm. Quoting the DIP: "If a pragma specifies always inline, whether or not the target function(s) are actually inlined is implementation defined, although the implementation will be expected to inline it if practical."
> 
> This is exactly the absolutely unacceptable part that makes your DIP useless and last discussion has stalled (from my POV) exactly at the point where you refused to negotiate any compromises on that matter.

Yes, and this is the sore point with the force-inline proponents. You're dangling the carrot of inline control in front of them, but snatch it away with the "implementation-defined" part. That might as well not be any control at all, since the default inlining behaviour is already implementation-defined; having two states of implementation-defined behaviour doesn't give us anything better than what we already have.

The whole point behind inline control is to give the programmer a way to *override* the compiler's decision when the compiler's decision is wrong. By saying it's implementation-defined, you put the decision back in the compiler's hands, and so the compiler may continue making the same wrong decision, and we have achieved nothing at all.

Of course, this is the pessimistic interpretation of DIP56, and perhaps, as a bystander, I can hazard a guess as to why forced inlining is left to the compiler's discretion -- one might want a compiler flag to disable forced inlining for debugging purposes, for example. However, without being more specific about exactly under what circumstances forced inlining is not obeyed, DIP56 leaves the decision completely in the implementor's hands, and users have no choice but to assume the worst.


T

-- 
Notwithstanding the eloquent discontent that you have just respectfully expressed at length against my verbal capabilities, I am afraid that I must unfortunately bring it to your attention that I am, in fact, NOT verbose.
February 02, 2015
Am Mon, 02 Feb 2015 13:44:41 -0800
schrieb Walter Bright <newshound2@digitalmars.com>:

> On 2/2/2015 9:06 AM, Johannes Pfau wrote:
> > _Dmain:
> > 	push   rbp
> > 	mov    rbp,rsp
> > 	sub    rsp,0x10
> > 	mov    rax,0x5                      <==
> > 	mov    QWORD PTR [rbp-0x8],rax
> > 	mov    ecx,DWORD PTR [rax]          <== a register based
> > load
> >
> > The instruction it should generate is
> > mov ecx, [0x5]
> 
> In 64 bit mode, there is no direct addressing like that. The above would be relative to the instruction pointer, which is RIP, and is actually:
> 
>     mov ECX, 5[RIP]
> 
> So, to load address location 5, you would have to load it into a register first.
> 
> (You'd be right for 32 bit x86. But also, all 32 bit x86's have an MMU rather than direct addressing, and it would be strange to set up the x86 embedded system to use MMIO rather than the IO instructions, which are designed for that purpose.)
> 

Well, as I said it's different on RISC. I'm mainly programming for ARM, AVR MSP430 and similar systems, not X86.

> 
> > Not sure if it's actually more efficient on X86 but it makes a huge difference on real microcontroller architectures.
> 
> What addressing mode is generated by the back end has nothing
> whatsoever to do with using volatileLoad() or pragma(address).

I does: if the backend can't know that a value is known at compile time it cant use absolute addresses:

void test(ubyte* ptr)
{
    volatileLoad(ptr); //Can't use literal addressing might be runtime
    value
}

The context here is that pragma(address) allows avoiding one wrapper
function. See below.

ARM can code address literals into instructions. So you end up with one instruction for a load from a compile time known address.

> 
> To reiterate, volatileLoad() and volatileStore() are not reordered by
> the optimizer, and replacing them with pragma(address) is not going
> to make for better code generation.
> 
> The only real issue is the forceinline one.

I think we're talking different languages. Nobody ever proposed pragma(address) to replace volatileLoad. It's meant to be used together with the volatile intrinsics like this:
-----------------------------------------------------------------
import core.bitop;

struct Volatile(T)
{
private:
    T _store;

public:
    @disable this(this);

    /**
     * Performs 1 load followed by 1 store
     */
    @attribute("inlineonly") void opOpAssign(string op)(in T rhs)
nothrow @trusted {
        T val = volatileLoad(&_store);
        mixin("val" ~ op ~ "= rhs;");
        volatileStore(&_store, val);
    }
    //In reality, much more complicated wrappers are possible
    //http://pastebin.com/RGhKdm9i
}

pragma(address, 0x05) extern __gshared Volatile!ubyte PORTA;

//...
PORTA |= 0b0000_0001;
auto addr = &PORTA;
-----------------------------------------------------------------

The pragma(address, 0x05) makes sure that the compiler backend always knows that PORTA is at 0x05. Thinks like &PORTA become trivial and the compiler backend has exactly the same knowledge as if you'd use C volatile => all optimizations apply.

And if you call opopAssign the backend knows that the this pointer is a
compile time literal value and generates exactly the same code as if
you wrote
        T val = volatileLoad(0x05);
        val ~ op ~ = rhs;
        volatileStore(0x05, val);




but if you instead write
@property ref Volatile!ubyte PORTA()
{
    return *(cast(Volatile!(ubyte)*)0x05)
}

PORTA |= now calls a function behind the scenes. The backend does not immediately know that &PORTA is always 0x05. Also the this pointer in opopAssign is no longer a compile time constant. And this is were the constant/runtime value code gen difference discussed above matters.

-O mostly fixes performance problems, but adding an additional property function is still much uglier than declaring an extern variable with an address in many ways. (compiler bugs, user-facing code, debug info, ...)


Also it's a conceptually nice way for typed registers: You can read it as: I've got a Register of type PORT which is an extern variable located add a fixed address. PORT abstract away volatile access.
February 02, 2015
On Monday, February 02, 2015 13:01:28 Walter Bright via Digitalmars-d wrote:
> On 2/2/2015 6:43 AM, Manu via Digitalmars-d wrote:
> > I'm pretty sure the only controversy is that you want it to be a pragma, everyone else wants it to be an attribute.
>
> That's correct.
>
> My reasoning is simple - an attribute defines the semantics of the interface, a pragma gives instructions to the compiler, and does not affect logical semantics.
>
> For example, attributes change the name mangling, because it affects the semantic interface. A pragma would not.

That makes sense, though the one issue that I see with making it a pragma is the fact that pragmas are supposed to be compiler-specific and not part of the language (at least as I understand it), and I would expect that anyone looking to force inlining would want it guaranteed regardless of the compiler. Of course, all compilers could implement it, and with a shared frontend for most of the D compilers, it would likely be in most of them anyway, but if it's a pragma, it does seem like it wouldn't necessarily be guaranteed.

- Jonathan M Davis

February 02, 2015
On 2/2/2015 1:53 PM, Dicebot wrote:
>> http://wiki.dlang.org/DIP56
>
> Erm. Quoting the DIP: "If a pragma specifies always inline, whether or not the
> target function(s) are actually inlined is implementation defined, although the
> implementation will be expected to inline it if practical."
>
> This is exactly the absolutely unacceptable part that makes your DIP useless and
> last discussion has stalled (from my POV) exactly at the point where you refused
> to negotiate any compromises on that matter.

That interpretation is a little over the top. Any reasonable implementation is going to do what it can to inline when asked to - people who write compilers do not try to perversely interpret the spec in order to be as useless as possible. (After all, we are not writing the tax code!)

Now, when it can't inline, do you expect the compiler to produce an error message? If so, what corrective action is the user faced with:

   pragma(inline, some expression that determines the compiler version and evaluates to true only if this particular function can be inlined);

? Such will necessarily be brittle, and of dubious utility.

February 02, 2015
On 2/2/2015 2:30 PM, Johannes Pfau wrote:
> I does: if the backend can't know that a value is known at compile time
> it cant use absolute addresses:
>
> void test(ubyte* ptr)
> {
>      volatileLoad(ptr); //Can't use literal addressing might be runtime
>      value
> }
>
> The context here is that pragma(address) allows avoiding one wrapper
> function. See below.

Again, that is simply an inlining issue.


> The pragma(address, 0x05) makes sure that the compiler backend always
> knows that PORTA is at 0x05.

Constant propagation and inlining do that. Both are standard optimizations that every compiler does. Adding language features on the presumption that compilers won't do that is like trying to fix the broken engine in your car by adding another engine in the trunk.


> -O mostly fixes performance problems, but adding an additional property
> function is still much uglier than declaring an extern variable with an
> address in many ways. (compiler bugs,

Language features should not be added because of compiler bugs.

> user-facing code,

Library wrapper types will be showing up more and more. How nice they are is up to the library designer.


> debug info, ...)

Symbolic debugging is always going to be an issue until there are debuggers that are better designed to work with D.


> Also it's a conceptually nice way for typed registers: You can read it
> as: I've got a Register of type PORT which is an extern variable located
> add a fixed address. PORT abstract away volatile access.

    auto a = PORT!0x1234;

looks nicer than:

    pragma(address, 0x1234) PORT a;