-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Add the PNaCl/JS targets to the backend. #28355
Conversation
How close does this get the backend to working? Is this all that's needed or are there still portions in the pipeline? The previous patches up until now have been incremental in the sense that they were just general refactorings we'd want to do anyway, but I'd prefer to have "pnacl not working" to "pnacl working" support land all at once rather than piecemeal. |
As far as Rust trans is concerned, this gets PNaCl working. In reality,
Previously, I just disabled the auto vectorizor and added wrappers for the [fiu]64 SIMD types in Also note I'd also like to allow users to disable the setjmp/longjmp EH (which isn't free) in the future (via an unstable |
write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::ObjectFileType); | ||
}); | ||
if !cgcx.is_like_pnacl { | ||
with_codegen(tm, llmod, config.no_builtins, |cpm| { |
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.
Should this logic go into pnacl itself? Basically when you request an object file to be emitted from pnacl it seems like it should naturally understand that it instead just emits bitcode.
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.
Except it's LLVM's target machine that does that. PNaCl/JS (well JS does have one, but it isn't used till post-linking) doesn't have a target machine (though PNaCl does use armv7-none-nacl-gnu
for optimizing, using it for codegen would produce an ARM NaCl object file, which isn't compatible with PNaCl).
In fact if you take a look at the toolchain's pnacl-clang
, you'll find it's just a python wrapper which invokes clang with arguments like -emit-llvm
.
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 may just be me being ignorant of the LLVM fork for pnacl, but if you're already forking LLVM couldn't support for this be added? In terms of interoperating with other compilers it seems like it'd be best to put logic into the pnacl target rather than every compiler using LLVM?
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.
But there doesn't exist any PNaCl LLVM target machine in (pnacl-
)LLVM's target registry (ie using the PNaCl LLVM fork doesn't help in any way). So there's no LLVM target to tell LLVM how to write an object file (of any format).
In an ideal world, I'd completely throw out the PNaCl IR simplification passes and restart afresh, and I'd do it with an actual, real LLVM target machine (since LLVM's ISD form and PNaCl's IR are actually pretty similar). Sadly, while LLVM's SelectionDAG does most (if not all) the heavy lifting w.r.t. legalizing IR to a specific target, the rest of the toolchain would still need modifications to know how to handle the new PNaCl object format (ie how to read/link), which I would have to create specifically for the target machine (another possible, but still non-trivial thing to implement). The required toolchain modifications are the reason JS also uses bitcode as its object format, despite having an official target machine in LLVM. Plus the translation from the object format back into LLVM IR for codegenning to the real native target.
While I grant that using bitcode as the object format is annoying at times, it is a lot easier because it integrates the preexisting LLVM gold plugin based linker.
I actually agree with you, but the impl cost of what you propose is pretty high vs what emcc
and pnacl-clang
currently do (ie -emit-llvm
(both are just scripts wrapping the real clang
underneath; no such luck for Rust)). Plus, the other toolchains would require breaking changes to conform (ie this logic makes Rust conform with the other toolchains).
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.
It sounds like we may want to take a similar strategy to those tools and instead of having the default output type be an object file for insertion into an archive we just have the default output type be bitcode to insert into an archive?
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.
--emit=obj
would still be broken. Plus the PNaCl linker expects bitcode as the main linker input (ie main.o
). This change does accomplish exactly what you propose and doesn't require special casing archive object output.
@brson, what are your feelings on this? This looks to be one of the only points of divergence where "if pnacl { ... } else { ... }" is needed, and while it's good that it's contained this basically all still looks to me like portions which would be best handled in LLVM somewhere instead of rustc itself (e.g. as it does for all other existing targets). From what @DiamondLovesYou is saying, however, it sounds like the way pnacl is integrated into LLVM makes this not easy unfortunately. I continue to be worried about the lack of automation we have for this kind of functionality where "some subset" of intrinsics isn't defined on pnacl, but any future intrinsics we add may or may not be part of this subset and we have no way of verifying one way or another. |
These patches are much easier to digest. I still don't understand why PNaCl believes it's ok not to handle intrinsic that the LLVM supports. The explanation that pnacl is static and can't do it isn't convincing - LLVM itself lowers intrinsics to libm calls and PNaCl can do that too. What happens if we do pass these intrinsic calls to PNaCl? Are they on a blacklist that causes it to fail to compile? Why not just pass the inttrinsic through to libm like LLVM? If we must do our own intrinsic lowering, then let's do it in a generic way - give target specs a mapping from intrinsics to C calls, not have a pnacl special case. Likewise the is_like_pnacl check for emitting llvm bitcode (into a .o file?) should be a generic 'output_bitcode_to_object_file' or something. |
I guess the issue is that there are no subsequent linkage steps in the pnacl toolchain. The bitcode output by rustc is the final product and there's no opportunity to link libm after the fact. Edit: but most of these functions are in libm and/or libc, and needed for most software to work. Doesn't PNaCl just always link to libc/libm? (Emscripten supposedly does). |
@brson Sorry for the delay.
Sure, since libm is included in libc, but that doesn't mean the linker will actually include the definitions (unless the defs are used), thus their availability isn't guaranteed post link. Also, PNaCl (and thus Emscripten) disables -simplify-libcalls, so calls to libm won't result in calls to an intrinsic. Thus normal, defined calls to libm (those that would happen in C) will still call libm after optimizations.
I'm fine with that, if that's what it takes. |
So if I understand things correctly, there's one giant LLVM module which contains the bitcode for libc, libm, and the application in question. This module is then optimized and such and is passed through the pnacl backend. The definitions of libm functions are all optimized away because they're not used, and then after this happens the intrinsics are lowered to calls to those libm functions, resulting in the undefined symbols? Is that what's going on? |
I wasn't aware that PNaCl disables that, and I don't think we use code from PNaCl that would cause Emscripten to do it. But maybe I'm wrong - do you know where PNaCl disables that pass? LLVM source code seems to show that the entire pass has been removed in upstream anyhow? http://llvm.org/viewvc/llvm-project?view=revision&revision=184459 Unless PNaCl has modified the places where parts of that pass have been moved to, as mentioned in that commit? |
No, the problem is that LLVM's math intrinsics create implicit dependencies on libm, but the linker isn't aware of this fact, and as a result omits libm (or rather, omits the objects containing no defined undefined symbols) from the resulting module. Then, post-link, when the PNaCl IR passes and optimizations are run, Normally this isn't an issue because codegen will rewrite these to libm as needed, thus allowing the linker to know about references to them. However, PNaCl/JS use bitcode linking, which doesn't have calls to I apologize if I'm making this confusing, as this area seems to have recurring misconceptions. Thankfully, I think my first proposal isn't as bad as I had initially feared (I'm dumb): generally, the implicit libm dep should just be made explicit, because this would also be an issue for any other target if libc is statically linked for WPO (in the same way it's an issue for PNaCl). After that's fixed, creating a PNaCl IR pass to rewritten the math intrinsics won't be an issue. Once I get time, I'll send a patch to upstream LLVM. @kripken No the file was just moved to a different folder in that commit. See: https://github.com/llvm-mirror/llvm/blob/master/lib/Transforms/Utils/SimplifyLibCalls.cpp It probably should be disabled, though it probably only creates issues in extreme corner cases. See this comment from # We disable the LLVM simplify-libcalls pass by default, since we
# statically link in libc, and pnacl-opt is typically used for post-link
# optimizations. Changing one library call to another can lead
# to undefined symbol errors since which definitions from libc are linked
# in is already decided. |
@DiamondLovesYou : thanks, interesting. I looked into this for emscripten, and it looks like it already isn't run during LTO anyhow (and it's fine to run otherwise). We mostly just do |
@kripken Yeah, PNaCl runs -On in addition to LTO (for even better optimization opportunities). W.r.t. the intrinsic/libm thingy: after doing some digging in LLVM, it seems LLVM already ensures libm is available at codegen time by emitting references to libm functions. BUT this is only done if there's a target machine available. Le sigh. I may end up creating a dummy target machine and lowering etc for PNaCl. |
☔ The latest upstream changes (presumably #28768) made this pull request unmergeable. Please resolve the merge conflicts. |
@DiamondLovesYou : thanks for the info. |
@DiamondLovesYou your proposal on the pnacl mailing seems promising! Perhaps this should hold off for a resolution on that? |
@alexcrichton Sorry, didn't see your reply in my inbox! There's no need to wait because the requisite changes for @kripken FYI, I've sent in a patch for the target machine here: https://codereview.chromium.org/1395453003 |
4470b17
to
1091e72
Compare
Okay, I've cleaned/removed up the last of the extra logics. This should be ready to merge! |
@@ -838,7 +838,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option<ValueRef> { | |||
|
|||
ifn!("llvm.trap", fn() -> void); | |||
ifn!("llvm.debugtrap", fn() -> void); | |||
ifn!("llvm.frameaddress", fn(t_i32) -> i8p); | |||
if !ccx.sess().target.target.options.is_like_pnacl { |
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.
It looks like this is the only use case of is_like_pnacl
, and it also looks like llvm.frameaddress
isn't used at all, so perhaps this could just be removed entirely?
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.
Fine by me; removed.
1091e72
to
e497d4a
Compare
Thanks for the patience @DiamondLovesYou! |
The first vector type legalizer pass PR is sent: https://codereview.chromium.org/1423873002. |
r? @alexcrichton