# Shifts of modular type 2\*\*K

**URL:** <https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589>\
**Category:** General\
**Created:** [December 12, 2024, 10:30pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589 "2024-12-12T22:30:41Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 12, 2024, 10:30pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/1 "2024-12-12T22:30:41Z")

</div>

The package Interfaces defines Shift\_Left and Shift\_Right for built in types like Unsigned\_32.

My question is if there is a way to define them for a user modular type. Given:

```ada
type T is mod 2**64;
type S is mod 2**128;
X : T;
Y : S;

```

Is there is a way to beat:

```ada
X := T (Y / 2**64);
Y := S (X) * 2**64;

```

A combination of a representation clause for a record type like

```ada
type S_Record is record
   L : T;
   H : T;
end record;
for S_Record use record
   L at ... -- A quite complicated expression involving Default_Bit_Order;
   H at ...
end record;

```

and Unchecked\_Conversion has a disastrous performance.

Or, maybe, -O3 optimizes / 2 \*\* 64 and X \* 2 \*\* 64 to shifts already?

---

<div class="post-metadata">

**Author:** ![jere](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jere/32/87_2.png) [@jere](https://forum.ada-lang.io/u/jere)\
**Post date:** [December 12, 2024, 11:45pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/2 "2024-12-12T23:45:02Z")

</div>

In GNAT I have been able to define them for some modular types using `Import, Convention => Intrinsic`. I don’t know the breadth of the sizes it allows for that.

Example:

```Ada
with Ada.Text_IO; use Ada.Text_IO;

procedure jdoodle is
    type T is mod 2**64;
    type S is mod 2**128;
    
    function Shift_Left(Value : T; Amount : Natural) return T
        with Import, Convention => Intrinsic;
    
    function Shift_Left(Value : S; Amount : Natural) return S
        with Import, Convention => Intrinsic;
        
    v1 : T := 16#000000010#;
    v2 : S := 16#000000010#;
begin
    Put_Line("v1:" & v1'Image);
    Put_Line("v2:" & v2'Image);
    Put_Line("v1:" & Shift_Left(v1,4)'Image);
    Put_Line("v2:" & Shift_Left(v2,5)'Image);
end jdoodle;

```

Output:

```ada
v1: 16
v2: 16
v1: 256
v2: 512

```

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 13, 2024, 12:51am UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/3 "2024-12-13T00:51:28Z")

</div>

Thanks, it worked! However shifts are twice slower than multiplication and division. So I stick to them,

---

<div class="post-metadata">

**Author:** ![JeremyGrosser](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jeremygrosser/32/3_2.png) [@JeremyGrosser](https://forum.ada-lang.io/u/JeremyGrosser)\
**Post date:** [December 13, 2024, 12:59am UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/4 "2024-12-13T00:59:15Z")

</div>

I tried to follow the path of shift operations through GNAT and gcc’s optimization passes, here’s what I found:

The GNAT frontend tries to simplify modular operations before handing the tree off to gcc [utils2.cc](https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ada/gcc-interface/utils2.cc;h=8eebf5935960ea277e21f08c0551b1f7a24d7831;hb=HEAD#l615)

GNAT’s documentation says the Shift and Rotate intrinsics work for 8, 16, 32, or 64 bit values though I believe this to be outdated as your example shows that larger values do work. [intrinsic\_subprograms.rst](https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ada/doc/gnat_rm/intrinsic_subprograms.rst;h=355b1399b2f831cfb85a4a6928d82e2496520bf4;hb=HEAD#l213)

gcc will optimize any divide by a power of 2 to a shift operation. [combine.cc](https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/combine.cc;h=0611433be408b2bf894d585afd4713862d723eaa;hb=HEAD#l6187)

If the shift is larger than a machine word, then GNAT _might_ depend on architecture-specific routines in libgcc. [trans.cc](https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ada/gcc-interface/trans.cc;h=3aa41253d74c08ee23c806aa2d3d0976b4031099;hb=HEAD#l7312)

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 13, 2024, 1:04am UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/5 "2024-12-13T01:04:06Z")

</div>

Actually performance is basically same, optimization fooled me reducing loop to nothing. The bottom line is that GNAT/gcc indeed do a good job.

---

<div class="post-metadata">

**Author:** ![Irvise](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/i/7ba0ec/32.png) [@Irvise](https://forum.ada-lang.io/u/Irvise)\
**Post date:** [December 13, 2024, 1:40pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/6 "2024-12-13T13:40:58Z")

</div>

I always recommend people to try out [Godbolt](https://godbolt.org/). You can select GNAT, with several versions and several architectures available. Then you can take a peak at the asm generated. It is great for learning how compilers optimize and what architectures do behind the scenes. Of course you can also pass different compiler flags 🙂

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 13, 2024, 2:43pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/7 "2024-12-13T14:43:06Z")

</div>

Nice, however x86 Assembly is not my thing.

P.S. I still have a virtual Windows 7 32-bit machine with GNAT GPL installed on it!

---

<div class="post-metadata">

**Author:** ![jere](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jere/32/87_2.png) [@jere](https://forum.ada-lang.io/u/jere)\
**Post date:** [December 13, 2024, 3:44pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/8 "2024-12-13T15:44:26Z")

</div>

if it helps, it provides various architectures (ARM assembly for example,others). It’s not just x86

---

<div class="post-metadata">

**Author:** ![Irvise](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/i/7ba0ec/32.png) [@Irvise](https://forum.ada-lang.io/u/Irvise)\
**Post date:** [December 13, 2024, 5:43pm UTC](https://forum.ada-lang.io/t/shifts-of-modular-type-2-k/1589/9 "2024-12-13T17:43:14Z")

</div>

As Jere says, there are other arches. I personally like AVR and RISC-V ASM… It is basically what I know 😛 Though I just saw that there is no AVR compiler in Godbolt, but we have one… We could ask for it to be added ^^
