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

Fix VaList and disable va_arg for AArch64 #9422

Merged
merged 1 commit into from
Jun 22, 2020

Conversation

jhass
Copy link
Member

@jhass jhass commented Jun 4, 2020

The va_arg LLVM instruction is a hoax really.

The official docs have this to say:

Note that the code generator does not yet fully support va_arg on many targets. Also, it does not currently support va_arg with aggregate types on any target.
http://llvm.org/docs/LangRef.html#id332

At least for AArch64 not fully supported is an understatement. It just returns garbage data. (for LLVM debug builds it may run into an assertion from what I've seen elsewhere.) Hence Clang does this: https://github.com/llvm/llvm-project/blob/a574edbba2b24fcfb733aa2d82308131f5b7d2d6/clang/lib/CodeGen/TargetInfo.cpp#L5677-L5921 If somebody wants to attempt porting this, be my guest. It makes use of metadata about the argument type which is computed god knows where in Clang, porting all of that sounds like fun. Not. You could also go by https://static.docs.arm.com/ihi0055/c/IHI0055C_beta_aapcs64.pdf Section 5.4, if that's more your thing.

Anyways, let's not expose broken functionality for now.

@asterite
Copy link
Member

asterite commented Jun 4, 2020

Man, LLVM looks so nice from the outside, and it really has a great optimizer, but it's full of holes. I wonder if we should have made Crystal generate C code instead, or have used GCC as a backend...

@jhass
Copy link
Member Author

jhass commented Jun 4, 2020

Ah yeah, I forgot I wanted to share this little exchange I had in the LLVM IRC channel after asking why Clang would do the above rather than use tthe va_arg instruction (excerpt, there was more in the vein before and after, by different people too):

<jhass> it almost feels like va_arg is just broken on aarch64 and rather than fixing that somebody went through the effort of reimplemnting it like this for clang
<nbjoerg> no
<nbjoerg> the IR stuff is really only appropiate and meant for the easy cases
<jhass> a bunch of i32's is an easy case, no? I can't get that to work
<nbjoerg> I don't know the aarch64 ABI from memory
<nbjoerg> in general, the IR is only really applicable if you have a nice stack based calling convention
<jhass> well, the call instruction seems to be implemented fine for the aarch64 variadic calling convention?
<jhass> why is it inappropriate for the va_arg instruction to handle it as well?
<jhass> why does it exist then?
<nbjoerg> jhass: legacy
<nbjoerg> jhass: noone bothered enough to remove it

@jhass
Copy link
Member Author

jhass commented Jun 4, 2020

Man, LLVM looks so nice from the outside, and it really has a great optimizer

A great optimizer that crashes in the default configuration on some targets for code that works just fine on others, see #9401

@jhass
Copy link
Member Author

jhass commented Jun 4, 2020

Oh and did I mention that the original code in stdarg.cr (well, usage of it) also crashes LLVM on AArch64? https://bugs.llvm.org/show_bug.cgi?id=46175

@bcardiff bcardiff added kind:bug A bug in the code. Does not apply to documentation, specs, etc. platform:aarch64 topic:compiler labels Jun 4, 2020
@jhass jhass added the pr:ready-to-merge The changes are good to go, we need to triage merging it. label Jun 4, 2020

pending_win32 "works with C code" do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current state of this spec represents that it's not passing but really should be made to pass. This change drops that distinction.
(But I don't have an immediate suggestion how to keep that in a nice way, so feel free to disregard)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't immediately get why this was pending but the above was completely wrapped. I knew I wanted to wrap this one, so I unified to the majority.

spec/std/va_list_spec.cr Show resolved Hide resolved
spec/std/va_list_spec.cr Outdated Show resolved Hide resolved
src/va_list.cr Outdated
# Clang implements va_arg on AArch64 like this: https://github.com/llvm/llvm-project/blob/a574edbba2b24fcfb733aa2d82308131f5b7d2d6/clang/lib/CodeGen/TargetInfo.cpp#L5677-L5921
# If somebody wants to fix the va_arg instruction on AArch64 upstream, or port the above here, that would be welcome
def next(type)
\{% raise "The LLVM va_arg instruction is broken on AArch64, please implement wrappers in C calling the va_arg macro for the types you need and bind to them" %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you reconcile this line with this one:

node.raise "va_arg is not yet supported on Windows"

as I'm pretty sure only one of them is needed (and I certainly don't insist that mine is the correct one)

Copy link
Member Author

@jhass jhass Jun 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both seems to be functionally equivalent. What I like about my version is that if somebody would generate docs on the affected platform, they'd see the note there. I picked documenting it in stdlib because in theory it could be solved as a standard library with some macro type inspection help, I think. Just some insane effort. (Either way, solving it in the compiler as well).

Also in the unlikely case the va_arg instruction gets actually fixed upstream for the platform, somebody could bypass the stdlib check here by re-implementing the primitive binding.

But I don't really know what's the preferred way. Any other opinions?

src/va_list.cr Outdated
# Clang implements va_arg on AArch64 like this: https://github.com/llvm/llvm-project/blob/a574edbba2b24fcfb733aa2d82308131f5b7d2d6/clang/lib/CodeGen/TargetInfo.cpp#L5677-L5921
# If somebody wants to fix the va_arg instruction on AArch64 upstream, or port the above here, that would be welcome
def next(type)
\{% raise "The LLVM va_arg instruction is broken on AArch64, please implement wrappers in C calling the va_arg macro for the types you need and bind to them" %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like how this message reads. Even as a knowledgeable user it's just hard to get the point.

Particularly (as I assume this is a user-facing message):

  • I don't immediately care that it's LLVM's fault.
  • I don't immediately want to see what the workaround is
    (also takes a while to realize that this is just a suggestion of a workaround).

I want to foremost plainly see what is not working.

But unfortunately, the entirety of the message is about the prior two irrelevant points.

Copy link
Member Author

@jhass jhass Jun 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions for a better message rather than just pointing out what you don't like here?

I don't agree suggesting how to workaround this limitation is irrelevant.

@jhass jhass removed the pr:ready-to-merge The changes are good to go, we need to triage merging it. label Jun 4, 2020
Copy link
Member

@oprypin oprypin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bearing with me!

@jhass jhass added the pr:ready-to-merge The changes are good to go, we need to triage merging it. label Jun 4, 2020
@jhass jhass mentioned this pull request Jun 8, 2020
va_arg is broken on most platforms, including AArch64
@oprypin
Copy link
Member

oprypin commented Jun 13, 2020

Why force push? Just commit (possibly merge) and push normally

@jhass
Copy link
Member Author

jhass commented Jun 13, 2020

Uh just habit, I tend to maintain clean commit histories. What's the harm without pending reviews?

@jhass jhass mentioned this pull request Jun 18, 2020
5 tasks
@bcardiff bcardiff added this to the 1.0.0 milestone Jun 22, 2020
@bcardiff bcardiff removed the pr:ready-to-merge The changes are good to go, we need to triage merging it. label Jun 22, 2020
@bcardiff bcardiff merged commit 3cdb9a9 into crystal-lang:master Jun 22, 2020
@jhass jhass deleted the aarch64_vaarg branch June 22, 2020 19:24
@jhass
Copy link
Member Author

jhass commented Aug 3, 2020

Rust just added a native implementation for AAPCS VaArg, if anyone wants to port that over: rust-lang/rust#73655

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. platform:aarch64 topic:compiler
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants