comp.lang.ada
 help / color / mirror / Atom feed
* Forcing GNAT to use 32-bit load/store instructions on ARM?
@ 2014-06-30 22:11 daniel.dmk
  2014-06-30 23:41 ` Jeffrey Carter
                   ` (4 more replies)
  0 siblings, 5 replies; 51+ messages in thread
From: daniel.dmk @ 2014-06-30 22:11 UTC (permalink / raw)


Hello,

I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on some code in SPARK 2014 to interface to memory-mapped registers to control registers on the STM32 F4 microcontroller, however I'm having trouble where GNAT is using byte loads/stores to the registers, instead of word load/stores (32-bit).

For a lot of registers on the STM32 it is necessary to always access the registers using 32-bit load/store instructions. Using half-word (16-bit) or byte (8-bit) accesses generates a CPU fault with these registers.

I'm representing the 32-bit register as a record as follows:

   type Bits_1 is mod 2**1 with Size => 1;

   type CR_Register is
      record
         RNGEN : Bits_1;
         IE    : Bits_1;
      end record;
   for CR_Register use
      record
         RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved
         IE    at 0 range 3 .. 3;
         -- bits 4 .. 31 are reserved
      end record;
   for CR_Register'Size use 32;

I then define the register of type CR_Register at the peripheral's base address:

   CR : CR_Register
     with Size => 32,
       Volatile,
       Async_Readers, Async_Writers,
       Address => System'To_Address(Base_Address);

I'm using a record instead of a simple Unsigned_32 type so that:
1) I can hide access to the "reserved" parts of the register,
2) The code to modify the register is straightfoward.

For example, enabling the peripheral is done by setting the RNGEN bit to 1:

   CR.RNGEN := 1;

However, the GNAT compiler uses the ARM instruction ldrb to load the lower 8 bits of the register, modify the byte (or 16#40#), then use strb to write the lower 8-bits back to memory. This causes a fault since the register must be accessed using a 32-bit load/store instructions (the ldr and str instructions).

Does anyone know how I can force GNAT to generate the appropriate instructions?

Things I have tried:
1) Using the Atomic aspect on the record type and CR object had no effect on the code generated.
2) Using Pack.
3) Declaring the bits inside the register as: Bits_32 range 0 .. 1;

So far, I am able to get GNAT to use 32-bit load/stores only when I read the entire record into a temporary variable, as follows:

   declare
      Temp : CR_Register;
   begin
      Temp := CR;
      Temp.RNGEN := 1;
      CR := Temp;
   end;

However, this makes it more "clunky" to use in my opinion. I would prefer to be able to modify the bits directly, and have the compiler always use 32-bit load/store instructions.

Does anyone else have any ideas that I could try?

Thanks,
Dan


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
@ 2014-06-30 23:41 ` Jeffrey Carter
  2014-07-01 12:06   ` Simon Clubley
  2014-07-01  0:55 ` anon
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 51+ messages in thread
From: Jeffrey Carter @ 2014-06-30 23:41 UTC (permalink / raw)


On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote:
>
> Does anyone know how I can force GNAT to generate the appropriate
> instructions?

If you need specific machine instructions, you should use a machine-code insertion.

-- 
Jeff Carter
"Now look, Col. Batguano, if that really is your name."
Dr. Strangelove
31

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
  2014-06-30 23:41 ` Jeffrey Carter
@ 2014-07-01  0:55 ` anon
  2014-07-01  4:30 ` Niklas Holsti
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 51+ messages in thread
From: anon @ 2014-07-01  0:55 UTC (permalink / raw)


     ...  -- other Ada instructions

      --  tells assembler to use 32-bit coding
      --  Must be before insert 32-bit instructions or the 
      --  assembler will try to decode the 32-bit Ada in 64-bit mode

      Asm ( Template => ".code32", 
            Volatile => True ) ;

--- 32-bit assembly instructions.
--  go here

      --  just an example: A 32-bit 'nop'
      --  In this case, only a single instruction 
      --  but could be more than 1

      Asm ( Template => " nop",   
            Volatile => True ) ;

--  go here
--- 32-bit assembly instructions

      --  tells assembler to switch back to 64-bit coding
      --  Must be after insert 32-bit instructions or the 
      --  assembler will try to decode the 64-bit Ada in 32-bit mode
      Asm ( Template => ".code64",
            Volatile => True ) ;

     ...  -- other Ada instructions


In <0e0b9ac2-e793-4cc5-8d8d-d3441ca28a58@googlegroups.com>, daniel.dmk@googlemail.com writes:
>Hello,
>
>I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on =
>some code in SPARK 2014 to interface to memory-mapped registers to control =
>registers on the STM32 F4 microcontroller, however I'm having trouble where=
> GNAT is using byte loads/stores to the registers, instead of word load/sto=
>res (32-bit).
>
>For a lot of registers on the STM32 it is necessary to always access the re=
>gisters using 32-bit load/store instructions. Using half-word (16-bit) or b=
>yte (8-bit) accesses generates a CPU fault with these registers.
>
>I'm representing the 32-bit register as a record as follows:
>
>   type Bits_1 is mod 2**1 with Size =3D> 1;
>
>   type CR_Register is
>      record
>         RNGEN : Bits_1;
>         IE    : Bits_1;
>      end record;
>   for CR_Register use
>      record
>         RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved
>         IE    at 0 range 3 .. 3;
>         -- bits 4 .. 31 are reserved
>      end record;
>   for CR_Register'Size use 32;
>
>I then define the register of type CR_Register at the peripheral's base add=
>ress:
>
>   CR : CR_Register
>     with Size =3D> 32,
>       Volatile,
>       Async_Readers, Async_Writers,
>       Address =3D> System'To_Address(Base_Address);
>
>I'm using a record instead of a simple Unsigned_32 type so that:
>1) I can hide access to the "reserved" parts of the register,
>2) The code to modify the register is straightfoward.
>
>For example, enabling the peripheral is done by setting the RNGEN bit to 1:
>
>   CR.RNGEN :=3D 1;
>
>However, the GNAT compiler uses the ARM instruction ldrb to load the lower =
>8 bits of the register, modify the byte (or 16#40#), then use strb to write=
> the lower 8-bits back to memory. This causes a fault since the register mu=
>st be accessed using a 32-bit load/store instructions (the ldr and str inst=
>ructions).
>
>Does anyone know how I can force GNAT to generate the appropriate instructi=
>ons?
>
>Things I have tried:
>1) Using the Atomic aspect on the record type and CR object had no effect o=
>n the code generated.
>2) Using Pack.
>3) Declaring the bits inside the register as: Bits_32 range 0 .. 1;
>
>So far, I am able to get GNAT to use 32-bit load/stores only when I read th=
>e entire record into a temporary variable, as follows:
>
>   declare
>      Temp : CR_Register;
>   begin
>      Temp :=3D CR;
>      Temp.RNGEN :=3D 1;
>      CR :=3D Temp;
>   end;
>
>However, this makes it more "clunky" to use in my opinion. I would prefer t=
>o be able to modify the bits directly, and have the compiler always use 32-=
>bit load/store instructions.
>
>Does anyone else have any ideas that I could try?
>
>Thanks,
>Dan



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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
  2014-06-30 23:41 ` Jeffrey Carter
  2014-07-01  0:55 ` anon
@ 2014-07-01  4:30 ` Niklas Holsti
  2014-07-01  8:11 ` Dmitry A. Kazakov
  2014-07-01 12:03 ` Simon Clubley
  4 siblings, 0 replies; 51+ messages in thread
From: Niklas Holsti @ 2014-07-01  4:30 UTC (permalink / raw)


On 14-07-01 01:11 , daniel.dmk@googlemail.com wrote:
> Hello,
> 
> I've started using GNAT GPL for ARM (hosted on Windows) and I'm
> working on some code in SPARK 2014 to interface to memory-mapped
> registers to control registers on the STM32 F4 microcontroller,
> however I'm having trouble where GNAT is using byte loads/stores
> to the registers, instead of word load/stores (32-bit).
> 
> For a lot of registers on the STM32 it is necessary to always
> access the registers using 32-bit load/store instructions. Using
> half-word (16-bit) or byte (8-bit) accesses generates a CPU fault
> with these registers.
> 
> I'm representing the 32-bit register as a record as follows:
> 
>    type Bits_1 is mod 2**1 with Size => 1;
> 
>    type CR_Register is
>       record
>          RNGEN : Bits_1;
>          IE    : Bits_1;
>       end record;
>    for CR_Register use
>       record
>          RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved
>          IE    at 0 range 3 .. 3;
>          -- bits 4 .. 31 are reserved
>       end record;
>    for CR_Register'Size use 32;
> 
> I then define the register of type CR_Register at the peripheral's
> base address:
> 
>    CR : CR_Register
>      with Size => 32,
>        Volatile,
>        Async_Readers, Async_Writers,
>        Address => System'To_Address(Base_Address);
> 
> I'm using a record instead of a simple Unsigned_32 type so that:
> 1) I can hide access to the "reserved" parts of the register,
> 2) The code to modify the register is straightfoward.
> 
> For example, enabling the peripheral is done by setting
> the RNGEN bit to 1:
> 
>    CR.RNGEN := 1;
> 
> However, the GNAT compiler uses the ARM instruction ldrb to
> load the lower 8 bits of the register, modify the byte (or
> 16#40#), then use strb to write the lower 8-bits back to memory.
> This causes a fault since the register must be accessed
> using a 32-bit load/store instructions (the ldr and str
> instructions).
> 
> Does anyone know how I can force GNAT to generate the
> appropriate instructions?
> 
> Things I have tried:
> 1) Using the Atomic aspect on the record type and CR object
>    had no effect on the code generated.
> 2) Using Pack.
> 3) Declaring the bits inside the register as: Bits_32 range 0 .. 1;

I agree in general with Jeff's answer that if you need specific machine
instructions, and the compiler documentation does not promise to
generate such instructions under certain conditions, you should use
assembly language.

But if you are willing to take the risk of not being sure, have you
tried to define "Reserved" components for bits 0..1 and 4..31 to fill
the gaps in the record type?

Filling the gaps with named components would also be safer from the HW
point of view, because any 32-bit store into the register necessarily
must write the reserved bits too, and usually the HW documentation says
that one should write zero to reserved bits. Your current, gappy record
type may write anything to those bits.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
                   ` (2 preceding siblings ...)
  2014-07-01  4:30 ` Niklas Holsti
@ 2014-07-01  8:11 ` Dmitry A. Kazakov
  2014-07-01 12:09   ` Simon Clubley
  2014-07-01 12:03 ` Simon Clubley
  4 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2014-07-01  8:11 UTC (permalink / raw)


On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote:

> I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on
> some code in SPARK 2014 to interface to memory-mapped registers to control
> registers on the STM32 F4 microcontroller, however I'm having trouble
> where GNAT is using byte loads/stores to the registers, instead of word
> load/stores (32-bit).

There is a middle way between assembly insertion and pure Ada. You could
try GCC's __sync_fetch_and_or and __sync_bool_compare_and_swap for atomic
load/store.

https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

> Things I have tried:
> 1) Using the Atomic aspect on the record type and CR object had no effect
> on the code generated.

Yes, I hope they will fix this for this and other platforms, e.g. 64-bit
atomic load/store for i686.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
                   ` (3 preceding siblings ...)
  2014-07-01  8:11 ` Dmitry A. Kazakov
@ 2014-07-01 12:03 ` Simon Clubley
  2014-07-01 19:52   ` daniel.dmk
  4 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 12:03 UTC (permalink / raw)


On 2014-06-30, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
> Hello,
>
> I've started using GNAT GPL for ARM (hosted on Windows) and I'm working on
> some code in SPARK 2014 to interface to memory-mapped registers to control
> registers on the STM32 F4 microcontroller, however I'm having trouble where
> GNAT is using byte loads/stores to the registers, instead of word load/stores
> (32-bit).
>

This is both a GNAT front end problem and a GCC ARM code generator problem.

A couple of years ago, I tried to use bitfields in C code instead of
bitmasks (which I don't like) in the same way you are using them here
in Ada and I ran into the same ldrb/strb problem.

At the time I could not find a reliable solution to this and I went back
to using bitmasks in my C code.

However, we had a discussion in a related area on comp.lang.ada recently
and, in Ada, the conclusion was that the Atomic pragma should indeed
either give you the guarantee you seek or GNAT should reject the code
during compilation.

If this isn't happening then I regard that as a major GNAT bug if Pragma
Atomic is indeed being ignored.

> For a lot of registers on the STM32 it is necessary to always access the
> registers using 32-bit load/store instructions. Using half-word (16-bit) or
> byte (8-bit) accesses generates a CPU fault with these registers.
>
> I'm representing the 32-bit register as a record as follows:
>
>    type Bits_1 is mod 2**1 with Size => 1;
>
>    type CR_Register is
>       record
>          RNGEN : Bits_1;
>          IE    : Bits_1;
>       end record;
>    for CR_Register use
>       record
>          RNGEN at 0 range 2 .. 2; -- bits 0 .. 1 are reserved
>          IE    at 0 range 3 .. 3;
>          -- bits 4 .. 31 are reserved
>       end record;
>    for CR_Register'Size use 32;
>

In the general case, you need to initialise those reserved bits to known
values; to not do this is too dangerous. I always do this in C and if I
was doing embedded code in Ada I would do the same thing in Ada as well.

> I then define the register of type CR_Register at the peripheral's base
> address:
>
>    CR : CR_Register
>      with Size => 32,
>        Volatile,
>        Async_Readers, Async_Writers,
>        Address => System'To_Address(Base_Address);
>
> I'm using a record instead of a simple Unsigned_32 type so that:
> 1) I can hide access to the "reserved" parts of the register,
> 2) The code to modify the register is straightfoward.
>
> For example, enabling the peripheral is done by setting the RNGEN bit to 1:
>
>    CR.RNGEN := 1;
>
> However, the GNAT compiler uses the ARM instruction ldrb to load the lower 8
> bits of the register, modify the byte (or 16#40#), then use strb to write the
> lower 8-bits back to memory. This causes a fault since the register must be
> accessed using a 32-bit load/store instructions (the ldr and str instructions).
>
> Does anyone know how I can force GNAT to generate the appropriate
> instructions?
>
> Things I have tried:
> 1) Using the Atomic aspect on the record type and CR object had no effect on
> the code generated.

That absolutely should have worked or GNAT should have raised a error
during compilation.

> 2) Using Pack.
> 3) Declaring the bits inside the register as: Bits_32 range 0 .. 1;
>
> So far, I am able to get GNAT to use 32-bit load/stores only when I read the
> entire record into a temporary variable, as follows:
>
>    declare
>       Temp : CR_Register;
>    begin
>       Temp := CR;
>       Temp.RNGEN := 1;
>       CR := Temp;
>    end;
>

FYI, if you need to set more than one bitfield at the same time (as part
of an atomic register update) this is the only way you can do this in Ada
unless you resort to using C style bitmasks.

> However, this makes it more "clunky" to use in my opinion. I would prefer to
> be able to modify the bits directly, and have the compiler always use 32-bit
> load/store instructions.
>
> Does anyone else have any ideas that I could try?
>

Pragma Atomic _should_ have given you the guarantee you needed.
Are you double checked how it's being used in the code ?

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-06-30 23:41 ` Jeffrey Carter
@ 2014-07-01 12:06   ` Simon Clubley
  2014-07-01 15:44     ` Niklas Holsti
                       ` (2 more replies)
  0 siblings, 3 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 12:06 UTC (permalink / raw)


On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote:
>>
>> Does anyone know how I can force GNAT to generate the appropriate
>> instructions?
>
> If you need specific machine instructions, you should use a machine-code insertion.
>

The issue here is that Pragma Atomic should have given him the guarantee
he needs.

There is a place for specific assembly language insertions (for example,
on ARM when you need to access the CPSR register), but that should not
be required here.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01  8:11 ` Dmitry A. Kazakov
@ 2014-07-01 12:09   ` Simon Clubley
  2014-07-01 12:20     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 12:09 UTC (permalink / raw)


On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote:
>> Things I have tried:
>> 1) Using the Atomic aspect on the record type and CR object had no effect
>> on the code generated.
>
> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit
> atomic load/store for i686.
>

Are you saying Pragma Atomic is known to be broken in GNAT ?

(I wasn't aware of that if so.)

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:09   ` Simon Clubley
@ 2014-07-01 12:20     ` Dmitry A. Kazakov
  2014-07-01 17:00       ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2014-07-01 12:20 UTC (permalink / raw)


On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote:

> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
>> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote:
>>> Things I have tried:
>>> 1) Using the Atomic aspect on the record type and CR object had no effect
>>> on the code generated.
>>
>> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit
>> atomic load/store for i686.
> 
> Are you saying Pragma Atomic is known to be broken in GNAT ?

It is not broken. The problem I know is that it is rejected on machines
that do support atomic load and store.

In a wider language design perspective, yes, it is broken because IMO
either the language shall require the pragma accepted for all scalar types
or else a system package for atomic operations must be provided.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:06   ` Simon Clubley
@ 2014-07-01 15:44     ` Niklas Holsti
  2014-07-01 17:26       ` Simon Clubley
  2014-07-01 17:18     ` Simon Wright
  2014-07-01 17:28     ` Jeffrey Carter
  2 siblings, 1 reply; 51+ messages in thread
From: Niklas Holsti @ 2014-07-01 15:44 UTC (permalink / raw)


On 14-07-01 15:06 , Simon Clubley wrote:
> On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote:
>>>
>>> Does anyone know how I can force GNAT to generate the appropriate
>>> instructions?
>>
>> If you need specific machine instructions, you should use a machine-code insertion.
>>
> 
> The issue here is that Pragma Atomic should have given him the guarantee
> he needs.

Perhaps pragma Atomic did not work because the record actually had only
2 significant bits, fitting in one octet, and the Size = 32 bits clause
did not make GNAT treat all 32 bits as atomic? I'm not sure if that
would be a bug -- does a Size clause determine the extent of pragma Atomic?

The OP should try to add components to fill all 32 bits, and also use
pragma Atomic. If that doesn't work, then it is a GNAT bug, methinks.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:20     ` Dmitry A. Kazakov
@ 2014-07-01 17:00       ` Simon Clubley
  2014-07-01 19:36         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 17:00 UTC (permalink / raw)


On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote:
>
>> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
>>> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote:
>>>> Things I have tried:
>>>> 1) Using the Atomic aspect on the record type and CR object had no effect
>>>> on the code generated.
>>>
>>> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit
>>> atomic load/store for i686.
>> 
>> Are you saying Pragma Atomic is known to be broken in GNAT ?
>
> It is not broken. The problem I know is that it is rejected on machines
> that do support atomic load and store.
>

That's not great, but at least you know there's a problem at compile
time.

In the OP's case (according to the problem description), pragma Atomic
was been accepted, but the generated code was not using a 32-bit store
and was using an 8-bit store into a 32-bit field instead.

If for some reason the compiler could not generate a 32-bit str opcode
instead of an 8-bit strb opcode, the pragma Atomic should have caused
an error during compilation.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:06   ` Simon Clubley
  2014-07-01 15:44     ` Niklas Holsti
@ 2014-07-01 17:18     ` Simon Wright
  2014-07-01 19:43       ` Simon Wright
  2014-07-01 17:28     ` Jeffrey Carter
  2 siblings, 1 reply; 51+ messages in thread
From: Simon Wright @ 2014-07-01 17:18 UTC (permalink / raw)


Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes:

> On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote:
>>>
>>> Does anyone know how I can force GNAT to generate the appropriate
>>> instructions?
>>
>> If you need specific machine instructions, you should use a
>> machine-code insertion.
>>
>
> The issue here is that Pragma Atomic should have given him the guarantee
> he needs.
>
> There is a place for specific assembly language insertions (for example,
> on ARM when you need to access the CPSR register), but that should not
> be required here.

Just for fun I tried this on Intel (x86_64) with GNAT GPL 2014 and GCC
4.9.0 on this:

   procedure Atom is

      type R is record
         A : Boolean;
         B : Boolean;
      end record with Size => 32;
      for R use record
         A at 0 range 0 .. 0;
         B at 0 range 31 .. 31;
      end record;

      V : R with Atomic, Import, Convention => C, External_Name => "foo";

   begin

      V := (A => True, B => True);
      V.A := False;

   end Atom;

and found that the compiler did a reaonable thing:

        movl    _T3b.2569(%rip), %edx
        movq    _foo@GOTPCREL(%rip), %rax
        movl    %edx, (%rax)
        mfence
        movq    _foo@GOTPCREL(%rip), %rax
        movl    (%rax), %edx
        andl    $-2, %edx
        movl    %edx, (%rax)

        .const
        .align 2
_T3b.2569:
        .byte   1
        .space 2
        .byte   128

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 15:44     ` Niklas Holsti
@ 2014-07-01 17:26       ` Simon Clubley
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 17:26 UTC (permalink / raw)


On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote:
> On 14-07-01 15:06 , Simon Clubley wrote:
>> On 2014-06-30, Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>>> On 06/30/2014 03:11 PM, daniel.dmk@googlemail.com wrote:
>>>>
>>>> Does anyone know how I can force GNAT to generate the appropriate
>>>> instructions?
>>>
>>> If you need specific machine instructions, you should use a machine-code insertion.
>>>
>> 
>> The issue here is that Pragma Atomic should have given him the guarantee
>> he needs.
>
> Perhaps pragma Atomic did not work because the record actually had only
> 2 significant bits, fitting in one octet, and the Size = 32 bits clause
> did not make GNAT treat all 32 bits as atomic? I'm not sure if that
> would be a bug -- does a Size clause determine the extent of pragma Atomic?
>

I suppose it's possible, but then again according to the OP it did work
when using a temporary record.

> The OP should try to add components to fill all 32 bits, and also use
> pragma Atomic. If that doesn't work, then it is a GNAT bug, methinks.
>

Filling out to 32-bits would be an interesting test (and allows the OP
to set them to a known value if performing a simple 32-bit store instead
of a R/M/W operation.)

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:06   ` Simon Clubley
  2014-07-01 15:44     ` Niklas Holsti
  2014-07-01 17:18     ` Simon Wright
@ 2014-07-01 17:28     ` Jeffrey Carter
  2 siblings, 0 replies; 51+ messages in thread
From: Jeffrey Carter @ 2014-07-01 17:28 UTC (permalink / raw)


On 07/01/2014 05:06 AM, Simon Clubley wrote:
>
> The issue here is that Pragma Atomic should have given him the guarantee
> he needs.

I think I agree with Holsti that the lack of reference to the other 30 bits 
results in the compiler concluding that it can satisfy the pragma with 8-bit 
loads and stores.

> There is a place for specific assembly language insertions (for example,
> on ARM when you need to access the CPSR register), but that should not
> be required here.

A machine-code insertion seems to be required to obtain the machine-code 
instructions he desires with the type definition he is using. Generally one 
wants to define the reserved fields so one can control what values they have, 
but if he doesn't want to do that, he'll probably need a machine-code insertion.

-- 
Jeff Carter
"C++ is like giving an AK-47 to a monk, shooting him
full of crack and letting him loose in a mall and
expecting him to balance your checking account
'when he has the time.'"
Drew Olbrich
52

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 17:00       ` Simon Clubley
@ 2014-07-01 19:36         ` Dmitry A. Kazakov
  2014-07-01 20:08           ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2014-07-01 19:36 UTC (permalink / raw)


On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote:

> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
>> On Tue, 1 Jul 2014 12:09:36 +0000 (UTC), Simon Clubley wrote:
>>
>>> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
>>>> On Mon, 30 Jun 2014 15:11:31 -0700 (PDT), daniel.dmk@googlemail.com wrote:
>>>>> Things I have tried:
>>>>> 1) Using the Atomic aspect on the record type and CR object had no effect
>>>>> on the code generated.
>>>>
>>>> Yes, I hope they will fix this for this and other platforms, e.g. 64-bit
>>>> atomic load/store for i686.
>>> 
>>> Are you saying Pragma Atomic is known to be broken in GNAT ?
>>
>> It is not broken. The problem I know is that it is rejected on machines
>> that do support atomic load and store.
>>
> 
> That's not great, but at least you know there's a problem at compile
> time.
> 
> In the OP's case (according to the problem description), pragma Atomic
> was been accepted, but the generated code was not using a 32-bit store
> and was using an 8-bit store into a 32-bit field instead.

Yes, my case was different. The pragma was rejected.

> If for some reason the compiler could not generate a 32-bit str opcode
> instead of an 8-bit strb opcode, the pragma Atomic should have caused
> an error during compilation.

Well, pragmas are permitted to be ignored. Atomic should never be a pragma.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 17:18     ` Simon Wright
@ 2014-07-01 19:43       ` Simon Wright
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Wright @ 2014-07-01 19:43 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> and found that the compiler did a reaonable thing:

I forgot to say that, _without_ the Atomic aspect and with -O0, the
compiler used byte operations; any higher optimisation and the compiler
used the longword access as with Atomic.


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 12:03 ` Simon Clubley
@ 2014-07-01 19:52   ` daniel.dmk
  2014-07-01 20:40     ` Simon Clubley
  2014-07-02  7:30     ` Simon Wright
  0 siblings, 2 replies; 51+ messages in thread
From: daniel.dmk @ 2014-07-01 19:52 UTC (permalink / raw)


Thank you everyone for your suggestions and comments. 

On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley  wrote:
> 
> In the general case, you need to initialise those reserved bits to known
> 
> values; to not do this is too dangerous. I always do this in C and if I
> 
> was doing embedded code in Ada I would do the same thing in Ada as well.

Thanks for this suggestion, I'll define the reserved bits in the register, and use static checks to enforce that they are not modified from their reset value in the code.

> > However, this makes it more "clunky" to use in my opinion. I would prefer to
> 
> > be able to modify the bits directly, and have the compiler always use 32-bit
> 
> > load/store instructions.
> 
> >
> 
> > Does anyone else have any ideas that I could try?
> 
> >
> 
> 
> 
> Pragma Atomic _should_ have given you the guarantee you needed.
> 
> Are you double checked how it's being used in the code ?

So I've set up a project to demonstrate only this problem. I've created a package called "Test" which contains the structure definition, and the definition of the register itself at the fixed address:

   with System;

   package Test is
      type Bits_1 is mod 2**1 with Size => 1;
      type Bits_2 is mod 2**2 with Size => 2;
      type Bits_28 is mod 2**28 with Size => 28;
      
      type CR_Register is
         record
            Reserved_1 : Bits_2;
            RNGEN      : Bits_1;
            IE         : Bits_1;
            Reserved_2 : Bits_28;
         end record;
      for CR_Register use
         record
            Reserved_1 at 0 range 0 .. 1;
            RNGEN      at 0 range 2 .. 2;
            IE         at 0 range 3 .. 3;
            Reserved_2 at 0 range 4 .. 31;
         end record;
      for CR_Register'Size use 32;

      CR : CR_Register with
        Volatile,
          Atomic,
          Address => System'To_Address(16#5006_0800#);
   end Test;

So I've now defined the reserved bits in the register, and I have added "Atomic" to the CR register.

In my main procedure I have the following:

   with System;
   with Test;

   procedure Main
     with SPARK_Mode => On
   is
      pragma Priority(System.Priority'First);
      
   begin
      
      Test.CR.RNGEN := 1;
      
      loop
         null;
      end loop;

   end Main;

The line where I assign the RNGEN bit produces the following assembly code (using no optimization: -O0):

   mov.w   r3, #2048       ; 0x800
   movt    r3, #20486      ; 0x5006
   ldrb    r2, [r3, #0]
   orr.w   r2, r2, #4
   strb    r2, [r3, #0]

As you can see, it is using byte load/store instructions.

So even when using Atomic, and when defining the other bits in the register it is still using the byte load/store instructions. The same assmebly code is generated at all optimization levels.

For reference, here's the code when I use a temporary copy of the register:

   declare
      Temp : Test.CR_Register;
   begin
      Temp := Test.CR;
      Temp.RNGEN := 1;
      Test.CR := Temp;
   end;

produces the following assembly code (the 3 segements of asm correspond to each of the 3 lines of code):

   mov.w   r3, #2048       ; 0x800
   movt    r3, #20486      ; 0x5006
   ldr     r3, [r3, #0]
   str     r3, [r7, #4]
   
   ldr     r3, [r7, #4]
   orr.w   r3, r3, #4
   str     r3, [r7, #4]
   
   mov.w   r3, #2048       ; 0x800
   movt    r3, #20486      ; 0x5006
   ldr     r2, [r7, #4]
   str     r2, [r3, #0]

In this case, it is always using the word load/store instructions (ldr and str). Here is the same code when optimization is enabled (-O1):

   mov.w   r3, #2048       ; 0x800
   movt    r3, #20486      ; 0x5006
   ldr     r2, [r3, #0]
   orr.w   r2, r2, #4
   str     r2, [r3, #0]

So could there be a problem with GNAT's Atomic on ARM?

I think the approach that I will take for the time being is to always use a temporary when reading/writing the registers. I can hide the registers behind procedures to enforce this access, and to also add pre/post conditions to enforce that the reserved bits are not modified from their reset value.

I would like to avoid machine code insertions if possible, since I would like to remain inside SPARK 2014 as much as possible (machine code insertions are not in SPARK 2014).


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 19:36         ` Dmitry A. Kazakov
@ 2014-07-01 20:08           ` Simon Clubley
  2014-07-02 22:24             ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 20:08 UTC (permalink / raw)


On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote:
>> If for some reason the compiler could not generate a 32-bit str opcode
>> instead of an 8-bit strb opcode, the pragma Atomic should have caused
>> an error during compilation.
>
> Well, pragmas are permitted to be ignored. Atomic should never be a pragma.
>

I thought that only applied to unrecognised pragmas.

OTOH, going back a couple of versions to the Ada 95 RM (the version
I have to hand and also the pragma only days), C.6(10) makes it clear
that an Atomic pragma is illegal if the implementation cannot support
the indivisible accesses required.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 19:52   ` daniel.dmk
@ 2014-07-01 20:40     ` Simon Clubley
  2014-07-01 20:55       ` Simon Clubley
  2014-07-01 21:01       ` Niklas Holsti
  2014-07-02  7:30     ` Simon Wright
  1 sibling, 2 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 20:40 UTC (permalink / raw)


On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
> Thank you everyone for your suggestions and comments. 
>
> On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley  wrote:
>> 
>> Pragma Atomic _should_ have given you the guarantee you needed.
>> 
>> Are you double checked how it's being used in the code ?
>
> So I've set up a project to demonstrate only this problem. I've created a package called "Test" which contains the structure definition, and the definition of the register itself at the fixed address:
>
>    with System;
>
>    package Test is
>       type Bits_1 is mod 2**1 with Size => 1;
>       type Bits_2 is mod 2**2 with Size => 2;
>       type Bits_28 is mod 2**28 with Size => 28;
>       
>       type CR_Register is
>          record
>             Reserved_1 : Bits_2;
>             RNGEN      : Bits_1;
>             IE         : Bits_1;
>             Reserved_2 : Bits_28;
>          end record;
>       for CR_Register use
>          record
>             Reserved_1 at 0 range 0 .. 1;
>             RNGEN      at 0 range 2 .. 2;
>             IE         at 0 range 3 .. 3;
>             Reserved_2 at 0 range 4 .. 31;
>          end record;
>       for CR_Register'Size use 32;
>
>       CR : CR_Register with
>         Volatile,
>           Atomic,
>           Address => System'To_Address(16#5006_0800#);
>    end Test;
>
> So I've now defined the reserved bits in the register, and I have added "Atomic" to the CR register.
>
> In my main procedure I have the following:
>
>    with System;
>    with Test;
>
>    procedure Main
>      with SPARK_Mode => On
>    is
>       pragma Priority(System.Priority'First);
>       
>    begin
>       
>       Test.CR.RNGEN := 1;
>       
>       loop
>          null;
>       end loop;
>
>    end Main;
>
> The line where I assign the RNGEN bit produces the following assembly code (using no optimization: -O0):
>
>    mov.w   r3, #2048       ; 0x800
>    movt    r3, #20486      ; 0x5006
>    ldrb    r2, [r3, #0]
>    orr.w   r2, r2, #4
>    strb    r2, [r3, #0]
>

This is the exact same issue I encountered when I tried to use bitfields
in C instead of bitmasks. The difference here is that Ada's Atomic pragma
is supposed to stop this type of code from being generated.

> As you can see, it is using byte load/store instructions.
>
> So even when using Atomic, and when defining the other bits in the register
> it is still using the byte load/store instructions. The same assmebly code is
> generated at all optimization levels.
>
> For reference, here's the code when I use a temporary copy of the register:
>
>    declare
>       Temp : Test.CR_Register;
>    begin
>       Temp := Test.CR;
>       Temp.RNGEN := 1;
>       Test.CR := Temp;
>    end;
>
> produces the following assembly code (the 3 segements of asm correspond to
> each of the 3 lines of code):
>
>    mov.w   r3, #2048       ; 0x800
>    movt    r3, #20486      ; 0x5006
>    ldr     r3, [r3, #0]
>    str     r3, [r7, #4]
>    
>    ldr     r3, [r7, #4]
>    orr.w   r3, r3, #4
>    str     r3, [r7, #4]
>    
>    mov.w   r3, #2048       ; 0x800
>    movt    r3, #20486      ; 0x5006
>    ldr     r2, [r7, #4]
>    str     r2, [r3, #0]
>

This is exactly the kind of ARM code I would expect to see generated.

> In this case, it is always using the word load/store instructions (ldr and str). Here is the same code when optimization is enabled (-O1):
>
>    mov.w   r3, #2048       ; 0x800
>    movt    r3, #20486      ; 0x5006
>    ldr     r2, [r3, #0]
>    orr.w   r2, r2, #4
>    str     r2, [r3, #0]
>
> So could there be a problem with GNAT's Atomic on ARM?
>

Yes, big time.

The Atomic pragma is making a guarantee which is not being honoured by
the gcc ARM code generator.

> I think the approach that I will take for the time being is to always use a
> temporary when reading/writing the registers. I can hide the registers behind
> procedures to enforce this access, and to also add pre/post conditions to
> enforce that the reserved bits are not modified from their reset value.
>

You would need to use a temporary variable anyway if you need to update
multiple bitfields at the same time as part of an atomic register update.

> I would like to avoid machine code insertions if possible, since I would like
> to remain inside SPARK 2014 as much as possible (machine code insertions are
> not in SPARK 2014).

If you need to do things like manipulate the CPSR or the ARM coprocessor
registers, then this might not be possible.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 20:40     ` Simon Clubley
@ 2014-07-01 20:55       ` Simon Clubley
  2014-07-01 21:01       ` Niklas Holsti
  1 sibling, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 20:55 UTC (permalink / raw)


On 2014-07-01, Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote:
> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
>>
>> So could there be a problem with GNAT's Atomic on ARM?
>>
>
> Yes, big time.
>
> The Atomic pragma is making a guarantee which is not being honoured by
> the gcc ARM code generator.
>

And before anyone pulls me up on it :-), I know it's not a pragma any
more, but Ada 2012 is still on my list to things to look at (along with
lots of other projects all competing for my spare time. :-))

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 20:40     ` Simon Clubley
  2014-07-01 20:55       ` Simon Clubley
@ 2014-07-01 21:01       ` Niklas Holsti
  2014-07-01 21:20         ` Simon Clubley
  2014-07-01 21:55         ` daniel.dmk
  1 sibling, 2 replies; 51+ messages in thread
From: Niklas Holsti @ 2014-07-01 21:01 UTC (permalink / raw)


On 14-07-01 23:40 , Simon Clubley wrote:
> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
>> Thank you everyone for your suggestions and comments. 
>>
>> On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley  wrote:
>>>
>>> Pragma Atomic _should_ have given you the guarantee you needed.

Unfortunately not, see below.

>>> Are you double checked how it's being used in the code ?
>>
>> So I've set up a project to demonstrate only this problem. I've
>> created a package called "Test" which contains the structure
>> definition, and the definition of the register itself at the
>> fixed address:
>>
>>    with System;
>>
>>    package Test is
>>       type Bits_1 is mod 2**1 with Size => 1;
>>       type Bits_2 is mod 2**2 with Size => 2;
>>       type Bits_28 is mod 2**28 with Size => 28;
>>       
>>       type CR_Register is
>>          record
>>             Reserved_1 : Bits_2;
>>             RNGEN      : Bits_1;
>>             IE         : Bits_1;
>>             Reserved_2 : Bits_28;
>>          end record;
>>       for CR_Register use
>>          record
>>             Reserved_1 at 0 range 0 .. 1;
>>             RNGEN      at 0 range 2 .. 2;
>>             IE         at 0 range 3 .. 3;
>>             Reserved_2 at 0 range 4 .. 31;
>>          end record;
>>       for CR_Register'Size use 32;
>>
>>       CR : CR_Register with
>>         Volatile,
>>           Atomic,
>>           Address => System'To_Address(16#5006_0800#);
>>    end Test;
>>
>> So I've now defined the reserved bits in the register, and I have
>> added "Atomic" to the CR register.
>>
>> In my main procedure I have the following:
>>
>>    with System;
>>    with Test;
>>
>>    procedure Main
>>      with SPARK_Mode => On
>>    is
>>       pragma Priority(System.Priority'First);
>>       
>>    begin
>>       
>>       Test.CR.RNGEN := 1;
>>       
>>       loop
>>          null;
>>       end loop;
>>
>>    end Main;
>>
>> The line where I assign the RNGEN bit produces the following
>> assembly code (using no optimization: -O0):
>>
>>    mov.w   r3, #2048       ; 0x800
>>    movt    r3, #20486      ; 0x5006
>>    ldrb    r2, [r3, #0]
>>    orr.w   r2, r2, #4
>>    strb    r2, [r3, #0]
>>
> 
> This is the exact same issue I encountered when I tried to use bitfields
> in C instead of bitmasks. The difference here is that Ada's Atomic pragma
> is supposed to stop this type of code from being generated.

Actually not... as I also forgot... because the Ada rule is RM C.6(15):

"For an atomic object (including an atomic component) all reads and
updates of the object as a whole are indivisible."

Note the part "as a whole". If you access a component of an atomic
record, that is not accessing the record "as a whole".

>> For reference, here's the code when I use a temporary copy of the register:
>>
>>    declare
>>       Temp : Test.CR_Register;
>>    begin
>>       Temp := Test.CR;
>>       Temp.RNGEN := 1;
>>       Test.CR := Temp;
>>    end;

This code accesses the record as a whole, and therefore...

> This is exactly the kind of ARM code I would expect to see generated.
> 
>> In this case, it is always using the word load/store instructions
>> (ldr and str).

>> So could there be a problem with GNAT's Atomic on ARM?
>>
> 
> Yes, big time.

No. The Atomic guarantee only applies to read/write of the whole record.
My earlier post in this thread was in error.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 21:01       ` Niklas Holsti
@ 2014-07-01 21:20         ` Simon Clubley
  2014-07-01 22:38           ` Niklas Holsti
  2014-07-01 21:55         ` daniel.dmk
  1 sibling, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-01 21:20 UTC (permalink / raw)


On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote:
> On 14-07-01 23:40 , Simon Clubley wrote:
>> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
>>> So could there be a problem with GNAT's Atomic on ARM?
>>>
>> 
>> Yes, big time.
>
> No. The Atomic guarantee only applies to read/write of the whole record.
> My earlier post in this thread was in error.
>

That's interesting, and depressing, as it reduces the usefulness of
Atomic hugely.

When c.l.a talked a few weeks ago about syntax for the atomic update
of multiple bitfields at the same time, I had thought the general
view was that Atomic on a record resulted in register updates in units
of the record size when updating a single bitfield, but that's clearly
not the case as you have just pointed out.

I think this whole area of the atomic updating of multiple bitfields is
something which needs work in Ada especially now the above revelation
means Ada is even weaker in this specific area than I thought it was.

Thanks for the interesting (if depressing :-)) insight.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 21:01       ` Niklas Holsti
  2014-07-01 21:20         ` Simon Clubley
@ 2014-07-01 21:55         ` daniel.dmk
  1 sibling, 0 replies; 51+ messages in thread
From: daniel.dmk @ 2014-07-01 21:55 UTC (permalink / raw)


On Tuesday, 1 July 2014 22:01:35 UTC+1, Niklas Holsti  wrote:
> On 14-07-01 23:40 , Simon Clubley wrote:
> 
> 
> >> On Tuesday, 1 July 2014 13:03:30 UTC+1, Simon Clubley  wrote:
> 
> >>>
> 
> >>> Pragma Atomic _should_ have given you the guarantee you needed.
> 
> 
> 
> Unfortunately not, see below.
> 
> 
> 
> >>> Are you double checked how it's being used in the code ?
> 
> >>
> 
> >> So I've set up a project to demonstrate only this problem. I've
> 
> >> created a package called "Test" which contains the structure
> 
> >> definition, and the definition of the register itself at the
> 
> >> fixed address:
> 
> >>
> 
> >>    with System;
> 
> >>
> 
> >>    package Test is
> 
> >>       type Bits_1 is mod 2**1 with Size => 1;
> 
> >>       type Bits_2 is mod 2**2 with Size => 2;
> 
> >>       type Bits_28 is mod 2**28 with Size => 28;
> 
> >>       
> 
> >>       type CR_Register is
> 
> >>          record
> 
> >>             Reserved_1 : Bits_2;
> 
> >>             RNGEN      : Bits_1;
> 
> >>             IE         : Bits_1;
> 
> >>             Reserved_2 : Bits_28;
> 
> >>          end record;
> 
> >>       for CR_Register use
> 
> >>          record
> 
> >>             Reserved_1 at 0 range 0 .. 1;
> 
> >>             RNGEN      at 0 range 2 .. 2;
> 
> >>             IE         at 0 range 3 .. 3;
> 
> >>             Reserved_2 at 0 range 4 .. 31;
> 
> >>          end record;
> 
> >>       for CR_Register'Size use 32;
> 
> >>
> 
> >>       CR : CR_Register with
> 
> >>         Volatile,
> 
> >>           Atomic,
> 
> >>           Address => System'To_Address(16#5006_0800#);
> 
> >>    end Test;
> 
> >>
> 
> >> So I've now defined the reserved bits in the register, and I have
> 
> >> added "Atomic" to the CR register.
> 
> >>
> 
> >> In my main procedure I have the following:
> 
> >>
> 
> >>    with System;
> 
> >>    with Test;
> 
> >>
> 
> >>    procedure Main
> 
> >>      with SPARK_Mode => On
> 
> >>    is
> 
> >>       pragma Priority(System.Priority'First);
> 
> >>       
> 
> >>    begin
> 
> >>       
> 
> >>       Test.CR.RNGEN := 1;
> 
> >>       
> 
> >>       loop
> 
> >>          null;
> 
> >>       end loop;
> 
> >>
> 
> >>    end Main;
> 
> >>
> 
> >> The line where I assign the RNGEN bit produces the following
> 
> >> assembly code (using no optimization: -O0):
> 
> >>
> 
> >>    mov.w   r3, #2048       ; 0x800
> 
> >>    movt    r3, #20486      ; 0x5006
> 
> >>    ldrb    r2, [r3, #0]
> 
> >>    orr.w   r2, r2, #4
> 
> >>    strb    r2, [r3, #0]
> 
> >>
> 
> > 
> 
> > This is the exact same issue I encountered when I tried to use bitfields
> 
> > in C instead of bitmasks. The difference here is that Ada's Atomic pragma
> 
> > is supposed to stop this type of code from being generated.
> 
> 
> 
> Actually not... as I also forgot... because the Ada rule is RM C.6(15):
> 
> 
> 
> "For an atomic object (including an atomic component) all reads and
> 
> updates of the object as a whole are indivisible."
> 
> 
> 
> Note the part "as a whole". If you access a component of an atomic
> 
> record, that is not accessing the record "as a whole".
> 

Aha, this clarifies it all perfectly. Thank you. I'll avoid modifying these registers in part, and make sure that the registers are always accessed in whole. 


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 21:20         ` Simon Clubley
@ 2014-07-01 22:38           ` Niklas Holsti
  2014-07-02 16:49             ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Niklas Holsti @ 2014-07-01 22:38 UTC (permalink / raw)


On 14-07-02 00:20 , Simon Clubley wrote:
> On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote:
>> On 14-07-01 23:40 , Simon Clubley wrote:
>>> On 2014-07-01, daniel.dmk@googlemail.com <daniel.dmk@googlemail.com> wrote:
>>>> So could there be a problem with GNAT's Atomic on ARM?
>>>>
>>>
>>> Yes, big time.
>>
>> No. The Atomic guarantee only applies to read/write of the whole record.
>> My earlier post in this thread was in error.
>>
> 
> That's interesting, and depressing, as it reduces the usefulness of
> Atomic hugely.
> 
> When c.l.a talked a few weeks ago about syntax for the atomic update
> of multiple bitfields at the same time, I had thought the general
> view was that Atomic on a record resulted in register updates in units
> of the record size when updating a single bitfield, but that's clearly
> not the case as you have just pointed out.

As I remember, the new syntax ideas in that discussion were meant to
update some bitfields in an atomic record as part of a read, modify,
write sequence, accessing the whole record without using a temporary
variable to hold the value. So Ada's rule for Atomic was included and
assumed in that discussion. I am ashamed for forgetting it... maybe
there have been too many midnight-football-viewing sessions lately :-)

> I think this whole area of the atomic updating of multiple bitfields is
> something which needs work in Ada especially now the above revelation
> means Ada is even weaker in this specific area than I thought it was.

I don't think the weakness is serious. Using a temporary variable to
ensure whole-record access is a pretty clean work-around, IMO. But the
new aggregate-like syntax suggested in the earlier discussion could be
used for other things, too, so I am still in favour of it.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 19:52   ` daniel.dmk
  2014-07-01 20:40     ` Simon Clubley
@ 2014-07-02  7:30     ` Simon Wright
  2014-07-02 18:52       ` daniel.dmk
  2014-07-04 23:51       ` Niklas Holsti
  1 sibling, 2 replies; 51+ messages in thread
From: Simon Wright @ 2014-07-02  7:30 UTC (permalink / raw)


daniel.dmk@googlemail.com writes:

> Thanks for this suggestion, I'll define the reserved bits in the
> register, and use static checks to enforce that they are not modified
> from their reset value in the code.

You could use something like

   type Reserved_Bit is range 0 .. 0 with Size => 1;
   type Reserved is array (Natural range <>) of Reserved_Bit
     with Component_Size => 1;

   ...

   type T is record
      A : Boolean;            -- at bit 0
      Res : Reserved (1 .. 6);
      B : Boolean;            -- at bit 7
   end record with Size => 8;

(with representation clauses as indicated)


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 22:38           ` Niklas Holsti
@ 2014-07-02 16:49             ` Simon Clubley
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-02 16:49 UTC (permalink / raw)


On 2014-07-01, Niklas Holsti <niklas.holsti@tidorum.invalid> wrote:
> On 14-07-02 00:20 , Simon Clubley wrote:
>> 
>> When c.l.a talked a few weeks ago about syntax for the atomic update
>> of multiple bitfields at the same time, I had thought the general
>> view was that Atomic on a record resulted in register updates in units
>> of the record size when updating a single bitfield, but that's clearly
>> not the case as you have just pointed out.
>
> As I remember, the new syntax ideas in that discussion were meant to
> update some bitfields in an atomic record as part of a read, modify,
> write sequence, accessing the whole record without using a temporary
> variable to hold the value. So Ada's rule for Atomic was included and
> assumed in that discussion.

Yes, you are correct. Thinking about it, this interpretation of Ada's
Atomic rule is still consistent with that discussion because the
underlying reference is to the _full_ record in those proposals.

> I am ashamed for forgetting it... maybe
> there have been too many midnight-football-viewing sessions lately :-)
>

:-)

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-02  7:30     ` Simon Wright
@ 2014-07-02 18:52       ` daniel.dmk
  2014-07-04 23:51       ` Niklas Holsti
  1 sibling, 0 replies; 51+ messages in thread
From: daniel.dmk @ 2014-07-02 18:52 UTC (permalink / raw)


On Wednesday, 2 July 2014 08:30:44 UTC+1, Simon Wright  wrote:
> 
> You could use something like
> 
> 
> 
>    type Reserved_Bit is range 0 .. 0 with Size => 1;
> 
>    type Reserved is array (Natural range <>) of Reserved_Bit
> 
>      with Component_Size => 1;
> 
> 
> 
>    ...
> 
> 
> 
>    type T is record
> 
>       A : Boolean;            -- at bit 0
> 
>       Res : Reserved (1 .. 6);
> 
>       B : Boolean;            -- at bit 7
> 
>    end record with Size => 8;
> 
> 
> 
> (with representation clauses as indicated)

That's quite elegant, I like it. Thanks!


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-01 20:08           ` Simon Clubley
@ 2014-07-02 22:24             ` Randy Brukardt
  2014-07-06 20:40               ` MatthiasR
  0 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2014-07-02 22:24 UTC (permalink / raw)


"Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in 
message news:lov4ga$3v9$1@dont-email.me...
> On 2014-07-01, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
>> On Tue, 1 Jul 2014 17:00:45 +0000 (UTC), Simon Clubley wrote:
>>> If for some reason the compiler could not generate a 32-bit str opcode
>>> instead of an 8-bit strb opcode, the pragma Atomic should have caused
>>> an error during compilation.
>>
>> Well, pragmas are permitted to be ignored. Atomic should never be a 
>> pragma.
>>
>
> I thought that only applied to unrecognised pragmas.

Correct. Pragma Atomic should be illegal if it is not supported.

But Dmitry is right, it should never have been a pragma. (Pragmas should 
only have been used for global configuration, never on individual entities, 
IMHO.)

> OTOH, going back a couple of versions to the Ada 95 RM (the version
> I have to hand and also the pragma only days), C.6(10) makes it clear
> that an Atomic pragma is illegal if the implementation cannot support
> the indivisible accesses required.

Right. If the OP really did exactly as he said, then GNAT has a bug (no 
matter what his declaration was). [But I've seen plenty of cases where 
someone (including me) thought they'd tried something when they really had 
not for one reason or another.]

                                    Randy.


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-02  7:30     ` Simon Wright
  2014-07-02 18:52       ` daniel.dmk
@ 2014-07-04 23:51       ` Niklas Holsti
  2014-07-05  0:18         ` Niklas Holsti
  1 sibling, 1 reply; 51+ messages in thread
From: Niklas Holsti @ 2014-07-04 23:51 UTC (permalink / raw)


On 14-07-02 09:30 , Simon Wright wrote:
> daniel.dmk@googlemail.com writes:
> 
>> Thanks for this suggestion, I'll define the reserved bits in the
>> register, and use static checks to enforce that they are not modified
>> from their reset value in the code.
> 
> You could use something like
> 
>    type Reserved_Bit is range 0 .. 0 with Size => 1;
>    type Reserved is array (Natural range <>) of Reserved_Bit
>      with Component_Size => 1;
> 
>    ...
> 
>    type T is record
>       A : Boolean;            -- at bit 0
>       Res : Reserved (1 .. 6);
>       B : Boolean;            -- at bit 7
>    end record with Size => 8;
> 
> (with representation clauses as indicated)

That has two potential problems...

- First, even if Reserved_Bit is constrained to a single value (0), that
does not mean that an uninitialized variable or component of this type
will have that value. It will still have to be assigned the value zero,
to be sure of having that value.

- Second, if you read the value of the control register into a variable
of type T, and some of the reserved bits read as 1 (which is not quite
possible), these Reserved_Bit components will now, very probably, have
an invalid representation, which is a nasty state.

For these reasons, I would define Reserved_Bit as range 0 .. 1 and
perhaps provide the default value (others => 0) for the Res component.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-04 23:51       ` Niklas Holsti
@ 2014-07-05  0:18         ` Niklas Holsti
  0 siblings, 0 replies; 51+ messages in thread
From: Niklas Holsti @ 2014-07-05  0:18 UTC (permalink / raw)


On 14-07-05 01:51 , Niklas Holsti wrote:
> On 14-07-02 09:30 , Simon Wright wrote:
>> daniel.dmk@googlemail.com writes:
>>
>>> Thanks for this suggestion, I'll define the reserved bits in the
>>> register, and use static checks to enforce that they are not modified
>>> from their reset value in the code.
>>
>> You could use something like
>>
>>    type Reserved_Bit is range 0 .. 0 with Size => 1;
>>    type Reserved is array (Natural range <>) of Reserved_Bit
>>      with Component_Size => 1;
>>
>>    ...
>>
>>    type T is record
>>       A : Boolean;            -- at bit 0
>>       Res : Reserved (1 .. 6);
>>       B : Boolean;            -- at bit 7
>>    end record with Size => 8;
>>
>> (with representation clauses as indicated)
> 
> That has two potential problems...
> 
> - First, even if Reserved_Bit is constrained to a single value (0), that
> does not mean that an uninitialized variable or component of this type
> will have that value. It will still have to be assigned the value zero,
> to be sure of having that value.
> 
> - Second, if you read the value of the control register into a variable
> of type T, and some of the reserved bits read as 1 (which is not quite
                                                               ^^^
(Delete the word "not", above -- it is quite possible that some reserved
bits read as 1, although they should be written with zero.)

> possible), these Reserved_Bit components will now, very probably, have
> an invalid representation, which is a nasty state.
> 
> For these reasons, I would define Reserved_Bit as range 0 .. 1 and
> perhaps provide the default value (others => 0) for the Res component.
> 


-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-02 22:24             ` Randy Brukardt
@ 2014-07-06 20:40               ` MatthiasR
  2014-07-07  0:25                 ` Simon Clubley
  2014-07-07 22:38                 ` Randy Brukardt
  0 siblings, 2 replies; 51+ messages in thread
From: MatthiasR @ 2014-07-06 20:40 UTC (permalink / raw)


Randy Brukardt wrote:

> Right. If the OP really did exactly as he said, then GNAT has a bug (no
> matter what his declaration was). [But I've seen plenty of cases where
> someone (including me) thought they'd tried something when they really had
> not for one reason or another.]

According to the RM, the compiler must not divide a read or write from/to a 
variable with pragma/aspect 'atomic' into multiple reads/writes. There is 
nothing said, that the variable always has to be read/written as a whole. So 
it seems to be perfectly OK to write only one byte of a 32 bit variable, if  
a value has been assigned to only a part of a record which is contained in 
this byte.

There is something said about this topic in the latest GNAT docs:
https://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_8.html#SEC97

They recommend to use a temporary variable to ensure an access to the record 
variable as a whole.

That is not really elegant, because records with representation clauses, 
directly mapped onto hardware registers, look like the most natural way to 
access these registers. Reading Ada books, one even could get the impression 
that record represenation clauses are made primarily for this purpose.
Unfortunately there seem to be no way to force a specific access width, so 
this feature is not really useable (without the mentioned workaround with 
the temporary variable) on architectures where the allowed access width is 
not uniform over the whole address range.

Matthias


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-06 20:40               ` MatthiasR
@ 2014-07-07  0:25                 ` Simon Clubley
  2014-07-07 22:38                 ` Randy Brukardt
  1 sibling, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-07  0:25 UTC (permalink / raw)


On 2014-07-06, MatthiasR <MatthiasR@invalid.invalid> wrote:
> They recommend to use a temporary variable to ensure an access to the record 
> variable as a whole.
>
> That is not really elegant, because records with representation clauses, 
> directly mapped onto hardware registers, look like the most natural way to 
> access these registers. Reading Ada books, one even could get the impression 
> that record represenation clauses are made primarily for this purpose.
> Unfortunately there seem to be no way to force a specific access width, so 
> this feature is not really useable (without the mentioned workaround with 
> the temporary variable) on architectures where the allowed access width is 
> not uniform over the whole address range.
>

Totally agree.

In addition, Ada needs syntax/semantics to update multiple bitfields
within a record as one write operation without having to use a
temporary. The size of the write (assuming the record itself was
marked as Atomic) would be the size of the record.

In that way, you could (finally) get rid of temporary variables and C
style bitmasks when updating registers.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-06 20:40               ` MatthiasR
  2014-07-07  0:25                 ` Simon Clubley
@ 2014-07-07 22:38                 ` Randy Brukardt
  2014-07-08  6:51                   ` Simon Wright
                                     ` (3 more replies)
  1 sibling, 4 replies; 51+ messages in thread
From: Randy Brukardt @ 2014-07-07 22:38 UTC (permalink / raw)


"MatthiasR" <MatthiasR@invalid.invalid> wrote in message 
news:lpcck1$vtv$1@dont-email.me...
> Randy Brukardt wrote:
>
>> Right. If the OP really did exactly as he said, then GNAT has a bug (no
>> matter what his declaration was). [But I've seen plenty of cases where
>> someone (including me) thought they'd tried something when they really 
>> had
>> not for one reason or another.]
>
> According to the RM, the compiler must not divide a read or write from/to 
> a
> variable with pragma/aspect 'atomic' into multiple reads/writes. There is
> nothing said, that the variable always has to be read/written as a whole. 
> So
> it seems to be perfectly OK to write only one byte of a 32 bit variable, 
> if
> a value has been assigned to only a part of a record which is contained in
> this byte.

No. C.6(22/2) surely applies. (All atomic objects are also volatile 
objects.) Anyone claiming that C.6(22/2) does not apply to a load/store of 
part of an object is seeing what they want - that would be inconsistent with 
the way such wording is intepreted in the rest of the standard.

But any attempt to write of a record component of an atomic object 
necessarily must violate either C.6(20) or C.6(22/2). (Either you don't 
access all of the bits, or you have to have a read not in the source code to 
read the bits that you aren't going to write.)  From that I conclude that 
Ada doesn't (really) support atomic composite types (and any attempt to 
declare such a thing ought to be rejected, since the language provides no 
other possibilities).

I doubt any compiler will do that for practical reasons. Since C.6(22/2) is 
Implementation Advice, a compiler is allowed to ignore it if it documents 
that it does so. That's probably what GNAT is doing here, but clearly that's 
harmful (as noted by this discussion). I'd rather that the implementation 
reject any assignments for which it cannot make this guarantee, but I 
suppose the language gives no justification for doing so. (That's a common 
problem in Chapter 13/Annex C features.) Does GNAT at least give a warning?

Clearly, we need a partial aggregate syntax (it's the only way for an atomic 
record write to make sense), and that needs to be clear that it includes 
both a read and a write of the object for the purposes of volatile 
variables. Probably someone should submit this problem to Ada-Comment for 
study in the next version of Ada (whenever that might be).

> There is something said about this topic in the latest GNAT docs:
> https://docs.adacore.com/gnat-unw-docs/html/gnat_ugn_8.html#SEC97
>
> They recommend to use a temporary variable to ensure an access to the 
> record
> variable as a whole.

Right. Partial writes of atomic objects shouldn't be allowed at all, and 
thus the programmer should never write one.

> That is not really elegant, because records with representation clauses,
> directly mapped onto hardware registers, look like the most natural way to
> access these registers.

That *is* the most natural way to access those registers. But you can never 
access a *part* of a register, you always have to read or write the entire 
register at a time. Ada makes you make that explicit in your code, thus a 
temporary is required (pending new syntax).

> Reading Ada books, one even could get the impression
> that record represenation clauses are made primarily for this purpose.

It is.

> Unfortunately there seem to be no way to force a specific access width, so
> this feature is not really useable (without the mentioned workaround with
> the temporary variable) on architectures where the allowed access width is
> not uniform over the whole address range.

No, you're looking at this the wrong way. If you write this in C, you read 
the entire register and then do some sort of bit-mask, and then write the 
thing back. You have to do that same thing in Ada, just using the record 
type instead of the bit mask. Ada replaces the bit masking operations by 
more readable record component accesses; it doesn't suddenly allow you to 
write something that you couldn't possibly write in C [a direct write of 
part of a register]. (Whether Ada *should* have allowed you do to that is a 
totally different question and relatively irrelevant at the moment because 
the language isn't likely to support anything new in the near future.)

                                                   Randy.




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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-07 22:38                 ` Randy Brukardt
@ 2014-07-08  6:51                   ` Simon Wright
  2014-07-10 11:47                     ` Simon Wright
  2014-07-08  8:50                   ` Brian Drummond
                                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 51+ messages in thread
From: Simon Wright @ 2014-07-08  6:51 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> No. C.6(22/2) surely applies. (All atomic objects are also volatile
> objects.) Anyone claiming that C.6(22/2) does not apply to a
> load/store of part of an object is seeing what they want - that would
> be inconsistent with the way such wording is intepreted in the rest of
> the standard.

I don't quite understand the conclusion of AI95-00272 in the light of
this! (It's expressed in terms of slices of an (atomic) array object,
but it would surely apply also to record components if anyone had
thought of that). I don't understand why anyone would say that an object
was atomic if they didn't want it to be always addressed as a whole (and
the prime reason for that must be memory-mapped I/O, given we now have
protected objects for inter-task communication).

See also the AARM ramification for C6(7), "A slice of an atomic array
object is not itself atomic. That's necessary as executing a read or
write of a dynamic number of components in a single instruction is not
possible on many targets." which strikes me as being back-to-front
reasoning.

See also C.6(15), "For an atomic object (including an atomic component)
all reads and updates of the object as a whole are indivisible.". I
can't help wondering whether "as a whole" was a mistake, given that the
IA in the AARM, back as far as Ada95, includes "The presumption is that
volatile or atomic objects might reside in an ``active'' part of the
address space where each read has a potential side-effect, and at the
very least might deliver a different value.".

> I doubt any compiler will do that for practical reasons. Since
> C.6(22/2) is Implementation Advice, a compiler is allowed to ignore it
> if it documents that it does so. That's probably what GNAT is doing
> here, but clearly that's harmful (as noted by this discussion). I'd
> rather that the implementation reject any assignments for which it
> cannot make this guarantee, but I suppose the language gives no
> justification for doing so. (That's a common problem in Chapter
> 13/Annex C features.) Does GNAT at least give a warning?

The GNAT RM doesn't contain notes on C.6 IA, and GNAT doesn't give a
warning.

FSF GCC 4.9.0 and GNAT GPL 2014 (Mac, x86_64) are both (IMO) a little
confused (maybe just legalistic) about this:

   procedure Atom is

      type R is record
         A : Boolean;
         B : Boolean;
      end record with Size => 32;
      for R use record
         A at 0 range 0 .. 0;
         B at 0 range 31 .. 31;
      end record;

      V : R with Import, Atomic, Convention => C, External_Name => "foo";

   begin

      V := (A => True, B => True);
      V.A := False;
      V.B := False;
      V := (A => True, B => True);

   end Atom;

in that the whole-record assignments are followed by an mfence
instruction while the component assignments (implemented by a read V,
modify, write V sequence of 3 instructions) are not; I think this means
that the component assignments are just treated as volatile, borne out
by the fact that the -gnatw.d switch (turn on info messages for atomic
synchronization) only reports 'info: atomic synchronization set for "V"'
for the whole-record assignments.

The x86_64 code accesses all 32 bits of V. If it is more efficient on
arm to access the relevant bytes for the component assignments, I expect
that's what would happen (as reported).

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-07 22:38                 ` Randy Brukardt
  2014-07-08  6:51                   ` Simon Wright
@ 2014-07-08  8:50                   ` Brian Drummond
  2014-07-08 12:12                   ` Simon Clubley
  2014-07-20 11:35                   ` MatthiasR
  3 siblings, 0 replies; 51+ messages in thread
From: Brian Drummond @ 2014-07-08  8:50 UTC (permalink / raw)


On Mon, 07 Jul 2014 17:38:54 -0500, Randy Brukardt wrote:

> "MatthiasR" <MatthiasR@invalid.invalid> wrote in message
> news:lpcck1$vtv$1@dont-email.me...

>> That is not really elegant, because records with representation
>> clauses, directly mapped onto hardware registers, look like the most
>> natural way to access these registers.
> 
> That *is* the most natural way to access those registers. But you can
> never access a *part* of a register, you always have to read or write
> the entire register at a time. Ada makes you make that explicit in your
> code, thus a temporary is required (pending new syntax).

There are exceptions to this. Some embedded CPUs (and even the old Z80) 
have atomic "bit test, set, clear" instructions. Where a register is 
represented in Ada as a packed array of booleans, setting one component 
of the array does actually compile down to a single "bit set" 
instruction. (I do not have a worked example with a record of packed 
booleans, but would expect the same).

(Except for bit 7 on the MSP430 gcc4.9 back end where you get a shift 
instead, which expands to about 30 instructions! Must report that one...)

But the bit access exception doesn't fundamentally change the argument : 
there are no access levels between the bit and the byte (or 32-bit word 
on some architectures) so there are no general hardware means for 
atomically accessing arbitrary sizes or alignments of record components. 

And thus, I see no way to coherently offer such facility in Ada with a 
guarantee of atomicity. 

One of Ada's strengths is that, however abstract the syntax and semantics 
may be, it is always close to the hardware in terms of the underlying 
operations it offers.

- Brian


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-07 22:38                 ` Randy Brukardt
  2014-07-08  6:51                   ` Simon Wright
  2014-07-08  8:50                   ` Brian Drummond
@ 2014-07-08 12:12                   ` Simon Clubley
  2014-07-08 13:26                     ` G.B.
                                       ` (2 more replies)
  2014-07-20 11:35                   ` MatthiasR
  3 siblings, 3 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-08 12:12 UTC (permalink / raw)


On 2014-07-07, Randy Brukardt <randy@rrsoftware.com> wrote:
>
> Clearly, we need a partial aggregate syntax (it's the only way for an atomic 
> record write to make sense), and that needs to be clear that it includes 
> both a read and a write of the object for the purposes of volatile 
> variables. Probably someone should submit this problem to Ada-Comment for 
> study in the next version of Ada (whenever that might be).
>

What are the submission details for Ada-Comment ? (Searching for Ada
Comments just points to links about using comments in Ada code.)

What is the level of formality and problem detail required in the
submission ?

I also wonder if "Atomic" is the correct word here; perhaps something
like "Non_Segmented_Access" would be a better attribute name when we
_must_ access the register in units of the record size and don't really
care about the Read-Modify-Write sequence itself being indivisible.

_We_ "know" that Atomic in this case really only means there's a single,
full-sized read and a single full-sized write of the register and that
the whole Read-Modify-Write sequence itself isn't really indivisible.

However, it's reasonable for a newcomer to Ada to wonder if Atomic
really does mean the whole Read-Modify-Write sequence itself is
indivisible.

One of the goals of Ada is to express clarity when writing code and
"Non_Segmented_Access" expresses the intent here better than Atomic
does.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 12:12                   ` Simon Clubley
@ 2014-07-08 13:26                     ` G.B.
  2014-07-08 17:13                       ` Simon Clubley
  2014-07-08 15:36                     ` Adam Beneschan
  2014-07-08 20:34                     ` Randy Brukardt
  2 siblings, 1 reply; 51+ messages in thread
From: G.B. @ 2014-07-08 13:26 UTC (permalink / raw)


On 08.07.14 14:12, Simon Clubley wrote:
> What are the submission details for Ada-Comment ? (Searching for Ada
> Comments just points to links about using comments in Ada code.)

Searching the LRM for "ada-comment" uses prior knowledge
which, by narrowing, is superior to anything that the WWW's
Search AI can possibly produce ;-)

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 12:12                   ` Simon Clubley
  2014-07-08 13:26                     ` G.B.
@ 2014-07-08 15:36                     ` Adam Beneschan
  2014-07-08 15:40                       ` Adam Beneschan
  2014-07-08 20:34                     ` Randy Brukardt
  2 siblings, 1 reply; 51+ messages in thread
From: Adam Beneschan @ 2014-07-08 15:36 UTC (permalink / raw)


On Tuesday, July 8, 2014 5:12:22 AM UTC-7, Simon Clubley wrote:

> What are the submission details for Ada-Comment ? 

http://www.ada-auth.org/standards/12aarm/html/AA-0-2.html, paragraph 58ff.

                                 -- Adam



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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 15:36                     ` Adam Beneschan
@ 2014-07-08 15:40                       ` Adam Beneschan
  0 siblings, 0 replies; 51+ messages in thread
From: Adam Beneschan @ 2014-07-08 15:40 UTC (permalink / raw)


On Tuesday, July 8, 2014 8:36:03 AM UTC-7, Adam Beneschan wrote:
> On Tuesday, July 8, 2014 5:12:22 AM UTC-7, Simon Clubley wrote:
 
> > What are the submission details for Ada-Comment ? 

> http://www.ada-auth.org/standards/12aarm/html/AA-0-2.html, paragraph 58ff.

Actually, http://www.ada-auth.org/standards/12rm/html/RM-0-2.html is slightly better.  (I tend to consult the AARM first always, so that's why I came up with that link.)

                                  -- Adam


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 13:26                     ` G.B.
@ 2014-07-08 17:13                       ` Simon Clubley
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-08 17:13 UTC (permalink / raw)


On 2014-07-08, G.B. <rm-dash-bau-haus@dash.futureapps.de> wrote:
> On 08.07.14 14:12, Simon Clubley wrote:
>> What are the submission details for Ada-Comment ? (Searching for Ada
>> Comments just points to links about using comments in Ada code.)
>
> Searching the LRM for "ada-comment" uses prior knowledge
> which, by narrowing, is superior to anything that the WWW's
> Search AI can possibly produce ;-)
>

My copy of the LRM is safely at home in my library. :-) (Ada is not
a part of my day job.)

Since I only tend to study it when needing to resolve a specific
issue (and look at the specific sections around that issue only)
I had overlooked this. I knew about the Ada Issues database, but
I didn't realise the initial submission was via an address starting
with ada-comment.

Thanks to you and Adam.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 12:12                   ` Simon Clubley
  2014-07-08 13:26                     ` G.B.
  2014-07-08 15:36                     ` Adam Beneschan
@ 2014-07-08 20:34                     ` Randy Brukardt
  2014-07-09  7:31                       ` Dmitry A. Kazakov
  2 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2014-07-08 20:34 UTC (permalink / raw)


"Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in 
message news:lpgn76$u7h$1@dont-email.me...
> On 2014-07-07, Randy Brukardt <randy@rrsoftware.com> wrote:
>>
>> Clearly, we need a partial aggregate syntax (it's the only way for an 
>> atomic
>> record write to make sense), and that needs to be clear that it includes
>> both a read and a write of the object for the purposes of volatile
>> variables. Probably someone should submit this problem to Ada-Comment for
>> study in the next version of Ada (whenever that might be).
>>
>
> What are the submission details for Ada-Comment ? (Searching for Ada
> Comments just points to links about using comments in Ada code.)

Others have answered this.

> What is the level of formality and problem detail required in the
> submission ?

Well, it's English, so there's no way to enforce anything. :-)

The expectation is that people report the problems they have, that are 
either hard or impossible to solve with Ada as it stands. A sufficient level 
of detail is needed so that we can understand the problem. It's not 
necessary to provide solutions (although few people can resist offering up 
their pet ideas).

> I also wonder if "Atomic" is the correct word here; perhaps something like
> "Non_Segmented_Access" would be a better attribute name when we
> _must_ access the register in units of the record size and don't really
> care about the Read-Modify-Write sequence itself being indivisible.

We discussed that years ago, that's why C.6(22/2) was added. And the answer 
was, yes, "Atomic" is the concept that we want to use for this. It's 
essentially the same idea. As far as the "Read-Modify-Write" sequence being 
indivisble, that definitely is *not* the purpose of Atomic. It just makes 
Read indivisible (and the same for Write, of course). To make 
"Read-Modify-Write" indivisible, you'd need a test-and-set instruction, 
which would require far more restrictions than Atomic does. (I don't see any 
way to make a general Read-Modify-Write to be indivisible on Windows or 
Linux, for instance, as that requires shutting off interrupts.)

I think the only reason that we'd consider adding yet another classification 
would be in case we were worried about compatibility (which certainly is 
possible) with the previous definition of Atomic.

                                                 Randy.


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08 20:34                     ` Randy Brukardt
@ 2014-07-09  7:31                       ` Dmitry A. Kazakov
  2014-07-10  0:11                         ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2014-07-09  7:31 UTC (permalink / raw)


On Tue, 8 Jul 2014 15:34:04 -0500, Randy Brukardt wrote:

> To make 
> "Read-Modify-Write" indivisible, you'd need a test-and-set instruction, 
> which would require far more restrictions than Atomic does. (I don't see any 
> way to make a general Read-Modify-Write to be indivisible on Windows or 
> Linux, for instance, as that requires shutting off interrupts.)

I don't think this should be the semantics of "indivisible". Because as you
said it incredibly difficult to ensure, but more importantly is that this
is mot what programmers actually need. They need it rather be logically
indivisible from the process' point of view. If the process could lose the
processor in between would be no problem for most if not all applications.

If anybody wanted on top of that to block all other processes, system
kernel, interrupts and the very memory bus itself, he would do this by
other means.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-09  7:31                       ` Dmitry A. Kazakov
@ 2014-07-10  0:11                         ` Simon Clubley
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-10  0:11 UTC (permalink / raw)


On 2014-07-09, Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> On Tue, 8 Jul 2014 15:34:04 -0500, Randy Brukardt wrote:
>
>> To make 
>> "Read-Modify-Write" indivisible, you'd need a test-and-set instruction, 
>> which would require far more restrictions than Atomic does. (I don't see any 
>> way to make a general Read-Modify-Write to be indivisible on Windows or 
>> Linux, for instance, as that requires shutting off interrupts.)
>
> I don't think this should be the semantics of "indivisible". Because as you
> said it incredibly difficult to ensure, but more importantly is that this
> is mot what programmers actually need. They need it rather be logically
> indivisible from the process' point of view. If the process could lose the
> processor in between would be no problem for most if not all applications.
>

Oh, I agree with this. :-)

I was just wondering if a newcomer to Ada might be confused by the
use of the word Atomic.

BTW, I'm planning on writing up the partial aggregate submission
sometime at the weekend (spare time permitting :-)).

I'm also planning on a second submission which is a request for a
formal decision regarding if Atomic on a record applies to the access
of a individual record component or not.

The wording identified by Niklas ("as a whole") would suggest not
but Randy appears to think it does. I think we need a firm decision
one way or another so we know for sure.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-08  6:51                   ` Simon Wright
@ 2014-07-10 11:47                     ` Simon Wright
  2014-07-10 13:06                       ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Wright @ 2014-07-10 11:47 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> The x86_64 code accesses all 32 bits of V. If it is more efficient on
> arm to access the relevant bytes for the component assignments, I
> expect that's what would happen (as reported).

Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the
relevant bytes.


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-10 11:47                     ` Simon Wright
@ 2014-07-10 13:06                       ` Simon Clubley
  2014-07-11 18:05                         ` Simon Wright
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-10 13:06 UTC (permalink / raw)


On 2014-07-10, Simon Wright <simon@pushface.org> wrote:
> Simon Wright <simon@pushface.org> writes:
>
>> The x86_64 code accesses all 32 bits of V. If it is more efficient on
>> arm to access the relevant bytes for the component assignments, I
>> expect that's what would happen (as reported).
>
> Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the
> relevant bytes.

Just to make sure: you mean it uses ldrb/strb instead of ldr/str
in the generated code ?

Thanks,

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-10 13:06                       ` Simon Clubley
@ 2014-07-11 18:05                         ` Simon Wright
  2014-07-11 20:22                           ` Simon Clubley
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Wright @ 2014-07-11 18:05 UTC (permalink / raw)


Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes:

> On 2014-07-10, Simon Wright <simon@pushface.org> wrote:
>> Simon Wright <simon@pushface.org> writes:
>>
>>> The x86_64 code accesses all 32 bits of V. If it is more efficient on
>>> arm to access the relevant bytes for the component assignments, I
>>> expect that's what would happen (as reported).
>>
>> Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the
>> relevant bytes.
>
> Just to make sure: you mean it uses ldrb/strb instead of ldr/str
> in the generated code ?

Yes. I don't understand all the asm, but that part is clear!

_ada_atom:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	ldr	r2, .L2
	ldr	r3, .L2+4
	ldmia	r2, {r1, r2}
	str	r1, [r3, #0]
	ldrb	r1, [r3, #0]	@ zero_extendqisi2
	bic	r1, r1, #1
	strb	r1, [r3, #0]
	ldrb	r1, [r3, #3]	@ zero_extendqisi2
	bic	r1, r1, #128
	strb	r1, [r3, #3]
	str	r2, [r3, #0]
	bx	lr

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-11 18:05                         ` Simon Wright
@ 2014-07-11 20:22                           ` Simon Clubley
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Clubley @ 2014-07-11 20:22 UTC (permalink / raw)


On 2014-07-11, Simon Wright <simon@pushface.org> wrote:
> Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> writes:
>
>> On 2014-07-10, Simon Wright <simon@pushface.org> wrote:
>>> Simon Wright <simon@pushface.org> writes:
>>>
>>>> The x86_64 code accesses all 32 bits of V. If it is more efficient on
>>>> arm to access the relevant bytes for the component assignments, I
>>>> expect that's what would happen (as reported).
>>>
>>> Just tried this on Raspberry Pi (GCC 4.6.3): yes, it only accesses the
>>> relevant bytes.
>>
>> Just to make sure: you mean it uses ldrb/strb instead of ldr/str
>> in the generated code ?
>
> Yes. I don't understand all the asm, but that part is clear!
>
> _ada_atom:
> 	@ args = 0, pretend = 0, frame = 0
> 	@ frame_needed = 0, uses_anonymous_args = 0
> 	@ link register save eliminated.
> 	ldr	r2, .L2
> 	ldr	r3, .L2+4
> 	ldmia	r2, {r1, r2}
> 	str	r1, [r3, #0]
> 	ldrb	r1, [r3, #0]	@ zero_extendqisi2
> 	bic	r1, r1, #1
> 	strb	r1, [r3, #0]
> 	ldrb	r1, [r3, #3]	@ zero_extendqisi2
                         ^^^ 
Eeeek! :-)

That's an "interesting" variant I have not seen before.

It looks like gcc is generating code to do a byte offset load directly
from the top byte of the 32-bit word. In my bitfield struct experiments
in C I only ever saw gcc use ldrb when the bitfield was in the low
8 bits of the 32-bit word. I never managed to get gcc to do the above.

Congratulations on finding yet another variant to this. :-)

> 	bic	r1, r1, #128
> 	strb	r1, [r3, #3]
> 	str	r2, [r3, #0]
> 	bx	lr

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-07 22:38                 ` Randy Brukardt
                                     ` (2 preceding siblings ...)
  2014-07-08 12:12                   ` Simon Clubley
@ 2014-07-20 11:35                   ` MatthiasR
  2014-07-20 15:49                     ` Simon Clubley
  3 siblings, 1 reply; 51+ messages in thread
From: MatthiasR @ 2014-07-20 11:35 UTC (permalink / raw)


Randy Brukardt wrote:

> [...]
> 
>> Unfortunately there seem to be no way to force a specific access width,
>> so this feature is not really useable (without the mentioned workaround
>> with the temporary variable) on architectures where the allowed access
>> width is not uniform over the whole address range.
> 
> No, you're looking at this the wrong way. If you write this in C, you read
> the entire register and then do some sort of bit-mask, and then write the
> thing back. You have to do that same thing in Ada, just using the record
> type instead of the bit mask. Ada replaces the bit masking operations by
> more readable record component accesses; it doesn't suddenly allow you to
> write something that you couldn't possibly write in C [a direct write of
> part of a register]. (Whether Ada *should* have allowed you do to that is
> a totally different question and relatively irrelevant at the moment
> because the language isn't likely to support anything new in the near
> future.)
> 
>                                                    Randy.

Ironically, there *is* another possibility, just in C. In principle, 
'Volatile Bitfields', mapped to the register via a pointer, can be used.

Bitfields are avoided by most C programmers because their layout is 
generally not well defined. Means to control the layout (like representation 
clauses in Ada) do not exist.

At least for the ARM platform, the situation is more convenient:
There are rules for the layout of bitfields given in the AAPCS (ABI 
specification for ARM, 'Procedure Call Standard for the ARM Architecture').
So, if the compiler is AAPCS-compliant, the layout of the bitfield records 
is exactly defined.

Additionaly, the AAPCS requires in chapter 7.1.7.5 
(http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf)
that all reads or writes from/to volatile bitfields must be done 'using the 
access width appropriate to the type of the container'.

The 'container' is not the record/struct as a whole, it is a type specifier 
given with each of the bitfields (this concept of a 'container type' is 
somewhat strange, I needed some time to get the idea of this...)

Example:

struct s 
{
  volatile int a:8;
  volatile char b:2
};

'int' and 'char' are the 'container types' of the bitfields 'a' and 'b'. A 
AAPCS-compliant compiler must read or write 's.a' using a 32-bit access 
(assuming 'int' is 32 bit wide). Accesses to 's.b' must be 8 bit wide.

So, if a C compiler is AAPCS-compliant, volatile bitfields should have the 
desired behaviour. Whether a compiler is *really* AAPCS-compliant, is 
another question. A well-known open source C compiler had bugs in this area 
in several releases. Last year, attempts were made to repair it. I don't 
know the current status.

Matthias



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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-20 11:35                   ` MatthiasR
@ 2014-07-20 15:49                     ` Simon Clubley
  2014-07-26 11:05                       ` MatthiasR
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Clubley @ 2014-07-20 15:49 UTC (permalink / raw)


On 2014-07-20, MatthiasR <MatthiasR@invalid.invalid> wrote:
>
> So, if a C compiler is AAPCS-compliant, volatile bitfields should have the 
> desired behaviour. Whether a compiler is *really* AAPCS-compliant, is 
> another question. A well-known open source C compiler had bugs in this area 
> in several releases. Last year, attempts were made to repair it. I don't 
> know the current status.
>

That open source C compiler wouldn't be called gcc by any chance
would it ? :-)

I did some experiments with using bitfields instead of bitmasks in
some bare metal ARM target C code a couple of years ago and ran into
the exact same problems as the OP's Ada code, with gcc's generated
code using ldrb instead of ldr.

I haven't tried building a ARM cross compiler using the very latest
versions of gcc however.

Simon.

-- 
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world


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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-20 15:49                     ` Simon Clubley
@ 2014-07-26 11:05                       ` MatthiasR
  2014-08-10 11:20                         ` MatthiasR
  0 siblings, 1 reply; 51+ messages in thread
From: MatthiasR @ 2014-07-26 11:05 UTC (permalink / raw)


Simon Clubley wrote:

> On 2014-07-20, MatthiasR <MatthiasR@invalid.invalid> wrote:
>>
>> So, if a C compiler is AAPCS-compliant, volatile bitfields should have
>> the desired behaviour. Whether a compiler is *really* AAPCS-compliant, is
>> another question. A well-known open source C compiler had bugs in this
>> area in several releases. Last year, attempts were made to repair it. I
>> don't know the current status.
>>
> 
> That open source C compiler wouldn't be called gcc by any chance
> would it ? :-)

How did you guess that? ;-)

> I did some experiments with using bitfields instead of bitmasks in
> some bare metal ARM target C code a couple of years ago and ran into
> the exact same problems as the OP's Ada code, with gcc's generated
> code using ldrb instead of ldr.

'strict volatile bitfields' are good keywords to find some informations 
about the bugs in this area - and the recent attempts to fix them.

> I haven't tried building a ARM cross compiler using the very latest
> versions of gcc however.
> 
> Simon.

It looks like there are indeed some changes in the latest versions: In
http://www.lpcware.com/content/forum/volatile-preventing-ldrb-byte-access
someone complains that the compiler does *not* use ldrb on a volatile 
struct...

Matthias

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

* Re: Forcing GNAT to use 32-bit load/store instructions on ARM?
  2014-07-26 11:05                       ` MatthiasR
@ 2014-08-10 11:20                         ` MatthiasR
  0 siblings, 0 replies; 51+ messages in thread
From: MatthiasR @ 2014-08-10 11:20 UTC (permalink / raw)


Latest GNAT Pro emits a warning on accesses to components of atomic records:

http://www.adacore.com/developers/development-log/NF-73-M715-002-gnat/

At least, one knows that something can go wrong here...


Some background story:
We stumbled upon this problem some time ago. After I had realised that the 
RM doesn't give any guarantees in this case (at least the RM can be 
interpreted in this way...), I filed an enhancement request to Adacore. I 
proposed to add a (implementation specific, since there isn't anything in 
standard and I didn't want to wait until Ada 202x) pragma and/or aspect 
which should enforce a specific access width.

That's basically the same as Simon Clubleys proposal in his second issue for 
'Ada-comments'.

After some discussions, the proposal was rejected, because
- there is a working way to solve the problem (the temporary variable)
- 'no one would know this implementation specific pragma/aspect'
- there is little chance to get this in the standard

The new warning is apparently the result of these discussions.


Matthias

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

end of thread, other threads:[~2014-08-10 11:20 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-30 22:11 Forcing GNAT to use 32-bit load/store instructions on ARM? daniel.dmk
2014-06-30 23:41 ` Jeffrey Carter
2014-07-01 12:06   ` Simon Clubley
2014-07-01 15:44     ` Niklas Holsti
2014-07-01 17:26       ` Simon Clubley
2014-07-01 17:18     ` Simon Wright
2014-07-01 19:43       ` Simon Wright
2014-07-01 17:28     ` Jeffrey Carter
2014-07-01  0:55 ` anon
2014-07-01  4:30 ` Niklas Holsti
2014-07-01  8:11 ` Dmitry A. Kazakov
2014-07-01 12:09   ` Simon Clubley
2014-07-01 12:20     ` Dmitry A. Kazakov
2014-07-01 17:00       ` Simon Clubley
2014-07-01 19:36         ` Dmitry A. Kazakov
2014-07-01 20:08           ` Simon Clubley
2014-07-02 22:24             ` Randy Brukardt
2014-07-06 20:40               ` MatthiasR
2014-07-07  0:25                 ` Simon Clubley
2014-07-07 22:38                 ` Randy Brukardt
2014-07-08  6:51                   ` Simon Wright
2014-07-10 11:47                     ` Simon Wright
2014-07-10 13:06                       ` Simon Clubley
2014-07-11 18:05                         ` Simon Wright
2014-07-11 20:22                           ` Simon Clubley
2014-07-08  8:50                   ` Brian Drummond
2014-07-08 12:12                   ` Simon Clubley
2014-07-08 13:26                     ` G.B.
2014-07-08 17:13                       ` Simon Clubley
2014-07-08 15:36                     ` Adam Beneschan
2014-07-08 15:40                       ` Adam Beneschan
2014-07-08 20:34                     ` Randy Brukardt
2014-07-09  7:31                       ` Dmitry A. Kazakov
2014-07-10  0:11                         ` Simon Clubley
2014-07-20 11:35                   ` MatthiasR
2014-07-20 15:49                     ` Simon Clubley
2014-07-26 11:05                       ` MatthiasR
2014-08-10 11:20                         ` MatthiasR
2014-07-01 12:03 ` Simon Clubley
2014-07-01 19:52   ` daniel.dmk
2014-07-01 20:40     ` Simon Clubley
2014-07-01 20:55       ` Simon Clubley
2014-07-01 21:01       ` Niklas Holsti
2014-07-01 21:20         ` Simon Clubley
2014-07-01 22:38           ` Niklas Holsti
2014-07-02 16:49             ` Simon Clubley
2014-07-01 21:55         ` daniel.dmk
2014-07-02  7:30     ` Simon Wright
2014-07-02 18:52       ` daniel.dmk
2014-07-04 23:51       ` Niklas Holsti
2014-07-05  0:18         ` Niklas Holsti

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