Manu343726 / ctti

Compile Time Type Information for C++
MIT License
573 stars 56 forks source link

Reimplement constexpr array initialization #6

Closed Manu343726 closed 9 years ago

Manu343726 commented 9 years ago

STL told us on reddit that constexpr array initialization is supported by VS2015, then @foonathan noticed that our issue is not array related but about ctor delegation. I would like to change the implementation of ctti::detail::array and ctti::detail::string to not apply the indices trick in a constructor but in an independent function, then pass array contents as a variadic pack.

foonathan commented 9 years ago

Go for it.

You've looked into disassembly and there is not much overhead for the arrays, isn't it? Did they completely optimized unused storage out, too? Because I still don't like the idea of having a fixed size array, 256 or what your size is, is too much, although to be strict standard conforming, it should be even more - 1024 (see appendix B, number of characters in internal or external identifiers).

Anyways, I suggest keeping string a complete implementation detail and returning const char* by the name() function.

Manu343726 commented 9 years ago

Well, the behavior is still a bit surprising for me. When storing arrays into the executable, the whole 256 array with tens of \0es is stored, but in the examples I have run most substrings are handled by pushing characters directly onto the stack prior to the function call that will use the string. I don't know the criteria both gcc and clang use to make this distinction. OTOH I still haven't examined MSVC assembly. It's too soon to have an opinion I think. I would like to do more tests.

Anyway, I don't like the idea of exposing string to the user too. If arrays work, I will continue with the const char* interface.

Manu343726 commented 9 years ago

Maybe we should document examples with disassemblies in the wiki, both as proof of concept and documenting expected library behavior.

foonathan commented 9 years ago

In a call to type_id(), do they store the whole array on the stack, or not?

Manu343726 commented 9 years ago

See this example.

As you can see the string contents (hash, length, and chars) are pushed onto the stack first as local variables (The string is "main()::FIND_ME_IN_THE_DISASSEMBLY"), then passed to called function (std::cout << in the example) using SIMDs. Note only used chars from the array are pushed, not the 128 ones. But as you can see at line 137, gcc also stores the string as static data.

Clang on the other hand seems to not inline any constexpr code, it actually generates code for sid_hash()! (See string ctor code). It stores __PRETTY_FUNCTION__ as static data, then calls all functions (make_string(), string ctor, etc) with pointer to that data as parameter.

foonathan commented 9 years ago

Okay, so it seems good enough.

Still, if static storage in constexpr functions would be allowed, it could be so much simpler.

Manu343726 commented 9 years ago

I still don't like the code clang generates. Almost any string code is inlined (There are calls!), generates very long code for sid_hash() after unrolling it, increasing code size a lot. I have tried the same example above with a static_assert(ctti::type_id<struct A>() != ctti::type_id<struct B>()) and it generates the same code (No code for struct A/B string instances, hashing, etc). Seems like that because the string is not being used in a constant context, constant folding is not triggered.