comp.lang.ada
 help / color / mirror / Atom feed
From: Per Jakobsen <pdj@knaldgas.dk>
Subject: Odd AVR-Ada code generation issue with constant record type
Date: Fri, 5 Jul 2019 01:57:41 -0700 (PDT)
Date: 2019-07-05T01:57:41-07:00	[thread overview]
Message-ID: <b78a975c-8ef1-41ac-b4c2-c1c07675765a@googlegroups.com> (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;


             reply	other threads:[~2019-07-05  8:57 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-05  8:57 Per Jakobsen [this message]
2019-07-05  9:24 ` Odd AVR-Ada code generation issue with constant record type 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
replies disabled

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