WEBVTT

00:00.000 --> 00:23.120
So, hello everyone, as mentioned, I'm Luis Cielbaum from Synopsis. I'm a junior

00:23.120 --> 00:28.000
compilet engineer working on GCCC, and I'm here to present a talk on understanding

00:28.000 --> 00:33.520
the AI compatibility between compilers targeting Luis Cielbaum. So, for our agenda today,

00:33.520 --> 00:42.320
we will talk about the why we started this project about the two implementation details

00:42.320 --> 00:47.360
and how it works and then finally the conclusion. Let's start with the problem statement.

00:48.560 --> 00:54.000
So, our goal is to be able to link

00:54.240 --> 01:00.000
resupply object files from different compilers and be able to make sure that the

01:00.000 --> 01:07.760
combination would work and our focusing is identify potential discrepancies in the ABIs

01:07.760 --> 01:14.880
used by different compilers or syncopiler with their different options. We want to make sure that

01:14.880 --> 01:22.080
we can identify deviations from the standard ABI, which is defined by resupply documentation.

01:22.960 --> 01:28.480
So, first of all, what's an application binary interface? So, according to the Wikipedia,

01:28.480 --> 01:35.280
ABI specifies an interface between the binary proposals for example object files or a program

01:35.280 --> 01:42.560
that depends on library. It also defines all-level details, for example properties of fundamental

01:42.560 --> 01:48.880
types, calling convention and main usage of registers, also defines high-level details.

01:49.600 --> 01:54.960
And it is managed by compilers operating systems in develops of libraries.

01:55.920 --> 02:02.480
But our focus is under the compatibility between compilers for a specific target.

02:04.000 --> 02:10.960
So, within ABI, it defines resupply usage. So, what is it? So, it specifies a purpose for each register.

02:11.920 --> 02:17.520
Here we have a list from the risked file ABI documentation that specifies each register

02:17.600 --> 02:22.560
in their purpose. You can see that on the right, we have something called caller and call E.

02:23.120 --> 02:28.880
So, basically, a caller means that this register needs to be saved before a function call.

02:29.440 --> 02:35.920
And the call E means that after the function call in the call E function, the register that will

02:35.920 --> 02:43.840
be needed to, needs to be stored in the stack. It also defines here, we have an example of the

02:43.840 --> 02:50.160
function arguments, which is defined by an ABI, which means that these are the registers from X to X

02:50.800 --> 02:54.880
17, expected to pass the arguments between functions.

02:56.160 --> 03:00.080
Data layout, this is a really important thing about the ABI that defines it.

03:00.080 --> 03:04.720
Specifies the sizes and alignments of fundamental C and C++ types.

03:04.720 --> 03:10.640
It specifies our structs, unions and classes are laid out in memory as well as for the bits fields

03:10.880 --> 03:16.960
or in the struct. And here, this is, again, a table from the risked file document that tells us

03:16.960 --> 03:22.960
for each, it's the 32 and 64 bits architecture, the size and alignment for each data type.

03:23.760 --> 03:28.320
Now, there's a really important thing called Indianness. There's two main ones,

03:28.320 --> 03:34.720
lipland and in big Indian, there's also mixed, but real quick, big Indian means that a value is

03:34.720 --> 03:41.440
stored in memory starting by the list significant bits. While the big Indian, it starts for the

03:41.440 --> 03:46.800
most significant bit. This is important because if we have two object files, one leafland and another

03:46.800 --> 03:51.360
in one big Indian, when we are combining each other, then we won't work because they'll try to

03:51.360 --> 03:57.840
fetch the different things for memory. Calling convention. So, between function calls, we need to

03:57.840 --> 04:03.200
understand which registers or memory locations are used to pass the arguments, how we turn

04:03.200 --> 04:09.680
value we specify, even either on a register or on the stack, who's responsible for saving these

04:09.680 --> 04:17.120
registers and the struct frame structure. So, here I have a really quick example. On the left, we have

04:17.120 --> 04:23.280
a simple SQL that does a function call with nine arguments and on the right, we have the corresponding

04:23.280 --> 04:32.960
assembly code. So, we can see the Y700 on CTS and line two to fifth on the same way. We have the

04:32.960 --> 04:40.240
pull log of the function, which will allocate a space on a stack and save the return address register

04:40.240 --> 04:49.520
and SZO register to the stack because we will be used during the function. And yeah, so for the yellow part,

04:49.520 --> 04:56.800
which is between the line six to 16, is the actual preparation to the function call. You can see that

04:56.800 --> 05:04.880
each value, it's been stored for the registers except for the argument nine, which is the value nine,

05:04.880 --> 05:10.640
it's actually been stored on the stack and the stack. So, the rest of them will be stored in registers

05:10.640 --> 05:18.880
from the A7 to A0, it starts from the end to first. So, line 17 is preparing for the return,

05:18.880 --> 05:24.880
which we set the return as one to three. So, we will save the value to I5 and later on specify

05:24.880 --> 05:31.040
to A0 register, which is what we expected from the ABA. And finally, there's the epilogue where

05:31.040 --> 05:37.200
it's restoring the registers that is saved earlier and then exiting to the caller function.

05:37.920 --> 05:46.240
Why barriers? Why barriers are really important for the ABA because if we have a C++ program,

05:46.240 --> 05:51.600
they can interact with each other as long as they are ABA compatible. It means for, for example,

05:51.600 --> 05:56.720
the header file, if we are calling a function, we are in C and calling a function in C++,

05:57.520 --> 06:02.160
the arguments need to be the same, data types, returns, etc. Also for macros,

06:02.160 --> 06:07.200
there are, there can be used together as long as they are compatible. It ensures functions

06:07.200 --> 06:11.120
from library that can be calculated correctly, either linked separately or dynamically,

06:11.920 --> 06:16.640
specifies all functions, our name and location and memory, and also the version compatibility

06:16.960 --> 06:23.520
libraries. Exceptional handling for C++ is also defined by the ABA and systems. It allows

06:23.520 --> 06:31.600
programs to run on different OS or other versions as long as they follow the same ABA.

06:32.400 --> 06:37.040
Now, there are a number of projects we see below the goal, but slightly different.

06:37.920 --> 06:43.440
First one is ABA dump, which is bought from the ABA compliance shaker. This one has a goal

06:43.440 --> 06:49.760
of extracting ABA properties from libraries, and how does it do it? He analyzes the dwarf

06:49.760 --> 06:54.800
debugging information from the libraries. Here have a really quick example, how it works,

06:54.800 --> 07:05.040
it will extract all the data using a JSON format. ABA compliance shaker ensures backwards

07:05.040 --> 07:13.120
binary source level compatibility of C and C++ libraries, how does it do it?

07:13.120 --> 07:16.960
He uses ABA dump from the previous slide to analyze the dwarf information.

07:18.160 --> 07:23.280
Lead that big ABA, the goal is to detect interface and capabilities in L shared libraries.

07:24.640 --> 07:29.040
How does it do with it analyzes the L shared libraries in their associated debugging

07:29.040 --> 07:36.480
information, again, with the dwarf, to build internal representations of expert functions and variables.

07:36.560 --> 07:44.960
It identifies changes in function variables and their data types, for example, the return type changes.

07:48.320 --> 07:56.880
ABA is cafe, so this one, the goal is to identify again with two compilers or languages they

07:56.880 --> 08:02.400
agree on the same ABA. How do they do it? They do it by both brute forcing. They generate

08:02.400 --> 08:09.280
random test cases, focusing on detecting ABA incompatibilities, and if they agree, and great,

08:09.280 --> 08:14.880
if they don't agree, then even better because we just learned something. It's essentially an ABA

08:14.880 --> 08:21.600
fuzzer, although it's more like an ABA fuzzer that detects ABA incompatibilities.

08:22.560 --> 08:29.200
Now let's jump into the about the framework and let's start with the end, basically the summary

08:29.200 --> 08:34.800
report, which is the output from our framework. This example is from GCC,

08:34.800 --> 08:41.280
exactly from GCC 32 bits, which fly. So we selected a number of test cases to display here,

08:41.280 --> 08:45.760
so the first one will be the most important one, is extracting the data types sizes.

08:45.760 --> 08:52.960
As you can see here, for the signs shot, an unsigned shot, we have a volume of 1 byte of size,

08:53.520 --> 08:58.400
and for an ink loan pointer and a float, we have the size of 4.

08:58.400 --> 09:03.840
This is everything corrected to what we expected. Second one is a stock direction, which is

09:03.840 --> 09:09.040
really important. We need to understand if the stock is going upwards or downwards in memory.

09:09.040 --> 09:14.000
And according to the ABA, it's downwards, which is exactly what the framework extracted.

09:15.280 --> 09:21.040
Next one is alignment of the stack. Again, the stock is aligned to 16 bytes, which is exactly

09:21.040 --> 09:27.600
what we expected. Now, this test case is a little more tricky. So here we want to understand,

09:27.760 --> 09:34.240
which registers or the stack is used when passing arguments from one function to one other.

09:34.240 --> 09:39.920
So here we can see in the summary that the short short ink loan inflow, they all use the same

09:39.920 --> 09:46.240
registers from 1 to 8 arguments. And then when we reach 9 argument, it starts putting the

09:46.240 --> 09:51.680
values to the stack. Now for a long long interval, it's a little different. Now remember that we are

09:51.760 --> 09:58.400
in a 32-bit architecture, and we saw that a long long interval, they are 8 bytes in size.

09:58.400 --> 10:04.000
That means that we cannot fit a whole value into one register. We need to, the compiler will

10:04.000 --> 10:09.600
split the value into and low and high. And this is exactly what our framework is telling us.

10:09.600 --> 10:15.920
For the long long interval, we can only store four values in the registers, because each one will

10:16.000 --> 10:22.240
be split in the low and high. And then when it reaches the stack, it continues to do the same thing.

10:22.240 --> 10:30.160
It's low and high. Next one is more tricky. We will talk about it more later, but really rough.

10:30.160 --> 10:37.200
This one for the structs, it doesn't go for the number of members, but the size of a struct.

10:38.000 --> 10:44.960
So we want to understand what's the boundary of the size of a struct until it starts going

10:45.280 --> 10:51.200
to pass by reference on the stack. And here we can see that a size of a struct less or equals to 8 bytes.

10:51.200 --> 10:56.640
It's best on registers. When it's greater than 8, it is best on the on by reference on the stack.

10:57.200 --> 11:03.760
Short short ink and long float, they use all the same registers, is your A1. And long double

11:04.320 --> 11:08.400
use the same registers, representing these ways for a low and high for each one.

11:09.040 --> 11:13.760
Now we also test to see if an empty struct went passing through one of the function

11:13.760 --> 11:17.520
is ignored by the second pilot. And this is exactly what the different work is selling is.

11:18.960 --> 11:24.640
Now, and in the test, this is what I discovered before we need to understand if our system is

11:24.640 --> 11:31.200
little end and begin or mix. Now, for what I test of this is for a little end and this is exactly

11:31.200 --> 11:36.240
what the test determines. So we wrote a volume and then it read from memory and from that

11:36.240 --> 11:42.560
he can understand which one it is. Colour saved and calles saved. This is what I also discussed earlier.

11:42.560 --> 11:49.040
We need to understand if the compiler is going according to the ABI, which registers are being

11:49.040 --> 11:53.760
called or saved and which registers are being called e-save. The framework was able to identify

11:53.760 --> 12:02.160
which ones are what and produce a report on it. Return registers is this is when we are going

12:02.160 --> 12:07.520
from the calle function to the color function. So as a return, we need to understand where the

12:07.520 --> 12:14.000
volume will be located when doing the proper function call. So this is the fact that we put the

12:14.000 --> 12:19.280
framework telling us. So for a short short, in long and float, the register is a zero for long,

12:19.280 --> 12:28.240
long and double the volume is split. Now, design choices. We decided not to use dwarf. So we wanted

12:28.240 --> 12:35.440
to eliminate all the layers between the compiler and what we can extract from it. So and also from

12:35.440 --> 12:42.160
different compilers might include information in the different way. Another thing is that we don't

12:42.160 --> 12:48.320
want to restrict this framework to compilers that only use that's produced dwarf. So we want to

12:48.320 --> 12:53.280
make sure that we can use this framework in any compiler even if he has dwarf or it doesn't work,

12:53.280 --> 13:01.200
we use dwarf. We assume the availability of a compiler. When I say compiler, I'm mentioning the

13:01.200 --> 13:06.720
whole full chain as a compiler and a template linker and a simulator to run the tests.

13:08.880 --> 13:17.520
The framework is developed in Python and it basically uses generic C test cases and runs them on

13:17.520 --> 13:23.600
the simulator and then extract to extract the behavior. It produces a summary report that we already

13:23.680 --> 13:32.880
discussed. It's easy to extend. So the base framework, it generates C tests, it runs them in extracts

13:32.880 --> 13:40.400
output. It's easy to add new analyzers and it's possible to share information between those analyzers.

13:41.360 --> 13:46.880
We have support for feedback loop and what does that mean? It means that for some tests,

13:46.880 --> 13:52.720
they are dynamically generated based on the results from the previous run. It doesn't all decide the

13:52.720 --> 13:58.400
same test case. For example, finding the boundary where it structs our best between function

13:58.400 --> 14:03.200
calls. We will talk a little bit more later for us to explain the example.

14:04.320 --> 14:09.280
Now let's go into implementation details. So how do we extract all this information? We use

14:09.920 --> 14:15.360
something called architecture don't be formation. We will extract the information from the current

14:16.000 --> 14:22.800
execution. We will be able to extract the contents of all the registers and then the stack

14:22.800 --> 14:28.880
and then also some header information. For example, size of a pointer, the register banks, etc.

14:31.200 --> 14:36.320
This one is used for mostly for the colony convention. We need to understand the location of the

14:36.320 --> 14:41.600
known special values when you're making the function call and it helps the analyzer reduce

14:42.320 --> 14:47.120
how the compiler passes the arguments. Also for the caller and call these saved register

14:47.120 --> 14:55.920
test case. Now let's go deep into one of the examples. The struct's arguments best in this case.

14:55.920 --> 15:02.640
So as I discussed earlier, we need to understand how structs are passed between function calls.

15:02.640 --> 15:08.400
We need to determine how non empty and empty structs are passed. The term in which

15:08.400 --> 15:15.360
registers are used and identifying the which conditions the struct is best by reference.

15:15.360 --> 15:21.920
So according to the ABI, aggregates larger than two times x length meaning the size of a register

15:21.920 --> 15:27.520
are passed by reference in the replacement in the argument list with the address. This is great.

15:27.520 --> 15:34.240
This is what we expect to happen but we need to understand if the compiler is behaving exactly like this.

15:35.200 --> 15:41.120
So we need to identify the maximum size at which the struct is best by reference.

15:41.120 --> 15:46.720
And so what we do, we will start by generating multiple tests, incrementing the size of the struct

15:46.720 --> 15:52.080
by one byte. We will use source as a for started until the boundary is reached.

15:52.080 --> 15:57.280
So for things first, we create a struct automatically generated a struct with one one one

15:57.920 --> 16:04.000
and we add a value to it and then we do a function call and then we will have the dump of it.

16:04.000 --> 16:09.360
So here we have a register bank zero and below we'll be all the register values.

16:10.160 --> 16:15.520
You know we're in it on the left and green we have the specified the corresponding register to it

16:15.520 --> 16:22.080
to help us analyze. So we can see that the value that we assigned to the struct is actually in the

16:22.080 --> 16:28.880
register is zero. So this is good. This is starting to look good although this is not we have already

16:28.880 --> 16:39.600
we haven't already which the limit. So we add another chart and so we do exactly the same thing

16:39.600 --> 16:43.920
we look into the dump and we try to identify where those values are and we can

16:45.920 --> 16:50.960
you know we can see that the value or the values are actually in the same registers one

16:51.040 --> 16:56.640
to another which is great. It's still being passed in registers but we still haven't found

16:56.640 --> 17:02.720
our answer yet. So we continue to do this until we reach a point where in this case with non

17:02.720 --> 17:08.400
arguments we'll see something different in the same register. So if you're looking to the A0

17:08.400 --> 17:15.120
there's something different there and if you look into the stack it's actually the stack value there

17:15.120 --> 17:20.480
and if you look into the stack values itself you will see that all the arguments values are there.

17:21.040 --> 17:26.880
So this is great. What does it mean? It means that we have reached the bottom of the boundary at

17:26.880 --> 17:33.760
eight bytes it goes to two range in size. Okay great information so far so good but we need to do this

17:33.760 --> 17:39.920
for all data types. It can be a little time consuming so this is where the feedback loop kicks in.

17:39.920 --> 17:44.480
So we already have the information that the size of the struct greater than eight bytes are expected

17:44.480 --> 17:50.240
to be passed by reference from the previous slide. So what we do is for the 32 bit architecture

17:50.320 --> 17:59.920
an inch is for bytes. So a struct we two the int are already equal to eight bytes so it's expected to

17:59.920 --> 18:06.160
be passed by registers. If we add a char it will be expected that it will be passed by reference.

18:06.160 --> 18:10.640
So this is exactly what we do. Instead of going from one inch to the integer we start

18:10.640 --> 18:19.520
all already we two int and we test it and if it doesn't reach the stack great we will add a char

18:19.600 --> 18:28.400
and it is expected to reach the stack. Now there might be moments that that doesn't happen so

18:28.400 --> 18:33.040
we have a fall through that if the expected boundary is not reached we increase the size by one

18:33.040 --> 18:41.520
and we repeat again we have three inch and then we have a char in so one. So for this test case we

18:41.520 --> 18:48.560
have the summary report which we already discussed. So we have the limit of eight is passed by

18:48.560 --> 18:54.080
reference by registers when it's greater than eight there's a typo there sorry when it's greater

18:54.080 --> 19:02.880
than eight is passed on the stack. Now what happens when we enable out of the where 14 points we have

19:02.880 --> 19:07.200
some different information here you can see that the boundary we have some information about the

19:07.200 --> 19:14.320
boundary being a limit of 16 and why does this happen is this above what is going on exactly right

19:14.720 --> 19:20.640
here. So we have the size if less or equals to 16. So we're in registers if it's greater than 16

19:20.640 --> 19:28.160
is passed by reference on the stack but it's only for double and why is that?

19:30.160 --> 19:37.920
So according to the the risk file ABI a short content in 2014 point reels is passed in 2014

19:37.920 --> 19:44.160
point registers if neither real is more than ABI flank bits why at least two registers

19:44.480 --> 19:49.600
four devices are available what this is meant it means that independent of the size of the

19:49.600 --> 19:57.040
struct if we have two floats two doubles float double or double float which the first one will be

19:57.040 --> 20:04.320
eight bytes rest of them will be 16 doesn't matter the size it matters the number of elements.

20:04.320 --> 20:09.280
So for this one we had to create a special taste case for risk file that will determine

20:10.160 --> 20:16.080
this behavior so they all will have the same behavior if we increase the number of elements

20:16.800 --> 20:21.440
in the struct resulting the struct being passed by reference this is exactly what the new

20:21.440 --> 20:27.200
summary special summary tell us so a member last sort equal to two it's passed in registers

20:27.200 --> 20:32.720
if when there's more than two members is passed by by reference on the stack and then below we have

20:32.720 --> 20:39.600
the least of the the contract system members so a float float double double double double and a double

20:39.600 --> 20:46.240
flow. Now for an empty struct how do we do this how do we make sure that an empty

20:46.240 --> 20:50.880
struct is being ignored by the sequimpiler so we make use of a sentence of all in which is a

20:50.880 --> 20:57.840
marker that indicates the end of a data structure so here we have an example the k k test case

20:57.840 --> 21:04.400
we have a signal value which is coffee everyone loves it and then we have a empty struct so for each

21:04.400 --> 21:10.880
argument possible argument that we we already know how many arguments we can we can test so this is also

21:10.880 --> 21:18.880
information from previous tests so we will test for the out possible eight arguments so the first one

21:18.880 --> 21:24.000
we will test for the first of the store empty structure then the Sentinel second one Sentinel empty

21:24.000 --> 21:29.680
struct and so on so if you look into the that place and empty struct between citizen of

21:29.680 --> 21:34.720
values for each possible argument position our registers should contain exactly so each

21:34.720 --> 21:41.600
register argument register should contain the keyword coffee that will tell us that indeed it's

21:41.600 --> 21:47.200
ignored by the signal bothers so if you're looking to the fourth argument position so we have

21:47.200 --> 21:52.400
three three Sentinel empty struct and a Sentinel if you're looking to the dump for the

21:52.400 --> 22:00.640
registers a zero to a three we have four keywords meaning that's indeed we are sure that in this case

22:00.640 --> 22:05.760
the empty struct is ignore by sequimpiler so we test this for all of the positions

22:07.360 --> 22:12.160
so this is a quick summary between the software 14 points and the hardware 14 point

22:12.160 --> 22:17.920
do you already discuss it the other 40 points it's more density has more information but it's more

22:17.920 --> 22:28.960
complete each everything that we want to know now there's some there's some situations where the

22:28.960 --> 22:35.600
ABI extract you cannot be sure what it's extracting so for example here we have a simple

22:35.840 --> 22:42.720
GCC extracted information everything it's great what we already discussed but when we put

22:42.720 --> 22:51.120
playing we have some differences so if you look into line five and nine playing there is a warning

22:51.120 --> 22:58.000
there so multiple value occurrences detected in t zero and stack being t zero the one of the temporary

22:58.000 --> 23:04.800
registers why not this happen so the framework detected the same value the same special volume

23:04.800 --> 23:08.880
in two different places and cannot be sure which one is actually being used for the other

23:08.880 --> 23:17.120
argument the passing argument to a function so we will tell us now if we look deeply into this

23:17.120 --> 23:26.320
which creates a simple set that sends nine values to a dump function doesn't matter the name

23:26.320 --> 23:32.800
and we're looking to the assembly we can see that actually what is going on is the compiler

23:32.800 --> 23:43.040
is saving the value to t zero and later on we'll be used to starting stack okay now this also happens

23:43.040 --> 23:50.800
in gcc but gcc uses a different argument with different registers sorry it uses the A5 register which

23:50.800 --> 23:56.640
is one of the arguments one so basically there's the same thing but it will start in the stack

23:56.640 --> 24:04.800
earlier and then we'll rewrite the register so extendability portability of the framework

24:06.800 --> 24:15.120
oops so we don't want to this to be exclusive for gcc or playing or whatever and the same

24:15.120 --> 24:20.080
for the simulator so we wanted to make sure that we could easily add new compilers similar to

24:20.080 --> 24:25.520
the way so we went ahead with the idea of having batch rappers each batch rapper will tell

24:26.000 --> 24:33.360
the framework how to execute the proper compiler we can use the same compiler we

24:33.360 --> 24:39.520
different ABI options and everything that will be placed in the rapper same thing for the

24:39.520 --> 24:45.120
simulator in this case we are using QMU to execute the test and on the right we have a tree

24:45.120 --> 24:51.440
of the folders and how it looks currently so we have inside scripts in rapper we have the compiler

24:51.600 --> 24:56.880
and then each each rapper which will be the for example the seal this is the playing the

24:56.880 --> 25:04.880
risk 532 and gcc risk 532 each one will have for the assembler the compiler and the linker

25:04.880 --> 25:12.320
rapper same thing for the simulator which can easily add new compilers to it no portability the same thing

25:12.320 --> 25:21.040
we don't want to be focusing only in a risk file we want later on to add new architecture x86 etc

25:21.440 --> 25:26.720
so to do that we had to make sure that we for example this is one of the reasons we didn't use

25:26.720 --> 25:34.080
more but to add that is we have a class in Python that specifies the register banks just specifies

25:34.080 --> 25:38.080
the names of it so that when generating the report we will give you the correct names for the

25:38.080 --> 25:46.400
registers all pretty and we have one assembly file specific which is also part of the architecture

25:46.480 --> 25:54.240
dumpy formation this assembly file will be responsible for saving the registers to the memory

25:54.240 --> 26:01.280
and later on bring them to as a dump it also have functions to reset the register to know

26:01.280 --> 26:08.480
nonvolve so that we don't have trash on it now future extensions this these are the least of

26:08.480 --> 26:14.960
potential extensions we are working on so currently we are working on supporting 64 bit

26:14.960 --> 26:29.520
long double and vector types so let's jump to the conclusion so here I presented the framework

26:29.520 --> 26:37.520
ABI extractor is able to extract ABI properties for a compiler and dumps the information in a

26:37.520 --> 26:44.000
human readable format it simplifies comparison between extracted ABI from different compilers

26:44.000 --> 26:48.240
and it helps with the validation that the ABI implementation for compilers is correct

26:50.480 --> 26:58.880
now where where can you find the ABI extractor so the ABI extractor is open source it's available

26:58.880 --> 27:06.480
in our synopsis repository but it's currently dummy repository we just got to approval from the

27:06.480 --> 27:12.800
legal team yesterday so in the following days we'll be working on the publishing the source code

27:12.880 --> 27:18.880
so for now if you're interested what you can do we subscribe to the open issue in the repository

27:18.880 --> 27:22.800
and once the framework source code is available you will get an notification

27:32.400 --> 27:37.680
and also we are hiring so if you're interested in working in compilers or any other hardware

27:38.560 --> 27:45.120
and the position feel free to look into our careers page we can go through the link or that you

27:45.120 --> 27:52.640
are code you can use LLVM or GCC as a search keywords to find relevant positions because

27:52.640 --> 28:01.760
synopsis has to provide to compilers GCC and LLVM based so if you can also reach out to me if

28:01.840 --> 28:06.720
you're interested thank you

28:13.120 --> 28:17.360
we have

28:31.760 --> 28:37.240
So, thank you for the presentation.

28:37.240 --> 28:42.880
So, if I have a respite code, where I have my own custom

28:42.880 --> 28:46.320
let's say some registers, right?

28:46.320 --> 28:50.320
How would, let's say I'm trying to also get it up

28:50.320 --> 28:54.520
speed with GCC and C-land, right?

28:54.520 --> 28:56.480
How do I make it compatible?

28:56.480 --> 28:58.920
Should I run it with your case?

28:58.920 --> 29:00.320
Extended in your case?

29:00.320 --> 29:03.080
How do you see this happening?

29:03.080 --> 29:08.320
Whether it's a different TCG group from this by extension, let's say,

29:08.320 --> 29:11.400
that comes up that does that, or somebody else who is doing

29:11.400 --> 29:12.760
some custom thing.

29:12.760 --> 29:17.280
How do you see this being compatible with those?

29:17.280 --> 29:20.960
So, you ask me if you develop a code and you want to make sure

29:20.960 --> 29:25.560
that it works, or what's that expected API for it, right?

29:25.560 --> 29:26.560
Yes.

29:26.560 --> 29:30.000
So, what you can do is there are two options.

29:30.000 --> 29:33.640
You either have a witness file that you create or someone creates

29:33.640 --> 29:40.080
for a generated compiler and then you create the report from your execution

29:40.080 --> 29:42.080
and then you will do a diff between those.

29:42.080 --> 29:45.440
Exactly what we did for the GCC and C-land.

29:45.440 --> 29:49.320
And if there is no differences, it means that everything is fine.

29:49.320 --> 29:54.360
If there is differences, then either something is wrong, right?

29:54.520 --> 29:55.360
Or yeah.

29:55.360 --> 30:00.400
So, this is a way to make sure that the developers make sure

30:00.400 --> 30:03.200
that the API is correct, everything is well implemented.

30:03.200 --> 30:04.600
There is no deviations.

30:04.600 --> 30:09.240
For example, internally, we can say that our LLM-based compiler

30:09.240 --> 30:11.320
for GCC has differences.

30:11.320 --> 30:14.600
So, if we try to combine both objects rather than work,

30:14.600 --> 30:17.840
if we use long double data types, because by default,

30:17.840 --> 30:22.840
we set all of the compiler as eight instead of 16 bytes.

30:22.880 --> 30:26.360
This is one way also to determine it.

30:26.360 --> 30:28.160
Thank you.

30:28.160 --> 30:29.160
Anymore?

30:29.160 --> 30:34.640
All right, we hear me?

30:34.640 --> 30:35.640
Yeah.

30:35.640 --> 30:39.080
Sorry, I missed a few first minutes of your presentation,

30:39.080 --> 30:41.120
so I don't know it could be repetitive.

30:41.120 --> 30:43.960
But how do you go down the rabbit mode?

30:43.960 --> 30:47.200
Like, from your slides, I notice you will check for

30:47.240 --> 30:50.840
a short floating point integer.

30:50.840 --> 30:52.160
Do you go for complex?

30:52.160 --> 30:56.280
I mean, because I can see that this can never end.

30:56.280 --> 30:59.720
Right now, we are not going for the complex, et cetera,

30:59.720 --> 31:02.440
that might be in the plans, but we don't promise anything.

31:02.440 --> 31:04.960
There's so much way to be connected to the framework.

31:04.960 --> 31:07.360
There's so much ideas we want to look into,

31:07.360 --> 31:11.640
for example, checking the L, compiler compatibility, et cetera.

31:11.640 --> 31:14.480
But yeah, currently now, we're just looking

31:14.480 --> 31:16.960
to the fundamental data types, which, in this case,

31:16.960 --> 31:18.720
would be this one's.

31:21.040 --> 31:21.880
That's what I mean.

31:30.880 --> 31:32.160
Hi, further talk.

31:32.160 --> 31:34.640
Just while I get it, would you be possible

31:34.640 --> 31:38.840
to make your work available as a plugin for you?

31:38.840 --> 31:40.480
Does it make sense?

31:40.480 --> 31:41.400
Applying for?

31:41.400 --> 31:42.280
Sure, you will.

31:42.320 --> 31:43.120
Ah, QMU.

31:45.760 --> 31:49.280
I've never thought of it, so I don't think so, honestly.

31:49.280 --> 31:53.320
I will put this as an external project.

31:53.320 --> 31:56.680
And not it, because we don't want this to be a for one thing.

31:56.680 --> 32:00.240
We want this to make this available for all possible

32:00.240 --> 32:03.600
c-related components that said they're not for the specific one.

32:12.280 --> 32:17.280
Hello.

32:17.280 --> 32:17.960
Hello.

32:17.960 --> 32:20.040
Thanks for the talk.

32:20.040 --> 32:24.000
I was curious if there are any plans in trying to incorporate

32:24.000 --> 32:27.800
all these extracted information into a nest boom.

32:27.800 --> 32:30.160
There's a relevant depth on for that.

32:30.160 --> 32:33.200
And there would be great interest in my view.

32:33.200 --> 32:36.520
Sorry to incorporate the extractor to.

32:36.520 --> 32:39.400
In a nest boom, software will look materials.

32:39.400 --> 32:40.240
Expo.

32:40.240 --> 32:41.080
Yeah.

32:41.080 --> 32:45.880
OK, yeah, I've never thought about it.

32:45.880 --> 32:48.480
I don't have a proper answer for it.

32:57.320 --> 32:57.680
Hi.

32:57.680 --> 33:00.320
Thank you for your presentation.

33:00.320 --> 33:02.200
I was just curious about one thing.

33:02.200 --> 33:06.640
So in this one example, you have each of the phasing

33:06.640 --> 33:08.840
from the simulator you're using.

33:08.840 --> 33:09.840
In this case, QMU.

33:11.080 --> 33:13.840
The thing is that on the other hand, you

33:13.840 --> 33:19.120
do manage to be compiler as well as a simulator

33:19.120 --> 33:23.080
into combat by not pressing on T-bike

33:23.080 --> 33:25.080
version instead of formats instead.

33:25.080 --> 33:29.920
You are essentially looking for an execution trace.

33:29.920 --> 33:35.200
But these tracks, I guess, involve that.

33:35.200 --> 33:40.000
You are also using a way to instrument the light, the code,

33:40.000 --> 33:44.040
which is not dependent on one-specific simulator.

33:44.040 --> 33:48.520
And so I was curious as to where the instrumentation

33:48.520 --> 33:51.960
the light is usually between the test case

33:51.960 --> 33:55.000
usually combined, like the two chains,

33:55.000 --> 33:57.880
or what kind of process it is here.

33:57.880 --> 34:01.840
And it is instrumentized with code without pressing

34:01.840 --> 34:03.880
on a specific simulator.

34:03.880 --> 34:06.920
So what we do is you just execute the code

34:06.920 --> 34:09.720
and get the output from the test case.

34:09.720 --> 34:11.880
And from there, we will analyze either.

34:11.880 --> 34:14.120
There are some tests that already give us everything

34:14.120 --> 34:15.320
that we want others.

34:15.320 --> 34:17.680
Then we need to look into the API.

34:17.680 --> 34:21.320
For example, this is this architecture

34:21.320 --> 34:22.080
don't be formation.

34:22.080 --> 34:24.800
This is the output from the test case itself.

34:24.800 --> 34:27.360
We don't look into assembly code or anything.

34:27.360 --> 34:30.960
We're looking to the output of the simulator.

34:30.960 --> 34:33.640
Because if we would look into the assembly code

34:33.640 --> 34:37.120
for each architecture that would never end,

34:37.120 --> 34:39.600
because if we were to add a new architecture,

34:39.600 --> 34:41.680
then we need to add a new one, a license for it.

34:41.680 --> 34:45.520
And et cetera, and it will be not easy to do.

34:45.520 --> 34:47.440
It doesn't mean that in the future,

34:47.440 --> 34:49.520
we might need to do it depending on certain tests

34:49.520 --> 34:51.920
that we might not be able to extract information

34:51.920 --> 34:53.480
from the execution.

34:53.480 --> 34:57.880
But so far, we don't look into the assembly or anything.

34:57.880 --> 35:00.640
So please, we don't waste time editing the code.

35:00.640 --> 35:02.120
And then the code can be executed.

35:02.120 --> 35:03.120
Yes.

35:21.440 --> 35:22.840
Thank you for the talk.

35:22.840 --> 35:24.600
I'm just wondering, is it possible

35:24.600 --> 35:30.000
to infer whether a parameter is being passed

35:30.000 --> 35:33.240
as an integer or a pointer?

35:33.240 --> 35:36.160
I'm thinking of a, sort of, cherry specification.

35:36.160 --> 35:40.080
Points are not the same as integers anymore.

35:40.080 --> 35:43.080
Do you have a way of handling that?

35:43.080 --> 35:47.880
Currently, no, we haven't done it.

35:47.880 --> 35:49.960
Maybe in the future, we'll open the end.

35:54.600 --> 36:04.600
All right, no more questions, so, thank you.

36:04.600 --> 36:05.600
Thank you.

36:05.600 --> 36:15.600
Thank you.

