-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
implement sizeof and alignof operator #5664
Conversation
I've always had a paranoid idea for implementing this feature btw. You can also modify the codegen to introduce a static assert that Nim's assumption was right. Below each C type declaration produced by Nim, you can use the |
Well I checked how the alignment of C structs actually behave. primitive types get self aligned, and structs get aligned to it's biggest alignment of a member. Compilers may not behave different here, because otherwise headers would not work for interfaces when they are compiled to a different memory layout. But there are ways to change the behaviour of alignment. I think that when I am already doing this, there should be an align pragma that allows me to set alignment of any type manually. |
keep in mind that alignment changes with os, architecture and compiler options - here's a telling example:
https://en.wikipedia.org/wiki/Data_structure_alignment#Architectures |
there's also a feature https://github.com/rust-lang/rust/tree/master/src/librustc_back/target is a good reference for common layouts - look for the data_layout string and the docs in http://llvm.org/docs/LangRef.html#data-layout |
@arnetheduck Thanks for the info, I will take that into consideration. Currently I am on Linux (64-bit) and here the double is 8 byte aligned, so I would not have noticed. I think the best thing to do here would be an alignment map (just a few constants that can be initialized with a few |
compiler/types.nim
Outdated
result = szNonConcreteType | ||
result = 1 | ||
|
||
proc computeObjectOffsetsRecursive(n: PNode, initialOffset: BiggestInt): tuple[size, align: BiggestInt] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now enough code that it should reside it its own module. Suggested name: sizeofimpl.nim
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where should that file be? same folder as types.nim, and then just include it from types.nim?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
module would be nicer than include file and it should not have many dependencies (ast.nim, and not much else?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well I guess that would be possible
I got a very weird problem: In computeObjectOffsetsRecursive I print the result, to check if it has the correct value, and in fact it has. But when I print the exact same values from This is the output I get:
I get different values. How is that possible? I made sure that the output is only printed for one single type, where I know that the result is wrong. this is the current testfile in the root of the project: |
ok, I got the problem fixed. There was one layer of recursion more of the same function that I thought that there would be and that changed the result. Now a lot more tests actually pass. |
6f84bba
to
7cc43d5
Compare
What's the status of this? Ready to be reviewed? (I might need this feature soon.) |
I thought so, but then I realized I am missing out on the |
That's a bug. Most enums fit in a single byte and so should get "byte alignment" (i.e. no alignment). An int sized enum should be aligned like an int, yes. |
recently I stumbled upon something like this in windows related header files of mingw-gcc. #include <pshpack2.h>
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
#include <poppack.h> gcc documentation says those kind of struct alignment exist to provide compatibility for Microsoft's compiler. gcc itself do not use them in it's own header files, only in windows related header files. pshpackXX force the compiler to use certain alignment of 1,2,4, and 8. As far as I know, Nim compiler only support byte alignment with clang compiler usually have compatible features with gcc although it is not in C standard. icc also support this feature because it claims source and binary compatibility with msvc compiler. I think if Nim want to support this feature, this PR is the right place to do it since sizeof, alignof and offsetof all deals with alignment. alignment up to 32 bytes might be needed with AVX instructions. |
I don't know of the |
pshpackXX and poppack contains something like this: #pragma pack(push,2) #pragma pack(pop) #pragma pack(push,1) basically equals with Nim packed pragma. |
compiler/semmagic.nim
Outdated
dotExpr = n[1][0] | ||
else: | ||
#echo "evaluating: ", n, " type1: ", type1, " type2: ", type2 | ||
debug n[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debug code left over.
I checked-out the PR locally, here are some results running tests/misc/tsizeof.nim: (x86_64 GNU/Linux) I could get any useful results with RESULTS without {.packed.}
running
running
|
@Parashurama thanks for the help. I am pretty sure where the problem is. Depending on the architecture and the platform the alignment might not be self aligned for all primitive types. My implementation does not handle those cases properly. Here is where the branching needs to take place: Here some branching based on the platform needs to happen, to get the correct alignment for the different types. |
Well this pull request is generally correct. The only problem it is facing now is that the alignment values for the builtin types are not set correctly by the compiler as described here: |
Well, alignment issues appear to be fixed with latest devel. (I tested by rebasing your branch on devel) |
if size == szImportedType: | ||
# Forward to the c code generation to emit a `sizeof` in the C code. | ||
result = n | ||
elif size >= 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will that work with incomplete types that have at least 1 field?
type
MyStruct {.importc: "MyStruct".} = object
field1: int
# missing field2
see also #9250 for a more robust solution (that can be implemented after your PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally I was looking at the wrong location for the importc flag. Now it should work properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are correct.
@krux02
|
@Araq this is the test that is currently failing: Can you explain me, why this should be an illegal recursion? |
odd indeed that these are invalid: given that these are valid:
also, the test in https://github.com/krux02/Nim/blob/sizeof-alignof/tests/typerel/trectuples.nim#L6 is not great since the lines after line 6 are not processed |
Recursive types need to be nominal types. Otherwise type equality checks need to have cycle detection, and that is expensive. Forbidding that kind of recursive types isn't really a big limitation. The reason for this limitation could be documented better though. |
=> squashed + rebased against devel in #9356 to allow fast fwd merge |
Don't pull yet. It's almost done. I only want to see if I already broke something by running the tests on the server.
This is the issue I am working on #5493