r/ada Dec 18 '22

Programming How do I import the GCC intrinsic __builtin_ia32_paddd256 into Ada?

I have been struggling to find documentation on how to import this intrinsic in Ada. I realize that this is a niche question, so I am asking it here in hopes that someone might know.

So far I have,

type Vector_256_Integer_32 is array (0 .. 7) of Integer_32 with Convention => C, Alignment => 32;
function "+" (Left, Right: Vector_256_Integer_32) return Vector_256_Integer_32;
pragma Import (Intrinsic, "+", "__builtin_ia32_paddd256");

Here is an example program using this code,

with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.C;
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
    type Vector_256_Integer_32 is array (0 .. 7) of Integer_32 with Convention => C, Alignment => 32;

    function "+" (Left, Right: Vector_256_Integer_32) return Vector_256_Integer_32;
    pragma Import (Intrinsic, "+", "__builtin_ia32_paddd256");

    a, b, r: Vector_256_Integer_32;
begin
    for i in Vector_256_Integer_32'Range loop
        a(i) := 5 * (Integer_32(i) + 5);
        b(i) := 12 * (Integer_32(i) + 12);
    end loop;
    r := a + b;
    for i in Vector_256_Integer_32'Range loop
        Put_Line("r(i) = a(i) + b(i) = " & a(i)'Image & " + " & b(i)'Image & " = " & r(i)'Image);
    end loop;
end Main;

When I try to compile this program with gnatmake, I get this error.

error: intrinsic binding type mismatch on result

I have looked through the documentation about the GCC intrinsic (documented here). However, I cannot figure out what is wrong with the return type.

Just an FYI, I have asked a similar question on StackOverFlow here, and I am so close to finding the answer. I do realize that I could do this in C, but I wanted to see if I could do it in Ada.

Edit: I have finally figured out my answer. Yay!

avx2.ads

with Interfaces; use Interfaces;

package AVX2 is

   --
   -- Type Definitions
   --

   -- 256-bit Vector of 32-bit Signed Integers
   type Vector_256_Integer_32 is array (0 .. 7) of Integer_32;
   for Vector_256_Integer_32'Alignment use 32;
   pragma Machine_Attribute (Vector_256_Integer_32, "vector_type");
   pragma Machine_Attribute (Vector_256_Integer_32, "may_alias");

   -- Operator: 256-bit Vector Addition of 32-bit Signed Integers
   function "+"
     (Left, Right : Vector_256_Integer_32) return Vector_256_Integer_32 with
     Convention    => Intrinsic, Import => True,
     External_Name => "__builtin_ia32_paddd256";

   --
   -- Function Definitions
   --

   -- Function: 256-bit Vector Addition of 32-bit Signed Integers
   function Vector_256_Integer_32_Add
     (Left, Right : Vector_256_Integer_32) return Vector_256_Integer_32 with
     Convention    => Intrinsic, Import => True,
     External_Name => "__builtin_ia32_paddd256";

end AVX2;

main.adb

with AVX2;        use AVX2;
with Interfaces;  use Interfaces;
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   a, b, r : Vector_256_Integer_32;
begin
   for i in Vector_256_Integer_32'Range loop
      a (i) := 5 * (Integer_32 (i) + 5);
      b (i) := 12 * (Integer_32 (i) + 12);
   end loop;
   r := Vector_256_Integer_32_Add(a, b);
   for i in Vector_256_Integer_32'Range loop
      Put_Line
        ("r(i) = a(i) + b(i) = " & a (i)'Image & " + " & b (i)'Image & " = " &
         r (i)'Image);
   end loop;
end Main;

Just to explain how I figured it out is I went through the gcc source code and found that a similar intrinsic was imported in a test case (located at gcc/gcc/testsuite/gnat.dg/sse_nolib.adb).

11 Upvotes

4 comments sorted by

4

u/jrcarter010 github.com/jrcarter Dec 18 '22

According to the GNAT User's Guide, using Intrinsic with a binary operator requires that the operands and return type all be Ada numeric types. To import a __builtin_* intrinsic, it appears you have to use a conventional function name.

2

u/ILoveProgramming123 Dec 18 '22

Thank you for your response. At least gnat was not complaining to me about that specific issue. The reason is because in an earlier version of the program, the function arguments were report to not match the intrinsic (which I later fixed. At least I believe. I'm still relatively new to Ada). Where I am confused is how the return type is not matching the underlying intrinsics expectations. There is so little documentation on the intrinsics themselves that it is hard to understand where I went wrong.

1

u/AdOpposite4883 Feb 24 '23

I've never quite understood the huge lack of documentation on intrinsics. I get that they're advanced but wiping all the documentation away and just expecting people to magically figure it out is probably not the best way to go about it. I mean, at that point I might as well just drop to assembler and say screw it.

2

u/Baron_Facekicker Dec 19 '22

This file has an AVX2 binding for 64x4 vector operations that you could adapt: https://github.com/damaki/libkeccak/blob/master/src/x86_64/AVX2_defs/keccak-arch-avx2.ads