Change:
This effectively means you can't compile for these targets.
This may have been caused by the i128 PR ( ). No LLVM assertion is raised if I compile with , which removes the i128 stuff. We could try to fix this or we could cfg away the i128 stuff for the nvptx targets in the meantine. The LLVM assertions render the NVPTX backend unusable in the nightlies. cc Have you seen any LLVM assertion like the ones above while working on implementing i128? cc cfg?
no, I can't remember seeing such an assertion. It seems to be in PTX related code. but its very likely that i128 broke some of the non tier1 platforms. You can only tell whether they break once they actually do :/ Can you try to generate a minimum reproducible example? Then we might know more...
Seems like the msp430 target broke too: with Using works fine. cc
Examples
msp430 EABI doesn't specify how to return 128 bit values, and LLVM does not support them on msp430, so I don't see an easy fix for this.
These are tier 3 platforms, so basically anything goes IMO in terms of language guarantees. If they don't support i128 at a fundamental level then it seems like if we want them to compile we'll have to cfg out support.
I'm trying to understand this better: If the ABI does not specify how 128-bit values are passed/returned, does that mean that the architecture doesn't support 128-bit values at the fundamental level?Do all the ABIs of the all the other platform 2 targets (x86, ARM, MIPS, PowerPC, SystemZ) specify how 128-bit values are returned?(What about wasm and Do those even have an ABI? How does the 128-bit stuff even works there?) I'm wondering if we should: Add a field to target specifications. For targets that don't support i128 at the fundamental level.Or, maybe add Cargo feature to to cfg away the i128 stuff.Or unilateraly cfg away i128 in core for nvptx and msp430. I personally don't like either option. To me this seems like a limitation in what LLVM can do today but that can be fixed in the future. Also, if we had pure MIR rlibs this wouldn't be a problem at all because the i128 stuff would never be passed to LLVM if it wasn't being used by the final application. To sum it up, I'm not sure what to do here ...
Right now on MSP430 values from the functions are returned using 4 16bit registers r12-r15. So in total you can return only 64 bits of data. There is an exception though, for returning large structs, the data is placed on the stack and reference is placed in the registers. So I guess it will be possible to bodge some hack that will treat i128 like a struct, but I don't know if anyone tried to implement 128 bit values on 16bit cpu, so it will be a new territory and potentially a lot of work for a feature that may not be useful at all on a small MCU.
yeah, but if LLVM can generate code for a function that returns then it should be able to use the same trick to return an . It's just that noboby has taught it how to do that. (i128 ops are totally different though but at least LLVM should emit intrinsics instead of raising assertions) How about on 8-bit AVR?
AFAIK, if Rust code calls Rust code, the ABI is totally irrelevant. We can do whatever we want. However, it starts getting a problem once we start talking to non Rust places, e.g. for FFI, or when LLVM emits a call to i128 intrinsics. For FFI we might want to end up forbidding fn's and structs that have i128 for targets where i128 is not specified by the convention or buggy in LLVM. With intrinsics, there has been major pain on Windows with because LLVM assumed a different ABI than what Rust provided with . It was "fixed" by introducing the "unadjusted" ABI, and it might work for nvptx64/msp430 as well, but it can just as well still cause an assertion failure. Real need for is only for platforms that want to cryptographic libraries, or maybe even std, as those two places might want to use . The higher stages of the compiler itself require i128 support as well, so if your platform wants to be a host platform for rustc, you'll need to support i128. I'm okay with any of the three options (flag in , feature for , only setting it for those two platforms) for these platforms.
No. No. Namely the x64 windows ABI is kinda fuzzy about how i128 values are handled so carefully reading it we arrived at a conclusion that they ought to be handled the same way as regular 16-byte structs on 64 bit window platforms. A target cannot not support i128 at a fundamental level the same way a target cannot not support writing turing complete software. IMO what we should do here is to fudge the ABIs somewhat to take and return arguments via pointers (or the same way would be handled) on these targets. C ABI will be more complex; as already said there will always be at least one user of the C ABI with i128 arguments and stuff – LLVM with their intrinsics. The question here is how does LLVM lower to the intrinsics on these targets. If the backend does not lower and asserts for whatever reason, the targets have what’s essentially a broken backend implementation. Which seems to be broken for at least NVPTX () in exactly the place where I’d expect it to be broken if it was broken: That being said, since the C compilers do not support i128 for those targets, the actual interoperation does not matter whatsoever. All that’s really needs to be fixed is LLVM’s lowering of instructions to intrinsics using whatever ABI that works, even if its passing in arguments and taking return value via pointers. I, myself, am very strongly against splitting the language feature sets depending on the target.
How do we break the stalemate? If we submitted changes upstream for each of the smaller targets w/o support for i128 (providing indirection like large structs) it seems like it would meet resistance. As says, it's likely not considered useful since there's many targets without any native registers or support for such large values. But we also also have reluctance to limit this type to only appropriate targets. Does the "vision for 2017 cycle" provide any guidance? Does "provide a more seamless FFI story" help push us in one direction or the other?
regardless whether useful or not, we do need to support i128 on all targets, otherwise people will start using libraries that provide it across platforms. Even if it needs to be "virtualized" in some way, and not wholly put into registers. In the worst case we'd have to provide some translation before passing things to LLVM, but it will affect things like alignment and generally looks like an ugly workaround. About FFI, I guess we can't really provide any FFI for i128 on targets where there is no C support for it, as generally the calling conventions only specify things that are part of C.
None of the targets Rust supports have native support for 128-bit integers, other than the fact that some can implement unchecked division and multiplication involving 128-bit integer operand with a single insn. Why? All that needs to be done here is to have the backends fixed. LLVM is supposed to be agnostic over bitwidth of integer, however useful or not somebody on the internet perceives such functionality to be. In other words, its a backend bug. So, its probably pretty clear that all it takes is to write a patch to fix bugs in these backends wrt operations on large values. I have no knowledge of these targets, am not familiar with the backends and haven’t the hardware to test any fixes on, so these patches will have to be written by somebody else. Late answer, but I’ve noticed this only now. This observation is wrong in multiple places. Firstly, (a.k.a. returning via pointer) is not a hack. Neither is it an exception. That’s what pretty much every single ABI¹ out there does for values that do not fit into register(s). It is most likely true that MSP430 ABI does not specify what to do with PODs this large, so it falls on us to pick whatever. ¹: For a less obscure example, x64 ABI used by code targetting Windows mandates to be used for any non-vector values over 64 bit in size, even though they could be fit it into registers. SysV ABI starts returning stuff via after some size threshold as well.
The MSP430 ABI specifies that aggregates larger than 32 bits are passed and returned via pointer. The backend just doesn't implement sret correctly yet (and in fact is implemented targeting an old and outdated ABI in any case). I'm working on fixing this in LLVM. I'd bet that similar problems explain the NVPTX problems but I know nothing about that platform so I can't say that for sure.
I also agree that fixing backend is the right thing to do. I just think that it is not that easy as you say it is. MSP430 is the only 16bit architecture in LLVM, and this creates some trouble by itself. Good to know that someone is working on this.
does that LLVM patch really fix NVPTX as well?
No, it doesn't. this should be reopened for NVPTX.
BTW, thanks to for fixing this in LLVM upstream.
Triage: MSP430 has been fixed. No change in the NVPTX backend.
What needs to be done to get NVPTX working again?
You can see the patch I did for the MSP430 above - if it's the same problem you basically just have to add sret (structure return) support to the LLVM backend. I don't know anything about NVPTX but I'd bet it's pretty much the same procedure as what I did for the MSP.
Note that you can use the NVPTX backend today with the nightly compiler if you use a fork of the libcore crate that doesn't include 128 bit integers. Instructions .
I have some progress on the issue. First, I tried a hacky workaround with replacing with in arguments and return values with a custom FunctionPass. Can be transformed to: And compiled to PTX with vanilla LLVM (): Then, I made less hacky workaround patching LLVM NVPTX backend so it became possible to compile the code with without additional passes. Is compiled with patched to pretty much valid and working PTX assembly ;) But another related problems appears. When instead of: I write: I receive an error: And similar error when I try to compile : Does anybody have any suggestions about the problems? Looks like PTX doesn't have an instructions for the functions, and LLVM can't expand them.
Looks like the expansion from i128 to i64 is going OK but the i64 sdiv/mulo instructions aren't properly implemented. Not sure why that might be... it kind of looks like it's trying to assign the address of a library call and that's not working. Possibly the way you implemented the i128 expansion prevented a subsequent i64 expansion from running but I can't tell without seeing the code. Run llc with -print-before-all and/or -print-machineinstrs to see where things diverge from what you expect. Look up in your platform ABI what the right action to take for 64-bit divides actually is. Post a link to your changes and someone may be able to take a look at them and see the problem.
Traditionally, in LLVM, is implemented by the library. However, its disabled on most platforms. Not sure why, but is written in C so they probably only can support i128 on platforms where they also provide C support, and clang's C support for i128 is right now very limited. Rust however the function, inside the crate (that is a wrapper for compiler-rt). There are good chances it works already!
It has pretty expected output before and after each pass. I think more interesting would be output with , but I don't really understand it. of the next commands: I tried to make changes over LLVM as minimal as possible: . I'm quite confused about and . Should they be compiled for target or host? If we can build at least for NVPTX, then can we just link against it? It still require some more changes for LLVM to be able to threat libcalls as normal calls. But then, all we would need is to link against . This blocked by but might be solved with my experimental .
For the target. At least its that way on other platforms. What is LLVM doing on 32 bit NVPTX when it encounters a 64 bit operation? On normal targets, this is one of the places compiler-rt gets used. Or idk, to cast a float to an int and back.
by the way, I didn't congratulate you yet for your progress. Really great work, loving it!
I'd like to see this move forward, so I'll summarize the above. Please correct me if I'm wrong: This issue was fixed for the MSP430 backend by submitting a patch to LLVM. worked on a patch to do the same for NVPTX, but it was not submitted to LLVM. I imagine that since that was a year ago, the patch will need some work to bring it up to date. Is this problem still happening with more recent builds? Perhaps it's been fixed by upstream in the meantime. If it is still a problem, what would have to be done to fix it?
Well, my patch related to landed in LLVM about year ago. Now we can compile simple examples without any problems: with which produces the PTX assembly: And as for me, the issue can be closed. I was able to compile a kernel from  with latest nightly. So the hack with custom is obsolete now.

Discussion:
<del> Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621 </del> <ins> Subproject commit 859fb269364623b17e092efaba3f94e70ce97c5e </ins>

# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. <del> 2017-03-02 </del> <ins> 2017-03-04 </ins>