Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation of MIR_T_BLK #332

Open
epitavy opened this issue May 12, 2023 · 8 comments
Open

Documentation of MIR_T_BLK #332

epitavy opened this issue May 12, 2023 · 8 comments

Comments

@epitavy
Copy link

epitavy commented May 12, 2023

I want to generate a function that takes a C struct as parameter and returns another C struct.
As far as I understand, the argument can be of type MIR_T_BLK. Can we have more documentation on the usage of MIR_T_BLK, MIR_T_RBLK and some examples in the mir-tests folder ?

Also the documentation is not clear on what is the difference between MIR_T_BLK and MIR_T_BLK + xxx.

@vnmakarov
Copy link
Owner

I want to generate a function that takes a C struct as parameter and returns another C struct. As far as I understand, the argument can be of type MIR_T_BLK. Can we have more documentation on the usage of MIR_T_BLK, MIR_T_RBLK and some examples in the mir-tests folder ?

Also the documentation is not clear on what is the difference between MIR_T_BLK and MIR_T_BLK + xxx.

Unfortunately, it is complicated because ABIs can be complicated too. For example. structure with two int members is passed through 2 integer regs on x86-64 and structure with one integer and one fp member are passed through 1 int reg and fp reg (nested structures can complicate passing even more). MIR_T_BLK+xxx are used as enumeration of all possible methods of passing structures and they described different passing methods heavily depended on a target.

I decided to use MIR_T_BLK+xxx approach instead of introducing structure/union types as in LLVM IR. It is a simpler solution, imho.

I'll try to document MIR_T_BLK+xxx for different targets for the next MIR release which will be probably be at the end of summer or begging of fall.

@epitavy
Copy link
Author

epitavy commented May 15, 2023

Ok, thank you for the answer. Can you tell me which MIR_T_BLK should I use if I generate code for x86_64 ? I would also appreciate a location to look in the code where the passing argument method depends on the BLK type.

@vnmakarov
Copy link
Owner

You can find how to use blk types for x86-64 in mir-gen-x8_64.c. Here are the brief descriptions for SYSV ABI:

o MIR_BLK + 1 is used for passing unions/structures (of size <= 16) with integer members
o MIR_BLK + 2 is used for passing unions/structures (of size <= 16) with fp members
o MIR_BLK + 3 is used for passing structures whose 1st member is of int type and 2nd one is of fp type
o MIR_BLK + 4 is used for passing structures whose 1st member is of fp type and 2nd one is of int type
o MIR_BLK is for all other cases

Depending on MIR_BLK type, the args can be passed (partially or fully) through integer or fp regs or on the stack. Please look at SYSV ABI for this.

You can also find how blk type are generated by c2m in cx86_64-ABI-code.c file.

@giann
Copy link

giann commented Oct 27, 2023

@vnmakarov would using MIR_BLK for all cases work even though it would be sub-optimal?

@vnmakarov
Copy link
Owner

@vnmakarov would using MIR_BLK for all cases work even though it would be sub-optimal?

Yes. I believe it should work. The problem will be only when you try to call external C functions (unfortunately there is no way to force a C compiler even with all implemented GCC extensions to accept MIR_BLK parameter passing for any type parameter).

@giann
Copy link

giann commented Oct 28, 2023

Alright. This is exactly the use case I'm trying to solve unfortunately.

So if i understand this: i have to change what type of BLK instruction i'm using depending on the architecture?

@giann
Copy link

giann commented Oct 29, 2023

@vnmakarov several question around passing struct/union by value:

  • How do I return a struct/union? MIR_T_RBLK is not accepted as return type (then what is that type compared to MIR_T_BLK) ?
  • I suppose only argument registers can hold a struct and I then operate on its address in the function body?
  • aarch64 seems to only need a simple MIR_T_BLK, am I correct?
  • For x86_64, it's more complicated, what I understand is that I have to flatten the struct (in the event that it contains another struct value), and follow the rules you layed out in the earlier comment?

@vnmakarov
Copy link
Owner

@vnmakarov several question around passing struct/union by value:

* How do I return a struct/union? `MIR_T_RBLK` is not accepted as return type (then what is that type compared to MIR_T_BLK) ?

Actually returning structures is less complicated than passing. Address of the function result is set up as the first argument. So if func returns 16-byte structure, the func will be one arg function and look like

f: func    rblk:16(Ret_Addr)

The return from f can be implemented by

call memcpy_p, memcpy, memcpy_res, Ret_Addr, address of structure to return, 16

or something analogous. The call of f will look like

call f_p, f, rblk:16(addr)

Here f_p is prototype of the func f, addr is where the result of call should be.

How the Ret_Addr passed is machine dependent (defined by the target C ABI). It can be really passed through a reg or calculated from the stack pointer.

* I suppose only argument registers can hold a struct and I then operate on its address in the function body?

* aarch64 seems to only need a simple MIR_T_BLK, am I correct?

I don't remember exactly C ABI on aarch64 but it seems so. Generally speaking MIR_T_BLK is the most generic structure arg passing. It should work for any size struct passing although for some small sizes it may be not conformant to target C ABI.

* For x86_64, it's more complicated, what I understand is that I have to flatten the struct (in the event that it contains another struct value), and follow the rules you layed out in the earlier comment?

Yes, it is complicated. You should read x86-64 SYSV ABI. It was designed by Jan Hibicka ( a GCC developer) when AMD introduced its 64-bit architecture. The major goal was performance. I hope recent Intel extension APX (adding another 16 general purpose registers) will not result in changing SYSV ABI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants