comp.lang.ada
 help / color / mirror / Atom feed
* GNAT not generating any code for sub‑program: known bug?
@ 2013-04-27 21:08 Yannick Duchêne (Hibou57)
  2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
  2013-04-28 22:35 ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
  0 siblings, 2 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-27 21:08 UTC (permalink / raw)


Hi all,

I will make a stripped‑down version of the case, later. So far I just  
wonder if any one already encountered a similar case: GNAT not generating  
any code for a sub‑program. Here what it generates instead, according to  
the assembly file:

     .cfi_startproc
     ret
     .cfi_endproc

And that's all. I could just notice it appears as soon as any `-On` option  
is given and disappears when `-O0` is explicitly given to disallow any  
optimization.

Is this a known bug?

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-27 21:08 GNAT not generating any code for sub‑program: known bug? Yannick Duchêne (Hibou57)
@ 2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
  2013-04-27 23:48   ` Yannick Duchêne (Hibou57)
  2013-04-28  7:14   ` Simon Wright
  2013-04-28 22:35 ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
  1 sibling, 2 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-27 22:22 UTC (permalink / raw)


Le Sat, 27 Apr 2013 23:08:52 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:

> Hi all,
>
> I will make a stripped‑down version of the case, later.

Here is:
http://www.les-ziboux.rasama.org/download/2013-04-28-cla-gnat-bug.zip

The bug disappears when optimization is disabled or else when the  
sub‑program is made inlinable. That's not only with this single  
sub‑program, I get it with all of the same kind. I've checked it's the  
same whether I'm compiling with `gprbuild` or `gnatmake`. I've checked  
this is not due to the heavily stripped down runtime (rather no runtime at  
all) I am using, as this occurs also when compiling using the compiler's  
default runtime. The case occurs with GNAT from GCC 4.8. I don't really  
know if it's a GNAT bug or a GCC bug.

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
@ 2013-04-27 23:48   ` Yannick Duchêne (Hibou57)
  2013-04-28  7:14   ` Simon Wright
  1 sibling, 0 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-27 23:48 UTC (permalink / raw)


Le Sun, 28 Apr 2013 00:22:41 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:

> Le Sat, 27 Apr 2013 23:08:52 +0200, Yannick Duchêne (Hibou57)  
> <yannick_duchene@yahoo.fr> a écrit:
>
>> Hi all,
>>
>> I will make a stripped‑down version of the case, later.
>
> Here is:
> http://www.les-ziboux.rasama.org/download/2013-04-28-cla-gnat-bug.zip
>
> The bug disappears when optimization is disabled or else when the  
> sub‑program is made inlinable.

Seems there is an issue with sub‑program using Ada's machine‑code  
insertion.

If the sub‑program which contains machine‑code insertion is not inlined,  
then the machine‑code insertion part gets dropped by compiler  
optimization, which so seems to be more a GCC bug than a GNAT bug. The  
sub‑programs invoke this sub‑program either directly or indirectly, also  
has to all be inlined too.

There is a work‑around: implement the sub‑program using machine‑code  
insertion as a generic, say `GP`. Then implement `P` which use an  
instantiation of `GP` internally, and it will works. `GP` cannot be  
declared inlined, or else you will get a GNAT bug‑box. However, if `P`  
declared inlined, then its containing `GP` instantiation will be properly  
inlined. `P` will be generated when it's either inlined or not  
(effectively workaround the bug), and will be really fully inline if  
declared inlined (no efficiency cost).

Template as a summary:

     generic
        …
     procedure/function GP (…);
     -- No `Inline` here! either `True` or `False`,
     -- or else GNAT says “kaboom”.

     procedure/function GP (…) is
     begin
       -- Machine code insertion here
     end;

     procedure/function P (…)
        [with Inline => True/False];
        -- Works with either of the three.

     procedure/function P (…) is
         procedure/function Implementation is
            new GP (…);
     begin
         [return] Implementation (…);
     end;


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
  2013-04-27 23:48   ` Yannick Duchêne (Hibou57)
@ 2013-04-28  7:14   ` Simon Wright
  2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
  1 sibling, 1 reply; 19+ messages in thread
From: Simon Wright @ 2013-04-28  7:14 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> Here is:
> http://www.les-ziboux.rasama.org/download/2013-04-28-cla-gnat-bug.zip

The code is

   function Syscall
     (Number  : Positive;
      Handle  : Natural;
      Address : System.Address;
      Size    : Natural)
      return Integer
   is
      Result : Integer;
   begin
      System.Machine_Code.Asm
        (Template => "int $0x80",
         Outputs => Integer'Asm_Output ("=a", Result),
         Inputs =>
           (Positive'Asm_Input       ("a", Number),
            Natural'Asm_Input        ("b", Handle),
            System.Address'Asm_Input ("c", Address),
            Natural'Asm_Input        ("d", Size)),
         Volatile => False);
      return Result;
   end;

and I think that the problem is that Template actually has to use the
inputs and outputs! So, while optimising, the compiler says

   "int $0x80" doesn't use any of the inputs, so I can ignore them
   "int $0x80" doesn't write to any of the outputs, so I can ignore them
   Result isn't changed, so it's undefined
   Therefore I don't need to do anything.

The assembler generated by GNAT GPL 2012 is different but equally
ineffective:

.globl _library__write
_library__write:
LFB3:
        pushq   %rbp
LCFI0:
        movq    %rsp, %rbp
LCFI1:
        leave
LCFI2:
        ret
LFE3:

I think that you have to write the template to show how the parameters
are set up and returned. Here's one I wrote earlier:

   with Ada.Unchecked_Conversion;
   with System.Machine_Code;

   separate (BC.Support.High_Resolution_Time)
   function Clock return Time is

      type Half is (Low, High);
      type Low_High is array (Half) of Interfaces.Unsigned_32;

      Lower, Upper : Interfaces.Unsigned_32;

      function To_Time is new Ada.Unchecked_Conversion (Low_High, Time);

   begin

      System.Machine_Code.Asm
        ("rdtsc" & ASCII.LF & ASCII.HT &
           "movl %%eax, %0"& ASCII.LF & ASCII.HT &
           "movl %%edx, %1",
         Outputs => (Interfaces.Unsigned_32'Asm_Output ("=g", Lower),
                     Interfaces.Unsigned_32'Asm_Output ("=g", Upper)),
         Clobber => "eax, edx",
         Volatile => True);

      return To_Time ((Low => Lower, High => Upper));

   end Clock;

By the way, this doesn't actually work as intended on kit such as the
Macbook Pro (more than one core? advanced power management?), presumably
because the core's clock is slowed down or stopped. Fortunately,
Ada.Calendar.Clock's resolution is 1 microsecond, good enough for most
purposes.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-28  7:14   ` Simon Wright
@ 2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
  2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
  2013-04-28 20:43       ` Simon Wright
  0 siblings, 2 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-28 17:52 UTC (permalink / raw)


Le Sun, 28 Apr 2013 09:14:55 +0200, Simon Wright <simon@pushface.org> a  
écrit:

> and I think that the problem is that Template actually has to use the
> inputs and outputs! So, while optimising, the compiler says
>
>    "int $0x80" doesn't use any of the inputs, so I can ignore them
>    "int $0x80" doesn't write to any of the outputs, so I can ignore them
>    Result isn't changed, so it's undefined
>    Therefore I don't need to do anything.

I thought about the same previously (not my first attempt), and retried  
what I tried before, with the same result:

     function Syscall_3
       (N  : Number_Type;
        P1 : P1_Type;
        P2 : P2_Type;
        P3 : P3_Type)
        return Result_Type
     is
        use System.Machine_Code;
        Result : Result_Type;
     begin
        Asm
          (Template =>
             "movl %1, %%eax"  & ASCII.LF &
             "movl %2, %%ebx"  & ASCII.LF &
             "movl %3, %%ecx"  & ASCII.LF &
             "movl %4, %%edx"  & ASCII.LF &
             "int $0x80"       & ASCII.LF &
             "movl %%eax, %0"  & ASCII.LF,
           Outputs => Result_Type'Asm_Output ("=g", Result),
           Inputs =>
             (Number_Type'Asm_Input ("g", N),
              P1_Type'Asm_Input     ("g", P1),
              P2_Type'Asm_Input     ("g", P2),
              P3_Type'Asm_Input     ("g", P3)),
           Clobber => "eax, ebx, ecx, edx",
           Volatile => True);

        return Result;

     end Syscall_3;

Here (except it's a generic to avoid error while copying similar things),  
the template contains all of the instructions loading registers, to be  
clear about the inputs the template uses. Then, I used a `Clobber` list  
[1][3] to explicitly notify the compiler of the registers used in the  
template and which must remains untouched, then I also added `Volatile =>  
True` [2][3] to notify the compiler it should avoid unwanted optimization.  
The result is still the same, and so, even if the generic instantiation is  
not inlined (the generic declaration is not inlined neither). That's  
enough for a a caller to be inlined for everything to be dropped, even if  
the above subprogram itself not inlined. I agree I must tell the compiler  
what it is dealing with and what not to do with it, but so far, I still  
feel that looks like a compiler bug (GCC's fault or GNAT's fault?). Will  
try something else later.


Side note: with the `type Low_High is array (Half) of  
Interfaces.Unsigned_32;` in your snippet, shouldn't you specify the array  
should be packed? Or may be that's already implied by the component type…  
will have to check the RM.


[1]: http://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_38.html#SEC382
[2]: http://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_38.html#SEC383
[3]: http://docs.adacore.com/gnat-unw-docs/html/gnat_rm_15.html#SEC626


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
@ 2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
  2013-04-28 20:46         ` Simon Wright
  2013-04-28 20:43       ` Simon Wright
  1 sibling, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-28 19:27 UTC (permalink / raw)


Le Sun, 28 Apr 2013 19:52:18 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:
> I still feel that looks like a compiler bug (GCC's fault or GNAT's  
> fault?).

That's me who bugged and that's my fault :D

Explanations with two points.

1) In the archive linked in this thread, if I change `Volatile => False`  
into `Volatile => True`, it works, without even a need to use `Clobber`.  
Thus, the initial case is solved.

2) In a later message I tried something else, with `Volatile => True`,  
this did not work neither as I said, while it should have work. That was  
because something else also changed: the package specification hold a  
`pragma Pure;` and that was wrong [1]. I changed `pragma Pure;` into  
`pragma Preelaborate;` and it now works as expected.


[1]: http://www.ada-auth.org/standards/12rm/html/RM-10-2-1.html#p18
> If a library unit is declared pure, then the implementationis permitted  
> to omit a call on a library-level subprogramof the library unit if the  
> results are not needed after thecall. In addition, the implementation  
> may omit a call on sucha subprogram and simply reuse the results  
> produced by an earliercall on the same subprogram, provided that […]

That's a quoted from “Implementation permissions”, and I forget it. Well,  
honestly, I believe this should part of the semantic. If you read the  
semantic part (above), which is what I typically focus on, nothing there  
implies or even suggest this implementation permission. The semantic part  
should have an explicit reference to side effects, and not just  
elaboration. By the way, the whole page is titled “Elaboration Control”,  
not “Sub‑program invocation semantic”. It's unlikely someone will search  
in elaboration control to learn about sub‑program call semantic, these are  
two different things. Well, that's a personal opinion, and I may be wrong  
with it (if so, please, tell me why).


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
  2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
@ 2013-04-28 20:43       ` Simon Wright
  1 sibling, 0 replies; 19+ messages in thread
From: Simon Wright @ 2013-04-28 20:43 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> Side note: with the `type Low_High is array (Half) of
> Interfaces.Unsigned_32;` in your snippet, shouldn't you specify the
> array should be packed? Or may be that's already implied by the
> component type... will have to check the RM.

It never occurred to me that it wouldn't be ... of course I'd get a GNAT
warning if the size of Low_High wasn't the size of a Time (64).



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: GNAT not generating any code for sub‑program: known bug?
  2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
@ 2013-04-28 20:46         ` Simon Wright
  0 siblings, 0 replies; 19+ messages in thread
From: Simon Wright @ 2013-04-28 20:46 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> 1) In the archive linked in this thread, if I change `Volatile =>
> False` into `Volatile => True`, it works, without even a need to use
> Clobber`. Thus, the initial case is solved.

Or you could, less satisfactorily, say

   procedure Write (Item : in String) is
      Status : Integer with Volatile;



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Erroneous code generation from GNAT or GCC?
  2013-04-27 21:08 GNAT not generating any code for sub‑program: known bug? Yannick Duchêne (Hibou57)
  2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
@ 2013-04-28 22:35 ` Yannick Duchêne (Hibou57)
  2013-04-28 22:49   ` Yannick Duchêne (Hibou57)
  2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
  1 sibling, 2 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-28 22:35 UTC (permalink / raw)


Le Sat, 27 Apr 2013 23:08:52 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:

> Hi all,
>
> I will make a stripped‑down version of the case, later. So far I just  
> wonder if any one already encountered a similar case: GNAT not  
> generating any code for a sub‑program. Here what it generates instead,  
> according to the assembly file:
>
>      .cfi_startproc
>      ret
>      .cfi_endproc
>
> […]
> Is this a known bug?

This topic was solved, but in the while, I'm encountering something which  
is frightening me a bit. That's not dropped code, but erroneous code  
generation.

The context: a sub‑program use machine‑code insertion. For convenience and  
avoid errors, this sub‑program is generic. Then, some sub‑program  
instantiate this generic locally, as part of their implementations.

As a remainder, here is the generic using machine‑code insertion:


     function Invoke_3
       (N  : Number_Type;
        P1 : P1_Type;
        P2 : P2_Type;
        P3 : P3_Type)
        return Result_Type
     is
        use System.Machine_Code;
        Result : Result_Type;
     begin

        Asm
          (Template => "int $0x80",
           Outputs => Result_Type'Asm_Output ("=a", Result),
           Inputs =>
             (Number_Type'Asm_Input ("a", N),
              P1_Type'Asm_Input     ("b", P1),
              P2_Type'Asm_Input     ("c", P2),
              P3_Type'Asm_Input     ("d", P3)),
           Volatile => True);

        return Result;

     end Invoke_3;


Now, here is a sample sub‑program instantiating this generic as part of  
its implementation:


     procedure Write (Item : in Character) is

        use Syscall_Numbers;
        use Syscalls;
        use Types;

        Status  : Result_Type;
        Size    : constant Size_Type := (Character'Size / 8);

        function Implementation
           is new Invoke_3
             (P1_Type     => Handle_Type,
              P2_Type     => Address_Type,
              P3_Type     => Size_Type)
              with Inline => True;

     begin
        Status := Implementation
          (N  => NR_write,
           P1 => 1,
           P2 => Item'Address,
           P3 => Size);
     end;


Note `P2`, which is the address argument, goes into ecx (see `Invoke_3`  
above).

This sub‑program will print an ASCII character to the standard output,  
using a Linux system‑call. It will later be changed a bit, to show an  
issue. This one version is working.

Note: so far, `Status` are not interpreted, I know, don't care.

Now, as sample use would be:


     Write ('[');


Note: the platform is 32 bits, so all stack operations are 32 bits  
(push/pop/add and sub on esp).

Here is the generated code for the invocation of the working version:


     movl	$91, (%esp)
     call	library__write__2


First, the character code passed as an argument is written at [esp], the  
the sub‑program in invoked, thus the character code argument is now at  
[esp+4] (32 bits platform).

Now, the generated code of the working version, which is invoked by the  
above:


     library__write__2:
     .LFB7:
        .cfi_startproc
        pushl   %ebx            #
        .cfi_def_cfa_offset 8
        .cfi_offset 3, -8
        subl    $12, %esp       #,
        .cfi_def_cfa_offset 20
        movl    20(%esp), %eax  # item, item
        movb    %al, (%esp)     # item, item
        movl    $1, %edx        #, tmp64
        movl    %esp, %ecx      #, item.19
        movl    $4, %eax        #, tmp63
        movl    %edx, %ebx      # tmp64, tmp64
        int $0x80


Remember when invoked, the argument is tat [esp+4]. The sub‑program pushes  
ebx, so the argument is now at [esp+4]. Then it substract 12 to esp, so  
the argument is now at [esp+20]. Then it reads the value at [esp+20],  
store it in eax, then write eax at [esp], in finally store esp to ecx,  
which is OK, ecx holds the address of the parameter. The system‑call is  
successfully invoked.


Now, change `Write` to that it does not get the address of it's argument,  
but get the address of a local copy of its argument (rather same as above,  
changes are marked):


     procedure Write (Item : in Character) is

        use Syscall_Numbers;
        use Syscalls;
        use Types;

        Element : Character := Item; -- <<< Copy of argument
        Status  : Result_Type;
        Size    : constant Size_Type := (Character'Size / 8);

        function Implementation
           is new Invoke_3
             (P1_Type     => Handle_Type,
              P2_Type     => Address_Type,
              P3_Type     => Size_Type)
              with Inline => True;

     begin
        Status := Implementation
          (N  => NR_write,
           P1 => 1,
           P2 => Element'Address, -- <<< Address of the copy
           P3 => Size);
     end;


This one should behave the same, isn't it? It just store of `Item` to  
local `Element` and so pass `Element'Address` to the system‑call, instead  
of `Item'Address`. Sounds right…


The code generated by GNAT for the invocation part is the same as earlier  
above:


     movl	$91, (%esp)
     call	library__write__2

Still the same, at the entry point of the sub‑program, the argument is at  
[esp+4].

Now, here the code generated for the slightly modified subprogram:


     library__write__2:
     .LFB7:
        .cfi_startproc
        pushl   %ebx            #
        .cfi_def_cfa_offset 8
        .cfi_offset 3, -8
        subl    $24, %esp       #,
        .cfi_def_cfa_offset 32
        movl    $1, %edx        #, tmp65
        leal    15(%esp), %ecx  #, element.19
        movl    $4, %eax        #, tmp64
        movl    %edx, %ebx      # tmp65, tmp65
        int $0x80


As with the previous version, it starts pushing ebx, so the argument is  
now at [esp+8]. Then it substract 24 to esp, so the argument is now at  
[esp+32]. But look at what it stores to ecx: it's the effective address  
(lea is the Intel assembly instruction Load Effective Address)  
corresponding to [esp+15]. This is the wrong address, the good address is  
17 bytes above. Above all, this address does not make any sense, it is not  
even 32 bits aligned. Obviously, the system‑call does not print what's  
expected (it print nothing, probably there is a non‑printable character at  
[esp+15]).

Also note nowhere a copy is made (remember the `Element : constant  
Character := Item;` above).

The generated code looks wrong to me: it does not get the good address, it  
not even a normal address, whatever it did of `Element` as a local copy of  
`Item`.


Sorry for being long with this post, I wanted to provide all the materials  
required to clearly expose the case.


This case makes me remind of an issue I get with GNAT 4.6, when I  
discovered GNATMake was not printing some error messages it should have  
print. I noted according to the GNAT tools sources, the message should  
have been printed, but it was not. Now I wonder if ever GNAT it‑self  
sometimes suffers from a similar bug as above.


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-28 22:35 ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
@ 2013-04-28 22:49   ` Yannick Duchêne (Hibou57)
  2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
  1 sibling, 0 replies; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-28 22:49 UTC (permalink / raw)


Le Mon, 29 Apr 2013 00:35:03 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:
>
>         function Implementation
>            is new Invoke_3
>              (P1_Type     => Handle_Type,
>               P2_Type     => Address_Type,
>               P3_Type     => Size_Type)
>               with Inline => True;

A note on this part: I get the exact same whether inlining is on or off.  
So don't focus too much on the inlining representation clause.

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-28 22:35 ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
  2013-04-28 22:49   ` Yannick Duchêne (Hibou57)
@ 2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
  2013-04-29  1:35     ` Yannick Duchêne (Hibou57)
  1 sibling, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-28 23:52 UTC (permalink / raw)


Le Mon, 29 Apr 2013 00:35:03 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:

>         Element : Character := Item; -- <<< Copy of argument

If this, is changed into:

           Element :
              Character := Item
              with Volatile => True;

The issue is solved. Here is the generated code:


     library__write__2:
     .LFB7:
        .cfi_startproc
        pushl   %ebx              #
        .cfi_def_cfa_offset 8
        .cfi_offset 3, -8
        subl    $24, %esp         #,
        .cfi_def_cfa_offset 32
        movl    32(%esp), %eax    # item, item
        movb    %al, 15(%esp)     # item, element
        movl    $1, %edx          #, tmp65
        leal    15(%esp), %ecx    #, element.19
        movl    $4, %eax          #, tmp64
        movl    %edx, %ebx        # tmp65, tmp65


It is still reading at a non‑32 bits aligned address even if there is only  
one character at that address (well, why not, Intel 32 bits CPU does not  
triggers exceptions for this), but now it is at least making a copy of  
`Item`, which is fetched from [esp+32] as I expected in the previous  
message, then store it at [esp+15], so the address stored in ecx is now an  
address which really correspond to an initialized memory area. The  
system‑call invocation succeed.

I wonder if this is normal or not. What's your opinion?

Here is what the RM says:

http://www.ada-auth.org/standards/12rm/html/RM-C-6.html#p20
> The external effect of a program (see 1.1.3) is definedto include each  
> read and update of a volatile or atomicobject. The implementation shall  
> not generate any memoryreads or updates of atomic or volatile objects  
> other thanthose specified by the program.

This is quoted from “C.6 Shared Variable Control”. But this is a local  
variable, not a shared object, and I don't intuitively agree with GNAT or  
GCC optimization here. Unless I'm wrong, in which case I welcome any  
rationale relevant to explain why.

The parameters passed to a sub‑program may also be used or not, and GNAT  
does not dropped them all. As it can be noticed, it did not dropped  
parameter passing, and the parameter is not declared as being of a  
volatile type.

Seems less care is taken by the compiler, with foreign machine‑code  
insertion, even if via some level of indirection, than with it's own  
generated code, while it should be the opposite.

Until now, I though the volatile aspect was typically to be used with  
object which may be updated as a non‑visible side effect, like with a  
peripheral writing at some memory area, asynchronously (or not, that's  
still not directly visible anyway). But here, that's a local variable,  
which is explicitly referred to and explicitly assigned. If the address is  
passed, that should implies the address means something, especially if the  
address is an input parameter as it is here. And what means the address of  
an uninitialised area when that area was directed to be explicitly  
initialized by the source? Isn't GNAT of GCC lacking some semantic  
dependency tracking here?

May be I should make parameter types of the system‑call's generic  
declaration, all volatile? If so, this would implies that can be said of  
all machine‑code insertions?

But then, why isn't it automatic so?


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
@ 2013-04-29  1:35     ` Yannick Duchêne (Hibou57)
  2013-04-30  0:48       ` Yannick Duchêne (Hibou57)
  0 siblings, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-29  1:35 UTC (permalink / raw)


Le Mon, 29 Apr 2013 01:52:22 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:
> Until now, I though the volatile aspect was typically to be used with  
> object which may be updated as a non‑visible side effect, like with a  
> peripheral writing at some memory area […]
This way of understanding things must not be entirely wrong.

In the above solution involving volatile (once again, like in the other  
thread), the object is locally constant, as it is assigned, and never  
modified. So wanted to turn its declaration into this:


     Element :
        constant Character := Item
        with Volatile => True;


But GNAT complained, with a trustable reason, as it refers to the RM:


     stand alone volatile constant must be imported (RM C.6(13))


Here, according to the RM, a volatile constant declared in the Ada world  
and initialized in the Ada world, is not a valid candidate for a volatile  
aspect:

RM C.6(13) says:
> If an aspect Volatile, Volatile_Components, Atomic, orAtomic_Components  
> is directly specified to have the valueTrue for a stand-alone constant  
> object, then the aspectImport shall also be specified as True for it.

(oops, the `Import` aspect is not of boolean type …but what it means is  
still clear)

This suggest if the object is not modified, then the volatile aspect  
should not be required, unless the so‑called constant is not a constant in  
the strict Ada meaning (imported from the external world, and so which may  
be initialized who‑know‑when, and may also be modified later, externally).

What would help, is a way to tell the compiler the address is used, not  
for its own, but for what it refers to.

If all parameters must be volatile when there address attribute is used,  
that implies systematic copy of everything, as types defined for Ada  
programs, are not to be volatile. Ex. each string should be copied to an  
array of characters whose components are volatile (there is a  
`Volatile_Components` aspect).

Surprisingly, there is not such issue (or I've just never encountered any  
case?) when linking to similar sub‑programs in C or assembly and declared  
imported: there is no need to tell what's referred to by a pointer, is  
really needed. I wanted to try to use machine‑code insertion, to have most  
of or all things in Ada packages and to benefit from Ada checking.

I feel to not really understand how machine‑code insertion works or is  
defined (especially when optimization is enabled), and it looks to me,  
surprisingly a lot harder to set‑up than linking to similar imported  
sub‑programs.

So now, I'm seeking for something which would have the effect of a (an  
invalid) `pragma Volatile (Item'Address'Memory)` which seems to be  
implicit or not required when interfacing to C.


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-29  1:35     ` Yannick Duchêne (Hibou57)
@ 2013-04-30  0:48       ` Yannick Duchêne (Hibou57)
  2013-04-30  6:40         ` Simon Wright
  0 siblings, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-30  0:48 UTC (permalink / raw)


Le Mon, 29 Apr 2013 03:35:53 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:
> If all parameters must be volatile when there address attribute is used,  
> that implies systematic copy of everything, as types defined for Ada  
> programs, are not to be volatile
Finally, this  may be seen as a kind of representation conversion, where  
copying to buffers before sending to the outside world is also required.

Beside this, I noted something from the RM:

http://www.adaic.org/resources/add_content/standards/05aarm/html/AA-13-8.html
> If a subprogram_body contains any code_statements, then
> within this subprogram_body the only allowed form of statement
> is a code_statement (labeled or not), the only allowed declarative_items
> are use_clauses, and no exception_handler is allowed (comments and  
> pragmas
> are allowed as usual).

This seems to mean object declarations are not allowed in this context.  
But I did use object declarations in this context and GNAT did not  
complained. Which is right and which is wrong?


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30  0:48       ` Yannick Duchêne (Hibou57)
@ 2013-04-30  6:40         ` Simon Wright
  2013-04-30 17:04           ` Yannick Duchêne (Hibou57)
  0 siblings, 1 reply; 19+ messages in thread
From: Simon Wright @ 2013-04-30  6:40 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> Le Mon, 29 Apr 2013 03:35:53 +0200, Yannick Duchêne (Hibou57)
> <yannick_duchene@yahoo.fr> a écrit:
>> If all parameters must be volatile when there address attribute is
>> used, that implies systematic copy of everything, as types defined
>> for Ada programs, are not to be volatile
> Finally, this  may be seen as a kind of representation conversion,
> where copying to buffers before sending to the outside world is also
> required.

I suspect that the problem may be the 'clobber'. In [1], it says "You
may not write a clobber description in a way that overlaps with an input
or output operand. For example, you may not have an operand describing a
register class with one member if you mention that register in the
clobber list." So the clobber description is for registers that are
overwritten implicitly.

> Beside this, I noted something from the RM:
>
> http://www.adaic.org/resources/add_content/standards/05aarm/html/AA-13-8.html
>> If a subprogram_body contains any code_statements, then
>> within this subprogram_body the only allowed form of statement
>> is a code_statement (labeled or not), the only allowed declarative_items
>> are use_clauses, and no exception_handler is allowed (comments and
>> pragmas
>> are allowed as usual).
>
> This seems to mean object declarations are not allowed in this
> context. But I did use object declarations in this context and GNAT
> did not complained. Which is right and which is wrong?

[2] says that the procedure version of the Asm subprograms "can be used
anywhere a procedure call would be valid, and correspond to what the RM
calls "intrinsic" routines. Such calls can be used to intersperse
machine instructions with other Ada statements.".

[1]
http://gcc.gnu.org/onlinedocs/gcc-4.6.0/gcc/Extended-Asm.html#Extended-Asm
[2]
http://gcc.gnu.org/onlinedocs/gcc-4.6.0/gnat_rm/Machine-Code-Insertions.html



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30  6:40         ` Simon Wright
@ 2013-04-30 17:04           ` Yannick Duchêne (Hibou57)
  2013-04-30 19:06             ` Simon Wright
  0 siblings, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-30 17:04 UTC (permalink / raw)


Le Tue, 30 Apr 2013 08:40:35 +0200, Simon Wright <simon@pushface.org> a  
écrit:
> I suspect that the problem may be the 'clobber'. In [1], it says "You
> may not write a clobber description in a way that overlaps with an input
> or output operand. For example, you may not have an operand describing a
> register class with one member if you mention that register in the
> clobber list." So the clobber description is for registers that are
> overwritten implicitly.

You're right about clobber, and GNAT takes care of it, when it tells you  
the constraint cannot be satisfied if you use a register for both  
input/output and in the clobber list.

In my use case, I don't use clobber, so that cannot be the reason. I  
didn't need it, as everything is explicit and the whole statement is  
volatile.

The issue in this thread seems to not be directly addressable with clobber  
of volatile applied to the machine‑code statement; that's an issue with  
indirection: a register holds an address to something, and the object at  
that address must be made volatile, or else it may be optimized out. So I  
wondered if when passing an address to something (the compiler knows if  
comes from an address attribute), if this makes sense to generate the  
address to the object while dropping the Ada instructions which creates  
this object. That's why I said “may be GNAT or GCC are lacking some  
semantic dependency tracking here”. That's just a question, I'm not sure  
of the answer and just personally believe if the address is generated and  
passed, then this should imply the Ada instructions creating the object  
should not be dropped.

In the mean time, that's output to the external world, and it most of time  
requires representation conversion which implies copying, so I will go  
with copying to volatile buffers and consider it as a similar issue as  
representation conversion is.

>> Beside this, I noted something from the RM:
>>
>> http://www.adaic.org/resources/add_content/standards/05aarm/html/AA-13-8.html
>>> If a subprogram_body contains any code_statements, then
>>> within this subprogram_body the only allowed form of statement
>>> is a code_statement (labeled or not), the only allowed  
>>> declarative_items
>>> are use_clauses, and no exception_handler is allowed (comments and
>>> pragmas
>>> are allowed as usual).
>>
>> This seems to mean object declarations are not allowed in this
>> context. But I did use object declarations in this context and GNAT
>> did not complained. Which is right and which is wrong?
>
> [2] says that the procedure version of the Asm subprograms "can be used
> anywhere a procedure call would be valid, and correspond to what the RM
> calls "intrinsic" routines. Such calls can be used to intersperse
> machine instructions with other Ada statements.".

So when the RM says “if a subprogram_body contains any code_statements”,  
what is the subject sub‑program body? I though it was the body containing  
the `Asm` sub‑program. Or may be it's the `Asm` sub‑program itself?

That's not a big issue, that's just that I prefer to stick to the RM when  
feasible, and if I have to write things a different way to conform to the  
RM, I will do so.

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30 17:04           ` Yannick Duchêne (Hibou57)
@ 2013-04-30 19:06             ` Simon Wright
  2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
  2013-05-01 18:19               ` J-P. Rosen
  0 siblings, 2 replies; 19+ messages in thread
From: Simon Wright @ 2013-04-30 19:06 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> So when the RM says "if a subprogram_body contains any
> code_statements", what is the subject sub‑program body? I though it
> was the body containing the 'Asm' sub‑program. Or may be it's the
> 'Asm' sub‑program itself?

The whole thing is bizarre: code statements are written using the form
of a qualified expression though clearly not a qualified expression
since it can't be assigned anywhere!

Each qualified expression typically represents one machine code
instruction or assembly directive.

If you are implementing a function using code statements you are
expected to know the calling convention, so that you can return the
result in the corrct way.

Clearly none of these apply to the code you wrote, so - I think - GNAT
takes advantage of the implementation permission in ARM13.8(11) [1] to
support intrinsic subprograms without all those tiresome restrictions.

As described in [2].

[2] also recommends using Volatile => True in most circumstances.

> That's not a big issue, that's just that I prefer to stick to the RM
> when feasible, and if I have to write things a different way to
> conform to the RM, I will do so.

Since everything to do with code statements/intrinsic subprograms is
compiler- and target-dependent, I don't see what you gain by this!

I was wondering what you meant by using constraints "a", "b", "c", "d"
.. I now see [3] that these are i386 constraints for the a..d registers
respectively, no wonder they gave wierd results on x86_64 where they
mean something quite different!

[1] http://www.ada-auth.org/standards/12rm/html/RM-13-8.html#p11
[2]
http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gnat_rm/Machine-Code-Insertions.html
[3] http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Machine-Constraints.html



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30 19:06             ` Simon Wright
@ 2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
  2013-04-30 22:22                 ` Simon Wright
  2013-05-01 18:19               ` J-P. Rosen
  1 sibling, 1 reply; 19+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2013-04-30 21:28 UTC (permalink / raw)


Le Tue, 30 Apr 2013 21:06:09 +0200, Simon Wright <simon@pushface.org> a  
écrit:
> I was wondering what you meant by using constraints "a", "b", "c", "d"
> .. I now see [3] that these are i386 constraints for the a..d registers
> respectively, no wonder they gave wierd results on x86_64 where they
> mean something quite different!

They do exists with 64 bits instructions too. a is eax; b is ebx, etc, for  
32 bits mode, and a is rax, b is rbx, etc, for 64 bits mode. There is also  
ax/ah/al, ax/bh/bl, etc, as sub‑parts of the above, except ax, bx, etc, is  
for 16 bits only, but ah, al, bh, bl are still a accessible in 32 bits  
mode — I don't know if it's still the case in 64 bits mode.

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
@ 2013-04-30 22:22                 ` Simon Wright
  0 siblings, 0 replies; 19+ messages in thread
From: Simon Wright @ 2013-04-30 22:22 UTC (permalink / raw)


"Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr> writes:

> Le Tue, 30 Apr 2013 21:06:09 +0200, Simon Wright <simon@pushface.org>
> a écrit:
>> I was wondering what you meant by using constraints "a", "b", "c", "d"
>> .. I now see [3] that these are i386 constraints for the a..d registers
>> respectively, no wonder they gave wierd results on x86_64 where they
>> mean something quite different!
>
> They do exists with 64 bits instructions too. a is eax; b is ebx, etc,
> for 32 bits mode, and a is rax, b is rbx, etc, for 64 bits mode. There
> is also ax/ah/al, ax/bh/bl, etc, as sub-parts of the above, except ax,
> bx, etc, is for 16 bits only, but ah, al, bh, bl are still a
> accessible in 32 bits mode - I don't know if it's still the case in 64
> bits mode.

Your

      System.Machine_Code.Asm
        (Template => "int $0x80",
         Outputs => Integer'Asm_Output ("=a", Result),
         Inputs =>
           (Positive'Asm_Input       ("a", Number),
            Natural'Asm_Input        ("b", Handle),
            System.Address'Asm_Input ("c", Address),
            Natural'Asm_Input        ("d", Size)),
         Volatile => True);

translated to

	movl	%ecx, %edx
	movl	%edi, %eax
	movl	%esi, %ebx
	movq	%r8, %rcx
# 14 "library.adb" 1
	int $0x80

but I think I really don't want to learn Intel assembler, lots of other
good things to do.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Erroneous code generation from GNAT or GCC?
  2013-04-30 19:06             ` Simon Wright
  2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
@ 2013-05-01 18:19               ` J-P. Rosen
  1 sibling, 0 replies; 19+ messages in thread
From: J-P. Rosen @ 2013-05-01 18:19 UTC (permalink / raw)


Le 30/04/2013 21:06, Simon Wright a écrit :
> The whole thing is bizarre: code statements are written using the form
> of a qualified expression though clearly not a qualified expression
> since it can't be assigned anywhere!

Ada 83 had a requirement to allow inclusion of machine code. There was
therefore a need to have a syntactic form that would fit every possible
machine code. It made sense to represent a machine instruction as a kind
of record, with fields like op-code, registers, address... Specifying
code statements as aggregates provided the necessary flexibility without
inventing a new syntactic form.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2013-05-01 18:19 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-27 21:08 GNAT not generating any code for sub‑program: known bug? Yannick Duchêne (Hibou57)
2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
2013-04-27 23:48   ` Yannick Duchêne (Hibou57)
2013-04-28  7:14   ` Simon Wright
2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
2013-04-28 20:46         ` Simon Wright
2013-04-28 20:43       ` Simon Wright
2013-04-28 22:35 ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
2013-04-28 22:49   ` Yannick Duchêne (Hibou57)
2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
2013-04-29  1:35     ` Yannick Duchêne (Hibou57)
2013-04-30  0:48       ` Yannick Duchêne (Hibou57)
2013-04-30  6:40         ` Simon Wright
2013-04-30 17:04           ` Yannick Duchêne (Hibou57)
2013-04-30 19:06             ` Simon Wright
2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
2013-04-30 22:22                 ` Simon Wright
2013-05-01 18:19               ` J-P. Rosen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox