* Odd AVR-Ada code generation issue with constant record type
@ 2019-07-05 8:57 Per Jakobsen
2019-07-05 9:24 ` Mark Lorenzen
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Per Jakobsen @ 2019-07-05 8:57 UTC (permalink / raw)
I'm trying to demonstrate some of Ada's strengths with regard to low-level programming, and ran into the following issue:
Having a byte-record consisting of bit-fields of different types (typical microcontroller register definitions). Compiling the below Ada code using avr-ada 1.2.2 (avr-gnat 4.9.3) gives some odd assembly code.
Summary:
All assignments is really constants that ought to be calculated in full at compile time.
1) Clearing all bitfields in the byte as one assignment, it loads, clears and stores for each field even though the result is constant. *Very* inefficient and even dangerous if the bitfields are assumed to be set atomically!!!
2) Setting one field (any), a calculated byte constant is stored directly.
3) Setting more than one field, a calculated byte constant is initialized in SRAM and used during execution. Inefficient.
4) Clearing a non-composite byte is done directly.
5) Setting a non-composite byte is done directly.
Is there an option or pragma I need to set, or is this something more fundamental with the compiler?
Code:
------------------------------------
### main.adb, compiled with Makefile and build.gpr from uart_echo in avr-ada package.
with AVR;
with System;
with Interfaces;
procedure Main is
use AVR;
use Interfaces;
type Enum_Type is (B00, B01, B10, B11);
for Enum_Type use (B00 => 0,
B01 => 1,
B10 => 2,
B11 => 3);
type List_Type is array (0 .. 4) of Boolean with Pack;
type Reg_Type is record
Enum : Enum_Type;
Bool : Boolean;
List : List_Type;
end record;
for Reg_Type use record
Enum at 0 range 6 .. 7;
Bool at 0 range 5 .. 5;
List at 0 range 0 .. 4;
end record;
for Reg_Type'Size use 8;
-- Reg_A --
Reg_A : Reg_Type;
for Reg_A'Address use System.Address (16#7a#);
pragma Volatile (Reg_A);
-- Reg_B --
Reg_B : Reg_Type;
for Reg_B'Address use System.Address (16#7b#);
pragma Volatile (Reg_B);
-- Reg_C --
Reg_C : Reg_Type;
for Reg_C'Address use System.Address (16#7c#);
pragma Volatile (Reg_C);
-- Reg_D --
Reg_D : Unsigned_8;
for Reg_D'Address use System.Address (16#7d#);
pragma Volatile (Reg_D);
-- Reg_E --
Reg_E : Unsigned_8;
for Reg_E'Address use System.Address (16#7e#);
pragma Volatile (Reg_E);
begin
-- Set composite with resulting zero-byte.
Reg_A := (Enum => B00,
Bool => False,
List => (others => False));
-- Generated assembly:
-- ldi r30, 0x7A ; Set address of register
-- ldi r31, 0x00
-- ld r24, Z ; Load
-- andi r24, 0xE0 ; Clear List.
-- st Z, r24 ; Store
-- ld r18, Z ; Load
-- andi r18, 0xDF ; Clear Bool.
-- st Z, r18 ; Store
-- ld r19, Z ; Load
-- andi r19, 0x3F ; Clear Enum.
-- st Z, r19 ; Store
-- Result : 22 bytes code, 0 bytes SRAM, 17 cycles
-- Optimal: 4 bytes code, 0 bytes SRAM, 2 cycles
-- Set composite with resulting non-zero-byte (any one field is set, others zero).
Reg_B := (Enum => B00,
Bool => True,
List => (others => False));
-- Generated assembly:
-- ldi r20, 0x20 ; Set register bits
-- sts 0x007B, r20 ; Store
-- Result: 6 bytes code, 0 bytes SRAM, 3 cycles
-- Is optimal!
-- Set composite with resulting non-zero-byte (multiple fields is set).
Reg_C := (Enum => B11,
Bool => True,
List => (others => True));
-- Generated assembly:
-- lds r21, 0x0100 ; Load pre-initialized SRAM-stored constant.
-- sts 0x007C, r21 ; Store
-- Result : 8 bytes code, 1 bytes SRAM, 4 cycles, requires initialization.
-- Optimal: 6 bytes code, 0 bytes SRAM, 3 cycles, no initialization.
-- Clear Unsigned_8 directly.
Reg_D := 16#00#;
-- Generated assembly:
-- sts 0x007D, r1 ; Store with "reserved" zero-register.
-- Result: 4 bytes code, 0 bytes SRAM, 2 cycles
-- Is optimal!
-- Setting Unsigned_8 directly.
Reg_E := 16#FF#;
-- Generated assembly:
-- ldi r22, 0xFF ; Load constant.
-- sts 0x007E, r22 ; Store
-- Result: 6 bytes code, 0 bytes SRAM, 3 cycles
-- Is optimal!
end Main;
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
@ 2019-07-05 9:24 ` Mark Lorenzen
2019-07-05 12:19 ` Per Jakobsen
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Mark Lorenzen @ 2019-07-05 9:24 UTC (permalink / raw)
On Friday, July 5, 2019 at 10:57:42 AM UTC+2, Per Jakobsen wrote:
> I'm trying to demonstrate some of Ada's strengths with regard to low-level programming, and ran into the following issue:
>
> Having a byte-record consisting of bit-fields of different types (typical microcontroller register definitions). Compiling the below Ada code using avr-ada 1.2.2 (avr-gnat 4.9.3) gives some odd assembly code.
>
> Summary:
> All assignments is really constants that ought to be calculated in full at compile time.
>
> 1) Clearing all bitfields in the byte as one assignment, it loads, clears and stores for each field even though the result is constant. *Very* inefficient and even dangerous if the bitfields are assumed to be set atomically!!!
>
> 2) Setting one field (any), a calculated byte constant is stored directly.
>
> 3) Setting more than one field, a calculated byte constant is initialized in SRAM and used during execution. Inefficient.
>
> 4) Clearing a non-composite byte is done directly.
>
> 5) Setting a non-composite byte is done directly.
>
>
> Is there an option or pragma I need to set, or is this something more fundamental with the compiler?
>
First of all you are using an old compiler... Maybe upgrading the compiler (if possible) would help.
I would (in the following order):
1) declare the registers as Atomic (or Atomic and Volatile but that doesn't matter as Atomic implies Volatile).
2) define constants for the values you are assigning.
Regards,
Mark L
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
2019-07-05 9:24 ` Mark Lorenzen
@ 2019-07-05 12:19 ` Per Jakobsen
2019-07-08 14:49 ` Stéphane Rivière
2019-07-09 12:12 ` Per Jakobsen
` (3 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Per Jakobsen @ 2019-07-05 12:19 UTC (permalink / raw)
> First of all you are using an old compiler... Maybe upgrading the compiler (if possible) would help.
It might, although I *am* using the newest avr-ada version I can find. If there is a newer I will certainly try!?
> I would (in the following order):
> 1) declare the registers as Atomic (or Atomic and Volatile but that doesn't matter as Atomic implies Volatile).
Declaring the registers Atomic certainly helped a lot - No more run-time "calculations", although all constants are put into SRAM (like Reg_C above), instead of pure "LDI" instructions (Reg_B).
> 2) define constants for the values you are assigning.
Does not help - Exactly the same behavior.
Thanks for the Atomic hint!
Anyone knows if there is a newer version of avr-ada out there? Or have instructions on how to create a new?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 12:19 ` Per Jakobsen
@ 2019-07-08 14:49 ` Stéphane Rivière
0 siblings, 0 replies; 8+ messages in thread
From: Stéphane Rivière @ 2019-07-08 14:49 UTC (permalink / raw)
Hi Per,
> Anyone knows if there is a newer version of avr-ada out there? Or have instructions on how to create a new?
Not really helpfull but... at 2017118...
https://stef.genesix.org/pub/embedded_AVR-Ada_-_Setup_POSS2017.pdf
See page 59 - Releases chapter...
The john Leimon fork is here...
https://github.com/evilspacepirate/avr-ada
If you find more accurate info... I would like to hear about it :)
All the best from Oleron Island - France
--
Be Seeing You
Number Six
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
2019-07-05 9:24 ` Mark Lorenzen
2019-07-05 12:19 ` Per Jakobsen
@ 2019-07-09 12:12 ` Per Jakobsen
2019-07-09 15:30 ` Simon Wright
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Per Jakobsen @ 2019-07-09 12:12 UTC (permalink / raw)
Hi Stéphane
Thanks for the link to "embedded AVR-Ada - Setup", I'm going to read it through more thoroughly later this week :-)
All the projects appear a bit dated all using 4.9.
I've tried AVR-Ada and the AVR-Ada-JLF projects, both failing when building on my setup.
Greetings from DK
~Per
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
` (2 preceding siblings ...)
2019-07-09 12:12 ` Per Jakobsen
@ 2019-07-09 15:30 ` Simon Wright
2019-07-09 18:10 ` Per Jakobsen
2019-07-09 18:46 ` Per Jakobsen
5 siblings, 0 replies; 8+ messages in thread
From: Simon Wright @ 2019-07-09 15:30 UTC (permalink / raw)
I don't have access to an up-to-date AVR compiler, so I had a go with
GCC 9.1 compiling for cortex-m4. There's a big improvement using
Volatile_Full_Access rather than just Volatile.
This code
========================================================================
with System;
with Interfaces;
procedure Main is
use Interfaces;
type Enum_Type is (B00, B01, B10, B11);
for Enum_Type use (B00 => 0,
B01 => 1,
B10 => 2,
B11 => 3);
type List_Type is array (0 .. 4) of Boolean with Pack;
type Reg_Type is record
Enum : Enum_Type;
Bool : Boolean;
List : List_Type;
end record;
for Reg_Type use record
Enum at 0 range 6 .. 7;
Bool at 0 range 5 .. 5;
List at 0 range 0 .. 4;
end record;
for Reg_Type'Size use 8;
-- Reg_A --
Reg_A : Reg_Type
with
Volatile_Full_Access,
Address => System'To_Address (16#7a#);
-- Reg_B --
Reg_B : Reg_Type
with
Volatile_Full_Access,
Address => System'To_Address (16#7b#);
-- Reg_C --
Reg_C : Reg_Type
with
Volatile_Full_Access,
Address => System'To_Address (16#7c#);
-- Reg_D --
Reg_D : Unsigned_8
with
Volatile_Full_Access,
Address => System'To_Address (16#7d#);
-- Reg_E --
Reg_E : Unsigned_8
with
Volatile_Full_Access,
Address => System'To_Address (16#7e#);
begin
-- Set composite with resulting zero-byte.
Reg_A := (Enum => B00,
Bool => False,
List => (others => False));
-- Set composite with resulting non-zero-byte (any one field is set, others zero).
Reg_B := (Enum => B00,
Bool => True,
List => (others => False));
-- Set composite with resulting non-zero-byte (multiple fields is set).
Reg_C := (Enum => B11,
Bool => True,
List => (others => True));
-- Clear Unsigned_8 directly.
Reg_D := 16#00#;
-- Setting Unsigned_8 directly.
Reg_E := 16#FF#;
end Main;
========================================================================
compiled with -O2 yields
========================================================================
Disassembly of section .text.startup._ada_main:
00000000 <_ada_main>:
0: 4b0a ldr r3, [pc, #40] ; (2c <_ada_main+0x2c>)
2: 4a0b ldr r2, [pc, #44] ; (30 <_ada_main+0x30>)
4: 480b ldr r0, [pc, #44] ; (34 <_ada_main+0x34>)
6: 217a movs r1, #122 ; 0x7a
8: b410 push {r4}
a: 781c ldrb r4, [r3, #0]
c: 700c strb r4, [r1, #0]
e: 237b movs r3, #123 ; 0x7b
10: 7812 ldrb r2, [r2, #0]
12: 701a strb r2, [r3, #0]
14: 227c movs r2, #124 ; 0x7c
16: 7800 ldrb r0, [r0, #0]
18: 7010 strb r0, [r2, #0]
1a: 217d movs r1, #125 ; 0x7d
1c: 237e movs r3, #126 ; 0x7e
1e: 2000 movs r0, #0
20: 22ff movs r2, #255 ; 0xff
22: 7008 strb r0, [r1, #0]
24: 701a strb r2, [r3, #0]
26: f85d 4b04 ldr.w r4, [sp], #4
2a: 4770 bx lr
========================================================================
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
` (3 preceding siblings ...)
2019-07-09 15:30 ` Simon Wright
@ 2019-07-09 18:10 ` Per Jakobsen
2019-07-09 18:46 ` Per Jakobsen
5 siblings, 0 replies; 8+ messages in thread
From: Per Jakobsen @ 2019-07-09 18:10 UTC (permalink / raw)
Right, so even GCC 9.1 chooses to load a constant from memory instead of loading as immediate, 2-3 cycles instead of 1 as well as using additional memory space. I wonder why GCC does not optimize this... It seems like a simple optimization, but then again, I'm no compiler developer so easy for me to say...
I just tried with arm-linux-gnueabihf-gnatmake and x86_64-linux-gnu-gnatmake both version 8.3, and both use the slower load from memory instead of load immediate.
I wonder if it is an Ada-specific thing, or a general GCC back-end deficiency?...
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Odd AVR-Ada code generation issue with constant record type
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
` (4 preceding siblings ...)
2019-07-09 18:10 ` Per Jakobsen
@ 2019-07-09 18:46 ` Per Jakobsen
5 siblings, 0 replies; 8+ messages in thread
From: Per Jakobsen @ 2019-07-09 18:46 UTC (permalink / raw)
Just tried with C bitfields:
================================
#include <stdint.h>
struct Reg_T {
unsigned int a : 3;
unsigned int b : 1;
unsigned int c : 4;
} __attribute__((packed));
volatile struct Reg_T Reg_A;
volatile struct Reg_T Reg_B;
volatile struct Reg_T Reg_C;
volatile uint8_t A;
volatile uint8_t B;
void main (void)
{
Reg_A = (struct Reg_T){ .a = 0, .b = 0, .c = 0 };
Reg_B = (struct Reg_T){ .a = 0, .b = 1, .c = 0 };
Reg_C = (struct Reg_T){ .a = 7, .b = 1, .c = 15 }
A = 0;
B = 255;
}
================================
Same type of result...
GCC back-end then?
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-07-09 18:46 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-05 8:57 Odd AVR-Ada code generation issue with constant record type Per Jakobsen
2019-07-05 9:24 ` Mark Lorenzen
2019-07-05 12:19 ` Per Jakobsen
2019-07-08 14:49 ` Stéphane Rivière
2019-07-09 12:12 ` Per Jakobsen
2019-07-09 15:30 ` Simon Wright
2019-07-09 18:10 ` Per Jakobsen
2019-07-09 18:46 ` Per Jakobsen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox