Discussion:
ABI understanding problem... :-)
Anders Magnusson
2014-06-23 19:58:11 UTC
Permalink
Hi,

I have just found that pcc will pass some parameters wrong on amd64, but
reading the ABI I have a slight problem to understand how it is supposed
to work :-)

For example, this code:

struct a {
float a,b;
} Y;

x(y);

should likely have the whole struct packed in one SSE register, but I
have quite some difficulty to understand how this should be handled;
merely the use of SSEUP and when it shall be packed. I would appreciate
a hint about this :-)

Specs are at http://www.x86-64.org/documentation/abi.pdf

-- Ragge
Joerg Sonnenberger
2014-06-23 20:45:17 UTC
Permalink
Post by Anders Magnusson
I have just found that pcc will pass some parameters wrong on amd64,
but reading the ABI I have a slight problem to understand how it is
supposed to work :-)
I agree that the spec is confusing at best. I don't see why floats are
put in class SSE. If they are in class SSEUP, it would make more sense.
BTW, a full test case is attached.

Joerg
Anders Magnusson
2014-06-25 14:48:57 UTC
Permalink
Post by Joerg Sonnenberger
Post by Anders Magnusson
I have just found that pcc will pass some parameters wrong on amd64,
but reading the ABI I have a slight problem to understand how it is
supposed to work :-)
I agree that the spec is confusing at best. I don't see why floats are
put in class SSE. If they are in class SSEUP, it would make more sense.
BTW, a full test case is attached.
My main problem is that I do not understand what is meant on page 19
clause 3 and 4:

3. If the size of the aggregate exceeds a single eightbyte, each is
classified separately. Each eightbyte gets initialized to class NO_CLASS.
??? What is each?

4. Each field of an object is classified recursively so that always two
fields are considered. The resulting class is calculated according to
the classes of the fields in the eightbyte:
??? What is a field? Cannot find that either.

-- Ragge
Iain Hibbert
2014-06-25 21:54:32 UTC
Permalink
Post by Joerg Sonnenberger
Post by Anders Magnusson
I have just found that pcc will pass some parameters wrong on amd64,
but reading the ABI I have a slight problem to understand how it is
supposed to work :-)
I agree that the spec is confusing at best. I don't see why floats are
put in class SSE. If they are in class SSEUP, it would make more sense.
BTW, a full test case is attached.
My main problem is that I do not understand what is meant on page 19 clause 3
3. If the size of the aggregate exceeds a single eightbyte, each is classified
separately. Each eightbyte gets initialized to class NO_CLASS.
??? What is each?
I think that "each is classified separately" means "each eightbyte is
classified separately" since the eightbytes were the subject of the
sentence.

I read this as; for aggregate objects which exceed one eightbyte but not
more than four (clause 1), each eightbyte in the object is initialized to
class NO_CLASS. Then, you proceed with clause 4.
4. Each field of an object is classified recursively so that always two fields
are considered. The resulting class is calculated according to the classes of
??? What is a field? Cannot find that either.
I think that a field is a sub-object, which may be an object.. eg

union {
float f;
__int128 i;
} u;

is equivalent to

union {
float f;
struct {
long low, high;
} i;
} u;

in which fields are f, i, low and high .. this is two eightbytes, and
the classes of the fields in the eightbytes are

init float struct low high final
0: NO_CLASS SSE NO_CLASS INTEGER => INTEGER
1: NO_CLASS NO_CLASS INTEGER => INTEGER

which you compare each against the one before according to the rules
in clause 4, resulting in the final class for each eightbyte.

regards,
iain
Anders Magnusson
2014-06-26 12:06:54 UTC
Permalink
Post by Iain Hibbert
Post by Joerg Sonnenberger
Post by Anders Magnusson
I have just found that pcc will pass some parameters wrong on amd64,
but reading the ABI I have a slight problem to understand how it is
supposed to work :-)
I agree that the spec is confusing at best. I don't see why floats are
put in class SSE. If they are in class SSEUP, it would make more sense.
BTW, a full test case is attached.
My main problem is that I do not understand what is meant on page 19 clause 3
3. If the size of the aggregate exceeds a single eightbyte, each is classified
separately. Each eightbyte gets initialized to class NO_CLASS.
??? What is each?
I think that "each is classified separately" means "each eightbyte is
classified separately" since the eightbytes were the subject of the
sentence.
I read this as; for aggregate objects which exceed one eightbyte but not
more than four (clause 1), each eightbyte in the object is initialized to
class NO_CLASS. Then, you proceed with clause 4.
4. Each field of an object is classified recursively so that always two fields
are considered. The resulting class is calculated according to the classes of
??? What is a field? Cannot find that either.
I think that a field is a sub-object, which may be an object.. eg
union {
float f;
__int128 i;
} u;
is equivalent to
union {
float f;
struct {
long low, high;
} i;
} u;
in which fields are f, i, low and high .. this is two eightbytes, and
the classes of the fields in the eightbytes are
init float struct low high final
0: NO_CLASS SSE NO_CLASS INTEGER => INTEGER
1: NO_CLASS NO_CLASS INTEGER => INTEGER
which you compare each against the one before according to the rules
in clause 4, resulting in the final class for each eightbyte.
Great, thanks for the explanation, now I think I understand :-)

To simplify I assume it shall be handled like this in pcc:
- If size > 16 bytes or there are packed fields, use memory.
- If any part of an eight-byte should be in a general register, the
eight-byte is stored in a general register
- If the eight-byte only contains float or double, use a SSE register
- Otherwise use memory.

Would this be a correct interpretation?

-- Ragge
Iain Hibbert
2014-06-27 10:23:14 UTC
Permalink
Post by Anders Magnusson
- If size > 16 bytes or there are packed fields, use memory.
- If any part of an eight-byte should be in a general register, the eight-byte
is stored in a general register
- If the eight-byte only contains float or double, use a SSE register
- Otherwise use memory.
Would this be a correct interpretation?
I think it seems ok

iain

Loading...